mirror of
https://github.com/ptitSeb/box86.git
synced 2026-11-07 17:43:14 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bedacef673 | ||
|
|
78bafd8b33 | ||
|
|
6ae9b28325 | ||
|
|
68f01f4267 | ||
|
|
d9f953ec82 | ||
|
|
d06795e979 | ||
|
|
979ce28de9 | ||
|
|
4aa2a95b59 | ||
|
|
b588709ad9 | ||
|
|
ca95cdcb91 | ||
|
|
bf046a68c4 | ||
|
|
490a4ab31c | ||
|
|
205133554f | ||
|
|
4df9b9ac6f | ||
|
|
0b5a943799 | ||
|
|
ede0e9d4c3 | ||
|
|
d33d231120 | ||
|
|
0c1ee23f55 | ||
|
|
f5554dec6e | ||
|
|
6239168118 | ||
|
|
fe9fea0807 | ||
|
|
d33917421b | ||
|
|
7c0b11e5e0 | ||
|
|
6a84e2eee9 | ||
|
|
26bad84244 | ||
|
|
eafd7081f3 | ||
|
|
2ad2851b2c | ||
|
|
f4924f6fd3 | ||
|
|
78920a61ad | ||
|
|
160f9f964f | ||
|
|
f81435cc2e | ||
|
|
62df3cbe98 | ||
|
|
b0b000a3f2 | ||
|
|
9e244e068d | ||
|
|
4a8d19da78 | ||
|
|
5a0fbcd7ba | ||
|
|
1ca20269b7 | ||
|
|
5b3eb577fc | ||
|
|
337d08d466 | ||
|
|
e784c34cb4 | ||
|
|
525c54a035 | ||
|
|
65cc054c9c | ||
|
|
64639ae623 | ||
|
|
74fb70a675 | ||
|
|
ca142fbc56 | ||
|
|
af498728b0 | ||
|
|
a68c5dc00e | ||
|
|
7e279e1963 | ||
|
|
01395347ce | ||
|
|
b5493c779f | ||
|
|
919b071990 | ||
|
|
46a9718d29 | ||
|
|
82e3fbfbad | ||
|
|
9004d2b80f | ||
|
|
ddb91106c2 | ||
|
|
9d7505a61c | ||
|
|
e1140c0401 | ||
|
|
76a0d9bfa3 | ||
|
|
a015c7a368 | ||
|
|
329ed0bb5b | ||
|
|
c3bc2808e9 | ||
|
|
584586dea8 | ||
|
|
8f84f73162 | ||
|
|
ce3bf7151a | ||
|
|
5cb5eb296d | ||
|
|
336b0a42e9 | ||
|
|
a32af2cf76 | ||
|
|
307a4f5010 | ||
|
|
5320b4f22f | ||
|
|
70a1d452f3 | ||
|
|
61869a91c7 | ||
|
|
68bc003fd2 | ||
|
|
f29912620d | ||
|
|
4a780af9fe | ||
|
|
6b6e6c874b | ||
|
|
d42d067945 | ||
|
|
17e80a3a09 | ||
|
|
674c5b5819 | ||
|
|
01629e1faf | ||
|
|
38a33ab15b | ||
|
|
2163365115 | ||
|
|
f67902f098 | ||
|
|
bfe47b408d | ||
|
|
aa2bea2d84 | ||
|
|
40c5b1b8d3 | ||
|
|
ee714259df | ||
|
|
aa7b620d8e | ||
|
|
794c16644b | ||
|
|
dda64c5b5e | ||
|
|
6784a79db0 | ||
|
|
564dfea143 | ||
|
|
7e9f514d8b | ||
|
|
68809a753d | ||
|
|
4ba390abd6 | ||
|
|
fe2b4cb8f3 | ||
|
|
dbef73bd75 | ||
|
|
ec19cc1e41 | ||
|
|
63e099a912 | ||
|
|
282309ee9b | ||
|
|
bd48cae19f | ||
|
|
b2d8a5ceb8 | ||
|
|
438677e61a | ||
|
|
44a7535791 | ||
|
|
2117a62dc1 | ||
|
|
99c27bed99 | ||
|
|
161cd9dc3f | ||
|
|
0228fcd7d3 | ||
|
|
3da4e03ddc | ||
|
|
8030af55b8 | ||
|
|
ee757c117c | ||
|
|
a93665abf4 | ||
|
|
e3c39f4f97 | ||
|
|
9bf5c20a9a | ||
|
|
c02a069c5e | ||
|
|
e5bf05c5c2 | ||
|
|
017d82d16e | ||
|
|
5f6d75da12 | ||
|
|
633919dd74 | ||
|
|
e83a119cbb | ||
|
|
00ac8ec1aa | ||
|
|
491f111caf | ||
|
|
8e92453f4c | ||
|
|
bc198c37d7 | ||
|
|
5ab84a6e78 | ||
|
|
334080dfd0 | ||
|
|
46012a6a8c | ||
|
|
3b546a6048 | ||
|
|
522b8d5fc0 | ||
|
|
74d3bb76da | ||
|
|
a28080e065 | ||
|
|
638b341ba5 | ||
|
|
c254dc3121 | ||
|
|
fe0778656b | ||
|
|
e478b99307 | ||
|
|
9d2cd89a7c | ||
|
|
be82ccbfcd | ||
|
|
18dfbb61b4 | ||
|
|
0f8e39d785 | ||
|
|
c4fdf490a2 | ||
|
|
55764011db | ||
|
|
9a483890b6 | ||
|
|
4421377624 | ||
|
|
f817d06e14 | ||
|
|
6b0b389a69 | ||
|
|
496899ffe3 | ||
|
|
7a05331e76 | ||
|
|
e7e725cb5e | ||
|
|
8385f6ad4e | ||
|
|
aeb3f7a438 | ||
|
|
d9fa04d2ed | ||
|
|
d4b5e585d1 | ||
|
|
8579037bb1 | ||
|
|
13cce1a4dd | ||
|
|
5724dfad87 | ||
|
|
f370bf77a8 | ||
|
|
fc3540ac08 | ||
|
|
c16f361c4a | ||
|
|
92a0f507af | ||
|
|
6bb7cdbdd4 | ||
|
|
1809a2bac3 | ||
|
|
430658c1a4 | ||
|
|
746383b72b | ||
|
|
d244151ca2 | ||
|
|
e4c1626638 | ||
|
|
c07cee0d01 | ||
|
|
43132bd9b0 | ||
|
|
ed982e1d2c | ||
|
|
7420ea052d | ||
|
|
044326d337 | ||
|
|
96c126bbcc | ||
|
|
ba0e524805 | ||
|
|
ba19f56338 | ||
|
|
14df602fa4 | ||
|
|
d972e205ac | ||
|
|
114f2b8cd2 | ||
|
|
87f8830d16 | ||
|
|
a0afe05995 | ||
|
|
ddd4d37ad1 | ||
|
|
ede296ef01 | ||
|
|
1307ce364d | ||
|
|
37fa84d762 | ||
|
|
b3e984bd22 | ||
|
|
7da5b9b7eb | ||
|
|
55b979f656 | ||
|
|
815a6c3ade | ||
|
|
33db7a8005 | ||
|
|
963ac3039e | ||
|
|
552db005b1 | ||
|
|
2d1e8cf1f2 | ||
|
|
8e44e8bf13 | ||
|
|
e7cc7b3409 | ||
|
|
4e5473150a | ||
|
|
e8e7597c62 | ||
|
|
f9b03600d1 | ||
|
|
88a8ebb1dc | ||
|
|
4445785ee1 | ||
|
|
3b3460cbba | ||
|
|
7eb6789a25 | ||
|
|
870fed75ad | ||
|
|
833c2809d9 | ||
|
|
24ec881fe5 | ||
|
|
d7d7bc91a2 | ||
|
|
1ea8dc828a | ||
|
|
ade7d82e52 | ||
|
|
fa5c6652b6 | ||
|
|
a5ab6b1520 | ||
|
|
bf74640917 | ||
|
|
420d309db6 | ||
|
|
c4d170ebb8 | ||
|
|
9cc69095d5 | ||
|
|
eb5dd2c005 | ||
|
|
39fbbe61a3 | ||
|
|
ba71080fb2 | ||
|
|
db176ad3e3 | ||
|
|
002638ef96 | ||
|
|
22b74477ac | ||
|
|
9c5a9ebba7 | ||
|
|
fce3f38e3a | ||
|
|
aabb600aed | ||
|
|
a062a8efa6 | ||
|
|
9b690667dc | ||
|
|
de7897c5c2 | ||
|
|
d3d431d5b1 | ||
|
|
6409f5d40a | ||
|
|
aeab3c815e | ||
|
|
4837797fae | ||
|
|
0ffc8682b1 | ||
|
|
cb35a8d85c | ||
|
|
5999255b5d | ||
|
|
a7654c6a80 | ||
|
|
2b3791f701 | ||
|
|
7f52a18fac | ||
|
|
ff8bb3b2e4 | ||
|
|
5b7cc6d4de | ||
|
|
1d9774c913 | ||
|
|
8b13ba26d7 | ||
|
|
8730f4daa6 | ||
|
|
52f4d2a1a6 | ||
|
|
6a498c373c | ||
|
|
007c7a887e | ||
|
|
922a8864e8 | ||
|
|
16383f4577 | ||
|
|
bc66bb5be9 | ||
|
|
84360f24c1 | ||
|
|
cad160205f | ||
|
|
807519e3c4 | ||
|
|
425ffb6e68 | ||
|
|
0ede6b8fa5 | ||
|
|
381d723462 | ||
|
|
cad8de8cd8 | ||
|
|
7d7d275e7e | ||
|
|
80db7d9a21 | ||
|
|
d8943af79a | ||
|
|
bcbf9360af | ||
|
|
6320b0928e | ||
|
|
74afa2551a | ||
|
|
dd733c4128 | ||
|
|
0eaa1b6c5e | ||
|
|
f595859cf0 | ||
|
|
85e0d01451 | ||
|
|
ec57e035d6 | ||
|
|
0d0b4d7364 | ||
|
|
aeb91fce74 | ||
|
|
e163bd842e | ||
|
|
2ff7bd1bc7 | ||
|
|
533c703b0d | ||
|
|
1d1a82f529 | ||
|
|
911b95a505 | ||
|
|
8209cf8398 | ||
|
|
02423d4a2d | ||
|
|
ba5c13fb6c | ||
|
|
ddd13bcab0 | ||
|
|
3b6800e38e | ||
|
|
6c2ebf91c0 | ||
|
|
a64d1de7cd | ||
|
|
d6ce7f5c16 | ||
|
|
1fe29c512f | ||
|
|
e76176b663 | ||
|
|
acbe0527d7 | ||
|
|
81d8f2f5c3 | ||
|
|
8976e77109 | ||
|
|
31bd7ebfbc | ||
|
|
487b979842 | ||
|
|
efd1408809 | ||
|
|
867e8aaa00 | ||
|
|
e3e5fd7568 | ||
|
|
7e6b012a08 | ||
|
|
546fe18836 | ||
|
|
1cb7683636 | ||
|
|
f89c7faf3c | ||
|
|
cf36c668b3 | ||
|
|
dd41352392 | ||
|
|
ec42322f23 | ||
|
|
3b8a9b5cc5 | ||
|
|
6d3b2fe902 | ||
|
|
819ec41320 | ||
|
|
40fd950b40 | ||
|
|
4f64c106a7 | ||
|
|
b2d5587ea1 | ||
|
|
4b020ab4f5 | ||
|
|
088a85c125 | ||
|
|
2bf60dc00d | ||
|
|
b5ffa0e92a | ||
|
|
258f7f9b50 | ||
|
|
07c403243d | ||
|
|
709de6a858 | ||
|
|
dfed557f61 | ||
|
|
f143771be8 | ||
|
|
fc20c410c0 | ||
|
|
677205a288 | ||
|
|
abb9acfd42 | ||
|
|
75dca68db0 | ||
|
|
5c1a8ad128 | ||
|
|
e4cf8f8c94 | ||
|
|
30968917a4 | ||
|
|
84ea9e3301 | ||
|
|
1f9c046919 | ||
|
|
cefe210184 | ||
|
|
02aa791fd9 | ||
|
|
d8c1341068 | ||
|
|
ca648ea128 | ||
|
|
daf5a9d91d | ||
|
|
16b95f2088 | ||
|
|
41dfcb559a | ||
|
|
37c871ec2e | ||
|
|
34bd1ff42f | ||
|
|
e0f1d4fecf | ||
|
|
c94d992ef6 | ||
|
|
bfe83d827d | ||
|
|
1c45795828 | ||
|
|
8dc5c164d8 | ||
|
|
326032aa23 | ||
|
|
b79e234da2 | ||
|
|
5bc6962a9d | ||
|
|
168717a90a | ||
|
|
dd6b0f6c9a | ||
|
|
0a3c678877 | ||
|
|
e2df6f6ce0 | ||
|
|
e58ebdac18 | ||
|
|
537312a91f | ||
|
|
11c08acd6c | ||
|
|
cf9a38fb02 | ||
|
|
83dff2bf25 | ||
|
|
49694f300a | ||
|
|
daddc8246e | ||
|
|
9f92377edc | ||
|
|
1ce392d968 | ||
|
|
bf730b43e2 | ||
|
|
a4adb47caf | ||
|
|
9317572874 | ||
|
|
eca39e6a8f | ||
|
|
4639dc8ffd | ||
|
|
5a9b34f54b | ||
|
|
dc07d477de | ||
|
|
db5efa8908 | ||
|
|
7d462dd837 | ||
|
|
76010f63c0 | ||
|
|
be7f72808b | ||
|
|
25f1e8e6fa | ||
|
|
047df311f0 | ||
|
|
bcdd99328c | ||
|
|
5cc76a0071 | ||
|
|
dee55a9ac2 | ||
|
|
9ff20da9bb | ||
|
|
0520f5abcd | ||
|
|
e1201ff0de | ||
|
|
bc2d7e7396 | ||
|
|
9a058a2416 | ||
|
|
49fea86b28 | ||
|
|
1617439d37 | ||
|
|
540459cb78 | ||
|
|
54b8522df6 | ||
|
|
bf65e606d3 | ||
|
|
5335a641df | ||
|
|
323ece7417 | ||
|
|
ca1fc0ffad | ||
|
|
c0706e227e | ||
|
|
995e4a9b68 | ||
|
|
7f53379552 | ||
|
|
3e17299a34 | ||
|
|
c63cdc9506 | ||
|
|
7965186817 | ||
|
|
f107612753 | ||
|
|
2295f7bb8b | ||
|
|
cc0845a9d3 | ||
|
|
e9019461b7 | ||
|
|
a19e3ed3dd | ||
|
|
10ec424e96 | ||
|
|
b838c8a7d0 | ||
|
|
0331af0643 | ||
|
|
24561fc37c | ||
|
|
d4ad5334b8 | ||
|
|
7fe3299282 | ||
|
|
23fef75ed5 | ||
|
|
62722b0618 | ||
|
|
e810dba2c9 | ||
|
|
7dfe545161 | ||
|
|
a5f3966b44 | ||
|
|
886573ed8b | ||
|
|
2758c1c955 | ||
|
|
591bafe8c3 | ||
|
|
211a8f42db | ||
|
|
fbc9029a8e | ||
|
|
ceb4b8b06d | ||
|
|
b88dda442f | ||
|
|
6e8163bded | ||
|
|
9b253abb53 | ||
|
|
e5e51e3ea3 | ||
|
|
6a2d9d7663 | ||
|
|
0546b1e212 | ||
|
|
320e6dae72 | ||
|
|
96f944c804 | ||
|
|
fd0e2195f7 | ||
|
|
d2f130a834 | ||
|
|
a3459712ce | ||
|
|
8bf2e49164 | ||
|
|
0f5cd39a64 | ||
|
|
e0ed0076f2 | ||
|
|
bfd4ad39af | ||
|
|
a8ff7d8769 | ||
|
|
39c77beb1c | ||
|
|
d576f7af39 | ||
|
|
74c3f43f75 | ||
|
|
ecacace01d | ||
|
|
a3b0149a84 | ||
|
|
63111577ec | ||
|
|
eb68520709 | ||
|
|
a7bf2c6cc3 | ||
|
|
190788efd9 | ||
|
|
2592a6a342 | ||
|
|
16ee4c348d | ||
|
|
8389097cd3 | ||
|
|
79a885c15e | ||
|
|
eb7c683a6d | ||
|
|
95b2b314f6 | ||
|
|
07eb0aa5cd | ||
|
|
fdce28590a | ||
|
|
572613e377 | ||
|
|
29e597b4ed | ||
|
|
981c464c36 | ||
|
|
d406c5717c | ||
|
|
92208efd24 | ||
|
|
edef6d7f99 |
No files matched your search
+1
-1
@@ -1,6 +1,6 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
github: ptitSeb
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
|
||||
@@ -4,3 +4,5 @@ build*/
|
||||
.gdb_history
|
||||
src/git_head.h
|
||||
backup/
|
||||
box86_update.sh
|
||||
restore_backup.sh
|
||||
-102
@@ -1,102 +0,0 @@
|
||||
v0.1.8
|
||||
======
|
||||
* Fixes on some float to int x87 convertions opcodes
|
||||
* Reworked all callback mecanisms
|
||||
* Added libturbojpeg wrapping (and a hack for zoom to force using native one)
|
||||
* Added BOX86_SAFEMMAP env. var.
|
||||
* Reworked dynarec memory manager
|
||||
* Added a few opcodes
|
||||
* Improve elfloader to not force PltResolver all the time (fixing SuperHexagon and maybe other)
|
||||
* Reworked Exet and Cancel Thread mecanism
|
||||
* Added wrapped libldap_r and liblber library (used by wine)
|
||||
* Reworked Dynarec block handling, and remove the "AddMark" mecanism that wasn't efficient enough
|
||||
* Added TokiTori 2+ detection and runtime patch on PI
|
||||
* Fixes on elfloader with TLS object
|
||||
|
||||
v0.1.6
|
||||
======
|
||||
* Changes in Dynarec to make flags optimizations before CALL and RET opcode less aggressive
|
||||
* Added Vulkan wrapper
|
||||
* Improved wrapping of SDL_mixer/ SDL2_mixer lib
|
||||
* Improved wrapping of some gtk structures
|
||||
* Added a quick and dirty wrapping of Gtk3 (based on current gtk2)
|
||||
* Improved the signal handling, should be more stable now (the signal handler from syscall still need some works)
|
||||
* Added RK3399 profile, and some hints to build the 32bits box86 on 64bits OS
|
||||
* Fixed some wrapped printf formating not handled correctly
|
||||
* Fixed some buserror with the new LOCK mecanism handling
|
||||
* A few more Dynarec opcodes added
|
||||
* If winedbg is tried to be launched, exit without launching it (it doesn't work anyway)
|
||||
|
||||
v0.1.4
|
||||
======
|
||||
* Change in Dynarec memory handling, to simplify it (and hopefully optimized it)
|
||||
* Even more opcodes added.
|
||||
* And some more Dynarec opcodes.
|
||||
* Fixed some issue were PltResolver was injected but should not
|
||||
* Fixed many Dynarec and non dynarec opcodes
|
||||
* Improved Signal handling
|
||||
* Added a few more wrapped lib (like curl)
|
||||
* Gallium9 is wrapped (thx @icecream95)
|
||||
* Fixed and simplied many wrapped functions (especialy the one were a callback is involved)
|
||||
* Fixed Dynarec "freeing" a Dynablock somthime corrupting the heap (happens in case of JIT mainly)
|
||||
* Optimized the way LOCK prefix work when using Dynarec on ARM
|
||||
* Printer of ARM opcode (for dumping Dynarec blocks) improvement (thx @rajdakin)
|
||||
|
||||
v0.1.2
|
||||
======
|
||||
* The Dynarec now handle JIT code
|
||||
* Added support for Unity games (not perfect yet)
|
||||
* Added support for Wine (not perfect yet). You need an x86 build of Wine to use it
|
||||
* Added support for Steam (not perfect yet). Note that steam have limited functionnalities on 32bits (only mini-mode is available)
|
||||
* More wrapped libs
|
||||
* Added support for "PltResolver", so order of library is less important and many symbol are resolved at runtime
|
||||
* Added an option to build box86 as a lib (to wrapped dynamic library)
|
||||
* Better Signal handling (not perfect yet)
|
||||
* More opcodes added, more opcode fixes.
|
||||
* More Dynarec opcodes.
|
||||
* Added support for FS:, and creating custom selector (needed by Wine)
|
||||
* There is now 1 x86emu_t structure per thread (simplifying/optimising many callback handling)
|
||||
* Box86 now have a logo!
|
||||
* Added options handling (only version and help for now). Now it's much usefull exept for version printing.
|
||||
|
||||
|
||||
v0.1.0
|
||||
=======
|
||||
* Dynarec!!! Only for ARM (note that dynarec doesn't support JITed code for now)
|
||||
* Added real support for getcontext/set/context/makecontext/swapcontext
|
||||
* Preliminary signal handling
|
||||
* Fixes to SDL(1/2) Image and SDL1 Mixer, and to SDL1.2 RWops usage
|
||||
* Fixed numerous issues in opcodes (both interpretor and dynarec). FTL works fine now, among many others
|
||||
* Added wrapped gtk support (still ongoing, many libs involved)
|
||||
* Make loading of libs more configurable
|
||||
* If a wrapped native libs is not found, try to use emulated one
|
||||
* Add en env. var. to force use of emulated lib for certain libs
|
||||
* Add an env. var. to define wich libGL to use
|
||||
* Added Install / Uninstall target (using systemd binfmt)
|
||||
* Added more hardware target (RPis, GameShell...)
|
||||
* Wrapped more libs (including FreeType, smpeg, ncurses, sndfile...)
|
||||
|
||||
v0.0.4
|
||||
=======
|
||||
* Improved the Init of dependant Libs. More things work now.
|
||||
* Added a lot of wrapped functions.
|
||||
* Added a few wrapped libs (like libz or some other x11 related libs)
|
||||
* For trace enabled build, Trace can be enabled only after a certain amount of opcodes (still, a debugger would be better)
|
||||
* Some fixes in a few opcodes, and implemented x87 rounding (SuperMeatBoy behaves better now)
|
||||
* FTL 1.6.9 still have corrupted music, but older 1.5.13 seems fine (different set of libs)
|
||||
|
||||
v0.0.2
|
||||
=======
|
||||
* A full commercial games runs fine on the Pandora: Airline Tycoon Deluxe
|
||||
* Implemented all planed subpart of Box86 except JIT
|
||||
* CPU Emulation is at 75%, roughly, including x87 and SSE/SSE2. MMX is barely implemented, but barely used anyway
|
||||
* x87 emulation is simplified, no real x87 State handling (but should not be mandatory, as native libm is used)
|
||||
* No Signal handling yet
|
||||
* ELF Loader is crude and probably full of bug. Also, the Init of libs is defered after all symbols are resolved for now.
|
||||
* Wrapped lib include libc, libm, rt, pthread, libdl, dllinux, libasound, GL, GLU, SDL1/mixer/image, SDL2/mixer/image/smpeg, OpenAL/ALUT, libz, libpng16, vorbisfile, x11/xrandr/xxf86vm.
|
||||
* Most wrapped libs are still partially implemented (SDL1 & GL should be complete)
|
||||
* Implemented specific mecanism for SDL(1/2) RWops, to be able to used them both in Native and x86 world
|
||||
* WorldOfGoo works, but painfully slow on th Pandora (too much double math, and lack of JIT)
|
||||
* FTL works, but sound is broken (issue with thread? asound? or CPU core?)
|
||||
* Limbo launch but crash before main menu
|
||||
|
||||
+98
-29
@@ -5,22 +5,30 @@ option(PYRA "Set to ON if targeting an OpenPandora device" ${PYRA})
|
||||
option(RPI2 "Set to ON if targeting an RaspberryPI2 device" ${RPI2})
|
||||
option(RPI3 "Set to ON if targeting an RaspberryPI3 device" ${RPI3})
|
||||
option(RPI4 "Set to ON if targeting an RaspberryPI4 device" ${RPI4})
|
||||
option(RPI4ARM64 "Set to ON if targeting an RaspberryPI4 device with multiarch arm64 and armhf" ${RPI4ARM64})
|
||||
option(RK3399 "Set to ON if targeting an Rockchip RK3399 based device" ${RK3399})
|
||||
option(GAMESHELL "Set to ON if targeting a GameShell device" ${GAMESHELL})
|
||||
option(ODROID "Set to ON if targeting an ODroid device" ${ODROID})
|
||||
option(POWER9 "Set to ON if targeting a POWER9 processor" ${POWER9})
|
||||
option(ANDROID "Set to ON if targeting an Android device" ${ANDROID})
|
||||
option(USE_CCACHE "Set to ON to use ccache if present in the system" ${USE_CCACHE})
|
||||
option(HAVE_TRACE "Set to ON to have Trace ability (needs ZydisInfo library)" ${HAVE_TRACE})
|
||||
option(NOLOADADDR "Set to ON to avoid fixing the load address of Box86" ${NO_LOADAADR})
|
||||
option(NOGETCLOCK "Set to ON to avoid using clock_gettime with CLOCK_MONOTONIC_COARSE for RDTSC opcode (use gltimeofday instead)" ${NOGETCLOCK})
|
||||
option(NOGIT "Set to ON if not building from a git clone repo (like when building from a zip download from github)" ${NOGIT})
|
||||
if(PANDORA OR PYRA OR RPI2 OR RPI3 OR RPI4 OR GAMESHELL OR ODROID OR RK3399)
|
||||
if(PANDORA OR PYRA OR RPI2 OR RPI3 OR RPI4 OR GAMESHELL OR ODROID OR RK3399 OR RPI4ARM64)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
set(ARM_DYNAREC ON CACHE BOOL "")
|
||||
endif()
|
||||
if(ANDROID)
|
||||
set(NOLOADADDR ON CACHE BOOL "")
|
||||
endif()
|
||||
option(LD80BITS "Set to ON if host device have 80bits long double (i.e. i386)" ${LD80BITS})
|
||||
option(NOALIGN "Set to ON if host device doesn't need re-align (i.e. i386)" ${NOALIGN})
|
||||
option(ARM_DYNAREC "Set to ON to use ARM Dynamic Recompilation (WIP, don't use yet)" ${ARM_DYNAREC})
|
||||
option(ARM_DYNAREC "Set to ON to use ARM Dynamic Recompilation" ${ARM_DYNAREC})
|
||||
option(POWERPCLE "Set to ON if targeting a little-endian PowerPC device" ${POWERPCLE})
|
||||
option(SYSV_VARARG "Set to ON if host device uses SysVR4 vararg calling convention" ${SYSV_VARARG})
|
||||
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.12.2")
|
||||
find_package(PythonInterp 3)
|
||||
@@ -38,7 +46,7 @@ else()
|
||||
set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE} CACHE INTERNAL "The Python3 executable" FORCE)
|
||||
endif()
|
||||
|
||||
if(RK3399)
|
||||
if(RK3399 OR RPI4ARM64)
|
||||
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
|
||||
#set(CMAKE_ASM_COMPILER arm-linux-gnueabihf-as) #will use gcc in fact
|
||||
set(CMAKE_C_COMPILER_TARGET arm-linux-gnueabihf)
|
||||
@@ -87,6 +95,12 @@ if(RPI4)
|
||||
add_definitions(-marm -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
endif()
|
||||
if(RPI4ARM64)
|
||||
add_definitions(-DRPI)
|
||||
add_definitions(-DRPI4ARM64)
|
||||
add_definitions(-marm -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
endif()
|
||||
if(ODROID)
|
||||
add_definitions(-DODROID)
|
||||
add_definitions(-mcpu=cortex-a9 -mfpu=neon-vfpv4 -mfloat-abi=hard -marm)
|
||||
@@ -98,6 +112,10 @@ if(RK3399)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a72+crypto")
|
||||
endif()
|
||||
|
||||
if(POWER9)
|
||||
add_definitions(-mcpu=power9 -mtune=power9)
|
||||
endif()
|
||||
|
||||
if(NOGIT)
|
||||
add_definitions(-DNOGIT)
|
||||
endif()
|
||||
@@ -132,6 +150,14 @@ if(ARM_DYNAREC)
|
||||
enable_language(ASM)
|
||||
endif()
|
||||
|
||||
if(POWERPCLE)
|
||||
add_definitions(-DPOWERPCLE)
|
||||
endif()
|
||||
|
||||
if(SYSV_VARARG)
|
||||
add_definitions(-DSYSV_VARARG)
|
||||
endif()
|
||||
|
||||
if(NOGETCLOCK)
|
||||
add_definitions(-DNOGETCLOCK)
|
||||
endif()
|
||||
@@ -176,6 +202,7 @@ set(ELFLOADER_SRC
|
||||
"${BOX86_ROOT}/src/main.c"
|
||||
"${BOX86_ROOT}/src/box86context.c"
|
||||
"${BOX86_ROOT}/src/build_info.c"
|
||||
"${BOX86_ROOT}/src/custommem.c"
|
||||
"${BOX86_ROOT}/src/tools/bridge.c"
|
||||
"${BOX86_ROOT}/src/tools/pathcoll.c"
|
||||
"${BOX86_ROOT}/src/tools/fileutils.c"
|
||||
@@ -205,7 +232,6 @@ set(ELFLOADER_SRC
|
||||
"${BOX86_ROOT}/src/libtools/myalign.c"
|
||||
"${BOX86_ROOT}/src/libtools/myalign64.c"
|
||||
"${BOX86_ROOT}/src/libtools/myfts.c"
|
||||
"${BOX86_ROOT}/src/libtools/obstack.c"
|
||||
"${BOX86_ROOT}/src/libtools/sdl1rwops.c"
|
||||
"${BOX86_ROOT}/src/libtools/sdl2rwops.c"
|
||||
"${BOX86_ROOT}/src/libtools/signals.c"
|
||||
@@ -214,6 +240,9 @@ set(ELFLOADER_SRC
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec.c"
|
||||
"${BOX86_ROOT}/src/wrapped/generated/wrapper.c"
|
||||
)
|
||||
if(NOT ANDROID)
|
||||
list(APPEND ELFLOADER_SRC "${BOX86_ROOT}/src/libtools/obstack.c")
|
||||
endif()
|
||||
|
||||
set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibc.c"
|
||||
@@ -227,10 +256,13 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibm.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl1.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl1mixer.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl1net.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl1image.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl1sound.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl1ttf.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl2mixer.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl2net.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl2image.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl2ttf.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsmpeg.c"
|
||||
@@ -247,6 +279,7 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxfixes.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxcursor.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxrender.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxft.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxi.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxss.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxpm.c"
|
||||
@@ -271,10 +304,8 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxmu.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibz.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedopenal.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedalure.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedalut.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibjpeg.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibjpeg62.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedturbojpeg.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedcurl.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedudev0.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedudev1.c"
|
||||
@@ -283,6 +314,7 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibdrm.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedcrypto.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibssl.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibcrypt.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedutil.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibuuid.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibresolv.c"
|
||||
@@ -292,6 +324,7 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedfontconfig.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedfreetype.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedbz2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedexpat.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibsm.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibice.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibusb1.c"
|
||||
@@ -316,6 +349,7 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappeddbusmenuglib.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedappindicator.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedatk.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedatkbridge.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedpangoft2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedpangocairo.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgthread2.c"
|
||||
@@ -335,14 +369,28 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedxslt.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedldapr.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlber.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlcms2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappednsl.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlcms2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedkrb5.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgssapikrb5.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibtiff.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedldlinux.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedcrashhandler.c"
|
||||
)
|
||||
if(NOT ANDROID)
|
||||
list(APPEND WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibjpeg.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibjpeg62.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedturbojpeg.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
set(WRAPPEDS_HEAD "${BOX86_ROOT}/src/wrapped/wrappedd3dadapter9_gen.h")
|
||||
# If BOX86_ROOT contains a ".c", the build breaks...
|
||||
string(REPLACE ".c" "_private.h" MODROOT ${BOX86_ROOT})
|
||||
set(WRAPPEDS_HEAD "")
|
||||
foreach(A ${WRAPPEDS})
|
||||
string(REPLACE ".c" "_private.h" B ${A})
|
||||
string(REPLACE ".c" "_private.h" C ${A})
|
||||
string(REPLACE "${MODROOT}" "${BOX86_ROOT}" B ${C})
|
||||
set(WRAPPEDS_HEAD ${WRAPPEDS_HEAD} ${B})
|
||||
set_source_files_properties(${A} PROPERTIES OBJECT_DEPENDS ${B})
|
||||
endforeach()
|
||||
@@ -351,7 +399,10 @@ set(WRAPPER "${BOX86_ROOT}/src/wrapped/generated/wrapper.c" "${BOX86_ROOT}/src/w
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT "${BOX86_ROOT}/src/wrapped/generated/functions_list.txt"
|
||||
COMMAND "${PYTHON_EXECUTABLE}" "${BOX86_ROOT}/rebuild_wrappers.py" "${BOX86_ROOT}" "PANDORA" "HAVE_LD80BITS" "NOALIGN" "HAVE_TRACE" "--" ${WRAPPEDS_HEAD}
|
||||
COMMAND "${PYTHON_EXECUTABLE}" "${BOX86_ROOT}/rebuild_wrappers.py"
|
||||
"${BOX86_ROOT}"
|
||||
"PANDORA" "HAVE_LD80BITS" "NOALIGN" "HAVE_TRACE" "POWERPCLE" "ANDROID" "--"
|
||||
${WRAPPEDS_HEAD}
|
||||
MAIN_DEPENDENCY "${BOX86_ROOT}/rebuild_wrappers.py"
|
||||
DEPENDS ${WRAPPEDS} ${WRAPPEDS_HEAD}
|
||||
BYPRODUCTS ${WRAPPER}
|
||||
@@ -378,8 +429,7 @@ if(ARM_DYNAREC)
|
||||
|
||||
"${BOX86_ROOT}/src/dynarec/arm_prolog.S"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_epilog.S"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_linker.S"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_table.S"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_next.S"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_lock_helper.S"
|
||||
)
|
||||
|
||||
@@ -460,7 +510,11 @@ else()
|
||||
add_library(${BOX86} OBJECT ${ELFLOADER_SRC} ${WRAPPEDS} "${BOX86_ROOT}/src/git_head.h")
|
||||
endif()
|
||||
if(ARM_DYNAREC)
|
||||
target_link_libraries(${BOX86} dynarec m dl rt pthread)
|
||||
if(ANDROID)
|
||||
target_link_libraries(${BOX86} dynarec m dl)
|
||||
else()
|
||||
target_link_libraries(${BOX86} dynarec m dl rt pthread)
|
||||
endif()
|
||||
endif()
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.13")
|
||||
set_target_properties(${BOX86} PROPERTIES LINK_FLAGS -rdynamic)
|
||||
@@ -478,7 +532,11 @@ else(BOX86LIB)
|
||||
add_executable(${BOX86} ${ELFLOADER_SRC} ${WRAPPEDS} "${BOX86_ROOT}/src/git_head.h")
|
||||
add_dependencies(${BOX86} WRAPPERS)
|
||||
add_dependencies(${BOX86} PRINTER)
|
||||
target_link_libraries(${BOX86} m dl rt pthread)
|
||||
if(ANDROID)
|
||||
target_link_libraries(${BOX86} m dl)
|
||||
else()
|
||||
target_link_libraries(${BOX86} m dl rt pthread)
|
||||
endif()
|
||||
if(ARM_DYNAREC)
|
||||
target_link_libraries(${BOX86} dynarec)
|
||||
endif()
|
||||
@@ -519,76 +577,87 @@ if(NOT TARGET uninstall)
|
||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
||||
endif()
|
||||
|
||||
add_test(test01 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
add_test(NAME bootSyscall COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test01 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref01.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test02 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
add_test(NAME bootSyscallC COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test02 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref02.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test03 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
add_test(NAME printf COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test03 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref03.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test04 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
add_test(NAME args COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test04 -D TEST_ARGS2=yeah -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref04.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test05 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
add_test(NAME maths1 COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test05 -D TEST_ARGS2=7 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref05.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test06 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
add_test(NAME threadsStart COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test06 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref06.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test07 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
add_test(NAME trig COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test07 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref07.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test08 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
add_test(NAME pi COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test08 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref08.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test09 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
add_test(NAME fork COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test09 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref09.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test10 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
add_test(NAME cppThreads COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test10 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref10.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test11 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
add_test(NAME tlsData COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test11 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref11.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test12 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
add_test(NAME fpu COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test12 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref12.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test13 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
add_test(NAME contexts COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test13 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref13.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test14 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
add_test(NAME conditionalThreads COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test14 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref14.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
# WIP
|
||||
#add_test(NAME linkingIndirectNoversion COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test15 -D TEST_OUTPUT=tmpfile.txt
|
||||
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref15.txt
|
||||
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
#
|
||||
#add_test(NAME linkingIndirectVersion COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test16 -D TEST_OUTPUT=tmpfile.txt
|
||||
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref16.txt
|
||||
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests/extensions/*.c")
|
||||
foreach(file ${extension_tests})
|
||||
get_filename_component(testname "${file}" NAME_WE)
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
# box86
|
||||
|
||||

|
||||
Linux Userspace x86 Emulator with a twist
|
||||
|
||||
Box86 lets you run x86 Linux programs (such as games) on non-x86 Linux, like ARM (host system needs to be 32bit little-endian).
|
||||
|
||||
You *NEED* a 32-bit subsystem to run and build Box86. Box86 is useless on 64-bit only systems. Also, you *NEED* a 32-bit toolchain to build Box86. A toolchain that only support 64-bit will not compile Box86, and you'll get errors (typically on aarch64, you get "-marm" not recognized, and you'll need a multiarch or chroot environnement).
|
||||
|
||||
Because Box86 uses the native versions of some "system" libraries, like libc, libm, SDL, and OpenGL, it's easy to integrate and use, and performance can be surprisingly high in some cases.
|
||||
|
||||
Most x86 Games need OpenGL, so on ARM platforms a solution like [gl4es](https://github.com/ptitSeb/gl4es) is usually necessary.
|
||||
|
||||
Box86 now integrates a DynaRec (dynamic recompiler) for the ARM platform, providing a speed boost between 5 to 10 times faster than only using the interpreter.
|
||||
|
||||
Many games already work, for example: WorldOfGoo, Airline Tycoon Deluxe, and FTL. Many of the GameMaker Linux games also run fine (there a long list, among them are UNDERTALE, A Risk of Rain, and Cook Server Delicious)
|
||||
|
||||
If you are serious about developing Box86, you should install ccache and activate its support in the cmake project (use ccmake for example)
|
||||
To enable TRACE (i.e. dumping to stdout all individual x86 instructions executed, with dump of registers), you'll also need [Zydis library](https://github.com/zyantific/zydis) available on your system.
|
||||
|
||||
Some x86 internal opcodes use parts of "Realmode X86 Emulator Library", see [x86primop.c](src/x86primop.c) for copyright details
|
||||
|
||||
Here are 6 videos, the first 2 of "Airline Tycoon Deluxe" and "Heretic 2" running on a gigahertz OpenPandora (the second one use the dynarec), and the next 2 of "Bit.Trip.Runner" and "Neverwinter Night" running on an ODroid XU4 (without dynarec), and the last 2 on a Pi4: Shovel Knight (video from @ITotalJustice) and Freedom Planet (video from @djazz), also without dynarec.
|
||||
|
||||
[](https://www.youtube.com/watch?v=bLt0hMoFDLk) [](https://www.youtube.com/watch?v=MM7kWYts7IA) [](https://www.youtube.com/watch?v=8hr71S029Hg) [](https://www.youtube.com/watch?v=B4YN37z3-ws) [](https://www.youtube.com/watch?v=xk8Q30mxqPg) [](https://www.youtube.com/watch?v=_QMRMVvYrqU)
|
||||
|
||||
You can find many more Box86 video on [PI Lab Channel](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g) [](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g).
|
||||
|
||||
Compatibility list is there: https://github.com/ptitSeb/box86-compatibility-list/issues
|
||||
|
||||
<img src="Box86Icon.png" width="96" height="96">
|
||||
|
||||
Logo and Icon made by @grayduck, thanks!
|
||||
|
||||
Note that this project is not to be mystaken with [86box](https://github.com/86Box/86Box), a nice "Full system" emulator specialized in early (to fairly recent) PC hardware.
|
||||
|
||||
----
|
||||
|
||||
Discord
|
||||
----
|
||||
|
||||
If you want to discuss about box86 on Discord, there is a frendly server there: [PI Lab Discord](https://discord.gg/Fh8sjmu)
|
||||
|
||||
|
||||
----
|
||||
|
||||
Compiling
|
||||
----
|
||||
Compilation instructions can be found [here](COMPILE.md)
|
||||
|
||||
----
|
||||
|
||||
Usage
|
||||
----
|
||||
|
||||
There are a few environment variables avaiable to control the behaviour of Box86.
|
||||
|
||||
See [here](USAGE.md) for all variables and what they do.
|
||||
|
||||
Note that now the Dynarec of Box86 uses a mecanism with Memory Protection and a SegFault signal handler to handle JIT code. That means if you want to use gdb to debug running a program that use JIT'd code (like mono/Unity3D), you will have many "normal" segfaults triggering. I suggest you use something like `handle SIGSEGV nostop` in gdb to not stop at each segfault, and maybe put a breakpoint inside `my_memprotectionhandler` in `signals.c` if you want to trap SegFaults.
|
||||
|
||||
----
|
||||
|
||||
Version history
|
||||
----
|
||||
|
||||
The change log is available [here](CHANGELOG.md)
|
||||
|
||||
----
|
||||
|
||||
A note about 64-bit platforms
|
||||
----
|
||||
|
||||
Because Box86 works by directly translating function calls from x86 to host system, the host system (the one Box86 is running on) needs to have 32-bit libraries. Box86 doesn't include any 32-bit <-> 64-bit translation. So basically, to run Box86 on, for example, an ARM64 platform, you will need to build Box86 for ARM 32-bit, and also need to have a chroot with 32-bit libraries.
|
||||
|
||||
Also note that, even if, on day, there is a Box86_64, this one will only be able to run x86_64 binaries on 64-bit platforms. You will still need Box86 (and see 32-bit chroot) to run x86 binaries (in fact, the same is the case on actual x86_64 Linux).
|
||||
|
||||
----
|
||||
|
||||
A note about Unity game emulation
|
||||
----
|
||||
|
||||
Running Unity games is a hit or miss for now. Unity uses Mono (which uses signals that are not well emulated enough), and a runtime embedded in the main binary. A solution would be to use a native version of the libmono library used by Unity (it can be found here: https://github.com/Unity-Technologies/mono and needs to be built from source). But the wrapping of this lib is tricky, and not done for now, so the only solution is to emulate everything. The tricky part is to emulate the "JIT" code emitted by Mono, however with he new "protected memory" mechanism implemented it is running with correct performance now.
|
||||
You should also note that some Unity3D games require OpenGL 3+ which can be tricky to provide on ARM SBC (single-board computers) for now.
|
||||
|
||||
TL;DR: Not all Unity games work and can require a high OpenGL profile, but the speed, for the ones running, should be correct now.
|
||||
|
||||
----
|
||||
|
||||
A note about Steam
|
||||
----
|
||||
|
||||
Linux Steam can run now with box86. But it's still a bit unstable., and not everything works. First is steam crashes after the Sign in, you may need to add libappindicator. On debian it's `sudo apt install libappindicator1`.
|
||||
Once open, Steam will only work on "Small mode" and in "Big Picture", not in the regular "Browser mode". So go in the "View" menu and witch to Small view (or Compact view?), else the list will stay empty (this is because some steam component used in the browser view are only 64bits now).
|
||||
Final word, to avoid the "libc.so.6 is absent" message, you can use `STEAMOS=1` and `STEAM_RUNTIME=1` export.
|
||||
(Steam for Windows install fine but doesn't work yet)
|
||||
Some steam games (most of Source engine one, like "Portal" or "Half-Life 2") use libtcmalloc. Box86 will detect it's use and will try to LD_PRELOAD it, for better compatibility. While it should work without, it is better to add it to your system if you intend to play those game (something like `sudo apt install libtcmalloc-minimal4` on debian familly)
|
||||
|
||||
----
|
||||
|
||||
A note about Wine
|
||||
----
|
||||
|
||||
Wine is now partly supported. Wine integreted program all runs, annd some windows program and games now run fine. Don't forget most Windows games use Direct3D, that may require a complete OpenGL driver and as high profile as possible (and gl4es with ES2 backend have issue with Wine for now). Also, vulkan is not wrapped on box86, so vk3d is not usable yet, even if supported by the hardware.
|
||||
A not if you plan to use box86 with wine on Raspberry PI 3 or earlier: those model use a default OS that have a kernle with a 2/2 Split (meaning 2G of space for user program, and 2G of space for Kernel). This is not compatible with wine, that need to access memory > 2Gb address. So you'll need to reconfigure your kernel for a 3G/1G split. Use your favorite search engine to find tutos on how to do that.
|
||||
|
||||
----
|
||||
|
||||
Final words
|
||||
----
|
||||
|
||||
(If you use Box86 in your project, please don't forget to mention Box86)
|
||||
@@ -1,157 +0,0 @@
|
||||
Usage
|
||||
----
|
||||
|
||||
There are many environment variable to control Box86 behaviour.
|
||||
|
||||
#### BOX86_LOG
|
||||
Controls the Verbose level of the log
|
||||
* 0
|
||||
* NONE : No message (except some fatal error)
|
||||
* 1
|
||||
* INFO : Current default. Show some log
|
||||
* 2
|
||||
* DEBUG : Verbose a lot of stuffs (like relocations or function called)
|
||||
* 3
|
||||
* DUMP : All DEBUG plus DUMP of all ELF Info
|
||||
|
||||
#### BOX86_NOBANNER
|
||||
Control Box86 printing it's version and build
|
||||
* 0 : Enabled the printing
|
||||
* 1 : Diable the printing
|
||||
|
||||
#### BOX86_LD_LIBRARY_PATH
|
||||
Controls the folder scanned to look for x86 libs. Default is current folder and `lib` in current folder.
|
||||
Also `/usr/lib/i386-linux-gnu` and `/lib/i386-linux-gnu` are added if they exists
|
||||
|
||||
#### BOX86_PATH
|
||||
Controls the folder scanned to look for x86 executable. Default is current folder and `bin` in current folder.
|
||||
|
||||
#### BOX86_DLSYM_ERROR
|
||||
* 0 : default. Don't log `dlsym` error
|
||||
* 1 : Log dlsym error
|
||||
|
||||
#### BOX86_TRACE_FILE
|
||||
Send all log and trace to a file instead of `stdout`
|
||||
Also, if name contains `%pid` then this is replaced by actual PID of box86 instance
|
||||
|
||||
#### BOX86_TRACE
|
||||
Only on build with trace enabled. Trace allow the logging of all instruction execute, along with register dump
|
||||
* 0 : No trace
|
||||
* 1 : Trace enabled. The trace start after the init of all depending libs is done
|
||||
* symbolname : Trace only `symbolname` (trace is disable if the symbol is not found)
|
||||
* 0xXXXXXXX-0xYYYYYYY : trace only between the 2 addresses
|
||||
|
||||
#### BOX86_TRACE_INIT
|
||||
Use BOX86_TRACE_INIT instead of BOX_TRACE to start trace before init of Libs and main program
|
||||
* 0 : No trace
|
||||
* 1 : Trace enabled. The trace start with the init of all depending libs is done
|
||||
|
||||
#### BOX86_TRACE_START
|
||||
Only on build with trace enabled.
|
||||
* NNNNNNN : Start trace only after NNNNNNNN opcode execute (number is an `uint64_t`)
|
||||
|
||||
#### BOX86_TRACE_XMM
|
||||
Only on build with trace enabled.
|
||||
* 0 : Default, the XMM (i.e. SSE/SSE2) register will not be logged with the general and x87 registers
|
||||
* 1 : Dump the XMM registers
|
||||
|
||||
#### BOX86_LOAD_ADDR
|
||||
Try to load at 0xXXXXXX main binaray (if binary is a PIE)
|
||||
* 0xXXXXXXXX the load address (only active on PIE programs)
|
||||
|
||||
#### BOX86_NOSIGSEGV
|
||||
To disable handling of SigSEGV (to ease debugging mainly)
|
||||
* 0 : default, let x86 program set sighandler for SEGV
|
||||
* 1 : disable handling of SigSEGV
|
||||
|
||||
#### BOX86_NOSIGILL
|
||||
To disable handling of SigILL (to ease debugging mainly)
|
||||
* 0 : default, let x86 program set sighandler for Illegal Instruction
|
||||
* 1 : disable handling of SigILL
|
||||
|
||||
#### BOX86_X11COLOR16
|
||||
PANDORA only: to try convert X11 color from 32 bits to 16 bits (to avoid light green on light cyan windows
|
||||
* 0 : default, don't touch X11 colors
|
||||
* 1 : Change colors arguments in XSetForeground, XSetBackground and XCreateGC
|
||||
|
||||
#### BOX86_X11THREADS
|
||||
To call XInitThreads when loading X11 (for old Loki games with Loki_Compat lib)
|
||||
* 0 : default, don't force call XInitThreads
|
||||
* 1 : Call XInitThreads as soon as libX11 is loaded
|
||||
|
||||
#### BOX86_X11GLX
|
||||
To Force libX11 GLX extension to be present
|
||||
* 0 : Disable the force.
|
||||
* 1 : default, GLX will always be present when using XQueryExtension
|
||||
|
||||
#### BOX86_DYNAREC_DUMP
|
||||
* 0 : Disable Dynarec blocks dump (default)
|
||||
* 1 : Enable Dynarec blocks dump
|
||||
* 2 : Enable Dynarec blocks dump with some colors
|
||||
|
||||
#### BOX86_DYNAREC_LOG
|
||||
Set level of DynaRec log
|
||||
* 0 :
|
||||
* NONE : No Log for DynaRec
|
||||
* 1 :
|
||||
* INFO : Minimum Dynarec Log (only unimplemented OpCode)
|
||||
* 2 :
|
||||
* DEBUG : Debug Log for Dynarec (with detail on block created / executed)
|
||||
* 3 :
|
||||
* VERBOSE : All above plus more
|
||||
|
||||
#### BOX86_DYNAREC
|
||||
* 0 : Disable Dynarec
|
||||
* 1 : Enable Dynarec (default)
|
||||
|
||||
#### BOX86_DYNAREC_LINKER
|
||||
* 0 : Disable Dynarec Linker (use that on debug, with dynarec log >= 2, to have detail on wich block get executed)
|
||||
* 1 : Enable Dynarec Linker (default)
|
||||
|
||||
#### BOX86_DYNAREC_SAFEMMAP
|
||||
* 0 : Default. Some mmp/mmap64 are consider unsafe (depending of flags mainly)
|
||||
* 1 : Consider all mmap/mmap64 safe to use linker (potential speedup, but potential crash for apps using JIT/Dynarec)
|
||||
|
||||
#### BOX86_DYNAREC_TRACE
|
||||
* 0 : Disable trace for generated code (default)
|
||||
* 1 : Enable trace for generated code (like regular Trace, this will slow down a lot and generate huge logs)
|
||||
|
||||
#### BOX86_LIBGL
|
||||
* libXXXX set the name for libGL (default to libGL.so.1)
|
||||
* /PATH/TO/libGLXXX set the name and path for libGL
|
||||
You can also use SDL_VIDEO_GL_DRIVER
|
||||
|
||||
#### BOX86_LD_PRELOAD
|
||||
* XXXX[:YYYYY] force loading XXXX (and YYYY...) libraries with the binary
|
||||
PreLoaded libs can be emulated or native, and are treated the same way as if they were comming from the binary
|
||||
|
||||
#### BOX86_EMULATED_LIBS
|
||||
* XXXX[:YYYYY] force lib XXXX (and YYYY...) to be emulated (and not wrapped)
|
||||
Some games use old version of some lib, with an ABI incompatible with native version.
|
||||
Note that LittleInferno for example is auto detected, and libvorbis.so.0 is automatical added to emulated libs, and same for Don't Starve (and Together / Server variant) that use an old SDL2 too
|
||||
|
||||
#### BOX86_ALLOWMISSINGLIBS
|
||||
Allow box86 to continue even if a lib is missing
|
||||
* 0 : default, stop if a lib cannot be loaded
|
||||
* 1 : continue even if a needed lib cannot be loaded. Unadvised, this will, in most cases, crash later on.
|
||||
|
||||
#### BOX86_NOPULSE
|
||||
Disable the load of pulseaudio libs
|
||||
* 0 : default, load pulseaudio libs if present
|
||||
* 1 : disable the load of pulse audio libs (libpulse and libpulse-simple), both native and x86 version
|
||||
|
||||
#### BOX86_NOGTK
|
||||
Disable the load of wrapped gtk libs
|
||||
* 0 : default, load wrapped gtk libs if present
|
||||
* 1 : disable the load of wrapped gtk libs (can be used with Steam, along with STEAM_RUNTIME=1 to use i386 versio of gtk)
|
||||
|
||||
#### BOX86_FIX_64BIT_INODES
|
||||
* 0 : Don't fix 64bit inodes (default)
|
||||
* 1 : Fix 64bit inodes. Helps when running on filesystems with 64bit inodes, the program uses API functions which don't support it and the program doesn't use inodes information.
|
||||
|
||||
#### BOX86_JITGDB
|
||||
* 0 : Just print the Segfault message on segfault (default)
|
||||
* 1 : Launch `gdb` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process, and go in an endless loop, waiting.
|
||||
When in gdb, you need to find the correct thread yourself (the one with `my_box86signalhandler` in is stack)
|
||||
then probably need to `finish` 1 or 2 functions (inside `usleep(..)`) and then you'll be in `my_box86signalhandler`,
|
||||
just before the printf of the Segfault message. Then simply `set waiting=0` to exit the infinite loop.
|
||||
@@ -0,0 +1 @@
|
||||
theme: jekyll-theme-hacker
|
||||
+14
-8
@@ -1,5 +1,5 @@
|
||||
# Maintainer: SpacingBat3 <youremail@domain.com>
|
||||
# Contributor: Sebastien Chevalier
|
||||
# Maintainer: SpacingBat3 <[email protected].com>
|
||||
# Contributor: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-arm-git
|
||||
pkgver=r2798.0edc0374
|
||||
pkgrel=1
|
||||
@@ -9,18 +9,18 @@ url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}")
|
||||
conflicts=("${pkgname%-git}")
|
||||
provides=("${pkgname%-git}" "${_pkgname%-arm-git}-git" "${_pkgname%-arm-git}")
|
||||
conflicts=("${pkgname%-git}" "${_pkgname%-arm-git}-git" "${_pkgname%-arm-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-git}"
|
||||
cd "$srcdir/${pkgname%-arm-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-git}"
|
||||
cd "${srcdir}/${pkgname%-arm-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
@@ -28,11 +28,17 @@ prepare() {
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-git}/build"
|
||||
cd "$srcdir/${pkgname%-arm-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-git}/build"
|
||||
cd "$srcdir/${pkgname%-arm-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
# Maintainer: SpacingBat3 <youremail@domain.com>
|
||||
# Contributor: Sebastien Chevalier
|
||||
# Maintainer: SpacingBat3 <[email protected].com>
|
||||
# Contributor: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-gameshell-git
|
||||
pkgver=r2798.0edc0374
|
||||
pkgrel=1
|
||||
@@ -9,18 +9,18 @@ url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}")
|
||||
conflicts=("${pkgname%-git}")
|
||||
provides=("${pkgname%-git}" "${pkgname%-gameshell-git}-git" "${pkgname%-gameshell-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-gameshell-git}-git" "${pkgname%-gameshell-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-git}"
|
||||
cd "$srcdir/${pkgname%-gameshell-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-git}"
|
||||
cd "${srcdir}/${pkgname%-gameshell-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DGAMESHELL=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
@@ -28,11 +28,17 @@ prepare() {
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-git}/build"
|
||||
cd "$srcdir/${pkgname%-gameshell-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-git}/build"
|
||||
cd "$srcdir/${pkgname%-gameshell-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
# Maintainer: SpacingBat3 <youremail@domain.com>
|
||||
# Contributor: Sebastien Chevalier
|
||||
# Maintainer: SpacingBat3 <[email protected].com>
|
||||
# Contributor: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-odroid-git
|
||||
pkgver=r2798.0edc0374
|
||||
pkgrel=1
|
||||
@@ -9,18 +9,18 @@ url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}")
|
||||
conflicts=("${pkgname%-git}")
|
||||
provides=("${pkgname%-git}" "${_pkgname%-odroid-git}-git" "${_pkgname%-odroid-git}")
|
||||
conflicts=("${pkgname%-git}" "${_pkgname%-odroid-git}-git" "${_pkgname%-odroid-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-git}"
|
||||
cd "$srcdir/${pkgname%-odroid-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-git}"
|
||||
cd "${srcdir}/${pkgname%-odroid-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DODROID=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
@@ -28,11 +28,17 @@ prepare() {
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-git}/build"
|
||||
cd "$srcdir/${pkgname%-odroid-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-git}/build"
|
||||
cd "$srcdir/${pkgname%-odroid-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
# Maintainer: SpacingBat3 <youremail@domain.com>
|
||||
# Contributor: Sebastien Chevalier
|
||||
# Maintainer: SpacingBat3 <[email protected].com>
|
||||
# Contributor: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-pandora-git
|
||||
_pkgname=box86-git
|
||||
pkgver=r2798.0edc0374
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
@@ -9,18 +10,18 @@ url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}")
|
||||
conflicts=("${pkgname%-git}")
|
||||
provides=("${pkgname%-git}" "${pkgname%-pandora-git}"-git "${pkgname%-pandora-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-pandora-git}"-git "${pkgname%-pandora-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-git}"
|
||||
cd "$srcdir/${pkgname%-pandora-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-git}"
|
||||
cd "${srcdir}/${pkgname%-pandora-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DPANDORA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
@@ -28,11 +29,17 @@ prepare() {
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-git}/build"
|
||||
cd "$srcdir/${pkgname%-pandora-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
+15
-8
@@ -1,6 +1,7 @@
|
||||
# Maintainer: SpacingBat3 <youremail@domain.com>
|
||||
# Contributor: Sebastien Chevalier
|
||||
# Maintainer: SpacingBat3 <[email protected].com>
|
||||
# Contributor: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-pyra-git
|
||||
_pkgname=box86-git
|
||||
pkgver=r2798.0edc0374
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
@@ -9,18 +10,18 @@ url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}")
|
||||
conflicts=("${pkgname%-git}")
|
||||
provides=("${pkgname%-git}" "${pkgname%-pyra-git}-git" "${pkgname%-pyra-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-pyra-git}-git" "${pkgname%-pyra-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-git}"
|
||||
cd "$srcdir/${pkgname%-pyra-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-git}"
|
||||
cd "${srcdir}/${pkgname%-pyra-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DPYRA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
@@ -28,11 +29,17 @@ prepare() {
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-git}/build"
|
||||
cd "$srcdir/${pkgname%-pyra-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-git}/build"
|
||||
cd "$srcdir/${pkgname%-pyra-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
# Maintainer: SpacingBat3 <youremail@domain.com>
|
||||
# Contributor: Sebastien Chevalier
|
||||
# Maintainer: SpacingBat3 <[email protected].com>
|
||||
# Contributor: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-rpi-git
|
||||
_pkgname=box86-git
|
||||
pkgver=r2798.0edc0374
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
@@ -9,29 +10,30 @@ url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}")
|
||||
conflicts=("${pkgname%-git}")
|
||||
provides=("${pkgname%-git}" "${pkgname%-rpi-git}-git" "${pkgname%--rpi-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-rpi-git}-git" "${pkgname%--rpi-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
_pimodel=`tr -d '\0' < /sys/firmware/devicetree/base/model`
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-git}"
|
||||
cd "$srcdir/${pkgname%-rpi-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-git}"
|
||||
cd "${srcdir}/${pkgname%-rpi-git}"
|
||||
# Check for Pi version number
|
||||
if [[ ${_pimodel} ~= "Raspberry Pi 4" ]]; then
|
||||
if [[ ${_pimodel} =~ "Raspberry Pi 4" ]]; then
|
||||
_piversion=4
|
||||
elif [[ ${_pimodel} ~= "Raspberry Pi 3" ]]; then
|
||||
elif [[ ${_pimodel} =~ "Raspberry Pi 3" ]]; then
|
||||
_piversion=3
|
||||
elif [[ ${_pimodel} ~= "Raspberry Pi 2" ]]; then
|
||||
elif [[ ${_pimodel} =~ "Raspberry Pi 2" ]]; then
|
||||
_piversion=2
|
||||
else
|
||||
# Your RPI is not supported or this device is not a pi, cancel build then
|
||||
echo -e "\033[01m\033[01;31m==> ERROR:\033[00;01m Your device is not supported! This script is for RPi model 4/3/2 (1/0 not supported).\033[00m"
|
||||
# This RPI is not supported or this device is not a pi.
|
||||
# We should cancel then the build.
|
||||
echo -e "\033[01m\033[01;31m==> ERROR:\033[00;01m Your device is not supported! This script is for RPi model 4/3/2 (1/0 isn't supported yet).\033[00m"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "\033[01m\033[01;34m==> INFO:\033[00;01m Your detected Pi verion number is: \033[01;31m${_piversion}\033[01m.\033[00m"
|
||||
@@ -42,11 +44,17 @@ prepare() {
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-git}/build"
|
||||
cd "$srcdir/${pkgname%-rpi-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-git}/build"
|
||||
cd "$srcdir/${pkgname%-rpi-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
# Maintainer: SpacingBat3 <[email protected]>
|
||||
# Contributor: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-rk3399-git
|
||||
_pkgname=box86-git
|
||||
pkgver=r2798.0edc0374
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-rk3399-git}-git" "${pkgname%-rk3399-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-rk3399-git}-git" "${pkgname%-rk3399-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-rk3399-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-rk3399-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-rk3399-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-rk3399-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
+15
-8
@@ -1,6 +1,7 @@
|
||||
# Maintainer: SpacingBat3 <youremail@domain.com>
|
||||
# Contributor: Sebastien Chevalier
|
||||
# Maintainer: SpacingBat3 <[email protected].com>
|
||||
# Contributor: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-x86-git
|
||||
_pkgname=box86-git
|
||||
pkgver=r2798.0edc0374
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
@@ -8,18 +9,18 @@ arch=('i386')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}")
|
||||
conflicts=("${pkgname%-git}")
|
||||
provides=("${pkgname%-x86-git}")
|
||||
conflicts=("${pkgname%-x86-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-git}"
|
||||
cd "$srcdir/${pkgname%-x86-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-git}"
|
||||
cd "${srcdir}/${pkgname%-x86-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
@@ -27,11 +28,17 @@ prepare() {
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-git}/build"
|
||||
cd "$srcdir/${pkgname%-x86-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-git}/build"
|
||||
cd "$srcdir/${pkgname%-x86-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
Executable
+131
@@ -0,0 +1,131 @@
|
||||
v0.2.2
|
||||
======
|
||||
* Reworked some elfloader relocation mecanism
|
||||
* Removed old "smart linker" and replace with a simple "jump table"
|
||||
* Also removed CALL/RET optomisation from Dynarec, simple Jump Table is faster
|
||||
* Reworked all memory protection tracking
|
||||
* A few more wrapped libs and wrapped functions
|
||||
* A few more opcodes
|
||||
* A few more dynarec opcodes
|
||||
* Some optimisation in Dynarec around ZF and CF flags handlings, and LL/GE/LE/G conditionnal opcodes
|
||||
* Some changes to the "cancel threads" handling
|
||||
* Some changes to the "thread once" handling
|
||||
|
||||
v0.2.0
|
||||
======
|
||||
* Improvements on x86 Flags handling.
|
||||
* A few more opcode has been added.
|
||||
* A few potential BusError are now fixed.
|
||||
* Added the BOX86_NOVULKAN en. var. . This is used to disable the wrapping of vulkan libraries.
|
||||
* Improvments on libc O_XXXX flags handling.
|
||||
* Box86 now uses a custom allocator for Dynarec and Hash tables.
|
||||
* Improved the wrapping of pulse audio.
|
||||
* Optimisation to a few Dynarec opcode (like SHRD/SHLD).
|
||||
* Improved the tracking of memory protection.
|
||||
* A few more wrapping of libraries (like libgssapi_krb5).
|
||||
* More function wrapping on libturbojpeg
|
||||
* Preliminary support for POWER9 (ppcle) build
|
||||
* Many contributions to remove typos and rephrase the README, COMPILE and USAGE documents
|
||||
|
||||
v0.1.8
|
||||
======
|
||||
* Fixes on some float to int x86 convertions opcodes.
|
||||
* Reworked all callback mecanisms.
|
||||
* Added libturbojpeg wrapping (and a hack for zoom to force using native one).
|
||||
* Added the BOX86_SAFEMMAP env. var.
|
||||
* Reworked Dynarec's memory manager.
|
||||
* Added a few opcodes.
|
||||
* Improve elfloader to not force PltResolver all the time (fixing SuperHexagon and maybe other)
|
||||
* Reworked Exet and Cancel Thread mecanism.
|
||||
* Added wrapped libldap_r and liblber library (used by wine)
|
||||
* Reworked Dynarec block handling, and remove the "AddMark" mecanism that wasn't efficient enough
|
||||
* Added TokiTori 2+ detection and runtime patch on the Raspberry Pi platform
|
||||
* Fixes on elfloader with TLS object.
|
||||
|
||||
v0.1.6
|
||||
======
|
||||
* Changes in Dynarec to make flags optimizations before CALL and RET opcode less aggressive.
|
||||
* Added a Vulkan wrapper.
|
||||
* Improved wrapping of SDL_mixer/ SDL2_mixer libraries.
|
||||
* Improved wrapping of some GTK structures.
|
||||
* Added a quick and dirty wrapping of GTK3 (based on current GTK2).
|
||||
* Improved the signal handling, should be more stable now (the signal handler from syscall still need some works).
|
||||
* Added the RK3399 profile, and some hints to build 32bits box86 on 64bits OS.
|
||||
* Fixed some wrapped printf formating not handled correctly.
|
||||
* Fixed some buserror with the new LOCK mecanism handling.
|
||||
* A few more Dynarec opcodes added.
|
||||
* If winedbg is tried to be launched, exit without launching it (it doesn't work anyways).
|
||||
|
||||
v0.1.4
|
||||
======
|
||||
* Change in Dynarec's memory handling, to simplify it (and hopefully optimized it).
|
||||
* Even more opcodes added.
|
||||
* And some more Dynarec opcodes.
|
||||
* Fixed some issue were PltResolver was injected but should not be.
|
||||
* Fixed many Dynarec and non dynarec opcodes.
|
||||
* Improved Signal handling.
|
||||
* Added a few more wrapped libraries (like curl).
|
||||
* Gallium9 is now wrapped (thx @icecream95).
|
||||
* Fixed and simplied many wrapped functions (especialy the one where a callback is involved).
|
||||
* Fixed Dynarec "freeing" a Dynablock sometimes causing a corruption of the heap (generally happens in case of JIT code).
|
||||
* Optimized the way LOCK prefix work when using Dynarec on ARM.
|
||||
* improvements to the ARM opcode Printer (for dumping Dynarec blocks) improvement (thx @rajdakin).
|
||||
|
||||
v0.1.2
|
||||
======
|
||||
* The Dynarec now handle JIT code
|
||||
* Added support for Unity games (not perfect yet).
|
||||
* Added support for Wine (not perfect yet). You need an x86 build of Wine to use it.
|
||||
* Added support for Steam (not perfect yet). Note that Steam have limited functionalities on 32bits (only mini-mode is available).
|
||||
* More wrapped libs
|
||||
* Added support for the "PltResolver". This makes the order of libraries less important and many symbols are now resolved at runtime.
|
||||
* Added an option to build Box86 as a library (to wrap dynamic library).
|
||||
* Better Signal handling (not perfect yet).
|
||||
* More opcodes added, more opcode fixes.
|
||||
* More Dynarec opcodes.
|
||||
* Added support for FS:, and creating custom selector (needed by Wine).
|
||||
* There is now 1 x86emu_t structure per thread (simplifying/optimising many callback handling).
|
||||
* Box86 now has a logo!
|
||||
* Added options handling (only version and help for now). Now it's much usefull exept for version printing.
|
||||
|
||||
|
||||
v0.1.0
|
||||
=======
|
||||
* Dynarec!!! Only for ARM (note that Dynarec doesn't support JITed code for now).
|
||||
* Added real support for getcontext/set/context/makecontext/swapcontext.
|
||||
* Preliminary signal handling.
|
||||
* Fixes to SDL(1/2) Image and SDL1 Mixer, and to SDL1.2 RWops usage.
|
||||
* Fixed numerous issues in opcodes (both interpretor and dynarec). FTL works fine now, among many others.
|
||||
* Added wrapped GTK support (still ongoing, many libraries involved).
|
||||
* Make loading of libraries more configurable.
|
||||
* If a wrapped native library is not found, try to use an emulated one.
|
||||
* Added an env. var. to force the use of emulated libraries for certain libraries.
|
||||
* Added an env. var. to precise which libGL to use.
|
||||
* Added Install / Uninstall target (using systemd binfmt).
|
||||
* Added more hardware targets (RPis, GameShell...).
|
||||
* Wrapped more libraries (including FreeType, smpeg, ncurses, sndfile...).
|
||||
|
||||
v0.0.4
|
||||
=======
|
||||
* Improved the initialisation of dependent libraries. More things work now.
|
||||
* Added a lot of wrapped functions.
|
||||
* Added a few wrapped libraries (like libz or some other x11 related library).
|
||||
* For trace enabled build, Trace can be enabled only after a certain amount of opcodes (still, a debugger would be better).
|
||||
* Some fixes in a few opcodes, and implemented x87 rounding (SuperMeatBoy behaves better now).
|
||||
* FTL 1.6.9 still has corrupted music, but older 1.5.13 seems fine (different set of libraries).
|
||||
|
||||
v0.0.2
|
||||
=======
|
||||
* A full commercial games runs fine on the Pandora platform: Airline Tycoon Deluxe.
|
||||
* Implemented all planned subparts of Box86 except JIT support.
|
||||
* CPU Emulation is at roughly 75%. This includes x87 and SSE/SSE2. MMX is barely implemented (but barely used anyway).
|
||||
* x87 emulation is simplified, no real x87 State handling (but should not be mandatory, as the native libm library is used)
|
||||
* No Signal handling yet
|
||||
* ELF Loader is crude and probably full of bugs. Also, the initialisation of libraries are defered after all symbols are resolved for now.
|
||||
* Wrapped libraries include libc, libm, rt, pthread, libdl, dllinux, libasound, GL, GLU, SDL1/mixer/image, SDL2/mixer/image/smpeg, OpenAL/ALUT, libz, libpng16, vorbisfile, x11/xrandr/xxf86vm.
|
||||
* Most wrapped libraries are still partially implemented ( the SDL1 & GL libraries should be complete).
|
||||
* Implemented specific mecanism for SDL(1/2) RWops, to be able to used them both in Native and x86 world.
|
||||
* WorldOfGoo works, but is painfully slow on the Pandora platform (there is too much double math, and lack of JIT).
|
||||
* FTL works, but sound is broken (issue with thread? asound? or CPU core?)
|
||||
* Limbo launches but crashes before main menu.
|
||||
|
||||
@@ -12,7 +12,7 @@ Compiling
|
||||
|
||||
`mkdir build; cd build; cmake .. -DGAMESHELL=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
|
||||
|
||||
#### for RaspberryPI
|
||||
#### for Raspberry Pi
|
||||
|
||||
_a build for model 2, 3 and 4 can be done. Model 1 and 0 cannot (at least not with Dynarec, as they lack NEON support)_
|
||||
|
||||
@@ -25,25 +25,25 @@ sudo make install
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
|
||||
_For Pi4. Change to RPI2 or RPI3 for other models._
|
||||
_For Pi4. Change to RPI2 or RPI3 for other models. Change to RPI4ARM64 for compiling on arm64. (armhf multiarch or chroot required alongside armhf gcc. Install it with 'sudo apt install gcc-arm-linux-gnueabihf'.)_
|
||||
|
||||
#### for ODROID
|
||||
|
||||
`mkdir build; cd build; cmake .. -DODROID=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
|
||||
`mkdir build; cd build; cmake .. -DODROID=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j$(nproc)`
|
||||
|
||||
#### for RK3399
|
||||
|
||||
`mkdir build; cd build; cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j4`
|
||||
|
||||
As most RK3399 device run AARCH64 OS, you'll need an `armhf` multiarch env, and an armhf gcc: use `sudo apt install gcc-arm-linux-gnueabihf` to install it.
|
||||
As most RK3399 device run AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
|
||||
#### for Other ARM Linux
|
||||
#### for Other ARM Linux platforms
|
||||
|
||||
`mkdir build; cd build; cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
|
||||
`mkdir build; cd build; cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j$(nproc)`
|
||||
|
||||
#### for x86 Linux
|
||||
|
||||
`mkdir build; cd build; cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
|
||||
`mkdir build; cd build; cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j$(nproc)`
|
||||
|
||||
#### use ccmake
|
||||
|
||||
@@ -57,19 +57,19 @@ Add `-DUSE_CCACHE=1` if you have ccache (it's better if you plan to touch the so
|
||||
|
||||
*have some debug info*
|
||||
|
||||
The `-DCMAKE_BUILD_TYPE=RelWithDebInfo` argument make a build that is both optimized for speed, and have debug information embedded. That way, if you have a crash or try to analyse performances, you'll have some symbols.
|
||||
The `-DCMAKE_BUILD_TYPE=RelWithDebInfo` argument makes a build that is both optimized for speed, and has debug information embedded. That way, if you have a crash or try to analyse performance, you'll have some symbols.
|
||||
|
||||
*to have a Trace Enabled build*
|
||||
|
||||
To have a trace enabled build (warning, it will be slower), add `-DHAVE_TRACE=1` but you will need, at runtime, to have the [Zydis library](https://github.com/zyantific/zydis) library in your `LD_LIBRARY_PATH` or in the system lib folders.
|
||||
To have a trace enabled build ( ***it will be slower***), add `-DHAVE_TRACE=1` but you will need, at runtime, to have the [Zydis library](https://github.com/zyantific/zydis) library in your `LD_LIBRARY_PATH` or in the system library folders.
|
||||
|
||||
*to have ARM Dynarec*
|
||||
|
||||
The Dynarec is only avaiable on ARM Cpu. Notes also that VFPv3 and NEON are required for the Dynarec. Activate it by using `-DARM_DYNAREC=1`. Also, be sure to use `-marm` in compilation flags (because many compileur use Thumb as default, and the dynarec will not work in this mode).
|
||||
The Dynarec is only available on the ARM architecture(Right now, anyways.). Notes also that VFPv3 and NEON are required for the Dynarec. Activate it by using `-DARM_DYNAREC=1`. Also, be sure to use `-marm` in compilation flags (because many compileur use Thumb as default, and the dynarec will not work in this mode).
|
||||
|
||||
*not building from a git clone*
|
||||
|
||||
If you are not building from a git clone (for example downloading a release sources Zipped from github), you need to activate `-DNOGIT=1` from cmake to be able to build (normal process include git sha1 of HEAD in the version that box86 print).
|
||||
If you are not building from a git clone (for example, downloading a release source zipped from github), you need to activate `-DNOGIT=1` from cmake to be able to build (normal process include git sha1 of HEAD in the version that box86 print).
|
||||
|
||||
----
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2018-2019 Sebastien Chevalier ("ptitSeb")
|
||||
Copyright (c) 2018-2021 Sebastien Chevalier ("ptitSeb")
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
Executable
+114
@@ -0,0 +1,114 @@
|
||||
# box86
|
||||
|
||||

|
||||
Linux Userspace x86 Emulator with a twist
|
||||
|
||||
----
|
||||
|
||||
Compiling/Installation
|
||||
----
|
||||
> Compilation instructions can be found [here](COMPILE.md)
|
||||
> Instructions for installing Wine for Box86 can be found [here](X86WINE.md)
|
||||
|
||||
Box86 lets you run x86 Linux programs (such as games) on non-x86 Linux systems, like ARM (host system needs to be 32bit little-endian).
|
||||
|
||||
You *NEED* a 32-bit subsystem to run and build Box86. Box86 is useless on 64-bit only systems. Also, you *NEED* a 32-bit toolchain to build Box86. A toolchain that only supports 64-bit will not compile Box86, and you'll get errors (typically on aarch64, you get "-marm" not recognized, and you'll need a multiarch or chroot environnement).
|
||||
|
||||
Because Box86 uses the native versions of some "system" libraries, like libc, libm, SDL, and OpenGL, it's easy to integrate and use with most applications, and performance can be surprisingly high in some cases.
|
||||
|
||||
Most x86 Games need OpenGL, so on ARM platforms an solution like [gl4es](https://github.com/ptitSeb/gl4es) is usually necessary. (Most ARM platforms only support OpenGL ES and/or their OpenGL implementation is dodgy (see OpenGL on Android).)
|
||||
|
||||
Box86 now integrates a DynaRec (dynamic recompiler) for the ARM platform, providing a speed boost between 5 to 10 times faster than only using the interpreter.
|
||||
|
||||
Many games already work without much tweaking, for example: WorldOfGoo, Airline Tycoon Deluxe, and FTL. Many of the GameMaker Linux games also run fine. (there's a long list, among them are UNDERTALE, A Risk of Rain, and Cook Serve Delicious)
|
||||
|
||||
If you are serious about developing Box86, you should install ccache and build Box86 with it. (Use ccmake for example.)
|
||||
To enable TRACE (i.e. dumping to stdout all individual x86 instructions executed, with dump of registers), you'll also need [Zydis library](https://github.com/zyantific/zydis) available on your system.
|
||||
|
||||
Some x86 internal opcodes use parts of "Realmode X86 Emulator Library", see [x86primop.c](../src/emu/x86primop.c) for copyright details
|
||||
|
||||
Here's 6 videos, the first 2 videos are videos of "Airline Tycoon Deluxe" and "Heretic 2" running on a GigaHertz OpenPandora (the second one is using the dynarec), and the next 2 videos are videos of of "Bit.Trip.Runner" and "Neverwinter Night" running on an ODroid XU4 (without dynarec), and the last 2 videos are on on a Pi4: Shovel Knight (video from @ITotalJustice) and Freedom Planet (video from @djazz), also without dynarec.
|
||||
|
||||
[](https://www.youtube.com/watch?v=bLt0hMoFDLk) [](https://www.youtube.com/watch?v=MM7kWYts7IA) [](https://www.youtube.com/watch?v=8hr71S029Hg) [](https://www.youtube.com/watch?v=B4YN37z3-ws) [](https://www.youtube.com/watch?v=xk8Q30mxqPg) [](https://www.youtube.com/watch?v=_QMRMVvYrqU)
|
||||
|
||||
You can find many more Box86 video on Youtube in the [Pi Labs Channel](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g) or [The Byteman Channel](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA)
|
||||
|
||||
Compatibility list is there: https://github.com/ptitSeb/box86-compatibility-list/issues
|
||||
|
||||
<img src="img/Box86Icon.png" width="96" height="96">
|
||||
|
||||
Logo and Icon made by @grayduck, thanks!
|
||||
|
||||
Note that this project is not to be mistaken with [86box](https://github.com/86Box/86Box), a nice "Full system" emulator specialized in early (to fairly recent) PC hardware.
|
||||
|
||||
----
|
||||
|
||||
Discord
|
||||
----
|
||||
|
||||
If you want to discuss (or have any problems) about box86, feel free to join the [Pi Labs Discord Server](https://discord.gg/Fh8sjmu)!
|
||||
|
||||
----
|
||||
|
||||
Usage
|
||||
----
|
||||
|
||||
There are a few environment variables to control the behaviour of Box86.
|
||||
|
||||
See [here](USAGE.md) for all environment variables and what they do.
|
||||
|
||||
Note: Box86's Dynarec uses a mechanism with Memory Protection and a SegFault signal handler to handle JIT code. In simpler terms, if you want to use GDB to debug a running program that use JIT'd code (like mono/Unity3D), you will still have many "normal" segfaults triggering. It is suggested to use something like `handle SIGSEGV nostop` in GDB to not stop at each segfault, and maybe put a breakpoint inside `my_memprotectionhandler` in `signals.c` if you want to trap SegFaults.
|
||||
|
||||
----
|
||||
|
||||
Version history
|
||||
----
|
||||
|
||||
The change log is available [here](CHANGELOG.md)
|
||||
|
||||
----
|
||||
|
||||
Notes about 64-bit platforms
|
||||
----
|
||||
|
||||
Because Box86 works by directly translating function calls from x86 to host system, the host system (the one Box86 is running on) needs to have 32-bit libraries. Box86 doesn't include any 32-bit <-> 64-bit translation. So basically, to run Box86 on, for example, an ARM64 platform, you will need to build Box86 for ARM 32-bit, and also need to have a chroot with 32-bit libraries.
|
||||
|
||||
Also note that, even if, on day, there is a Box86_64, this one will only be able to run x86_64 binaries on 64-bit platforms. You will still need Box86 (and a 32-bit chroot) to run x86 binaries (in fact, the same is the case on actual x86_64 Linux).
|
||||
|
||||
----
|
||||
|
||||
A note about Unity game emulation
|
||||
----
|
||||
|
||||
Running Unity games is a hit or miss for now. Unity uses Mono (which uses signals that are not well emulated enough), and a runtime embedded in the main binary. A solution would be to use a native version of the libmono library used by Unity (it can be found here: https://github.com/Unity-Technologies/mono and needs to be built from source). But the wrapping of this lib is tricky, and not done for now, so the only solution is to emulate everything. The tricky part is to emulate the "JIT" code emitted by Mono, however with the new "protected memory" mechanism implemented it should be running with correct performance now.
|
||||
You should also note that some Unity3D games require OpenGL 3+ which can be tricky to provide on ARM SBC (single-board computers) for now.
|
||||
|
||||
TL;DR: Not all Unity games work and can require a high OpenGL profile, but the speed, for the ones running, should be correct now.
|
||||
|
||||
----
|
||||
|
||||
Notes about Steam
|
||||
----
|
||||
|
||||
Linux Steam's can run now with box86. But it's still a bit unstable, and not everything works:
|
||||
- First problem is Steam crashing after the sign-in window, if you encounter this issue, you may need to add libappindicator. To install it on Debian, run `sudo apt install libappindicator1`.
|
||||
- If you select to "Remember password", Steam is crashing on subsequent starts, unless you have libnm intalled. To install it on Debian, run `sudo apt install libnm0`.
|
||||
- Once open, Steam will only work on "Small Mode" and in "Big Picture", not in the regular "Large Mode". This is because some Steam components used in the browser view are only 64-bit now. So go in the "View" menu and switch to "Small view", else the list will stay empty. Alternatively, Steam can be started in small mode directly by using `+open steam://open/minigameslist` command line arguments.
|
||||
- To avoid the "libc.so.6 is absent" message, you can use `STEAMOS=1` and `STEAM_RUNTIME=1` as environment variables.
|
||||
- Some Steam games (most Source engine games, like "Portal" or "Half-Life 2") use libtcmalloc. Box86 will detect it and will try to LD_PRELOAD it, for better compatibility. While it should work without the aformentionned feature, it is safer to add it to your system if you intend to play those game. To install it on Debian, run `sudo apt install libtcmalloc-minimal4`.
|
||||
|
||||
Steam for Windows installs fine but doesn't work yet.
|
||||
|
||||
----
|
||||
|
||||
Notes about Wine
|
||||
----
|
||||
|
||||
Wine is now partly supported. Wine integrated program all runs, and some windows programs and games now runs fine. Don't forget most Windows games use Direct3D, this may require a complete OpenGL driver and as high profile as possible (and gl4es with ES2 backend have issue with Wine for now). Also, vulkan is not wrapped on box86, so vk3d is not usable yet, even if supported by the hardware.
|
||||
Note: if you plan to use box86 with Wine on Raspberry Pi 3 or earlier, those models use a default OS that have a kernel with a 2/2 Split (meaning 2G of space for user program, and 2G of space for the Kernel). This is not compatible with Wine programs that needs to access memory > 2Gb address. So you'll need to reconfigure your kernel for a 3G/1G split.
|
||||
----
|
||||
|
||||
Final words
|
||||
----
|
||||
|
||||
(If you use Box86 in your project, please don't forget to mention Box86!)
|
||||
Executable
+161
@@ -0,0 +1,161 @@
|
||||
|
||||
Usage
|
||||
----
|
||||
|
||||
There are many environment variables to control Box86 behaviour.
|
||||
|
||||
#### BOX86_LOG
|
||||
Controls the Verbosity level of the logs
|
||||
* 0: NONE : No message (except some fatal error). (Default.)
|
||||
* 1: INFO : Show some minimum log (Example: librairies not found)
|
||||
* 2: DEBUG : Details a lot of stuff (Example: relocations or functions called).
|
||||
* 3: DUMP : All DEBUG plus DUMP of all ELF Info.
|
||||
|
||||
#### BOX86_NOBANNER
|
||||
Disables Box86 printing its version and build
|
||||
* 0 : Enable printing its banner. (Default.)
|
||||
* 1 : Disable printing its banner.
|
||||
|
||||
#### BOX86_LD_LIBRARY_PATH
|
||||
Path to look for x86 libraries. Default is current folder and `lib` in current folder.
|
||||
Also, `/usr/lib/i386-linux-gnu` and `/lib/i386-linux-gnu` are added if they exist.
|
||||
|
||||
#### BOX86_PATH
|
||||
Path to look for x86 executable. Default is current folder and `bin` in current folder.
|
||||
|
||||
#### BOX86_DLSYM_ERROR
|
||||
Enables/Disables the logging of `dlsym` errors.
|
||||
* 0 : Don't log `dlsym` errors. (Default.)
|
||||
* 1 : Log dlsym errors.
|
||||
|
||||
#### BOX86_TRACE_FILE
|
||||
Send all log and trace to a file instead of `stdout`
|
||||
Also, if name contains `%pid` then this is replaced by the actual PID of box86 instance
|
||||
|
||||
#### BOX86_TRACE
|
||||
Only on build with trace enabled. Trace allow the logging of all instruction executed, along with register dump
|
||||
* 0 : No trace. (Default.)
|
||||
* 1 : Trace enabled. Trace start after the initialisation of all depending libraries is done.
|
||||
* symbolname : Trace only `symbolname` (trace is disable if the symbol is not found).
|
||||
* 0xXXXXXXX-0xYYYYYYY : Trace only between the 2 addresses.
|
||||
|
||||
#### BOX86_TRACE_INIT
|
||||
Use BOX86_TRACE_INIT instead of BOX_TRACE to start trace before the initialisation of libraries and the running program
|
||||
* 0 : No trace. (Default.)
|
||||
* 1 : Trace enabled. The trace start with the initialisation of all depending libraries is done.
|
||||
|
||||
#### BOX86_TRACE_START
|
||||
Only on builds with trace enabled.
|
||||
* NNNNNNN : Start trace only after NNNNNNNN opcode execute (number is an `uint64_t`).
|
||||
|
||||
#### BOX86_TRACE_XMM
|
||||
Only on builds with trace enabled.
|
||||
* 0 : The XMM (i.e. SSE/SSE2) register will not be logged with the general and x86 registers. (Default.)
|
||||
* 1 : Dump the XMM registers.
|
||||
|
||||
#### BOX86_LOAD_ADDR
|
||||
Try to load at 0xXXXXXX main binary (if binary is a PIE)
|
||||
* 0xXXXXXXXX : The load address . (Only active on PIE programs.)
|
||||
|
||||
#### BOX86_NOSIGSEGV
|
||||
Disable handling of SigSEGV. (Very useful for debugging.)
|
||||
* 0 : Let the x86 program set sighandler for SEGV (Default.)
|
||||
* 1 : Disable the handling of SigSEGV.
|
||||
|
||||
#### BOX86_NOSIGILL
|
||||
Disable handling of SigILL (to ease debugging mainly).
|
||||
* 0 : Let x86 program set sighandler for Illegal Instruction
|
||||
* 1 : Disables the handling of SigILL
|
||||
|
||||
#### BOX86_X11COLOR16
|
||||
PANDORA only: Try converting X11 color from 32 bits to 16 bits (to avoid light green on light cyan windows).
|
||||
* 0 : Don't touch X11 colors. (Default.)
|
||||
* 1 : Change colors arguments in XSetForeground, XSetBackground and XCreateGC.
|
||||
|
||||
#### BOX86_X11THREADS
|
||||
Call XInitThreads when loading X11. (This is mostly for old Loki games with the Loki_Compat library.)
|
||||
* 0 : Don't force call XInitThreads. (Default.)
|
||||
* 1 : Call XInitThreads as soon as libX11 is loaded.
|
||||
|
||||
#### BOX86_X11GLX
|
||||
Force libX11's GLX extension to be present.
|
||||
* 0 : Do not force libX11's GLX extension to be present.
|
||||
* 1 : GLX will always be present when using XQueryExtension. (Default.)
|
||||
|
||||
#### BOX86_DYNAREC_DUMP
|
||||
Enables/disables Box86's Dynarec's dump.
|
||||
* 0 : Disable Dynarec's blocks dump. (Default.)
|
||||
* 1 : Enable Dynarec's blocks dump.
|
||||
* 2 : Enable Dynarec's blocks dump with some colors.
|
||||
|
||||
#### BOX86_DYNAREC_LOG
|
||||
Set the level of DynaRec's logs.
|
||||
* 0 : NONE : No Logs for DynaRec. (Default.)
|
||||
* 1 :INFO : Minimum Dynarec Logs (only unimplemented OpCode).
|
||||
* 2 : DEBUG : Debug Logs for Dynarec (with details on block created / executed).
|
||||
* 3 : VERBOSE : All of the above plus more.
|
||||
|
||||
#### BOX86_DYNAREC
|
||||
Enables/Disables Box86's Dynarec.
|
||||
* 0 : Disables Dynarec.
|
||||
* 1 : Enable Dynarec. (Default.)
|
||||
|
||||
#### BOX86_DYNAREC_TRACE
|
||||
Enables/Disables trace for generated code.
|
||||
* 0 : Disable trace for generated code. (Default.)
|
||||
* 1 : Enable trace for generated code (like regular Trace, this will slow down the program a lot and generate huge logs).
|
||||
|
||||
#### BOX86_NODYNAREC
|
||||
Forbid dynablock creation in the interval specified (helpfull for debugging behaviour difference between Dynarec and Interpretor)
|
||||
* 0xXXXXXXXX-0xYYYYYYYY : define the interval where dynablock cannot start (inclusive-exclusive)
|
||||
|
||||
#### BOX86_LIBGL
|
||||
* libXXXX set the name for libGL (defaults to libGL.so.1).
|
||||
* /PATH/TO/libGLXXX : Sets the name and path for libGL
|
||||
You can also use SDL_VIDEO_GL_DRIVER
|
||||
|
||||
#### BOX86_LD_PRELOAD
|
||||
* XXXX[:YYYYY] force loading XXXX (and YYYY...) libraries with the binary
|
||||
PreLoaded libs can be emulated or native, and are treated the same way as if they were comming from the binary
|
||||
|
||||
#### BOX86_EMULATED_LIBS
|
||||
* XXXX[:YYYYY] force lib XXXX (and YYYY...) to be emulated (and not wrapped)
|
||||
Some games uses an old version of some libraries, with an ABI incompatible with native version.
|
||||
Note that LittleInferno for example is auto detected, and libvorbis.so.0 is automatical added to emulated libs, and same for Don't Starve (and Together / Server variant) that use an old SDL2 too
|
||||
|
||||
#### BOX86_ALLOWMISSINGLIBS
|
||||
Allow Box86 to continue even if a library is missing.
|
||||
* 0 : Box86 will stop if a library cannot be loaded. (Default.)
|
||||
* 1 : Continue even if a needed library cannot be loaded. Unadvised, this will, in most cases, crash later on.
|
||||
|
||||
#### BOX86_NOPULSE
|
||||
Disables the load of pulseaudio libraries.
|
||||
* 0 : Load pulseaudio libraries if found. (Default.)
|
||||
* 1 : Disables the load of pulse audio libraries (libpulse and libpulse-simple), both the native library and the x86 library
|
||||
|
||||
#### BOX86_NOGTK
|
||||
Disables the loading of wrapped GTK libraries.
|
||||
* 0 : Load wrapped GTK libraries if found. (Default.)
|
||||
* 1 : Disables loading wrapped GTK libraries (can be used with Steam, along with STEAM_RUNTIME=1 to use the i386 version of GTK).
|
||||
|
||||
#### BOX86_NOVULKAN
|
||||
Disables the load of vulkan libraries.
|
||||
* 0 : Load vulkan libraries if found.
|
||||
* 1 : Disables the load of vulkan libraries, both the native and the i386 version (can be useful on Pi4, where the vulkan driver is not quite there yet.)
|
||||
|
||||
#### BOX86_FIX_64BIT_INODES
|
||||
Fix/Don't fix 64bit inodes
|
||||
* 0 : Don't fix 64bit inodes. (Default.)
|
||||
* 1 : Fix 64bit inodes. Helps when running on Filesystems with 64bit inodes. Is useful when a program uses API functions which doesn't support it and the program doesn't use inodes information.
|
||||
|
||||
#### BOX86_JITGDB
|
||||
|
||||
* 0 : Just print the Segfault message on segfault (default)
|
||||
* 1 : Launch `gdb` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process and go in an endless loop, waiting.
|
||||
When in gdb, you need to find the correct thread yourself (the one with `my_box86signalhandler` in is stack)
|
||||
then probably need to `finish` 1 or 2 functions (inside `usleep(..)`) and then you'll be in `my_box86signalhandler`,
|
||||
just before the printf of the Segfault message. Then simply
|
||||
`set waiting=0` to exit the infinite loop.
|
||||
* 2 : Launch `gdbserver` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process, and go in an endless loop, waiting.
|
||||
Use `gdb /PATH/TO/box86` and then `target remote 127.0.0.1:1234` to connect to the gdbserver (or use actual IP if not on the machine). After that, the procedure is the same as with ` BOX86_JITGDB=1`.
|
||||
This mode can be usefullwhen programs redirect all console output to a file (like Unity3D Games)
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
# Installing Wine (and winetricks)
|
||||
Using Wine with Box86 allows (x86) Windows programs to run on ARM Linux computers (x64 is not yet implemented).
|
||||
See installation steps below (in the [Examples](#examples) section).
|
||||
|
||||
_TwisterOS users, take note: Wine, winetricks, and Box86 are pre-installed in TwisterOS. TwisterOS users do not have to install anything._
|
||||
|
||||
Box86 actually needs `wine-i386` to be installed **manually** on ARM devices. Even though `wine-armhf` is available in many repo's on ARM devices (ie using _apt-get_ will attempt to install `wine-armhf` by default), `wine-armhf` will not work with Box86. Note that manual installation is required since using `multiarch` will result in your ARM device thinking it needs to install lots of i386 dependencies to make `wine-i386` work. The "twist" in Box86 is that Box86 "wraps" many Windows and Wine i386 libraries (`.so` or `.dll` files) so that they will work with your ARM device's libraries. Also note that wrapping libraries is an ongoing process throughout Box86 development and that some programs may not run properly until all of their i386 library dependencies are wrapped.
|
||||
|
||||
Installation files for Wine can be found in the [WineHQ repository](https://dl.winehq.org/wine-builds/debian/dists/buster/main/binary-i386/), the [TwisterOS FAQ](https://twisteros.com/faq.html) page, or the [PlayOnLinux website repository](https://www.playonlinux.com/wine/). Box86 requires the "i386" (x86) versions of Wine install files (even though we are installing it on an ARM processor). Box86 "wraps" many of Wine's core Linux i386 libraries so that their calls are interpretable by Linux ARM libraries. Below are examples of how to install Wine from each of those places.
|
||||
|
||||
_Raspberry Pi users: Wine requires a 3G/1G split memory kernel. Raspberry Pi OS for the Pi 4 has a 3G/1G split kernel, but **the Pi 3 and earlier models have a 2G/2G kernel by default and will need you to install a custom-compiled 3G/1G kernel to get Wine to work.**
|
||||
|
||||
## Overview
|
||||
The general procedure for installing Wine for Box86 is to...
|
||||
- Download all the install files (.deb, .zip, or even .pol files) for the version of Wine you wish to install
|
||||
- Unzip or dpkg the install files into one folder
|
||||
- Move that folder to the directory that you wish Wine to run from (in TwisterOS, this is `~/wine/` by default)
|
||||
- Go to `/usr/local/bin` and make symlinks or scripts that will point to your main wine binaries (`wine`, `winecfg`, and `wineserver`).
|
||||
- Boot wine to create a new wineprefix (`wine wineboot`).
|
||||
- Download winetricks (which is simply a very complicated bash script), make it executable, then copy it to `/usr/local/bin`.
|
||||
|
||||
## Examples
|
||||
_These examples were all tested on Raspberry Pi 4. Note the similarities between the different install methods._
|
||||
|
||||
### Installing wine-devel, wine-stable, or wine-staging for Raspberry Pi OS Buster from WineHQ deb files
|
||||
_Links from the [WineHQ repo](https://dl.winehq.org/wine-builds/debian/dists/buster/main/binary-i386/)_
|
||||
```
|
||||
# Backup any old wine installations
|
||||
sudo mv ~/wine ~/wine-old
|
||||
sudo mv ~/.wine ~/.wine-old
|
||||
sudo mv /usr/local/bin/wine /usr/local/bin/wine-old
|
||||
sudo mv /usr/local/bin/wineboot /usr/local/bin/wineboot-old
|
||||
sudo mv /usr/local/bin/winecfg /usr/local/bin/winecfg-old
|
||||
sudo mv /usr/local/bin/wineserver /usr/local/bin/wineserver-old
|
||||
|
||||
# Download, extract wine, and install wine
|
||||
# (Replace the links/versions below with links/versions from the WineHQ site for the version of wine you wish to install. Note that we need the i386 version for Box86 even though we're installing it on our ARM processor.)
|
||||
# (Pick an i386 version of wine-devel, wine-staging, or wine-stable)
|
||||
cd ~/Downloads
|
||||
wget https://dl.winehq.org/wine-builds/debian/dists/buster/main/binary-i386/wine-devel-i386_5.21~buster_i386.deb # NOTE: Replace this link with the version you want
|
||||
wget https://dl.winehq.org/wine-builds/debian/dists/buster/main/binary-i386/wine-devel_5.21~buster_i386.deb # NOTE: Also replace this link with the version you want
|
||||
dpkg-deb -xv wine-devel-i386_5.21~buster_i386.deb wine-installer # NOTE: Make sure these dpkg command matches the filename of the deb package you just downloaded
|
||||
dpkg-deb -xv wine-devel_5.21~buster_i386.deb wine-installer
|
||||
mv ~/Downloads/wine-installer/opt/wine* ~/wine
|
||||
rm wine*.deb # clean up
|
||||
rm -rf wine-installer # clean up
|
||||
|
||||
# Install shortcuts (make 32bit launcher & symlinks. Credits: grayduck, Botspot)
|
||||
echo -e '#!/bin/bash\nsetarch linux32 -L '"$HOME/wine/bin/wine "'"$@"' | sudo tee -a /usr/local/bin/wine >/dev/null # Create a script to launch wine programs as 32bit only
|
||||
#sudo ln -s ~/wine/bin/wine /usr/local/bin/wine # You could aslo just make a symlink, but box86 only works for 32bit apps at the moment
|
||||
sudo ln -s ~/wine/bin/wineboot /usr/local/bin/wineboot
|
||||
sudo ln -s ~/wine/bin/winecfg /usr/local/bin/winecfg
|
||||
sudo ln -s ~/wine/bin/wineserver /usr/local/bin/wineserver
|
||||
sudo chmod +x /usr/local/bin/wine /usr/local/bin/wineboot /usr/local/bin/winecfg /usr/local/bin/wineserver
|
||||
|
||||
# These packages are needed for running wine-staging on RPi 4 (Credits: chills340)
|
||||
sudo apt install libstb0 -y
|
||||
cd ~/Downloads
|
||||
wget -r -l1 -np -nd -A "libfaudio0_*~bpo10+1_i386.deb" http://ftp.us.debian.org/debian/pool/main/f/faudio/ # Download libfaudio i386 no matter its version number
|
||||
dpkg-deb -xv libfaudio0_*~bpo10+1_i386.deb libfaudio
|
||||
sudo cp -TRv libfaudio/usr/ /usr/
|
||||
rm libfaudio0_*~bpo10+1_i386.deb # clean up
|
||||
rm -rf libfaudio # clean up
|
||||
|
||||
# Boot wine (make fresh wineprefix in ~/.wine )
|
||||
wine wineboot
|
||||
```
|
||||
|
||||
### Installing Wine for Raspberry Pi OS from the Twister OS FAQ page
|
||||
_Links from the [TwisterOS FAQ](https://twisteros.com/faq.html)_
|
||||
```
|
||||
# Backup any old wine installations
|
||||
sudo mv ~/wine ~/wine-old
|
||||
sudo mv ~/.wine ~/.wine-old
|
||||
sudo mv /usr/local/bin/wine /usr/local/bin/wine-old
|
||||
sudo mv /usr/local/bin/wineboot /usr/local/bin/wineboot-old
|
||||
sudo mv /usr/local/bin/winecfg /usr/local/bin/winecfg-old
|
||||
sudo mv /usr/local/bin/wineserver /usr/local/bin/wineserver-old
|
||||
|
||||
# Download, extract wine, and install wine (last I checked, the Twister OS FAQ page had Wine 5.13-devel)
|
||||
wget https://twisteros.com/wine.tgz -O ~/wine.tgz
|
||||
tar -xzvf ~/wine.tgz
|
||||
rm ~/wine.tgz # clean up
|
||||
|
||||
# Install shortcuts (make launcher & symlinks. Credits: grayduck, Botspot)
|
||||
echo -e '#!/bin/bash\nsetarch linux32 -L '"$HOME/wine/bin/wine "'"$@"' | sudo tee -a /usr/local/bin/wine >/dev/null # Create a script to launch wine programs as 32bit only
|
||||
#sudo ln -s ~/wine/bin/wine /usr/local/bin/wine # You could aslo just make a symlink, but box86 only works for 32bit apps at the moment
|
||||
sudo ln -s ~/wine/bin/wineboot /usr/local/bin/wineboot
|
||||
sudo ln -s ~/wine/bin/winecfg /usr/local/bin/winecfg
|
||||
sudo ln -s ~/wine/bin/wineserver /usr/local/bin/wineserver
|
||||
sudo chmod +x /usr/local/bin/wine /usr/local/bin/wineboot /usr/local/bin/winecfg /usr/local/bin/wineserver
|
||||
|
||||
# Boot wine (make fresh wineprefix in ~/.wine )
|
||||
wine wineboot
|
||||
```
|
||||
## Installing winetricks
|
||||
Winetricks is a script which makes it easier to install & configure any desired Windows core system software packages which may be dependencies for certain Windows programs.
|
||||
|
||||
```
|
||||
# Backup old winetricks
|
||||
sudo mv /usr/local/bin/winetricks /usr/local/bin/winetricks-old
|
||||
|
||||
# Download
|
||||
cd ~/Downloads
|
||||
wget https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks
|
||||
|
||||
# Install
|
||||
sudo chmod +x winetricks
|
||||
sudo mv winetricks /usr/local/bin/
|
||||
|
||||
# winetricks needs this installed
|
||||
sudo apt-get install cabextract -y
|
||||
```
|
||||
|
||||
If you have a desktop menu itm for wintricks, you may need to edit it to add the nobanner env var. Do so by edition `/usr/share/applications/winetricks.desktop` with your favorite text editor (not that you'll need `sudo` to save the file) and change from `Exec=winetricks --gui` to `Exec=env BOX86_NOBANNER=1 winetricks --gui`
|
||||
|
||||
## Example commands
|
||||
Here is an example of how we should run a winetricks command with box86:
|
||||
`BOX86_NOBANNER=1 winetricks -q corefonts vcrun2010 dotnet20sp1`
|
||||
_This command will silently install three packages in series: Windows core fonts, VC++ 2010 Runtimes, and .NET 2.0 SP1. `-q` is the "install silent/quiet" command._
|
||||
|
||||
Whenever we run winetricks, we must suppress Box86's banner by typing `BOX86_NOBANNER=1` to prevent winetricks from crashing. Invoking Box86's logging features (with `BOX86_LOG=1` or similar) will also cause winetricks to crash. (If Box86 logging is necessary though, we can patch winetricks to avoid these crashes - see the *Troubleshooting* section) # future work.
|
||||
|
||||
For a list of all the different Windows packages & libraries that winetricks can help you install, run `winetricks list-all`
|
||||
|
||||
## Other notes
|
||||
|
||||
### Wineprefixes (and Wine initialization)
|
||||
The first time Wine is run (`wine wineboot`), it will create a fresh wineprefix for you (by default, located in the hidden folder `~/.wine`). Think of a wineprefix as Wine's virtual 'harddrive' where it installs software and saves settings. Wineprefixes are portable and deletable.
|
||||
|
||||
If you at any point corrupt something inside your default wineprefix, you can start "fresh" by deleting your `~/.wine` directory (with the `rm -rf ~/.wine` command) and boot wine again to create a new default wineprefix.
|
||||
|
||||
### Transplanting wineprefixes (side-loading)
|
||||
When you first run or boot Wine (`wine wineboot`), Wine will create a new user environment within which to install Windows software. This user environment is called a "wineprefix" (or "wine bottle") and is located (by default) in `~/.wine` (note that Linux folders with a `.` in front of them are "hidden" folders). For more Wine documentation, see [WineHQ](https://www.winehq.org/documentation).
|
||||
|
||||
If software isn't installing in Wine with Box86, but is installing for you in Wine on a regular x86 Linux computer, you can copy a wineprefix from your x86 Linux computer to the device you're running Box86 on. This is most easily done by tarring the `~/.wine` folder on your x86 Linux computer (`tar -cvf winebottle.tar ~/.wine`), transferring the tar file to your device, then un-tarring the tar file (`tar -xf winebottle.tar`) on your device running Box86 & Wine. Tarring the wineprefix preserves any symlinks that are inside it.
|
||||
|
||||
### Swapping out different versions of Wine
|
||||
Some versions of Wine work better with certain software. It is best to install a version of Wine that is known to work with the software you would like to run. There are three main development branches of Wine you can pick from, referred to as wine-stable, wine-devel, and wine-staging. _Note that the wine-staging branch requires extra installation steps on Raspberry Pi._
|
||||
|
||||
Your entire Wine installation can reside within a single folder on your Linux computer. TwisterOS assumes that your Wine installation is located inside the `~/wine/` directory. The actual directory where you put your `wine` folder doesn't matter as long as you have symlinks within the `/usr/local/bin/` directory which point to the `wine` folder so that Linux can find Wine when you type `wine` into the terminal).
|
||||
|
||||
You can change which version of Wine you are running simply by renaming your old `wine` and `.wine` folders to something else, then putting a new `wine` folder (containing your new version of Wine) in its place. Running `wine wineboot` again will make a fresh wineprefix with your new version of Wine. You can check which version of Wine you're running with the `wine --version` command.
|
||||
@@ -0,0 +1 @@
|
||||
theme: jekyll-theme-hacker
|
||||
File renamed without changes.
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB |
File renamed without changes.
|
Before Width: | Height: | Size: 171 KiB After Width: | Height: | Size: 171 KiB |
+13
-12
@@ -5,6 +5,13 @@ import re
|
||||
import sys
|
||||
from math import ceil
|
||||
|
||||
"""
|
||||
Generates src/dynarec/arm_printer.c
|
||||
===
|
||||
|
||||
See src/dynarec/arm_instructions.txt (the input file) for the syntax documentation.
|
||||
"""
|
||||
|
||||
# Helper class to avoid displaying '\x1b[' on errors
|
||||
class string(str):
|
||||
def __repr__(self):
|
||||
@@ -172,13 +179,6 @@ def main(root, ver, __debug_forceAllDebugging=False):
|
||||
- specifics is an array of arrays the same length as positions that contains a tuple (mask, correctBit)
|
||||
that is at position positions[current_pos]
|
||||
"""
|
||||
if len(positions) != len(specifics):
|
||||
fail(
|
||||
AssertionError,
|
||||
"generate_bin_tests requires the same length for positions ({}) and specifics ({})!".format(
|
||||
len(positions), len(specifics)
|
||||
)
|
||||
)
|
||||
|
||||
if specifics == []:
|
||||
append("if ((opcode & " + arr2hex(mask) + ") == " + arr2hex(correctBits) + ") {\n")
|
||||
@@ -194,8 +194,9 @@ def main(root, ver, __debug_forceAllDebugging=False):
|
||||
if any(map(lambda s: len(s) != l, specifics)):
|
||||
fail(
|
||||
AssertionError,
|
||||
"generate_bin_tests requires the same length for positions ({}) and specifics ({})!".format(
|
||||
len(positions), len(specifics)
|
||||
"generate_bin_tests requires the same length for positions ({}) and each element "
|
||||
"of the specifics array ({})!".format(
|
||||
len(positions), [len(s) for s in specifics]
|
||||
)
|
||||
)
|
||||
|
||||
@@ -290,7 +291,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
|
||||
# Custom ifs
|
||||
# Also, requires only a single '='
|
||||
if eq != "=":
|
||||
fail(ValueError, "Too many '=' switches (!@ modifier)")
|
||||
fail(ValueError, "Too many '=' switches (@@ modifier)")
|
||||
|
||||
# Extract the statements
|
||||
statements = []
|
||||
@@ -1653,7 +1654,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
|
||||
|
||||
# No C variable since we're invalidating!
|
||||
|
||||
# Now print the invalidation, numerote if debugging
|
||||
# Now print the invalidation, number if debugging
|
||||
if numberInvalids:
|
||||
append("strcpy(ret, \"??? #" + str(invalidationCount) + "\");\n} else ")
|
||||
invalidationCount = invalidationCount + 1
|
||||
@@ -1963,12 +1964,12 @@ const char* arm_print(uint32_t opcode) {
|
||||
"""}
|
||||
|
||||
for f in files_header:
|
||||
# Save the string for the next iteration, writing was successful
|
||||
with open(os.path.join(root, "src", "dynarec", f), 'w') as file:
|
||||
file.write(header.format(version = ver))
|
||||
file.write(files_header[f])
|
||||
file.write(output)
|
||||
file.write(files_guard[f])
|
||||
# Save the string for the next iteration, writing was successful
|
||||
with open(os.path.join(root, "src", "dynarec", "last_run.txt"), 'w') as file:
|
||||
file.write('\n'.join(insts))
|
||||
|
||||
|
||||
+311
-77
@@ -3,7 +3,60 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
values = ['E', 'e', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'V', 'O', 'S', '2', 'P', 'G']
|
||||
"""
|
||||
Generates all files in src/wrapped/generated
|
||||
===
|
||||
|
||||
TL;DR: Automagically creates type definitions (/.F.+/ functions/typedefs...).
|
||||
All '//%' in the headers are used by the script.
|
||||
|
||||
Reads each lines of each "_private.h" headers (plus wrappedd3dadapter9_gen.h as a special case).
|
||||
For each of them:
|
||||
- If if starts with a #ifdef, #else, #ifndef, #endif, it memorizes which definition is required
|
||||
- If it starts with a "GO", it will do multiple things:
|
||||
- It memorizes the type used by the function (second macro argument)
|
||||
- It memorizes the type it is mapped to, if needed (eg, iFEv is mapped to iFE: the second argument is dropped)
|
||||
- It checks if the type given (both original and )
|
||||
- If the signature contains a 'E', it will memorize the original function's signature:
|
||||
- If it is the special file case, or if the line contains "//%%", it stops there.
|
||||
- Otherwise, if it starts with "GOS":
|
||||
- It will search for the special marker "//%".
|
||||
That special marker is used to detect the following step:
|
||||
- If the marker is followed by a registered structure ID (see later), it transforms the assembly function signature
|
||||
into the original signature (eg, transforms pFEp into XFv if //%X was used)
|
||||
- If the marker is followed by a '{', it will not attempt to alter the given signature, and instead use the
|
||||
signature between '{' and '}'
|
||||
- Otherwise, if the line contains '//%{', like before it will use the signature given and not the original one.
|
||||
- Finally, if it still didn't stop, it will use the assembly signature (without the emulator).
|
||||
- If the line starts with a '//%'
|
||||
|
||||
`gbl` contains the first list, `redirects` the second, `mytypedefs` the third.
|
||||
`mystructs` and `mystructs_vals` constains data about the structures.
|
||||
|
||||
After sorting the data, it generates:
|
||||
|
||||
wrapper.c
|
||||
---------
|
||||
(Private) type definitions (/.F.+_t/)
|
||||
Function definitions (/.F.+/ functions, that actually execute the function given as argument)
|
||||
isSimpleWrapper definition
|
||||
|
||||
wrapper.h
|
||||
---------
|
||||
Generic "wrapper_t" type definition
|
||||
Function declarations (/.F.+/ functions)
|
||||
|
||||
*types.h
|
||||
--------
|
||||
Local types definition, for the original signatures (eg, XFv for the earlier example)
|
||||
The SUPER() macro definition, used to generate and initialize the `*_my_t` library structure
|
||||
(TODO: also automate this declaration/definition? It would require more metadata,
|
||||
and may break sometime in the future due to the system changing...)
|
||||
"""
|
||||
|
||||
# Free values:
|
||||
# AB F H J QR T XYZab gh jk mno qrst xyz
|
||||
values = ['E', 'e', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'V', 'O', 'S', '2', 'P', 'G', 'N', 'M']
|
||||
def splitchar(s):
|
||||
try:
|
||||
ret = [len(s), values.index(s[0])]
|
||||
@@ -38,15 +91,26 @@ def main(root, defines, files, ver):
|
||||
global values
|
||||
|
||||
# Initialize variables: gbl for all values, redirects for redirections
|
||||
gbl = {}
|
||||
redirects = {}
|
||||
# mytypedefs is a list of all functions per "*FE*" types per filename, mystructs of structures per filename
|
||||
gbl = {}
|
||||
redirects = {}
|
||||
mytypedefs = {}
|
||||
mystructs = {}
|
||||
mystructs_vals = {}
|
||||
|
||||
# First read the files inside the headers
|
||||
for filepath in files:
|
||||
# TODO: remove the special case...
|
||||
for filepath in files + [os.path.join(root, "src", "wrapped", "wrappedd3dadapter9_gen.h")]:
|
||||
filename = filepath.split("/")[-1]
|
||||
dependants = []
|
||||
with open(filepath, 'r') as file:
|
||||
for line in file:
|
||||
def fail(s, causedby=None):
|
||||
if causedby:
|
||||
raise NotImplementedError(s + " ({0}:{1})".format(filename, line[:-1])) from causedby
|
||||
else:
|
||||
raise NotImplementedError(s + " ({0}:{1})".format(filename, line[:-1]))
|
||||
|
||||
ln = line.strip()
|
||||
# If the line is a `#' line (#ifdef LD80BITS/#ifndef LD80BITS/header)
|
||||
if ln.startswith("#"):
|
||||
@@ -58,6 +122,8 @@ def main(root, defines, files, ver):
|
||||
continue #if !(defined(GO) && defined(GOM)...)
|
||||
elif preproc_cmd.startswith("error"):
|
||||
continue #error meh!
|
||||
elif preproc_cmd.startswith("include"):
|
||||
continue #inherit other library
|
||||
elif preproc_cmd.startswith("endif"):
|
||||
if dependants != []:
|
||||
dependants.pop()
|
||||
@@ -72,28 +138,36 @@ def main(root, defines, files, ver):
|
||||
elif preproc_cmd.startswith("else"):
|
||||
dependants[-1] = invert(dependants[-1])
|
||||
else:
|
||||
raise NotImplementedError("Unknown preprocessor directive: {0} ({1}:{2})".format(
|
||||
preproc_cmd.split(" ")[0], filename, line[:-1]
|
||||
))
|
||||
fail("Unknown preprocessor directive: {0}".format(preproc_cmd.split(" ")[0]))
|
||||
except KeyError as k:
|
||||
raise NotImplementedError("Unknown key: {0} ({1}:{2})".format(
|
||||
k.args[0], filename, line[:-1]
|
||||
), k)
|
||||
fail("Unknown key: {0}".format(k.args[0]), k)
|
||||
# If the line is a `GO...' line (GO/GOM/GO2/...)...
|
||||
elif ln.startswith("GO"):
|
||||
# ... then look at the second parameter of the line
|
||||
gotype = ln.split("(")[0].strip()
|
||||
funname = ln.split(",")[0].split("(")[1].strip()
|
||||
ln = ln.split(",")[1].split(")")[0].strip()
|
||||
|
||||
if ln[1] not in ["F"]:
|
||||
raise NotImplementedError("Bad middle letter {0} ({1}:{2})".format(ln[1], filename, line[:-1]))
|
||||
if len(ln) < 3:
|
||||
fail("Type {0} too short".format(ln))
|
||||
if "E" in ln:
|
||||
if ("E" in ln[:2]) or ("E" in ln[3:]):
|
||||
fail("emu64_t* not as the first parameter")
|
||||
if len(ln) < 4:
|
||||
fail("Type {0} too short".format(ln))
|
||||
if ln[0] not in values:
|
||||
fail("Invalid return type {0}".format(ln[0]))
|
||||
|
||||
if ln[1] != "F":
|
||||
fail("Bad middle letter {0}".format(ln[1]))
|
||||
if any(c not in values for c in ln[2:]) or (('v' in ln[2:]) and (len(ln) > 3)):
|
||||
old = ln
|
||||
# This needs more work
|
||||
acceptables = ['v', '0', '1'] + values
|
||||
if any(c not in acceptables for c in ln[2:]):
|
||||
raise NotImplementedError("{0} ({1}:{2})".format(ln[2:], filename, line[:-1]))
|
||||
fail("Invalid type {0}".format(ln[2:]))
|
||||
# Ok, this is acceptable: there is 0, 1 and/or void
|
||||
ln = (ln
|
||||
ln = ln[:2] + (ln[2:]
|
||||
.replace("v", "") # void -> nothing
|
||||
.replace("0", "p") # 0 -> pointer
|
||||
.replace("1", "i")) # 1 -> integer
|
||||
@@ -103,6 +177,111 @@ def main(root, defines, files, ver):
|
||||
gbl.setdefault(" && ".join(dependants), [])
|
||||
if ln not in gbl[" && ".join(dependants)]:
|
||||
gbl[" && ".join(dependants)].append(ln)
|
||||
|
||||
if filename == "wrappedd3dadapter9_gen.h":
|
||||
pass # Special case...
|
||||
elif ln[2] == 'E':
|
||||
if "//%%" in line:
|
||||
# Do not dlsym functions containing "//%%" as metadata
|
||||
pass
|
||||
elif gotype == "GOS":
|
||||
# Scan the rest of the line to extract the return structure ID
|
||||
if filename[:-10] not in mystructs:
|
||||
fail("No structure info in the file")
|
||||
if "//%" not in line:
|
||||
fail("Invalid GOS (missing structure ID info)")
|
||||
if ln[0] != 'p':
|
||||
fail("Invalid GOS return type ('{0}' and not 'p')".format(ln[0]))
|
||||
#if (ln[2] != 'p') and ((ln[2] != 'E') or (ln[3] != 'p')): -> only allow pFEp for now
|
||||
# fail("Invalid GOS first parameter ('{0}' and not 'p' or 'Ep')".format(ln[2:4]))
|
||||
if (ln[2] != 'E') or (ln[3] != 'p'):
|
||||
fail("Invalid GOS first parameter ('{0}' and not 'Ep')".format(ln[2:4]))
|
||||
|
||||
sid = line.split("//%")[1].split(" ")[0].strip()
|
||||
if sid[0] == '{':
|
||||
# Change type completely, not just the return type...
|
||||
if sid[-1] != '}':
|
||||
fail("Invalid type (EOL or space met, expected '}')")
|
||||
if len(sid) < 5:
|
||||
fail("Invalid type (Type {0} too short)".format(sid[1:-1]))
|
||||
if sid[2] != "F":
|
||||
fail("Invalid type (Bad middle letter {0})".format(sid[2]))
|
||||
inval_char = lambda c:\
|
||||
(c not in mystructs[filename[:-10]]) and (c not in acceptables) \
|
||||
or (c == 'E') or (c == 'e')
|
||||
if inval_char(sid[1]):
|
||||
fail("Invalid type (Invalid return type {0})".format(sid[1]))
|
||||
if any(map(inval_char, sid[3:-1])):
|
||||
fail("Invalid type (Invalid type {0})".format(sid[3:-1]))
|
||||
mytypedefs.setdefault(filename[:-10], {})
|
||||
mytypedefs[filename[:-10]].setdefault(sid[1:-1], [])
|
||||
mytypedefs[filename[:-10]][sid[1:-1]].append((0, funname))
|
||||
else:
|
||||
if len(sid) != 1:
|
||||
fail("Invalid structure ID {0} (length is too big)".format(sid))
|
||||
if sid not in mystructs[filename[:-10]]:
|
||||
fail("Invalid structure ID {0} (unknown ID)".format(sid))
|
||||
mytypedefs.setdefault(filename[:-10], {})
|
||||
mytypedefs[filename[:-10]].setdefault(sid + "F" + ln[4:], [])
|
||||
mytypedefs[filename[:-10]][sid + "F" + ln[4:]].append((1, funname))
|
||||
elif "//%{" in line:
|
||||
# Change type completely...
|
||||
# ...Maybe?
|
||||
if filename[:-10] not in mystructs:
|
||||
fail("No structure info in the file")
|
||||
|
||||
newtype = line.split("//%")[1].split(" ")[0].strip()
|
||||
if newtype[-1] != '}':
|
||||
fail("Invalid type (EOL or space met, expected '}')")
|
||||
if len(newtype) < 5:
|
||||
fail("Invalid type (Type {0} too short)".format(newtype[1:-1]))
|
||||
if newtype[2] != "F":
|
||||
fail("Invalid type (Bad middle letter {0})".format(newtype[2]))
|
||||
inval_char = lambda c:\
|
||||
(c not in mystructs[filename[:-10]]) and (c not in acceptables) \
|
||||
or (c == 'E') or (c == 'e')
|
||||
if inval_char(newtype[1]):
|
||||
fail("Invalid type (Invalid return type {0})".format(newtype[1]))
|
||||
if any(map(inval_char, newtype[3:-1])):
|
||||
fail("Invalid type (Invalid type {0})".format(newtype[3:-1]))
|
||||
mytypedefs.setdefault(filename[:-10], {})
|
||||
mytypedefs[filename[:-10]].setdefault(newtype[1:-1], [])
|
||||
mytypedefs[filename[:-10]][newtype[1:-1]].append((2, funname))
|
||||
else:
|
||||
# filename isn't stored with the '_private.h' part
|
||||
if not filename.endswith('_private.h'):
|
||||
fail("??? {0}".format(filename))
|
||||
if len(ln) > 3:
|
||||
ln = ln[:2] + ln[3:]
|
||||
else:
|
||||
ln = ln[:2] + "v"
|
||||
mytypedefs.setdefault(filename[:-10], {})
|
||||
mytypedefs[filename[:-10]].setdefault(ln, [])
|
||||
mytypedefs[filename[:-10]][ln].append((3, funname))
|
||||
elif ln.startswith("//%S"):
|
||||
# Extract a structure ID-name pair
|
||||
data = [s for s in map(lambda s: s.strip(), ln.split(" ")) if s != ""]
|
||||
if len(data) != 3:
|
||||
fail("Too much data ({0})".format(len(data)))
|
||||
if not filename.endswith('_private.h'):
|
||||
fail("??? {0}".format(filename))
|
||||
if (data[0] != "//%S") or (len(data[1]) != 1):
|
||||
fail("Invalid structure data {0} {1}".format(data[0], data[1]))
|
||||
if data[1] in values:
|
||||
fail("{0} cannot be used as a structure type".format(data[1]))
|
||||
mystructs.setdefault(filename[:-10], {})
|
||||
if data[1] in mystructs[filename[:-10]]:
|
||||
fail("Duplicate structure ID {0} ({1}/{2})".format(data[1], mystructs[filename[:-10]], data[2]))
|
||||
mystructs[filename[:-10]][data[1]] = data[2]
|
||||
mystructs_vals.setdefault(filename[:-10], [])
|
||||
mystructs_vals[filename[:-10]].append(data[1])
|
||||
|
||||
if ("" not in gbl) or ("" not in redirects):
|
||||
print("\033[1;31mThere is suspiciously not many types...\033[m")
|
||||
print("Check the CMakeLists.txt file. If you are SURE there is nothing wrong"
|
||||
" (as a random example, `set()` resets the variable...), then comment out the following return.")
|
||||
print("(Also, the program WILL crash later if you proceed.)")
|
||||
return 2 # Check what you did, not proceeding
|
||||
|
||||
gbl_vals = {}
|
||||
for k in gbl:
|
||||
@@ -182,8 +361,17 @@ def main(root, defines, files, ver):
|
||||
gbl[k].sort(key=lambda v: splitchar(v))
|
||||
values = values + ['0', '1']
|
||||
for k in redirects:
|
||||
redirects[k].sort(key=lambda v: splitchar(v[0]) + [0] + splitchar(v[1]))
|
||||
redirects[k].sort(key=lambda v: splitchar(v[0]) + [-1] + splitchar(v[1]))
|
||||
values = values[:-2]
|
||||
mytypedefs_vals = {}
|
||||
for fn in mytypedefs:
|
||||
if fn in mystructs:
|
||||
values = values + list(mystructs[fn].keys())
|
||||
mytypedefs_vals[fn] = sorted(mytypedefs[fn].keys(), key=lambda v: splitchar(v))
|
||||
if fn in mystructs:
|
||||
values = values[:-len(mystructs[fn])]
|
||||
for v in mytypedefs_vals[fn]:
|
||||
mytypedefs[fn][v].sort()
|
||||
|
||||
# Check if there was any new functions
|
||||
functions_list = ""
|
||||
@@ -193,6 +381,15 @@ def main(root, defines, files, ver):
|
||||
for k in ["()"] + redirects_idxs:
|
||||
for v in redirects[k]:
|
||||
functions_list = functions_list + "#" + k + " " + v[0] + " -> " + v[1] + "\n"
|
||||
for fn in sorted(mystructs.keys()):
|
||||
for t in mystructs_vals[fn]:
|
||||
# Structure Definition
|
||||
functions_list = functions_list + fn + "/Sd" + t + mystructs[fn][t] + "\n"
|
||||
for fn in sorted(mytypedefs.keys()):
|
||||
for t in mytypedefs_vals[fn]:
|
||||
# Structure Usage
|
||||
for tnum, f in mytypedefs[fn][t]:
|
||||
functions_list = functions_list + fn + "/Su" + t + str(tnum) + f + "\n"
|
||||
|
||||
# functions_list is a unique string, compare it with the last run
|
||||
try:
|
||||
@@ -203,16 +400,16 @@ def main(root, defines, files, ver):
|
||||
# Mark as OK for CMake
|
||||
with open(os.path.join(root, "src", "wrapped", "generated", "functions_list.txt"), 'w') as file:
|
||||
file.write(functions_list)
|
||||
#return 0
|
||||
return 0
|
||||
except IOError:
|
||||
# The file does not exist yet, first run
|
||||
pass
|
||||
|
||||
# Now the files rebuilding part
|
||||
# File headers and guards
|
||||
files_headers = {
|
||||
# Files header and guard
|
||||
files_header = {
|
||||
"wrapper.c": """/*****************************************************************
|
||||
* File automatically generated by rebuild_wrappers.py (v%s)
|
||||
* File automatically generated by rebuild_wrappers.py (v{version})
|
||||
*****************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -224,23 +421,23 @@ def main(root, defines, files, ver):
|
||||
#include "regs.h"
|
||||
#include "x86emu.h"
|
||||
|
||||
typedef union ui64_s {
|
||||
typedef union ui64_s {lbr}
|
||||
int64_t i;
|
||||
uint64_t u;
|
||||
uint32_t d[2];
|
||||
} ui64_t;
|
||||
{rbr} ui64_t;
|
||||
|
||||
typedef struct _2uint_struct_s {
|
||||
typedef struct _2uint_struct_s {lbr}
|
||||
uint32_t a;
|
||||
uint32_t b;
|
||||
} _2uint_struct_t;
|
||||
{rbr} _2uint_struct_t;
|
||||
|
||||
extern void* my__IO_2_1_stderr_;
|
||||
extern void* my__IO_2_1_stdin_ ;
|
||||
extern void* my__IO_2_1_stdout_;
|
||||
|
||||
static void* io_convert(void* v)
|
||||
{
|
||||
{lbr}
|
||||
if(!v)
|
||||
return v;
|
||||
if(v==my__IO_2_1_stderr_)
|
||||
@@ -250,31 +447,31 @@ static void* io_convert(void* v)
|
||||
if(v==my__IO_2_1_stdout_)
|
||||
return stdout;
|
||||
return v;
|
||||
}
|
||||
{rbr}
|
||||
|
||||
typedef struct my_GValue_s
|
||||
{
|
||||
{lbr}
|
||||
int g_type;
|
||||
union {
|
||||
union {lbr}
|
||||
int v_int;
|
||||
int64_t v_int64;
|
||||
uint64_t v_uint64;
|
||||
float v_float;
|
||||
double v_double;
|
||||
void* v_pointer;
|
||||
} data[2];
|
||||
} my_GValue_t;
|
||||
{rbr} data[2];
|
||||
{rbr} my_GValue_t;
|
||||
|
||||
static void alignGValue(my_GValue_t* v, void* value)
|
||||
{
|
||||
{lbr}
|
||||
v->g_type = *(int*)value;
|
||||
memcpy(v->data, value+4, 2*sizeof(double));
|
||||
}
|
||||
{rbr}
|
||||
static void unalignGValue(void* value, my_GValue_t* v)
|
||||
{
|
||||
{lbr}
|
||||
*(int*)value = v->g_type;
|
||||
memcpy(value+4, v->data, 2*sizeof(double));
|
||||
}
|
||||
{rbr}
|
||||
|
||||
void* VulkanFromx86(void* src, void** save);
|
||||
void VulkanTox86(void* src, void* save);
|
||||
@@ -282,9 +479,10 @@ void VulkanTox86(void* src, void* save);
|
||||
#define ST0val ST0.d
|
||||
|
||||
int of_convert(int);
|
||||
|
||||
""",
|
||||
"wrapper.h": """/*****************************************************************
|
||||
* File automatically generated by rebuild_wrappers.py (v%s)
|
||||
* File automatically generated by rebuild_wrappers.py (v{version})
|
||||
*****************************************************************/
|
||||
#ifndef __WRAPPER_H_
|
||||
#define __WRAPPER_H_
|
||||
@@ -312,58 +510,52 @@ typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
|
||||
// 2 = struct of 2 uint
|
||||
// P = Vulkan struture pointer
|
||||
// G = a single GValue pointer
|
||||
// N = ... automatically sending 1 arg
|
||||
// M = ... automatically sending 2 args
|
||||
|
||||
""",
|
||||
"fntypes.h": """/*****************************************************************
|
||||
* File automatically generated by rebuild_wrappers.py (v{version})
|
||||
*****************************************************************/
|
||||
#ifndef __{filename}TYPES_H_
|
||||
#define __{filename}TYPES_H_
|
||||
|
||||
#ifndef LIBNAME
|
||||
#error You should only #include this file inside a wrapped*.c file
|
||||
#endif
|
||||
#ifndef ADDED_FUNCTIONS
|
||||
#define ADDED_FUNCTIONS()
|
||||
#endif
|
||||
|
||||
"""
|
||||
}
|
||||
files_guards = {"wrapper.c": """""",
|
||||
files_guard = {"wrapper.c": """""",
|
||||
"wrapper.h": """
|
||||
#endif //__WRAPPER_H_
|
||||
#endif // __WRAPPER_H_
|
||||
""",
|
||||
"fntypes.h": """
|
||||
#endif // __{filename}TYPES_H_
|
||||
"""
|
||||
}
|
||||
|
||||
# Rewrite the wrapper.h file:
|
||||
with open(os.path.join(root, "src", "wrapped", "generated", "wrapper.h"), 'w') as file:
|
||||
file.write(files_headers["wrapper.h"] % ver)
|
||||
for v in gbl["()"]:
|
||||
file.write("void " + v + "(x86emu_t *emu, uintptr_t fnc);\n")
|
||||
for k in gbl_idxs:
|
||||
file.write("\n#if " + k + "\n")
|
||||
for v in gbl[k]:
|
||||
file.write("void " + v + "(x86emu_t *emu, uintptr_t fnc);\n")
|
||||
file.write("#endif\n")
|
||||
file.write("\n")
|
||||
for v in redirects["()"]:
|
||||
file.write("void " + v[0] + "(x86emu_t *emu, uintptr_t fnc);\n")
|
||||
for k in redirects_idxs:
|
||||
file.write("\n#if " + k + "\n")
|
||||
for v in redirects[k]:
|
||||
file.write("void " + v[0] + "(x86emu_t *emu, uintptr_t fnc);\n")
|
||||
file.write("#endif\n")
|
||||
file.write(files_guards["wrapper.h"])
|
||||
# E e v c w i I C W u U f d D K l L p V O S 2 P G N M
|
||||
tdtypes = ["x86emu_t*", "x86emu_t**", "void", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t", "float", "double", "long double", "double", "intptr_t", "uintptr_t", "void*", "void*", "int32_t", "void*", "_2uint_struct_t", "void*", "void*", "...", "..."]
|
||||
if len(values) != len(tdtypes):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(tdtypes) = {lentypes}".format(lenval=len(values), lentypes=len(tdtypes)))
|
||||
def generate_typedefs(arr, file):
|
||||
for v in arr:
|
||||
file.write("typedef " + tdtypes[values.index(v[0])] + " (*" + v + "_t)"
|
||||
+ "(" + ', '.join(tdtypes[values.index(t)] for t in v[2:]) + ");\n")
|
||||
|
||||
# Rewrite the wrapper.c file:
|
||||
with open(os.path.join(root, "src", "wrapped", "generated", "wrapper.c"), 'w') as file:
|
||||
file.write(files_headers["wrapper.c"] % ver)
|
||||
file.write(files_header["wrapper.c"].format(lbr="{", rbr="}", version=ver))
|
||||
|
||||
# First part: typedefs
|
||||
for v in gbl["()"]:
|
||||
# E e v c w i I C W u U f d D K l L p V O S 2 P G
|
||||
types = ["x86emu_t*", "x86emu_t**", "void", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t", "float", "double", "long double", "double", "intptr_t", "uintptr_t", "void*", "void*", "int32_t", "void*", "_2uint_struct_t", "void*", "void*"]
|
||||
if len(values) != len(types):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(types) = {lentypes}".format(lenval=len(values), lentypes=len(types)))
|
||||
|
||||
file.write("typedef " + types[values.index(v[0])] + " (*" + v + "_t)"
|
||||
+ "(" + ', '.join(types[values.index(t)] for t in v[2:]) + ");\n")
|
||||
generate_typedefs(gbl["()"], file)
|
||||
for k in gbl_idxs:
|
||||
file.write("\n#if " + k + "\n")
|
||||
for v in gbl[k]:
|
||||
# E e v c w i I C W u U f d D K l L p V O S 2 P G
|
||||
types = ["x86emu_t*", "x86emu_t**", "void", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t", "float", "double", "long double", "double", "intptr_t", "uintptr_t", "void*", "void*", "int32_t", "void*", "_2uint_struct_t", "void*", "void*"]
|
||||
if len(values) != len(types):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(types) = {lentypes}".format(lenval=len(values), lentypes=len(types)))
|
||||
|
||||
file.write("typedef " + types[values.index(v[0])] + " (*" + v + "_t)"
|
||||
+ "(" + ', '.join(types[values.index(t)] for t in v[2:]) + ");\n")
|
||||
generate_typedefs(gbl[k], file)
|
||||
file.write("#endif\n")
|
||||
|
||||
file.write("\n")
|
||||
@@ -385,7 +577,7 @@ typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
|
||||
"*(uint64_t*)(R_ESP + {p}), ", # U
|
||||
"*(float*)(R_ESP + {p}), ", # f
|
||||
"*(double*)(R_ESP + {p}), ", # d
|
||||
"*(long double*)(R_ESP + {p}), ", # D
|
||||
"LD2localLD((void*)(R_ESP + {p})), ", # D
|
||||
"FromLD((void*)(R_ESP + {p})), ", # K
|
||||
"*(intptr_t*)(R_ESP + {p}), ", # l
|
||||
"*(uintptr_t*)(R_ESP + {p}), ", # L
|
||||
@@ -393,12 +585,14 @@ typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
|
||||
"(void*)(R_ESP + {p}), ", # V
|
||||
"of_convert(*(int32_t*)(R_ESP + {p})), ", # O
|
||||
"io_convert(*(void**)(R_ESP + {p})), ", # S
|
||||
"(_2uint_struct_t){{*(uintptr_t*)(R_ESP + {p}),*(uintptr_t*)(R_ESP + {p} + 4)}}, ", #2
|
||||
"(_2uint_struct_t){{*(uintptr_t*)(R_ESP + {p}),*(uintptr_t*)(R_ESP + {p} + 4)}}, ", # 2
|
||||
"arg{p}, ", # P
|
||||
"&arg{p}, ", # G
|
||||
"*(void**)(R_ESP + {p}), ", # N
|
||||
"*(void**)(R_ESP + {p}),*(void**)(R_ESP + {p} + 4), ", # M
|
||||
]
|
||||
# E e v c w i I C W u U f d D K l L p V O S 2 P G
|
||||
deltas = [0, 0, 4, 4, 4, 4, 8, 4, 4, 4, 8, 4, 8, 12, 12, 4, 4, 4, 0, 4, 4, 8, 4, 4]
|
||||
# E e v c w i I C W u U f d D K l L p V O S 2 P G N, M
|
||||
deltas = [0, 0, 4, 4, 4, 4, 8, 4, 4, 4, 8, 4, 8, 12, 12, 4, 4, 4, 0, 4, 4, 8, 4, 4, 0, 0]
|
||||
vals = [
|
||||
"\n#error Invalid return type: emulator\n", # E
|
||||
"\n#error Invalid return type: &emulator\n", # e
|
||||
@@ -424,6 +618,8 @@ typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
|
||||
"\n#error Invalid return type: _2uint_struct\n", # 2
|
||||
"\n#error Invalid return type: Vulkan Struct\n", # P
|
||||
"\n#error Invalid return type: GValue Pointer\n", # G
|
||||
"\n#error Invalid return type: ... with 1 arg\n", # N
|
||||
"\n#error Invalid return type: ... with 2 args\n", # M
|
||||
]
|
||||
# Asserts
|
||||
if len(values) != len(arg):
|
||||
@@ -487,7 +683,45 @@ typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
|
||||
function_writer(file, v[0], v[1] + "_t", v[0][0], v[0][2:])
|
||||
file.write("#endif\n")
|
||||
|
||||
file.write(files_guards["wrapper.c"])
|
||||
file.write(files_guard["wrapper.c"].format(lbr="{", rbr="}", version=ver))
|
||||
|
||||
# Rewrite the wrapper.h file:
|
||||
with open(os.path.join(root, "src", "wrapped", "generated", "wrapper.h"), 'w') as file:
|
||||
file.write(files_header["wrapper.h"].format(lbr="{", rbr="}", version=ver))
|
||||
for v in gbl["()"]:
|
||||
file.write("void " + v + "(x86emu_t *emu, uintptr_t fnc);\n")
|
||||
for k in gbl_idxs:
|
||||
file.write("\n#if " + k + "\n")
|
||||
for v in gbl[k]:
|
||||
file.write("void " + v + "(x86emu_t *emu, uintptr_t fnc);\n")
|
||||
file.write("#endif\n")
|
||||
file.write("\n")
|
||||
for v in redirects["()"]:
|
||||
file.write("void " + v[0] + "(x86emu_t *emu, uintptr_t fnc);\n")
|
||||
for k in redirects_idxs:
|
||||
file.write("\n#if " + k + "\n")
|
||||
for v in redirects[k]:
|
||||
file.write("void " + v[0] + "(x86emu_t *emu, uintptr_t fnc);\n")
|
||||
file.write("#endif\n")
|
||||
file.write(files_guard["wrapper.h"].format(lbr="{", rbr="}", version=ver))
|
||||
|
||||
for fn in mytypedefs:
|
||||
with open(os.path.join(root, "src", "wrapped", "generated", fn + "types.h"), 'w') as file:
|
||||
file.write(files_header["fntypes.h"].format(lbr="{", rbr="}", version=ver, filename=fn))
|
||||
if fn in mystructs:
|
||||
values = values + mystructs_vals[fn]
|
||||
tdtypes = tdtypes + [mystructs[fn][k] for k in mystructs_vals[fn]]
|
||||
generate_typedefs(mytypedefs_vals[fn], file)
|
||||
if fn in mystructs:
|
||||
values = values[:-len(mystructs_vals[fn])]
|
||||
tdtypes = tdtypes[:-len(mystructs_vals[fn])]
|
||||
file.write("\n#define SUPER() ADDED_FUNCTIONS()")
|
||||
for v in mytypedefs_vals[fn]:
|
||||
for t, f in mytypedefs[fn][v]:
|
||||
assert(t in [0, 1, 2, 3])
|
||||
file.write(" \\\n\tGO({0}, {1}_t)".format(f, v))
|
||||
file.write("\n")
|
||||
file.write(files_guard["fntypes.h"].format(lbr="{", rbr="}", version=ver, filename=fn))
|
||||
|
||||
# Save the string for the next iteration, writing was successful
|
||||
with open(os.path.join(root, "src", "wrapped", "generated", "functions_list.txt"), 'w') as file:
|
||||
|
||||
+7
-1
@@ -32,17 +32,23 @@ execute_process(
|
||||
|
||||
# if the return value is !=0 bail out
|
||||
if( TEST_RESULT )
|
||||
get_filename_component(TESTNAME "${TEST_ARGS}" NAME)
|
||||
file(RENAME "${TEST_OUTPUT}" "${CMAKE_BINARY_DIR}/${TESTNAME}.out")
|
||||
file(WRITE "${CMAKE_BINARY_DIR}/${TESTNAME}.err" ${TEST_ERROR})
|
||||
message( FATAL_ERROR "Failed: Test program ${TEST_PROGRAM} exited != 0.\n${TEST_ERROR}" )
|
||||
endif( TEST_RESULT )
|
||||
|
||||
# now compare the output with the reference
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E compare_files ${TEST_OUTPUT} ${TEST_REFERENCE}
|
||||
COMMAND "${CMAKE_COMMAND}" -E compare_files "${TEST_OUTPUT}" "${TEST_REFERENCE}"
|
||||
RESULT_VARIABLE TEST_RESULT
|
||||
)
|
||||
|
||||
# again, if return value is !=0 scream and shout
|
||||
if( TEST_RESULT )
|
||||
get_filename_component(TESTNAME "${TEST_ARGS}" NAME)
|
||||
file(RENAME "${TEST_OUTPUT}" "${CMAKE_BINARY_DIR}/${TESTNAME}.out")
|
||||
file(WRITE "${CMAKE_BINARY_DIR}/${TESTNAME}.err" ${TEST_ERROR})
|
||||
message( FATAL_ERROR "Failed: The output of ${TEST_PROGRAM} did not match ${TEST_REFERENCE}")
|
||||
endif( TEST_RESULT )
|
||||
|
||||
|
||||
+93
-404
@@ -19,334 +19,15 @@
|
||||
#include "threads.h"
|
||||
#include "x86trace.h"
|
||||
#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include <sys/mman.h>
|
||||
#include "custommem.h"
|
||||
#ifdef DYNAREC
|
||||
#include "dynablock.h"
|
||||
#include "khash.h"
|
||||
|
||||
#define MMAPSIZE (256*1024) // allocate 256kb sized blocks
|
||||
|
||||
// init inside dynablocks.c
|
||||
KHASH_MAP_INIT_INT(dynablocks, dynablock_t*)
|
||||
|
||||
typedef union mark_s {
|
||||
struct {
|
||||
unsigned int fill:1;
|
||||
unsigned int size:31;
|
||||
};
|
||||
uint32_t x32;
|
||||
} mark_t;
|
||||
typedef struct blockmark_s {
|
||||
mark_t prev;
|
||||
mark_t next;
|
||||
} blockmark_t;
|
||||
|
||||
typedef struct mmaplist_s {
|
||||
void* block;
|
||||
int maxfree;
|
||||
kh_dynablocks_t* dblist;
|
||||
} mmaplist_t;
|
||||
|
||||
|
||||
// get first subblock free in block, stating at start (from block). return NULL if no block, else first subblock free (mark included), filling size
|
||||
static void* getFirstBlock(void* block, int maxsize, int* size)
|
||||
{
|
||||
// get start of block
|
||||
blockmark_t *m = (blockmark_t*)block;
|
||||
while(m->next.x32) { // while there is a subblock
|
||||
if(!m->next.fill && m->next.size>=maxsize+sizeof(blockmark_t)) {
|
||||
*size = m->next.size;
|
||||
return m;
|
||||
}
|
||||
m = (blockmark_t*)((uintptr_t)m + m->next.size);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int getMaxFreeBlock(void* block)
|
||||
{
|
||||
// get start of block
|
||||
blockmark_t *m = (blockmark_t*)((uintptr_t)block+MMAPSIZE-sizeof(blockmark_t)); // styart with the end
|
||||
int maxsize = 0;
|
||||
while(m->prev.x32) { // while there is a subblock
|
||||
if(!m->prev.fill && m->prev.size>maxsize) {
|
||||
maxsize = m->prev.size;
|
||||
if((uintptr_t)block+maxsize>(uintptr_t)m)
|
||||
return maxsize; // no block large enough left...
|
||||
}
|
||||
m = (blockmark_t*)((uintptr_t)m - m->prev.size);
|
||||
}
|
||||
return maxsize;
|
||||
}
|
||||
|
||||
static void* allocBlock(void* block, void *sub, int size)
|
||||
{
|
||||
blockmark_t *s = (blockmark_t*)sub;
|
||||
blockmark_t *n = (blockmark_t*)((uintptr_t)s + s->next.size);
|
||||
|
||||
s->next.fill = 1;
|
||||
s->next.size = size+sizeof(blockmark_t);
|
||||
blockmark_t *m = (blockmark_t*)((uintptr_t)s + s->next.size); // this is new n
|
||||
m->prev.fill = 1;
|
||||
m->prev.size = s->next.size;
|
||||
if(n!=m) {
|
||||
// new mark
|
||||
m->prev.fill = 1;
|
||||
m->prev.size = s->next.size;
|
||||
m->next.fill = 0;
|
||||
m->next.size = (uintptr_t)n - (uintptr_t)m;
|
||||
n->prev.fill = 0;
|
||||
n->prev.size = m->next.size;
|
||||
}
|
||||
|
||||
return (void*)((uintptr_t)sub + sizeof(blockmark_t));
|
||||
}
|
||||
static void freeBlock(void *block, void* sub, int size)
|
||||
{
|
||||
blockmark_t *m = (blockmark_t*)block;
|
||||
blockmark_t *s = (blockmark_t*)sub;
|
||||
blockmark_t *n = (blockmark_t*)((uintptr_t)s + s->next.size);
|
||||
if(block!=sub)
|
||||
m = (blockmark_t*)((uintptr_t)s - s->prev.size);
|
||||
s->next.fill = 0;
|
||||
n->prev.fill = 0;
|
||||
// check if merge with previous
|
||||
if (s->prev.x32 && !s->prev.fill) {
|
||||
// remove s...
|
||||
m->next.size += s->next.size;
|
||||
n->prev.size = m->next.size;
|
||||
s = m;
|
||||
}
|
||||
// check if merge with next
|
||||
if(n->next.x32 && !n->next.fill) {
|
||||
blockmark_t *n2 = (blockmark_t*)((uintptr_t)n + n->next.size);
|
||||
//remove n
|
||||
s->next.size += n->next.size;
|
||||
n2->prev.size = s->next.size;
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t FindFreeDynarecMap(dynablock_t* db, int size)
|
||||
{
|
||||
// look for free space
|
||||
void* sub = NULL;
|
||||
for(int i=0; i<my_context->mmapsize; ++i) {
|
||||
if(my_context->mmaplist[i].maxfree>=size) {
|
||||
int rsize = 0;
|
||||
sub = getFirstBlock(my_context->mmaplist[i].block, size, &rsize);
|
||||
if(sub) {
|
||||
uintptr_t ret = (uintptr_t)allocBlock(my_context->mmaplist[i].block, sub, size);
|
||||
if(rsize==my_context->mmaplist[i].maxfree)
|
||||
my_context->mmaplist[i].maxfree = getMaxFreeBlock(my_context->mmaplist[i].block);
|
||||
kh_dynablocks_t *blocks = my_context->mmaplist[i].dblist;
|
||||
if(!blocks) {
|
||||
blocks = my_context->mmaplist[i].dblist = kh_init(dynablocks);
|
||||
kh_resize(dynablocks, blocks, 64);
|
||||
}
|
||||
khint_t k;
|
||||
int r;
|
||||
k = kh_put(dynablocks, blocks, (uintptr_t)db, &r);
|
||||
kh_value(blocks, k) = db;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uintptr_t AddNewDynarecMap(dynablock_t* db, int size)
|
||||
{
|
||||
int i = my_context->mmapsize++; // yeah, useful post incrementation
|
||||
dynarec_log(LOG_DEBUG, "Ask for DynaRec Block Alloc #%d\n", my_context->mmapsize);
|
||||
my_context->mmaplist = (mmaplist_t*)realloc(my_context->mmaplist, my_context->mmapsize*sizeof(mmaplist_t));
|
||||
void *p = NULL;
|
||||
if(posix_memalign(&p, box86_pagesize, MMAPSIZE)) {
|
||||
dynarec_log(LOG_INFO, "Cannot create memory map of %d byte for dynarec block #%d\n", MMAPSIZE, i);
|
||||
--my_context->mmapsize;
|
||||
return 0;
|
||||
}
|
||||
mprotect(p, MMAPSIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
|
||||
my_context->mmaplist[i].block = p;
|
||||
// setup marks
|
||||
blockmark_t* m = (blockmark_t*)p;
|
||||
m->prev.x32 = 0;
|
||||
m->next.fill = 0;
|
||||
m->next.size = MMAPSIZE-sizeof(blockmark_t);
|
||||
m = (blockmark_t*)(p+MMAPSIZE-sizeof(blockmark_t));
|
||||
m->next.x32 = 0;
|
||||
m->prev.fill = 0;
|
||||
m->prev.size = MMAPSIZE-sizeof(blockmark_t);
|
||||
// alloc 1st block
|
||||
uintptr_t sub = (uintptr_t)allocBlock(my_context->mmaplist[i].block, p, size);
|
||||
my_context->mmaplist[i].maxfree = getMaxFreeBlock(my_context->mmaplist[i].block);
|
||||
kh_dynablocks_t *blocks = my_context->mmaplist[i].dblist = kh_init(dynablocks);
|
||||
kh_resize(dynablocks, blocks, 64);
|
||||
khint_t k;
|
||||
int ret;
|
||||
k = kh_put(dynablocks, blocks, (uintptr_t)db, &ret);
|
||||
kh_value(blocks, k) = db;
|
||||
return sub;
|
||||
}
|
||||
|
||||
void ActuallyFreeDynarecMap(dynablock_t* db, uintptr_t addr, int size)
|
||||
{
|
||||
if(!addr || !size)
|
||||
return;
|
||||
for(int i=0; i<my_context->mmapsize; ++i) {
|
||||
if ((addr>(uintptr_t)my_context->mmaplist[i].block)
|
||||
&& (addr<((uintptr_t)my_context->mmaplist[i].block+MMAPSIZE))) {
|
||||
void* sub = (void*)(addr-sizeof(blockmark_t));
|
||||
freeBlock(my_context->mmaplist[i].block, sub, size);
|
||||
my_context->mmaplist[i].maxfree = getMaxFreeBlock(my_context->mmaplist[i].block);
|
||||
kh_dynablocks_t *blocks = my_context->mmaplist[i].dblist;
|
||||
if(blocks) {
|
||||
khint_t k = kh_get(dynablocks, blocks, (uintptr_t)db);
|
||||
if(k!=kh_end(blocks))
|
||||
kh_del(dynablocks, blocks, k);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(my_context->mmapsize)
|
||||
dynarec_log(LOG_NONE, "Warning, block %p (size %d) not found in mmaplist for Free\n", (void*)addr, size);
|
||||
}
|
||||
|
||||
dynablock_t* FindDynablockFromNativeAddress(void* addr)
|
||||
{
|
||||
// look in actual list
|
||||
for(int i=0; i<my_context->mmapsize; ++i) {
|
||||
if ((uintptr_t)addr>=(uintptr_t)my_context->mmaplist[i].block
|
||||
&& ((uintptr_t)addr<(uintptr_t)my_context->mmaplist[i].block+MMAPSIZE))
|
||||
return FindDynablockDynablocklist(addr, my_context->mmaplist[i].dblist);
|
||||
}
|
||||
// look in oversized
|
||||
return FindDynablockDynablocklist(addr, my_context->dblist_oversized);
|
||||
}
|
||||
|
||||
uintptr_t AllocDynarecMap(dynablock_t* db, int size)
|
||||
{
|
||||
if(!size)
|
||||
return 0;
|
||||
if(size>MMAPSIZE-2*sizeof(blockmark_t)) {
|
||||
void *p = NULL;
|
||||
if(posix_memalign(&p, box86_pagesize, size)) {
|
||||
dynarec_log(LOG_INFO, "Cannot create dynamic map of %d bytes\n", size);
|
||||
return 0;
|
||||
}
|
||||
mprotect(p, size, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
kh_dynablocks_t *blocks = my_context->dblist_oversized;
|
||||
if(!blocks) {
|
||||
blocks = my_context->dblist_oversized = kh_init(dynablocks);
|
||||
kh_resize(dynablocks, blocks, 64);
|
||||
}
|
||||
khint_t k;
|
||||
int ret;
|
||||
k = kh_put(dynablocks, blocks, (uintptr_t)db, &ret);
|
||||
kh_value(blocks, k) = db;
|
||||
return (uintptr_t)p;
|
||||
}
|
||||
|
||||
if(pthread_mutex_trylock(&my_context->mutex_mmap)) {
|
||||
sched_yield(); // give it a chance
|
||||
if(pthread_mutex_trylock(&my_context->mutex_mmap))
|
||||
return 0; // cannot lock, baillout
|
||||
}
|
||||
|
||||
uintptr_t ret = FindFreeDynarecMap(db, size);
|
||||
if(!ret)
|
||||
ret = AddNewDynarecMap(db, size);
|
||||
|
||||
pthread_mutex_unlock(&my_context->mutex_mmap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void FreeDynarecMap(dynablock_t* db, uintptr_t addr, uint32_t size)
|
||||
{
|
||||
if(size>MMAPSIZE) {
|
||||
munmap((void*)addr, size);
|
||||
kh_dynablocks_t *blocks = my_context->dblist_oversized;
|
||||
if(blocks) {
|
||||
khint_t k = kh_get(dynablocks, blocks, (uintptr_t)db);
|
||||
if(k!=kh_end(blocks))
|
||||
kh_del(dynablocks, blocks, k);
|
||||
}
|
||||
return;
|
||||
}
|
||||
pthread_mutex_lock(&my_context->mutex_mmap);
|
||||
ActuallyFreeDynarecMap(db, addr, size);
|
||||
pthread_mutex_unlock(&my_context->mutex_mmap);
|
||||
}
|
||||
|
||||
// each dynmap is 64k of size
|
||||
|
||||
void addDBFromAddressRange(box86context_t* context, uintptr_t addr, uintptr_t size, int nolinker)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "addDBFromAddressRange %p -> %p\n", (void*)addr, (void*)(addr+size-1));
|
||||
uintptr_t idx = (addr>>DYNAMAP_SHIFT);
|
||||
uintptr_t end = ((addr+size-1)>>DYNAMAP_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
if(!context->dynmap[i]) {
|
||||
context->dynmap[i] = NewDynablockList(i<<DYNAMAP_SHIFT, i<<DYNAMAP_SHIFT, 1<<DYNAMAP_SHIFT, nolinker, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cleanDBFromAddressRange(box86context_t* context, uintptr_t addr, uintptr_t size, int destroy)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "cleanDBFromAddressRange %p -> %p %s\n", (void*)addr, (void*)(addr+size-1), destroy?"destroy":"mark");
|
||||
uintptr_t idx = (addr>box86_dynarec_largest && !destroy)?((addr-box86_dynarec_largest)>>DYNAMAP_SHIFT):(addr>>DYNAMAP_SHIFT);
|
||||
uintptr_t end = ((addr+size-1)>>DYNAMAP_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
dynablocklist_t* dblist = context->dynmap[i];
|
||||
if(dblist) {
|
||||
uintptr_t startdb = StartDynablockList(dblist);
|
||||
uintptr_t enddb = EndDynablockList(dblist);
|
||||
uintptr_t startaddr = addr;
|
||||
if(startaddr<startdb) startaddr = startdb;
|
||||
uintptr_t endaddr = addr + size - 1;
|
||||
if(endaddr>enddb) endaddr = enddb;
|
||||
if(startaddr==startdb && endaddr==enddb) {
|
||||
if(destroy) {
|
||||
context->dynmap[i] = NULL;
|
||||
FreeDynablockList(&dblist);
|
||||
} else
|
||||
MarkDynablockList(&dblist);
|
||||
} else
|
||||
if(destroy)
|
||||
FreeRangeDynablock(dblist, startaddr, endaddr-startaddr+1);
|
||||
else
|
||||
MarkRangeDynablock(dblist, startaddr, endaddr-startaddr+1);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the Write flag from an adress range, so DB can be executed
|
||||
// no log, as it can be executed inside a signal handler
|
||||
void protectDB(uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
uintptr_t start = (addr)&~(box86_pagesize-1);
|
||||
uintptr_t end = (addr+size+(box86_pagesize-1))&~(box86_pagesize-1);
|
||||
// should get "end" according to last block inside the window
|
||||
mprotect((void*)start, end-start, PROT_READ|PROT_EXEC);
|
||||
}
|
||||
|
||||
// Add the Write flag from an adress range, and mark all block as dirty
|
||||
// no log, as it can be executed inside a signal handler
|
||||
void unprotectDB(uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
uintptr_t start = (addr)&~(box86_pagesize-1);
|
||||
uintptr_t end = (addr+size+(box86_pagesize-1))&~(box86_pagesize-1);
|
||||
// should get "end" according to last block inside the window
|
||||
mprotect((void*)start, end-start, PROT_READ|PROT_WRITE|PROT_EXEC);
|
||||
cleanDBFromAddressRange(my_context, start, end-start, 0);
|
||||
}
|
||||
|
||||
#include "dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
EXPORTDYN
|
||||
void initAllHelpers(box86context_t* context)
|
||||
{
|
||||
@@ -356,10 +37,6 @@ void initAllHelpers(box86context_t* context)
|
||||
my_context = context;
|
||||
init_pthread_helper();
|
||||
init_signal_helper(context);
|
||||
#ifdef DYNAREC
|
||||
if(box86_dynarec)
|
||||
DynablockEmuMarker(context);
|
||||
#endif
|
||||
inited = 1;
|
||||
}
|
||||
|
||||
@@ -372,6 +49,7 @@ void finiAllHelpers(box86context_t* context)
|
||||
fini_pthread_helper(context);
|
||||
fini_signal_helper();
|
||||
cleanAlternate();
|
||||
fini_custommem_helper(context);
|
||||
finied = 1;
|
||||
}
|
||||
|
||||
@@ -382,11 +60,11 @@ int getrand(int maxval)
|
||||
{
|
||||
if(maxval<1024) {
|
||||
return ((random()&0x7fff)*maxval)/0x7fff;
|
||||
} else {
|
||||
}
|
||||
uint64_t r = random();
|
||||
r = (r*maxval) / RAND_MAX;
|
||||
return r;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void free_tlsdatasize(void* p)
|
||||
@@ -398,6 +76,76 @@ void free_tlsdatasize(void* p)
|
||||
free(p);
|
||||
}
|
||||
|
||||
int unlockMutex()
|
||||
{
|
||||
int ret = unlockCustommemMutex();
|
||||
int i;
|
||||
#define GO(A, B) \
|
||||
i = checkUnlockMutex(&A); \
|
||||
if(i) { \
|
||||
ret|=(1<<B); \
|
||||
}
|
||||
|
||||
GO(my_context->mutex_once, 5)
|
||||
GO(my_context->mutex_once2, 6)
|
||||
GO(my_context->mutex_trace, 7)
|
||||
#ifdef DYNAREC
|
||||
GO(my_context->mutex_dyndump, 8)
|
||||
#else
|
||||
GO(my_context->mutex_lock, 8)
|
||||
#endif
|
||||
GO(my_context->mutex_tls, 9)
|
||||
GO(my_context->mutex_thread, 10)
|
||||
#undef GO
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void relockMutex(int locks)
|
||||
{
|
||||
relockCustommemMutex(locks);
|
||||
#define GO(A, B) \
|
||||
if(locks&(1<<B)) \
|
||||
pthread_mutex_lock(&A); \
|
||||
|
||||
GO(my_context->mutex_once, 5)
|
||||
GO(my_context->mutex_once2, 6)
|
||||
GO(my_context->mutex_trace, 7)
|
||||
#ifdef DYNAREC
|
||||
GO(my_context->mutex_dyndump, 8)
|
||||
#else
|
||||
GO(my_context->mutex_lock, 8)
|
||||
#endif
|
||||
GO(my_context->mutex_tls, 9)
|
||||
GO(my_context->mutex_thread, 10)
|
||||
#undef GO
|
||||
}
|
||||
|
||||
static void init_mutexes(box86context_t* context)
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
pthread_mutex_init(&context->mutex_once, &attr);
|
||||
pthread_mutex_init(&context->mutex_once2, &attr);
|
||||
pthread_mutex_init(&context->mutex_trace, &attr);
|
||||
#ifndef DYNAREC
|
||||
pthread_mutex_init(&context->mutex_lock, &attr);
|
||||
#else
|
||||
pthread_mutex_init(&context->mutex_dyndump, &attr);
|
||||
#endif
|
||||
pthread_mutex_init(&context->mutex_tls, &attr);
|
||||
pthread_mutex_init(&context->mutex_thread, &attr);
|
||||
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
}
|
||||
|
||||
static void atfork_child_box64context(void)
|
||||
{
|
||||
// (re)init mutex if it was lock before the fork
|
||||
init_mutexes(my_context);
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
box86context_t *NewBox86Context(int argc)
|
||||
{
|
||||
@@ -408,7 +156,7 @@ box86context_t *NewBox86Context(int argc)
|
||||
}
|
||||
#endif
|
||||
// init and put default values
|
||||
box86context_t *context = (box86context_t*)calloc(1, sizeof(box86context_t));
|
||||
box86context_t *context = my_context = (box86context_t*)calloc(1, sizeof(box86context_t));
|
||||
|
||||
#ifdef BUILD_LIB
|
||||
context->deferedInit = 0;
|
||||
@@ -417,17 +165,13 @@ box86context_t *NewBox86Context(int argc)
|
||||
#endif
|
||||
context->sel_serial = 1;
|
||||
|
||||
#ifdef DYNAREC
|
||||
pthread_mutex_init(&context->mutex_blocks, NULL);
|
||||
pthread_mutex_init(&context->mutex_mmap, NULL);
|
||||
context->dynmap = (dynablocklist_t**)calloc(DYNAMAP_SIZE, sizeof(dynablocklist_t*));
|
||||
#endif
|
||||
init_custommem_helper(context);
|
||||
|
||||
context->maplib = NewLibrarian(context, 1);
|
||||
context->local_maplib = NewLibrarian(context, 1);
|
||||
context->system = NewBridge();
|
||||
// create vsyscall
|
||||
context->vsyscall = AddBridge(context->system, context, vFv, x86Syscall, 0);
|
||||
context->vsyscall = AddBridge(context->system, vFv, x86Syscall, 0);
|
||||
#ifdef BUILD_LIB
|
||||
context->box86lib = RTLD_DEFAULT; // not ideal
|
||||
#else
|
||||
@@ -438,23 +182,15 @@ box86context_t *NewBox86Context(int argc)
|
||||
context->argc = argc;
|
||||
context->argv = (char**)calloc(context->argc+1, sizeof(char*));
|
||||
|
||||
pthread_mutex_init(&context->mutex_once, NULL);
|
||||
pthread_mutex_init(&context->mutex_once2, NULL);
|
||||
pthread_mutex_init(&context->mutex_trace, NULL);
|
||||
#ifndef DYNAREC
|
||||
pthread_mutex_init(&context->mutex_lock, NULL);
|
||||
#endif
|
||||
pthread_mutex_init(&context->mutex_tls, NULL);
|
||||
pthread_mutex_init(&context->mutex_thread, NULL);
|
||||
#ifdef DYNAREC
|
||||
pthread_mutex_init(&context->mutex_dyndump, NULL);
|
||||
#endif
|
||||
init_mutexes(context);
|
||||
pthread_atfork(NULL, NULL, atfork_child_box64context);
|
||||
|
||||
pthread_key_create(&context->tlskey, free_tlsdatasize);
|
||||
|
||||
InitFTSMap(context);
|
||||
|
||||
for (int i=0; i<4; ++i) context->canary[i] = 1 + getrand(255);
|
||||
context->canary[getrand(4)] = 0;
|
||||
context->canary[/*getrand(4)*/0] = 0;
|
||||
printf_log(LOG_DEBUG, "Setting up canary (for Stack protector) at GS:0x14, value:%08X\n", *(uint32_t*)context->canary);
|
||||
|
||||
initAllHelpers(context);
|
||||
@@ -477,6 +213,11 @@ void FreeBox86Context(box86context_t** context)
|
||||
|
||||
box86context_t* ctx = *context; // local copy to do the cleanning
|
||||
|
||||
if(ctx->local_maplib)
|
||||
FreeLibrarian(&ctx->local_maplib, NULL);
|
||||
if(ctx->maplib)
|
||||
FreeLibrarian(&ctx->maplib, NULL);
|
||||
|
||||
for(int i=0; i<ctx->elfsize; ++i) {
|
||||
FreeElfHeader(&ctx->elfs[i]);
|
||||
}
|
||||
@@ -484,11 +225,6 @@ void FreeBox86Context(box86context_t** context)
|
||||
|
||||
FreeFTSMap(ctx);
|
||||
|
||||
if(ctx->maplib)
|
||||
FreeLibrarian(&ctx->maplib);
|
||||
if(ctx->local_maplib)
|
||||
FreeLibrarian(&ctx->local_maplib);
|
||||
|
||||
FreeCollection(&ctx->box86_path);
|
||||
FreeCollection(&ctx->box86_ld_lib);
|
||||
FreeCollection(&ctx->box86_emulated_libs);
|
||||
@@ -518,28 +254,6 @@ void FreeBox86Context(box86context_t** context)
|
||||
signal(i, SIG_DFL);
|
||||
}
|
||||
|
||||
#ifdef DYNAREC
|
||||
dynarec_log(LOG_DEBUG, "Free global Dynarecblocks\n");
|
||||
for (int i=0; i<ctx->mmapsize; ++i) {
|
||||
if(ctx->mmaplist[i].block)
|
||||
free(ctx->mmaplist[i].block);
|
||||
if(ctx->mmaplist[i].dblist) {
|
||||
kh_destroy(dynablocks, ctx->mmaplist[i].dblist);
|
||||
ctx->mmaplist[i].dblist = NULL;
|
||||
}
|
||||
}
|
||||
if(ctx->dblist_oversized) {
|
||||
kh_destroy(dynablocks, ctx->dblist_oversized);
|
||||
ctx->dblist_oversized = NULL;
|
||||
}
|
||||
ctx->mmapsize = 0;
|
||||
dynarec_log(LOG_DEBUG, "Free dynamic Dynarecblocks\n");
|
||||
cleanDBFromAddressRange(ctx, 0, 0xffffffff, 1);
|
||||
pthread_mutex_destroy(&ctx->mutex_blocks);
|
||||
pthread_mutex_destroy(&ctx->mutex_mmap);
|
||||
free(ctx->mmaplist);
|
||||
#endif
|
||||
|
||||
*context = NULL; // bye bye my_context
|
||||
|
||||
CleanStackSize(ctx);
|
||||
@@ -551,7 +265,7 @@ void FreeBox86Context(box86context_t** context)
|
||||
|
||||
FreeDLPrivate(&ctx->dlprivate);
|
||||
|
||||
free(ctx->stack);
|
||||
// free(ctx->stack); // don't free the stack, it's owned by main emu!
|
||||
|
||||
free(ctx->fullpath);
|
||||
free(ctx->box86path);
|
||||
@@ -583,14 +297,11 @@ void FreeBox86Context(box86context_t** context)
|
||||
pthread_mutex_destroy(&ctx->mutex_trace);
|
||||
#ifndef DYNAREC
|
||||
pthread_mutex_destroy(&ctx->mutex_lock);
|
||||
#else
|
||||
pthread_mutex_destroy(&ctx->mutex_dyndump);
|
||||
#endif
|
||||
pthread_mutex_destroy(&ctx->mutex_tls);
|
||||
pthread_mutex_destroy(&ctx->mutex_thread);
|
||||
#ifdef DYNAREC
|
||||
pthread_mutex_destroy(&ctx->mutex_dyndump);
|
||||
free(ctx->dynmap);
|
||||
ctx->dynmap = NULL;
|
||||
#endif
|
||||
|
||||
free_neededlib(&ctx->neededlibs);
|
||||
|
||||
@@ -630,25 +341,3 @@ int AddTLSPartition(box86context_t* context, int tlssize) {
|
||||
|
||||
return -context->tlssize; // negative offset
|
||||
}
|
||||
|
||||
void add_neededlib(needed_libs_t* needed, library_t* lib)
|
||||
{
|
||||
if(!needed)
|
||||
return;
|
||||
if(needed->size == needed->cap) {
|
||||
needed->cap += 8;
|
||||
needed->libs = (library_t**)realloc(needed->libs, needed->cap*sizeof(library_t*));
|
||||
}
|
||||
needed->libs[needed->size++] = lib;
|
||||
}
|
||||
|
||||
void free_neededlib(needed_libs_t* needed)
|
||||
{
|
||||
if(!needed)
|
||||
return;
|
||||
needed->cap = 0;
|
||||
needed->size = 0;
|
||||
if(needed->libs)
|
||||
free(needed->libs);
|
||||
needed->libs = NULL;
|
||||
}
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
#define __BOX86_VERSION_H_
|
||||
|
||||
#define BOX86_MAJOR 0
|
||||
#define BOX86_MINOR 1
|
||||
#define BOX86_REVISION 8
|
||||
#define BOX86_MINOR 2
|
||||
#define BOX86_REVISION 2
|
||||
|
||||
#endif //__BOX86_VERSION_H_
|
||||
+774
@@ -0,0 +1,774 @@
|
||||
#define _GNU_SOURCE /* See feature_test_macros(7) */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dlfcn.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "box86context.h"
|
||||
#include "elfloader.h"
|
||||
#include "debug.h"
|
||||
#include "x86trace.h"
|
||||
#include "x86emu.h"
|
||||
#include "librarian.h"
|
||||
#include "bridge.h"
|
||||
#include "library.h"
|
||||
#include "callback.h"
|
||||
#include "wrapper.h"
|
||||
#include "myfts.h"
|
||||
#include "threads.h"
|
||||
#include "x86trace.h"
|
||||
#include "signals.h"
|
||||
#include <sys/mman.h>
|
||||
#include "custommem.h"
|
||||
#include "threads.h"
|
||||
#ifdef DYNAREC
|
||||
#include "dynablock.h"
|
||||
#include "dynarec/arm_lock_helper.h"
|
||||
#include "khash.h"
|
||||
|
||||
#define USE_MMAP
|
||||
|
||||
// init inside dynablocks.c
|
||||
KHASH_MAP_INIT_INT(dynablocks, dynablock_t*)
|
||||
static dynablocklist_t* dynmap[DYNAMAP_SIZE]; // 4G of memory mapped by 4K block
|
||||
static pthread_mutex_t mutex_mmap;
|
||||
static mmaplist_t *mmaplist;
|
||||
static int mmapsize;
|
||||
static kh_dynablocks_t *dblist_oversized; // store the list of oversized dynablocks (normal sized are inside mmaplist)
|
||||
static uintptr_t *box86_jumptable[JMPTABL_SIZE];
|
||||
static uintptr_t box86_jmptbl_default[1<<JMPTABL_SHIFT];
|
||||
#endif
|
||||
#define MEMPROT_SHIFT 12
|
||||
#define MEMPROT_SIZE (1<<(32-MEMPROT_SHIFT))
|
||||
static uint8_t memprot[MEMPROT_SIZE] = {0}; // protection flags by 4K block
|
||||
static int inited = 0;
|
||||
|
||||
typedef struct blocklist_s {
|
||||
void* block;
|
||||
int maxfree;
|
||||
size_t size;
|
||||
} blocklist_t;
|
||||
|
||||
#define MMAPSIZE (256*1024) // allocate 256kb sized blocks
|
||||
|
||||
static pthread_mutex_t mutex_blocks;
|
||||
static int n_blocks = 0; // number of blocks for custom malloc
|
||||
static blocklist_t* p_blocks = NULL; // actual blocks for custom malloc
|
||||
|
||||
typedef union mark_s {
|
||||
struct {
|
||||
unsigned int fill:1;
|
||||
unsigned int size:31;
|
||||
};
|
||||
uint32_t x32;
|
||||
} mark_t;
|
||||
typedef struct blockmark_s {
|
||||
mark_t prev;
|
||||
mark_t next;
|
||||
} blockmark_t;
|
||||
|
||||
|
||||
// get first subblock free in block. Return NULL if no block, else first subblock free (mark included), filling size
|
||||
static void* getFirstBlock(void* block, int maxsize, int* size)
|
||||
{
|
||||
// get start of block
|
||||
blockmark_t *m = (blockmark_t*)block;
|
||||
while(m->next.x32) { // while there is a subblock
|
||||
if(!m->next.fill && m->next.size>=maxsize+sizeof(blockmark_t)) {
|
||||
*size = m->next.size-sizeof(blockmark_t);
|
||||
return m;
|
||||
}
|
||||
m = (blockmark_t*)((uintptr_t)m + m->next.size);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int getMaxFreeBlock(void* block, size_t block_size)
|
||||
{
|
||||
// get start of block
|
||||
blockmark_t *m = (blockmark_t*)((uintptr_t)block+block_size-sizeof(blockmark_t)); // start with the end
|
||||
int maxsize = 0;
|
||||
while(m->prev.x32) { // while there is a subblock
|
||||
if(!m->prev.fill && m->prev.size>maxsize) {
|
||||
maxsize = m->prev.size;
|
||||
if((uintptr_t)block+maxsize>(uintptr_t)m)
|
||||
return (maxsize>=sizeof(blockmark_t))?(maxsize-sizeof(blockmark_t)):0; // no block large enough left...
|
||||
}
|
||||
m = (blockmark_t*)((uintptr_t)m - m->prev.size);
|
||||
}
|
||||
return (maxsize>=sizeof(blockmark_t))?(maxsize-sizeof(blockmark_t)):0;
|
||||
}
|
||||
|
||||
static void* allocBlock(void* block, void *sub, int size)
|
||||
{
|
||||
blockmark_t *s = (blockmark_t*)sub;
|
||||
blockmark_t *n = (blockmark_t*)((uintptr_t)s + s->next.size);
|
||||
|
||||
s->next.fill = 1;
|
||||
s->next.size = size+sizeof(blockmark_t);
|
||||
blockmark_t *m = (blockmark_t*)((uintptr_t)s + s->next.size); // this is new n
|
||||
m->prev.fill = 1;
|
||||
m->prev.size = s->next.size;
|
||||
if(n!=m) {
|
||||
// new mark
|
||||
m->prev.fill = 1;
|
||||
m->prev.size = s->next.size;
|
||||
m->next.fill = 0;
|
||||
m->next.size = (uintptr_t)n - (uintptr_t)m;
|
||||
n->prev.fill = 0;
|
||||
n->prev.size = m->next.size;
|
||||
}
|
||||
|
||||
return (void*)((uintptr_t)sub + sizeof(blockmark_t));
|
||||
}
|
||||
static void freeBlock(void *block, void* sub)
|
||||
{
|
||||
blockmark_t *m = (blockmark_t*)block;
|
||||
blockmark_t *s = (blockmark_t*)sub;
|
||||
blockmark_t *n = (blockmark_t*)((uintptr_t)s + s->next.size);
|
||||
if(block!=sub)
|
||||
m = (blockmark_t*)((uintptr_t)s - s->prev.size);
|
||||
s->next.fill = 0;
|
||||
n->prev.fill = 0;
|
||||
// check if merge with previous
|
||||
if (s->prev.x32 && !s->prev.fill) {
|
||||
// remove s...
|
||||
m->next.size += s->next.size;
|
||||
n->prev.size = m->next.size;
|
||||
s = m;
|
||||
}
|
||||
// check if merge with next
|
||||
if(n->next.x32 && !n->next.fill) {
|
||||
blockmark_t *n2 = (blockmark_t*)((uintptr_t)n + n->next.size);
|
||||
//remove n
|
||||
s->next.size += n->next.size;
|
||||
n2->prev.size = s->next.size;
|
||||
}
|
||||
}
|
||||
// return 1 if block has been expanded to new size, 0 if not
|
||||
static int expandBlock(void* block, void* sub, int newsize)
|
||||
{
|
||||
newsize = (newsize+3)&~3;
|
||||
blockmark_t *s = (blockmark_t*)sub;
|
||||
blockmark_t *n = (blockmark_t*)((uintptr_t)s + s->next.size);
|
||||
if(s->next.fill)
|
||||
return 0; // next block is filled
|
||||
if(s->next.size + n->next.size < newsize)
|
||||
return 0; // free space too short
|
||||
// ok, doing the alloc!
|
||||
s->next.size = newsize+sizeof(blockmark_t);
|
||||
blockmark_t *m = (blockmark_t*)((uintptr_t)s + s->next.size); // this is new n
|
||||
m->prev.fill = 1;
|
||||
m->prev.size = s->next.size;
|
||||
if(n!=m) {
|
||||
// new mark
|
||||
m->prev.fill = 1;
|
||||
m->prev.size = s->next.size;
|
||||
m->next.fill = 0;
|
||||
m->next.size = (uintptr_t)n - (uintptr_t)m;
|
||||
n->prev.fill = 0;
|
||||
n->prev.size = m->next.size;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
// return size of block
|
||||
static int sizeBlock(void* sub)
|
||||
{
|
||||
blockmark_t *s = (blockmark_t*)sub;
|
||||
return s->next.size;
|
||||
}
|
||||
|
||||
void* customMalloc(size_t size)
|
||||
{
|
||||
// look for free space
|
||||
void* sub = NULL;
|
||||
pthread_mutex_lock(&mutex_blocks);
|
||||
for(int i=0; i<n_blocks; ++i) {
|
||||
if(p_blocks[i].maxfree>=size) {
|
||||
int rsize = 0;
|
||||
sub = getFirstBlock(p_blocks[i].block, size, &rsize);
|
||||
if(sub) {
|
||||
void* ret = allocBlock(p_blocks[i].block, sub, size);
|
||||
if(rsize==p_blocks[i].maxfree)
|
||||
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size);
|
||||
pthread_mutex_unlock(&mutex_blocks);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
// add a new block
|
||||
int i = n_blocks++;
|
||||
p_blocks = (blocklist_t*)realloc(p_blocks, n_blocks*sizeof(blocklist_t));
|
||||
size_t allocsize = MMAPSIZE;
|
||||
if(size+2*sizeof(blockmark_t)>allocsize)
|
||||
allocsize = size+2*sizeof(blockmark_t);
|
||||
#ifdef USE_MMAP
|
||||
void* p = mmap(NULL, allocsize, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
|
||||
memset(p, 0, allocsize);
|
||||
#else
|
||||
void* p = calloc(1, allocsize);
|
||||
#endif
|
||||
p_blocks[i].block = p;
|
||||
p_blocks[i].size = allocsize;
|
||||
// setup marks
|
||||
blockmark_t* m = (blockmark_t*)p;
|
||||
m->prev.x32 = 0;
|
||||
m->next.fill = 0;
|
||||
m->next.size = allocsize-sizeof(blockmark_t);
|
||||
m = (blockmark_t*)(p+allocsize-sizeof(blockmark_t));
|
||||
m->next.x32 = 0;
|
||||
m->prev.fill = 0;
|
||||
m->prev.size = allocsize-sizeof(blockmark_t);
|
||||
// alloc 1st block
|
||||
void* ret = allocBlock(p_blocks[i].block, p, size);
|
||||
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size);
|
||||
pthread_mutex_unlock(&mutex_blocks);
|
||||
return ret;
|
||||
}
|
||||
void* customCalloc(size_t n, size_t size)
|
||||
{
|
||||
size_t newsize = n*size;
|
||||
void* ret = customMalloc(newsize);
|
||||
memset(ret, 0, newsize);
|
||||
return ret;
|
||||
}
|
||||
void* customRealloc(void* p, size_t size)
|
||||
{
|
||||
if(!p)
|
||||
return customMalloc(size);
|
||||
uintptr_t addr = (uintptr_t)p;
|
||||
pthread_mutex_lock(&mutex_blocks);
|
||||
for(int i=0; i<n_blocks; ++i) {
|
||||
if ((addr>(uintptr_t)p_blocks[i].block)
|
||||
&& (addr<((uintptr_t)p_blocks[i].block+p_blocks[i].size))) {
|
||||
void* sub = (void*)(addr-sizeof(blockmark_t));
|
||||
if(expandBlock(p_blocks[i].block, sub, size)) {
|
||||
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size);
|
||||
pthread_mutex_unlock(&mutex_blocks);
|
||||
return p;
|
||||
}
|
||||
pthread_mutex_unlock(&mutex_blocks);
|
||||
void* newp = customMalloc(size);
|
||||
memcpy(newp, p, sizeBlock(sub));
|
||||
customFree(p);
|
||||
return newp;
|
||||
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&mutex_blocks);
|
||||
if(n_blocks)
|
||||
dynarec_log(LOG_NONE, "Warning, block %p not found in p_blocks for Realloc, Malloc'ng again without free\n", (void*)addr);
|
||||
return customMalloc(size);
|
||||
}
|
||||
void customFree(void* p)
|
||||
{
|
||||
if(!p)
|
||||
return;
|
||||
uintptr_t addr = (uintptr_t)p;
|
||||
pthread_mutex_lock(&mutex_blocks);
|
||||
for(int i=0; i<n_blocks; ++i) {
|
||||
if ((addr>(uintptr_t)p_blocks[i].block)
|
||||
&& (addr<((uintptr_t)p_blocks[i].block+p_blocks[i].size))) {
|
||||
void* sub = (void*)(addr-sizeof(blockmark_t));
|
||||
freeBlock(p_blocks[i].block, sub);
|
||||
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size);
|
||||
pthread_mutex_unlock(&mutex_blocks);
|
||||
return;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&mutex_blocks);
|
||||
if(n_blocks)
|
||||
dynarec_log(LOG_NONE, "Warning, block %p not found in p_blocks for Free\n", (void*)addr);
|
||||
}
|
||||
|
||||
#ifdef DYNAREC
|
||||
typedef struct mmaplist_s {
|
||||
void* block;
|
||||
int maxfree;
|
||||
size_t size;
|
||||
kh_dynablocks_t* dblist;
|
||||
uint8_t* helper;
|
||||
} mmaplist_t;
|
||||
|
||||
uintptr_t FindFreeDynarecMap(dynablock_t* db, int size)
|
||||
{
|
||||
// look for free space
|
||||
void* sub = NULL;
|
||||
for(int i=0; i<mmapsize; ++i) {
|
||||
if(mmaplist[i].maxfree>=size) {
|
||||
int rsize = 0;
|
||||
sub = getFirstBlock(mmaplist[i].block, size, &rsize);
|
||||
if(sub) {
|
||||
uintptr_t ret = (uintptr_t)allocBlock(mmaplist[i].block, sub, size);
|
||||
if(rsize==mmaplist[i].maxfree)
|
||||
mmaplist[i].maxfree = getMaxFreeBlock(mmaplist[i].block, mmaplist[i].size);
|
||||
kh_dynablocks_t *blocks = mmaplist[i].dblist;
|
||||
if(!blocks) {
|
||||
blocks = mmaplist[i].dblist = kh_init(dynablocks);
|
||||
kh_resize(dynablocks, blocks, 64);
|
||||
}
|
||||
khint_t k;
|
||||
int r;
|
||||
k = kh_put(dynablocks, blocks, (uintptr_t)ret, &r);
|
||||
kh_value(blocks, k) = db;
|
||||
for(int j=0; j<size; ++j)
|
||||
mmaplist[i].helper[(uintptr_t)ret-(uintptr_t)mmaplist[i].block+j] = (j<256)?j:255;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uintptr_t AddNewDynarecMap(dynablock_t* db, int size)
|
||||
{
|
||||
int i = mmapsize++; // yeah, useful post incrementation
|
||||
dynarec_log(LOG_DEBUG, "Ask for DynaRec Block Alloc #%d\n", mmapsize);
|
||||
mmaplist = (mmaplist_t*)realloc(mmaplist, mmapsize*sizeof(mmaplist_t));
|
||||
#ifndef USE_MMAP
|
||||
void *p = NULL;
|
||||
if(posix_memalign(&p, box86_pagesize, MMAPSIZE)) {
|
||||
dynarec_log(LOG_INFO, "Cannot create memory map of %d byte for dynarec block #%d\n", MMAPSIZE, i);
|
||||
--mmapsize;
|
||||
return 0;
|
||||
}
|
||||
mprotect(p, MMAPSIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
#else
|
||||
void* p = mmap(NULL, MMAPSIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
||||
if(p==(void*)-1) {
|
||||
dynarec_log(LOG_INFO, "Cannot create memory map of %d byte for dynarec block #%d\n", MMAPSIZE, i);
|
||||
--mmapsize;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
setProtection((uintptr_t)p, MMAPSIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
|
||||
mmaplist[i].block = p;
|
||||
mmaplist[i].size = MMAPSIZE;
|
||||
mmaplist[i].helper = (uint8_t*)calloc(1, MMAPSIZE);
|
||||
// setup marks
|
||||
blockmark_t* m = (blockmark_t*)p;
|
||||
m->prev.x32 = 0;
|
||||
m->next.fill = 0;
|
||||
m->next.size = MMAPSIZE-sizeof(blockmark_t);
|
||||
m = (blockmark_t*)(p+MMAPSIZE-sizeof(blockmark_t));
|
||||
m->next.x32 = 0;
|
||||
m->prev.fill = 0;
|
||||
m->prev.size = MMAPSIZE-sizeof(blockmark_t);
|
||||
// alloc 1st block
|
||||
uintptr_t sub = (uintptr_t)allocBlock(mmaplist[i].block, p, size);
|
||||
mmaplist[i].maxfree = getMaxFreeBlock(mmaplist[i].block, mmaplist[i].size);
|
||||
kh_dynablocks_t *blocks = mmaplist[i].dblist = kh_init(dynablocks);
|
||||
kh_resize(dynablocks, blocks, 64);
|
||||
khint_t k;
|
||||
int ret;
|
||||
k = kh_put(dynablocks, blocks, (uintptr_t)sub, &ret);
|
||||
kh_value(blocks, k) = db;
|
||||
for(int j=0; j<size; ++j)
|
||||
mmaplist[i].helper[(uintptr_t)sub-(uintptr_t)mmaplist[i].block + j] = (j<256)?j:255;
|
||||
return sub;
|
||||
}
|
||||
|
||||
void ActuallyFreeDynarecMap(dynablock_t* db, uintptr_t addr, int size)
|
||||
{
|
||||
if(!addr || !size)
|
||||
return;
|
||||
for(int i=0; i<mmapsize; ++i) {
|
||||
if ((addr>(uintptr_t)mmaplist[i].block)
|
||||
&& (addr<((uintptr_t)mmaplist[i].block+mmaplist[i].size))) {
|
||||
void* sub = (void*)(addr-sizeof(blockmark_t));
|
||||
freeBlock(mmaplist[i].block, sub);
|
||||
mmaplist[i].maxfree = getMaxFreeBlock(mmaplist[i].block, mmaplist[i].size);
|
||||
kh_dynablocks_t *blocks = mmaplist[i].dblist;
|
||||
if(blocks) {
|
||||
khint_t k = kh_get(dynablocks, blocks, (uintptr_t)sub);
|
||||
if(k!=kh_end(blocks))
|
||||
kh_del(dynablocks, blocks, k);
|
||||
for(int j=0; j<size; ++j)
|
||||
mmaplist[i].helper[(uintptr_t)sub-(uintptr_t)mmaplist[i].block+j] = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(mmapsize)
|
||||
dynarec_log(LOG_NONE, "Warning, block %p (size %d) not found in mmaplist for Free\n", (void*)addr, size);
|
||||
}
|
||||
|
||||
dynablock_t* FindDynablockFromNativeAddress(void* addr)
|
||||
{
|
||||
// look in actual list
|
||||
for(int i=0; i<mmapsize; ++i) {
|
||||
if ((uintptr_t)addr>=(uintptr_t)mmaplist[i].block
|
||||
&& ((uintptr_t)addr<(uintptr_t)mmaplist[i].block+mmaplist[i].size)) {
|
||||
if(!mmaplist[i].helper)
|
||||
return FindDynablockDynablocklist(addr, mmaplist[i].dblist);
|
||||
else {
|
||||
uintptr_t p = (uintptr_t)addr - (uintptr_t)mmaplist[i].block;
|
||||
while(mmaplist[i].helper[p]) p -= mmaplist[i].helper[p];
|
||||
khint_t k = kh_get(dynablocks, mmaplist[i].dblist, (uintptr_t)mmaplist[i].block + p);
|
||||
if(k!=kh_end(mmaplist[i].dblist))
|
||||
return kh_value(mmaplist[i].dblist, k);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
// look in oversized
|
||||
return FindDynablockDynablocklist(addr, dblist_oversized);
|
||||
}
|
||||
|
||||
uintptr_t AllocDynarecMap(dynablock_t* db, int size)
|
||||
{
|
||||
if(!size)
|
||||
return 0;
|
||||
if(size>MMAPSIZE-2*sizeof(blockmark_t)) {
|
||||
#ifndef USE_MMAP
|
||||
pthread_mutex_lock(&mutex_mmap);
|
||||
void *p = NULL;
|
||||
if(posix_memalign(&p, box86_pagesize, size)) {
|
||||
dynarec_log(LOG_INFO, "Cannot create dynamic map of %d bytes\n", size);
|
||||
return 0;
|
||||
}
|
||||
mprotect(p, size, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
#else
|
||||
void* p = mmap(NULL, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
|
||||
if(p==(void*)-1) {
|
||||
dynarec_log(LOG_INFO, "Cannot create dynamic map of %d bytes\n", size);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
setProtection((uintptr_t)p, size, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
kh_dynablocks_t *blocks = dblist_oversized;
|
||||
if(!blocks) {
|
||||
blocks = dblist_oversized = kh_init(dynablocks);
|
||||
kh_resize(dynablocks, blocks, 64);
|
||||
}
|
||||
khint_t k;
|
||||
int ret;
|
||||
k = kh_put(dynablocks, blocks, (uintptr_t)p, &ret);
|
||||
kh_value(blocks, k) = db;
|
||||
pthread_mutex_unlock(&mutex_mmap);
|
||||
return (uintptr_t)p;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&mutex_mmap);
|
||||
|
||||
uintptr_t ret = FindFreeDynarecMap(db, size);
|
||||
if(!ret)
|
||||
ret = AddNewDynarecMap(db, size);
|
||||
|
||||
pthread_mutex_unlock(&mutex_mmap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void FreeDynarecMap(dynablock_t* db, uintptr_t addr, uint32_t size)
|
||||
{
|
||||
if(!addr || !size)
|
||||
return;
|
||||
if(size>MMAPSIZE-2*sizeof(blockmark_t)) {
|
||||
pthread_mutex_lock(&mutex_mmap);
|
||||
#ifndef USE_MMAP
|
||||
free((void*)addr);
|
||||
#else
|
||||
munmap((void*)addr, size);
|
||||
#endif
|
||||
kh_dynablocks_t *blocks = dblist_oversized;
|
||||
if(blocks) {
|
||||
khint_t k = kh_get(dynablocks, blocks, addr);
|
||||
if(k!=kh_end(blocks))
|
||||
kh_del(dynablocks, blocks, k);
|
||||
}
|
||||
pthread_mutex_unlock(&mutex_mmap);
|
||||
return;
|
||||
}
|
||||
pthread_mutex_lock(&mutex_mmap);
|
||||
ActuallyFreeDynarecMap(db, addr, size);
|
||||
pthread_mutex_unlock(&mutex_mmap);
|
||||
}
|
||||
|
||||
dynablocklist_t* getDB(uintptr_t idx)
|
||||
{
|
||||
return dynmap[idx];
|
||||
}
|
||||
|
||||
// each dynmap is 64k of size
|
||||
|
||||
void addDBFromAddressRange(uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "addDBFromAddressRange %p -> %p\n", (void*)addr, (void*)(addr+size-1));
|
||||
uintptr_t idx = (addr>>DYNAMAP_SHIFT);
|
||||
uintptr_t end = ((addr+size-1)>>DYNAMAP_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
if(!dynmap[i]) {
|
||||
dynablocklist_t* p = NewDynablockList(i<<DYNAMAP_SHIFT, 1<<DYNAMAP_SHIFT, 0);
|
||||
if(arm_lock_storeifnull(&dynmap[i], p)!=p)
|
||||
FreeDynablockList(&p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cleanDBFromAddressRange(uintptr_t addr, uintptr_t size, int destroy)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "cleanDBFromAddressRange %p -> %p %s\n", (void*)addr, (void*)(addr+size-1), destroy?"destroy":"mark");
|
||||
uintptr_t idx = (addr>>DYNAMAP_SHIFT);
|
||||
uintptr_t end = ((addr+size-1)>>DYNAMAP_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
dynablocklist_t* dblist = dynmap[i];
|
||||
if(dblist) {
|
||||
if(destroy)
|
||||
FreeRangeDynablock(dblist, addr, size);
|
||||
else
|
||||
MarkRangeDynablock(dblist, addr, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ARM
|
||||
void arm_next(void);
|
||||
#endif
|
||||
|
||||
void addJumpTableIfDefault(void* addr, void* jmp)
|
||||
{
|
||||
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
|
||||
if(box86_jumptable[idx] == box86_jmptbl_default) {
|
||||
uintptr_t* tbl = (uintptr_t*)malloc((1<<JMPTABL_SHIFT)*sizeof(uintptr_t));
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT); ++i)
|
||||
tbl[i] = (uintptr_t)arm_next;
|
||||
if(arm_lock_storeifref(&box86_jumptable[idx], tbl, box86_jmptbl_default)!=tbl)
|
||||
free(tbl);
|
||||
}
|
||||
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
|
||||
arm_lock_storeifref(&box86_jumptable[idx][off], jmp, arm_next);
|
||||
}
|
||||
void setJumpTableDefault(void* addr)
|
||||
{
|
||||
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
|
||||
if(box86_jumptable[idx] == box86_jmptbl_default) {
|
||||
return;
|
||||
}
|
||||
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
|
||||
box86_jumptable[idx][off] = (uintptr_t)arm_next;
|
||||
}
|
||||
int isJumpTableDefault(void* addr)
|
||||
{
|
||||
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
|
||||
if(box86_jumptable[idx] == box86_jmptbl_default) {
|
||||
return 1;
|
||||
}
|
||||
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
|
||||
return (box86_jumptable[idx][off]==(uintptr_t)arm_next)?1:0;
|
||||
}
|
||||
uintptr_t getJumpTable()
|
||||
{
|
||||
return (uintptr_t)box86_jumptable;
|
||||
}
|
||||
|
||||
uintptr_t getJumpTableAddress(uintptr_t addr)
|
||||
{
|
||||
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
|
||||
if(box86_jumptable[idx] == box86_jmptbl_default) {
|
||||
uintptr_t* tbl = (uintptr_t*)malloc((1<<JMPTABL_SHIFT)*sizeof(uintptr_t));
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT); ++i)
|
||||
tbl[i] = (uintptr_t)arm_next;
|
||||
if(arm_lock_storeifref(&box86_jumptable[idx], tbl, box86_jmptbl_default)!=tbl)
|
||||
free(tbl);
|
||||
}
|
||||
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
|
||||
return (uintptr_t)&box86_jumptable[idx][off];
|
||||
}
|
||||
|
||||
// Remove the Write flag from an adress range, so DB can be executed
|
||||
// no log, as it can be executed inside a signal handler
|
||||
void protectDB(uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "protectDB %p -> %p\n", (void*)addr, (void*)(addr+size-1));
|
||||
uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
uint32_t prot = memprot[i];
|
||||
if(!prot)
|
||||
prot = PROT_READ | PROT_WRITE; // comes from malloc & co, so should not be able to execute
|
||||
memprot[i] = prot|PROT_DYNAREC;
|
||||
if(!(prot&PROT_DYNAREC))
|
||||
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_WRITE);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the Write flag from an adress range, and mark all block as dirty
|
||||
// no log, as it can be executed inside a signal handler
|
||||
void unprotectDB(uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "unprotectDB %p -> %p\n", (void*)addr, (void*)(addr+size-1));
|
||||
uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
uint32_t prot = memprot[i];
|
||||
memprot[i] = prot&~PROT_DYNAREC;
|
||||
if(prot&PROT_DYNAREC) {
|
||||
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_DYNAREC);
|
||||
cleanDBFromAddressRange((i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void updateProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
|
||||
{
|
||||
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
uint32_t dyn=(memprot[i]&PROT_DYNAREC);
|
||||
if(dyn && (prot&PROT_WRITE)) // need to remove the write protection from this block
|
||||
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_WRITE);
|
||||
memprot[i] = prot|dyn;
|
||||
}
|
||||
}
|
||||
|
||||
void setProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
|
||||
{
|
||||
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
memprot[i] = prot;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t getProtection(uintptr_t addr)
|
||||
{
|
||||
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
uint32_t ret = memprot[idx];
|
||||
return ret;
|
||||
}
|
||||
|
||||
int unlockCustommemMutex()
|
||||
{
|
||||
int ret = 0;
|
||||
int i = 0;
|
||||
#define GO(A, B) \
|
||||
i = checkUnlockMutex(&A); \
|
||||
if(i) { \
|
||||
ret|=(1<<B); \
|
||||
}
|
||||
GO(mutex_blocks, 0)
|
||||
#ifdef DYNAREC
|
||||
GO(mutex_mmap, 1)
|
||||
#endif
|
||||
#undef GO
|
||||
return ret;
|
||||
}
|
||||
|
||||
void relockCustommemMutex(int locks)
|
||||
{
|
||||
#define GO(A, B) \
|
||||
if(locks&(1<<B)) \
|
||||
pthread_mutex_lock(&A); \
|
||||
|
||||
GO(mutex_blocks, 0)
|
||||
#ifdef DYNAREC
|
||||
GO(mutex_mmap, 1)
|
||||
#endif
|
||||
#undef GO
|
||||
}
|
||||
|
||||
static void init_mutexes(void)
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
pthread_mutex_init(&mutex_blocks, &attr);
|
||||
#ifdef DYNAREC
|
||||
pthread_mutex_init(&mutex_mmap, &attr);
|
||||
#endif
|
||||
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
}
|
||||
|
||||
static void atfork_child_custommem(void)
|
||||
{
|
||||
// (re))init mutex if it was lock before the fork
|
||||
init_mutexes();
|
||||
}
|
||||
|
||||
void init_custommem_helper(box86context_t* ctx)
|
||||
{
|
||||
if(inited) // already initialized
|
||||
return;
|
||||
inited = 1;
|
||||
init_mutexes();
|
||||
#ifdef DYNAREC
|
||||
#ifdef ARM
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT); ++i)
|
||||
box86_jmptbl_default[i] = (uintptr_t)arm_next;
|
||||
for(int i=0; i<JMPTABL_SIZE; ++i)
|
||||
box86_jumptable[i] = box86_jmptbl_default;
|
||||
#else
|
||||
#error Unsupported architecture!
|
||||
#endif
|
||||
#endif
|
||||
pthread_atfork(NULL, NULL, atfork_child_custommem);
|
||||
}
|
||||
|
||||
void fini_custommem_helper(box86context_t *ctx)
|
||||
{
|
||||
if(!inited)
|
||||
return;
|
||||
inited = 0;
|
||||
#ifdef DYNAREC
|
||||
dynarec_log(LOG_DEBUG, "Free global Dynarecblocks\n");
|
||||
for (int i=0; i<mmapsize; ++i) {
|
||||
if(mmaplist[i].block)
|
||||
#ifdef USE_MMAP
|
||||
munmap(mmaplist[i].block, mmaplist[i].size);
|
||||
#else
|
||||
free(mmaplist[i].block);
|
||||
#endif
|
||||
if(mmaplist[i].dblist) {
|
||||
kh_destroy(dynablocks, mmaplist[i].dblist);
|
||||
mmaplist[i].dblist = NULL;
|
||||
}
|
||||
if(mmaplist[i].helper) {
|
||||
free(mmaplist[i].helper);
|
||||
mmaplist[i].helper = NULL;
|
||||
}
|
||||
}
|
||||
if(dblist_oversized) {
|
||||
kh_destroy(dynablocks, dblist_oversized);
|
||||
dblist_oversized = NULL;
|
||||
}
|
||||
mmapsize = 0;
|
||||
dynarec_log(LOG_DEBUG, "Free dynamic Dynarecblocks\n");
|
||||
uintptr_t idx = 0;
|
||||
uintptr_t end = ((0xFFFFFFFF)>>DYNAMAP_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
dynablocklist_t* dblist = dynmap[i];
|
||||
if(dblist) {
|
||||
uintptr_t startdb = StartDynablockList(dblist);
|
||||
uintptr_t enddb = EndDynablockList(dblist);
|
||||
uintptr_t startaddr = 0;
|
||||
if(startaddr<startdb) startaddr = startdb;
|
||||
uintptr_t endaddr = 0xFFFFFFFF;
|
||||
if(endaddr>enddb) endaddr = enddb;
|
||||
FreeRangeDynablock(dblist, startaddr, endaddr-startaddr+1);
|
||||
}
|
||||
}
|
||||
for (uintptr_t i=idx; i<=end; ++i)
|
||||
if(dynmap[i])
|
||||
FreeDynablockList(&dynmap[i]);
|
||||
pthread_mutex_destroy(&mutex_mmap);
|
||||
free(mmaplist);
|
||||
for (int i=0; i<DYNAMAP_SIZE; ++i)
|
||||
if(box86_jumptable[i]!=box86_jmptbl_default)
|
||||
free(box86_jumptable[i]);
|
||||
#endif
|
||||
for(int i=0; i<n_blocks; ++i)
|
||||
#ifdef USE_MMAP
|
||||
munmap(p_blocks[i].block, p_blocks[i].size);
|
||||
#else
|
||||
free(p_blocks[i].block);
|
||||
#endif
|
||||
free(p_blocks);
|
||||
pthread_mutex_destroy(&mutex_blocks);
|
||||
}
|
||||
+59
-13
@@ -21,12 +21,13 @@ Op is 20-27
|
||||
#define xEBP 9
|
||||
#define xESI 10
|
||||
#define xEDI 11
|
||||
#define xEIP 12
|
||||
#define xFlags 12
|
||||
#define xEIP 14
|
||||
// scratch registers
|
||||
#define x1 1
|
||||
#define x2 2
|
||||
#define x3 3
|
||||
#define x12 12
|
||||
#define x14 14
|
||||
// emu is r0
|
||||
#define xEmu 0
|
||||
// ARM SP is r13
|
||||
@@ -77,13 +78,17 @@ Op is 20-27
|
||||
// movt dst, #imm16
|
||||
#define MOVT(dst, imm16) EMIT(0xe3400000 | ((dst) << 12) | (((imm16) & 0xf000) << 4) | brIMM((imm16) & 0x0fff) )
|
||||
// pseudo insruction: mov reg, #imm with imm a 32bits value
|
||||
#define MOV32(dst, imm32) \
|
||||
MOVW(dst, ((uint32_t)imm32)&0xffff); \
|
||||
if (((uint32_t)(imm32))>>16) { \
|
||||
MOVT(dst, (((uint32_t)imm32)>>16)); }
|
||||
#define MOV32(dst, imm32) \
|
||||
if((~(uint32_t)(imm32))<0x100) { \
|
||||
MVN_IMM8(dst, ~(uint32_t)(imm32), 0); \
|
||||
} else { \
|
||||
MOVW(dst, ((uint32_t)imm32)&0xffff); \
|
||||
if (((uint32_t)(imm32))>>16) { \
|
||||
MOVT(dst, (((uint32_t)imm32)>>16));} \
|
||||
}
|
||||
// pseudo insruction: mov reg, #imm with imm a 32bits value, fixed size
|
||||
#define MOV32_(dst, imm32) \
|
||||
MOVW(dst, ((uint32_t)(imm32))&0xffff); \
|
||||
#define MOV32_(dst, imm32) \
|
||||
MOVW(dst, ((uint32_t)(imm32))&0xffff); \
|
||||
MOVT(dst, (((uint32_t)(imm32))>>16))
|
||||
// movw.cond dst, #imm16
|
||||
#define MOVW_COND(cond, dst, imm16) EMIT(cond | 0x03000000 | ((dst) << 12) | (((imm16) & 0xf000) << 4) | brIMM((imm16) & 0x0fff) )
|
||||
@@ -96,6 +101,8 @@ Op is 20-27
|
||||
#define MOV_REG_LSL_IMM5(dst, src, imm5) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (0<<4) | (0<<5) | ((imm5)<<7))
|
||||
// mov dst, src lsr imm5
|
||||
#define MOV_REG_LSR_IMM5(dst, src, imm5) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (0<<4) | (1<<5) | ((imm5)<<7))
|
||||
// mov.cond dst, src lsr imm5
|
||||
#define MOV_REG_LSR_IMM5_COND(cond, dst, src, imm5) EMIT(cond | 0x01a00000 | ((dst) << 12) | (src) | (0<<4) | (1<<5) | ((imm5)<<7))
|
||||
// mov dst, src asr imm5
|
||||
#define MOV_REG_ASR_IMM5(dst, src, imm5) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (0<<4) | (2<<5) | ((imm5)<<7))
|
||||
// mov dst, src ror imm5
|
||||
@@ -109,8 +116,14 @@ Op is 20-27
|
||||
// mov.s dst, src ror imm5
|
||||
#define MOVS_REG_ROR_IMM5(dst, src, imm5) EMIT(0xe1b00000 | ((dst) << 12) | (src) | (0<<4) | (3<<5) | ((imm5)<<7))
|
||||
|
||||
// mov.s dst, src lsl rs
|
||||
#define MOVS_REG_LSL_REG(dst, src, rs) EMIT(0xe1b00000 | ((dst) << 12) | (src) | (1<<4) | (0<<5) | ((rs)<<8))
|
||||
// mov.s dst, src lsr rs
|
||||
#define MOVS_REG_LSR_REG(dst, src, rs) EMIT(0xe1b00000 | ((dst) << 12) | (src) | (1<<4) | (1<<5) | ((rs)<<8))
|
||||
// mov dst, src lsl rs
|
||||
#define MOV_REG_LSL_REG(dst, src, rs) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (1<<4) | (0<<5) | ((rs)<<8))
|
||||
// mov.cond dst, src lsl rs
|
||||
#define MOV_REG_LSL_REG_COND(cond, dst, src, rs) EMIT(cond | 0x01a00000 | ((dst) << 12) | (src) | (1<<4) | (0<<5) | ((rs)<<8))
|
||||
// mov dst, src lsr rs
|
||||
#define MOV_REG_LSR_REG(dst, src, rs) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (1<<4) | (1<<5) | ((rs)<<8))
|
||||
// mov dst, src asr rs
|
||||
@@ -234,13 +247,22 @@ Op is 20-27
|
||||
// orr.s dst, src1, src2, lsl #imm
|
||||
#define ORRS_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe1900000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// orr dst, src1, src2, lsr #imm
|
||||
#define ORR_REG_LSR_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe1800000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm5, src2) )
|
||||
// orr.s dst, src1, src2, lsr #imm
|
||||
#define ORRS_REG_LSR_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe1900000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm5, src2) )
|
||||
// orr dst, src1, #imm8
|
||||
#define ORR_IMM8(dst, src, imm8, rot) \
|
||||
EMIT(0xe3800000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
|
||||
// orr.s dst, src1, #imm8
|
||||
#define ORRS_IMM8(dst, src, imm8, rot) \
|
||||
EMIT(0xe3900000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
|
||||
// orr dst, src1, src2, lsl #rs
|
||||
// orr.cond dst, src1, #imm8 ror rot*2
|
||||
#define ORR_IMM8_COND(cond, dst, src, imm8, rot) \
|
||||
EMIT((cond) | 0x03800000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
|
||||
// orr dst, src1, src2, lsl rs
|
||||
#define ORR_REG_LSL_REG(dst, src1, src2, rs) \
|
||||
EMIT(0xe1800000 | ((dst) << 12) | ((src1) << 16) | brRLSL(rs, src2) )
|
||||
// xor dst, src1, src2, lsl #imm
|
||||
@@ -256,6 +278,9 @@ Op is 20-27
|
||||
EMIT(0xe2200000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
#define XORS_IMM8(dst, src, imm8) \
|
||||
EMIT(0xe2300000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// xor dst, src, #(imm8 ror rot*2)
|
||||
#define XOR_IMM8_ROR(dst, src, imm8, rot) \
|
||||
EMIT(0xe2200000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(imm8) )
|
||||
// xor.cond dst, src, #(imm8)
|
||||
#define XOR_IMM8_COND(cond, dst, src, imm8) \
|
||||
EMIT(cond | 0x02200000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
@@ -265,12 +290,18 @@ Op is 20-27
|
||||
// xor dst, src1, src2, lsl #imm
|
||||
#define XOR_REG_LSR_IMM8(dst, src1, src2, imm8) \
|
||||
EMIT(0xe0200000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm8, src2) )
|
||||
// xor.cond dst, src1, src2, lsl #imm
|
||||
#define XOR_REG_LSR_IMM8_COND(cond, dst, src1, src2, imm8) \
|
||||
EMIT(cond | 0x00200000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm8, src2) )
|
||||
// bic dst, src1, src2, lsl #imm
|
||||
#define BIC_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe1c00000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// bic dst, src, IMM8
|
||||
// bic dst, src, IMM8 ror rot*2
|
||||
#define BIC_IMM8(dst, src, imm8, rot) \
|
||||
EMIT(0xe3c00000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
|
||||
// bic.cond dst, src, IMM8
|
||||
#define BIC_IMM8_COND(cond, dst, src, imm8, rot) \
|
||||
EMIT((cond) | 0x03c00000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
|
||||
// bic.s dst, src1, #imm ror rot*2
|
||||
#define BICS_IMM8_ROR(dst, src, imm8, rot) \
|
||||
EMIT(0xe3d00000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(imm8) )
|
||||
@@ -281,8 +312,8 @@ Op is 20-27
|
||||
#define MVN_REG_LSL_IMM5(dst, rm, imm5) \
|
||||
EMIT(0xe1e00000 | ((dst) << 12) | (0 << 16) | brLSL(imm5, rm) )
|
||||
// mvn dst, src, IMM8
|
||||
#define MVN_IMM8(dst, src, imm8, rot) \
|
||||
EMIT(0xe3e00000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
|
||||
#define MVN_IMM8(dst, imm8, rot) \
|
||||
EMIT(0xe3e00000 | ((dst) << 12) | (rot)<<8 | ((imm8)&0xff) )
|
||||
// mvn dst, src1, src2, lsr #imm
|
||||
#define MVN_REG_LSR_IMM8(dst, rm, imm8) \
|
||||
EMIT(0xe1e00000 | ((dst) << 12) | (0 << 16) | brLSR(imm8, rm) )
|
||||
@@ -327,6 +358,8 @@ Op is 20-27
|
||||
#define STR_IMM9(reg, addr, imm9) EMIT(0xe5000000 | (((imm9)<0)?0:1)<<23 | ((reg) << 12) | ((addr) << 16) | brIMM(imm9) )
|
||||
// str with cond reg, [addr, #+/-imm9]
|
||||
#define STR_IMM9_COND(cond, reg, addr, imm9) EMIT(cond | 0x05000000 | (((imm9)<0)?0:1)<<23 | ((reg) << 12) | ((addr) << 16) | brIMM(imm9) )
|
||||
// str reg, [addr, #+/-imm9]!
|
||||
#define STR_IMM9_W(reg, addr, imm9) EMIT(0xe5200000 | (((imm9)<0)?0:1)<<23 | ((reg) << 12) | ((addr) << 16) | brIMM(imm9) )
|
||||
// strb reg, [addr, #+/-imm9]
|
||||
#define STRB_IMM9(reg, addr, imm9) EMIT(0xe5400000 | (((imm9)<0)?0:1)<<23 | ((reg) << 12) | ((addr) << 16) | brIMM(imm9) )
|
||||
// str reg, [addr], #+/-imm9
|
||||
@@ -364,10 +397,16 @@ Op is 20-27
|
||||
// all | const |pre-index| subs | no PSR |writeback| store | base |reg list
|
||||
#define PUSH(reg, list) EMIT(c__ | (0b100<<25) | (1<<24) | (0<<23) | (0<<22) | (1<<21) | (0<<20) | ((reg)<<16) | (list))
|
||||
|
||||
// push reg to xESP
|
||||
#define PUSH1(reg) STR_IMM9_W(reg, xESP, -4)
|
||||
|
||||
// pop reg!, {list}
|
||||
// all | const |postindex| add | no PSR |writeback| load | base |reg list
|
||||
#define POP(reg, list) EMIT(c__ | (0b100<<25) | (0<<24) | (1<<23) | (0<<22) | (1<<21) | (1<<20) | ((reg)<<16) | (list))
|
||||
|
||||
// pop reg from xESP
|
||||
#define POP1(reg) LDRAI_IMM9_W(reg, xESP, 4)
|
||||
|
||||
// STMDB reg, {list}
|
||||
// all | const |pre-index| subs | no PSR | no wb | store | base |reg list
|
||||
#define STMDB(reg, list) EMIT(c__ | (0b100<<25) | (1<<24) | (0<<23) | (0<<22) | (0<<21) | (0<<20) | ((reg)<<16) | (list))
|
||||
@@ -433,8 +472,15 @@ Op is 20-27
|
||||
// BFI_COND: Bit Field Insert with condition: copy any number of low order bit from Rn to any position of Rd
|
||||
#define BFI_COND(cond, rd, rn, lsb, width) EMIT(cond | (0b0111110<<21) | (((lsb)+(width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b001<<4) | (rn))
|
||||
|
||||
// BFC: Bit Field Clear: clear any number of adjacent bit from Rd
|
||||
#define BFC(rd, lsb, width) EMIT(c__ | (0b0111110<<21) | (((lsb)+(width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b001<<4) | 0b1111)
|
||||
// BFC_COND: Bit Field Clear with condition: clear any number of adjacent bit from Rd
|
||||
#define BFC_COND(cond, rd, lsb, width) EMIT(cond | (0b0111110<<21) | (((lsb)+(width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b001<<4) | 0b1111)
|
||||
|
||||
// REV: Reverse byte of a 32bits word
|
||||
#define REV(rd, rm) EMIT(c__ | (0b01101<<23) | (0<<22) | (0b11<<20) | (0b1111<<16) | ((rd)<<12) | (0b1111<<8) | (0b0011<<4) | (rm))
|
||||
#define REV(rd, rm) EMIT(c__ | (0b01101<<23) | (0<<22) | (0b11<<20) | (0b1111<<16) | ((rd)<<12) | (0b1111<<8) | (0b0011<<4) | (rm))
|
||||
// REV16: Reverse byte of a 16bits word
|
||||
#define REV16(rd, rm) EMIT(c__ | (0b01101<<23) | (0<<22) | (0b11<<20) | (0b1111<<16) | ((rd)<<12) | (0b1111<<8) | (0b1011<<4) | (rm))
|
||||
|
||||
#define SSAT_gen(cond, sat_imm, Rd, imm5, sh, Rn) (cond | 0b0110101<<21 | (sat_imm)<<16 | (Rd)<<12 | (imm5)<<7 | (sh)<<6 | 0b01<<4 | (Rn))
|
||||
// Signed Staturate Rn to 2^(staturate_to-1) into Rd. Optionnaly shift left Rn before saturate
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
arm_epilog:
|
||||
//update register -> emu
|
||||
//pop {r0}
|
||||
stm r0, {r4-r12} // put back reg value in emu, including EIP (so r12 must be EIP now)
|
||||
stm r0, {r4-r12,r14} // put back reg value in emu, including EIP (so r14 must be EIP now)
|
||||
//restore all used register
|
||||
//vpop {d8-d15}
|
||||
vpop {d8-d15}
|
||||
pop {r4-r11, pc}
|
||||
//end, return...
|
||||
//bx lr
|
||||
@@ -21,7 +21,7 @@ arm_epilog:
|
||||
.global arm_epilog_fast
|
||||
arm_epilog_fast:
|
||||
//restore all used register
|
||||
//vpop {d8-d15}
|
||||
vpop {d8-d15}
|
||||
pop {r4-r11, pc}
|
||||
//end, return...
|
||||
//bx lr
|
||||
@@ -396,6 +396,7 @@ ARM_ cond 0 0 0 1 0 0 1 0 (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) 0 0 1
|
||||
ARM_ cond/=1110 0 0 0 1 0 0 1 0 imm12 0 1 1 1 imm4 BKPT #<imm16>
|
||||
ARMS cond 0 0 0 1 0 0 1 1 Rn (0) (0) (0) (0) imm5 type 0 Rm TEQ<c> <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 1 0 1 0 0 Rn Rt (0) (0) (0) (0) 1 0 0 1 Rm SWPB<c> <Rt>, <Rm>, [<Rn>]
|
||||
ARM_ cond 0 0 0 1 0 1 1 0 (1) (1) (1) (1) Rd (1) (1) (1) (1) 0 0 0 1 Rm CLZ<c> <Rd>, <Rm>
|
||||
ARM_ cond 0 0 0 1 U 1 W 0 Rn Rt imm4H 1 0 1 1 imm4L STRH<c> <Rt>, [<Rn>, #+/-<imm8>]{!}
|
||||
ARM_ cond 0 0 0 1 U 1 W 0 Rn Rt imm4H 1 1 0 1 imm4L LDRD<c> <Rt>, <Rt2>, [<Rn>, #+/-<imm8>]{!}
|
||||
ARM_ cond 0 0 0 1 U 1 W 0 Rn Rt imm4H 1 1 1 1 imm4L STRD<c> <Rt>, <Rt2>, [<Rn>, #+/-<imm8>]{!}
|
||||
@@ -482,6 +483,7 @@ ARMs cond 0 1 1 0 1 1 1 sat_imm Rd imm5 sh 0 1 Rn USAT<c> <Rd>, #<imm>, <Rn>{, <
|
||||
ARM_ cond 0 1 1 0 1 1 1 0 sat_imm Rd (1) (1) (1) (1) 0 0 1 1 Rn USAT16<c> <Rd>, #<imm>, <Rn>
|
||||
ARM_ cond 0 1 1 0 1 1 1 0 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm UXTB<c> <Rd>, <Rm>{, <rotation>}
|
||||
ARM_ cond 0 1 1 0 1 1 1 0 Rn Rd rotate (0) (0) 0 1 1 1 Rm UXTAB<c> <Rd>, <Rn>, <Rm>{, <rotation>}
|
||||
ARM_ cond 0 1 1 0 1 1 1 1 (1) (1) (1) (1) Rd (1) (1) (1) (1) 0 0 1 1 Rm RBIT<c> <Rd>, <Rm>
|
||||
ARM_ cond 0 1 1 0 1 1 1 1 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm UXTH<c> <Rd>, <Rm>{, <rotation>}
|
||||
ARM_ cond 0 1 1 0 1 1 1 1 (1) (1) (1) (1) Rd (1) (1) (1) (1) 1 0 1 1 Rm REVSH<c> <Rd>, <Rm>
|
||||
ARM_ cond 0 1 1 0 1 1 1 1 Rn Rd rotate (0) (0) 0 1 1 1 Rm UXTAH<c> <Rd>, <Rn>, <Rm>{, <rotation>}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
//arm update linker table for dynarec
|
||||
//called with pointer to emu as 1st parameter
|
||||
//and address of table to as 2nd parameter
|
||||
//ip is at r12
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.extern UpdateLinkTable
|
||||
|
||||
.global arm_linker
|
||||
arm_linker:
|
||||
// emu is r0
|
||||
stm r0, {r4-r12} // put back reg value in emu, including EIP (easier debugging, and safer)
|
||||
// table offset is r1
|
||||
// IP address is r12
|
||||
push {r0, r1, r12}
|
||||
mov r2, r12
|
||||
// call the function
|
||||
bl UpdateLinkTable
|
||||
// return offset is jump address
|
||||
mov r3, r0
|
||||
pop {r0, r1, r12}
|
||||
bx r3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//arm lock helper
|
||||
//there is 2 part: read and write
|
||||
// arm lock helper
|
||||
// there is 2 part: read and write
|
||||
// write return 0 on success, 1 on fail (value has been changed)
|
||||
|
||||
.text
|
||||
@@ -15,6 +15,7 @@
|
||||
.global arm_lock_write_dd
|
||||
.global arm_lock_xchg
|
||||
.global arm_lock_storeifnull
|
||||
.global arm_lock_storeifref
|
||||
|
||||
|
||||
arm_lock_read_b:
|
||||
@@ -81,9 +82,27 @@ arm_lock_storeifnull:
|
||||
// r0 needs to be aligned
|
||||
ldrex r2, [r0]
|
||||
cmp r2, #0
|
||||
moveq r2, r1
|
||||
bne arm_lock_storeifnull_exit
|
||||
mov r2, r1
|
||||
strex r3, r2, [r0]
|
||||
cmp r3, #1
|
||||
beq arm_lock_storeifnull
|
||||
arm_lock_storeifnull_exit:
|
||||
mov r0, r2
|
||||
bx lr
|
||||
|
||||
arm_lock_storeifref:
|
||||
push {r4}
|
||||
arm_lock_storeifref_loop:
|
||||
// address is r0, value is r1, r1 store to r0 only if [r0] is r2. return new [r0] value (so r1 or old value)
|
||||
ldrex r3, [r0]
|
||||
cmp r3, r2
|
||||
bne arm_lock_storeifref_exit
|
||||
mov r3, r1
|
||||
strex r4, r3, [r0]
|
||||
cmp r4, #1
|
||||
beq arm_lock_storeifref_loop
|
||||
arm_lock_storeifref_exit:
|
||||
mov r0, r3
|
||||
pop {r4}
|
||||
bx lr
|
||||
@@ -22,10 +22,13 @@ extern void arm_lock_read_dd(uint32_t* a, uint32_t* b, void* addr);
|
||||
// STREX of ADDR, return 0 if ok, 1 if not
|
||||
extern int arm_lock_write_dd(uint32_t a, uint32_t b, void* addr);
|
||||
|
||||
// Atomicaly exchange value at [p] with val, return old p
|
||||
// Atomically exchange value at [p] with val, return old p
|
||||
extern uintptr_t arm_lock_xchg(void* p, uintptr_t val);
|
||||
|
||||
// Atomicaly store value to [p] only if [p] is NULL. Return new [p] value (so val or old)
|
||||
extern void* arm_lock_storeifnull(void*p, void* val);
|
||||
// Atomically store value to [p] only if [p] is NULL. Return new [p] value (so val or old)
|
||||
extern void* arm_lock_storeifnull(void* p, void* val);
|
||||
|
||||
// Atomically store value to [p] only if [p] is ref. Return new [p] value (so val or old)
|
||||
extern void* arm_lock_storeifref(void* p, void* val, void* ref);
|
||||
|
||||
#endif //__ARM_LOCK_HELPER__H__
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
//arm update linker table for dynarec
|
||||
//called with pointer to emu as 1st parameter
|
||||
//and address of table to as 2nd parameter
|
||||
//ip is at r12
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.extern LinkNext
|
||||
|
||||
.global arm_next
|
||||
arm_next:
|
||||
// emu is r0
|
||||
//stm r0, {r4-r12,r14} // don't put put back reg value in emu, faster but more tricky to debug
|
||||
// IP address is r1
|
||||
push {r0, r1, r12, r14}
|
||||
// call the function
|
||||
bl LinkNext
|
||||
// return offset is jump address
|
||||
mov r3, r0
|
||||
pop {r0, r1, r12, r14}
|
||||
bx r3
|
||||
|
||||
@@ -3605,6 +3605,12 @@ const char* arm_print(uint32_t opcode) {
|
||||
int rm = (opcode >> 0) & 0xF;
|
||||
|
||||
sprintf(ret, "SWPB%s %s, %s, [%s]", cond, regname[rt], regname[rm], regname[rn]);
|
||||
} else if ((opcode & 0x0FF000F0) == 0x01600010) {
|
||||
const char* cond = conds[(opcode >> 28) & 0xF];
|
||||
int rd = (opcode >> 12) & 0xF;
|
||||
int rm = (opcode >> 0) & 0xF;
|
||||
|
||||
sprintf(ret, "CLZ%s %s, %s", cond, regname[rd], regname[rm]);
|
||||
} else if ((opcode & 0x0F5000F0) == 0x014000B0) {
|
||||
const char* cond = conds[(opcode >> 28) & 0xF];
|
||||
int rt = (opcode >> 12) & 0xF;
|
||||
@@ -4288,6 +4294,12 @@ const char* arm_print(uint32_t opcode) {
|
||||
}
|
||||
|
||||
sprintf(ret, "UXTAB%s %s, %s, %s%s}", cond, regname[rd], regname[rn], regname[rm], tmprot);
|
||||
} else if ((opcode & 0x0FF000F0) == 0x06F00030) {
|
||||
const char* cond = conds[(opcode >> 28) & 0xF];
|
||||
int rd = (opcode >> 12) & 0xF;
|
||||
int rm = (opcode >> 0) & 0xF;
|
||||
|
||||
sprintf(ret, "RBIT%s %s, %s", cond, regname[rd], regname[rm]);
|
||||
} else if ((opcode & 0x0FFF00F0) == 0x06FF0070) {
|
||||
const char* cond = conds[(opcode >> 28) & 0xF];
|
||||
int rd = (opcode >> 12) & 0xF;
|
||||
|
||||
@@ -10,10 +10,10 @@
|
||||
arm_prolog:
|
||||
//save all used register
|
||||
push {r4-r11, lr}
|
||||
//vpush {d8-d15}
|
||||
vpush {d8-d15}
|
||||
//setup emu -> register
|
||||
//push {r0}
|
||||
ldm r0, {r4-r11} // all 8 register in direct access, no EIP (so r12 can be used as scratch)
|
||||
ldm r0, {r4-r12} // all 8 register in direct access, plus flags, no EIP (so r14 can be used as scratch)
|
||||
//TODO
|
||||
//jump to function
|
||||
bx r1
|
||||
@@ -1,19 +0,0 @@
|
||||
//arm try to update linker table for dynarec
|
||||
//and address of table to as 1st parameter
|
||||
//jump addres as second and ip as third
|
||||
// don't retry if failed to write...
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.global arm_tableupdate
|
||||
arm_tableupdate:
|
||||
// jump address is r0 and IP address is r1
|
||||
// table offset is r2
|
||||
push {r4, r5}
|
||||
ldrexd r4, r5, [r2]
|
||||
strexd r3, r0, r1, [r2]
|
||||
pop {r4, r5}
|
||||
mov r0, r3
|
||||
bx lr
|
||||
|
||||
+96
-98
@@ -24,7 +24,7 @@
|
||||
#else
|
||||
#error Unsupported architecture!
|
||||
#endif
|
||||
|
||||
#include "custommem.h"
|
||||
#include "khash.h"
|
||||
|
||||
KHASH_MAP_INIT_INT(dynablocks, dynablock_t*)
|
||||
@@ -38,28 +38,27 @@ uint32_t X31_hash_code(void* addr, int len)
|
||||
return (uint32_t)h;
|
||||
}
|
||||
|
||||
dynablocklist_t* NewDynablockList(uintptr_t base, uintptr_t text, int textsz, int nolinker, int direct)
|
||||
dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int direct)
|
||||
{
|
||||
if(!textsz) {
|
||||
printf_log(LOG_NONE, "Error, creating a NULL sized Dynablock\n");
|
||||
return NULL;
|
||||
}
|
||||
dynablocklist_t* ret = (dynablocklist_t*)calloc(1, sizeof(dynablocklist_t));
|
||||
ret->base = base;
|
||||
ret->text = text;
|
||||
ret->textsz = textsz;
|
||||
ret->nolinker = nolinker;
|
||||
if(direct && textsz) {
|
||||
ret->direct = (dynablock_t**)calloc(textsz, sizeof(dynablock_t*));
|
||||
if(!ret->direct) {printf_log(LOG_NONE, "Warning, fail to create direct block for dynablock @%p\n", (void*)text);}
|
||||
}
|
||||
dynarec_log(LOG_DEBUG, "New Dynablocklist %p, from %p->%p\n", ret, (void*)text, (void*)(text+textsz));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void FreeDynablock(dynablock_t* db)
|
||||
{
|
||||
if(db) {
|
||||
dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x86=%p:%p father=%p, tablesz=%d, with %d son(s) already gone=%d\n", db, db->block, db->x86_addr, db->x86_addr+db->x86_size, db->father, db->tablesz, db->sons_size, db->gone);
|
||||
dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x86=%p:%p father=%p, with %d son(s) already gone=%d\n", db, db->block, db->x86_addr, db->x86_addr+db->x86_size, db->father, db->sons_size, db->gone);
|
||||
if(db->gone)
|
||||
return; // already in the process of deletion!
|
||||
db->done = 0;
|
||||
@@ -72,6 +71,8 @@ void FreeDynablock(dynablock_t* db)
|
||||
if(addr>=startdb && addr<enddb)
|
||||
db->parent->direct[addr-startdb] = NULL;
|
||||
}
|
||||
// remove jumptable
|
||||
setJumpTableDefault(db->x86_addr);
|
||||
// remove and free the sons
|
||||
for (int i=0; i<db->sons_size; ++i) {
|
||||
dynablock_t *son = (dynablock_t*)arm_lock_xchg(&db->sons[i], 0);
|
||||
@@ -83,7 +84,6 @@ void FreeDynablock(dynablock_t* db)
|
||||
FreeDynarecMap(db, (uintptr_t)db->block, db->size);
|
||||
}
|
||||
free(db->sons);
|
||||
free(db->table);
|
||||
free(db->instsize);
|
||||
free(db);
|
||||
}
|
||||
@@ -95,7 +95,7 @@ void FreeDynablockList(dynablocklist_t** dynablocks)
|
||||
return;
|
||||
if(!*dynablocks)
|
||||
return;
|
||||
dynarec_log(LOG_DEBUG, "Free Direct Blocks %p from Dynablocklist nolinker=%d\n", (*dynablocks)->direct, (*dynablocks)->nolinker);
|
||||
dynarec_log(LOG_DEBUG, "Free Dynablocklist %p, with Direct Blocks %p\n", *dynablocks, (*dynablocks)->direct);
|
||||
if((*dynablocks)->direct) {
|
||||
for (int i=0; i<(*dynablocks)->textsz; ++i) {
|
||||
if((*dynablocks)->direct[i] && !(*dynablocks)->direct[i]->father)
|
||||
@@ -114,53 +114,12 @@ void MarkDynablock(dynablock_t* db)
|
||||
if(db) {
|
||||
if(db->father)
|
||||
db = db->father; // mark only father
|
||||
if(db->nolinker)
|
||||
db->need_test = 1; // test only blocks that can be marked (and so deleted)
|
||||
}
|
||||
}
|
||||
|
||||
void ProtectDynablock(dynablock_t* db)
|
||||
{
|
||||
if(db) {
|
||||
if(db->father)
|
||||
return; // protect only father, child(ren) will be automatically
|
||||
protectDB((uintptr_t)db->x86_addr, db->x86_size);
|
||||
}
|
||||
}
|
||||
|
||||
void MarkDynablockList(dynablocklist_t** dynablocks)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
if(!*dynablocks)
|
||||
return;
|
||||
if(!(*dynablocks)->nolinker)
|
||||
return;
|
||||
dynarec_log(LOG_DEBUG, "Marked Blocks from Dynablocklist nolinker=%d %p:0x%x\n", (*dynablocks)->nolinker, (void*)(*dynablocks)->text, (*dynablocks)->textsz);
|
||||
dynablock_t* db;
|
||||
if((*dynablocks)->direct) {
|
||||
for (int i=0; i<(*dynablocks)->textsz; ++i) {
|
||||
db = (*dynablocks)->direct[i];
|
||||
if(db)
|
||||
MarkDynablock(db);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProtectDynablockList(dynablocklist_t** dynablocks)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
if(!*dynablocks)
|
||||
return;
|
||||
dynarec_log(LOG_DEBUG, "Protect Blocks from Dynablocklist nolinker=%d %p:0x%x\n", (*dynablocks)->nolinker, (void*)(*dynablocks)->text, (*dynablocks)->textsz);
|
||||
dynablock_t* db;
|
||||
if((*dynablocks)->direct) {
|
||||
for (int i=0; i<(*dynablocks)->textsz; ++i) {
|
||||
db = (*dynablocks)->direct[i];
|
||||
if(db)
|
||||
ProtectDynablock(db);
|
||||
}
|
||||
if(db->need_test)
|
||||
return; // already done
|
||||
db->need_test = 1; // test only blocks that can be marked (and so deleted)
|
||||
setJumpTableDefault(db->x86_addr);
|
||||
for(int i=0; i<db->sons_size; ++i)
|
||||
setJumpTableDefault(db->sons[i]->x86_addr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,41 +135,34 @@ uintptr_t EndDynablockList(dynablocklist_t* db)
|
||||
return db->text+db->textsz-1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IntervalIntersects(uintptr_t start1, uintptr_t end1, uintptr_t start2, uintptr_t end2)
|
||||
{
|
||||
if(start1 > end2 || start2 > end1)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void MarkDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
if(!dynablocks->nolinker)
|
||||
if(!dynablocks->direct)
|
||||
return;
|
||||
uintptr_t startdb = dynablocks->text;
|
||||
uintptr_t enddb = startdb + dynablocks->textsz;
|
||||
uintptr_t enddb = startdb + dynablocks->textsz -1;
|
||||
uintptr_t start = addr;
|
||||
uintptr_t end = addr+size;
|
||||
uintptr_t end = addr+size-1;
|
||||
if(start<startdb)
|
||||
start = startdb;
|
||||
if(end>enddb)
|
||||
end = enddb;
|
||||
dynablock_t *db;
|
||||
if(end>startdb && start<enddb)
|
||||
for(uintptr_t i = start; i<end; ++i)
|
||||
if(dynablocks->direct[i-startdb]) {
|
||||
MarkDynablock(dynablocks->direct[i-startdb]);
|
||||
}
|
||||
}
|
||||
|
||||
void ProtectDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
uintptr_t startdb = dynablocks->text;
|
||||
uintptr_t enddb = startdb + dynablocks->textsz;
|
||||
uintptr_t start = addr;
|
||||
uintptr_t end = addr+size;
|
||||
if(start<startdb)
|
||||
start = startdb;
|
||||
if(end>enddb)
|
||||
end = enddb;
|
||||
if(end>startdb && start<enddb)
|
||||
protectDB(start, end-start); //no +1; as end/enddb is exclusive and not inclusive
|
||||
if((db=dynablocks->direct[i-startdb]))
|
||||
if(IntervalIntersects((uintptr_t)db->x86_addr, (uintptr_t)db->x86_addr+db->x86_size-1, addr, addr+size+1))
|
||||
MarkDynablock(db);
|
||||
}
|
||||
|
||||
void FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
@@ -239,8 +191,10 @@ void FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t s
|
||||
if(db) {
|
||||
if(db->father)
|
||||
db = db->father;
|
||||
k = kh_put(dynablocks, blocks, (uintptr_t)db, &ret);
|
||||
kh_value(blocks, k) = db;
|
||||
if(db->parent==dynablocks) {
|
||||
k = kh_put(dynablocks, blocks, (uintptr_t)db, &ret);
|
||||
kh_value(blocks, k) = db;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -255,10 +209,14 @@ void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t s
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
if(!dynablocks->nolinker)
|
||||
return;
|
||||
if(dynablocks->direct)
|
||||
MarkDirectDynablock(dynablocks, addr, size);
|
||||
if(dynablocks->direct) {
|
||||
uintptr_t new_addr = addr - dynablocks->maxsz;
|
||||
uintptr_t new_size = size + dynablocks->maxsz;
|
||||
MarkDirectDynablock(dynablocks, new_addr, new_size);
|
||||
// the blocks check before
|
||||
for(int idx=(new_addr)>>DYNAMAP_SHIFT; idx<(addr>>DYNAMAP_SHIFT); ++idx)
|
||||
MarkDirectDynablock(getDB(idx), new_addr, new_size);
|
||||
}
|
||||
}
|
||||
|
||||
dynablock_t* FindDynablockDynablocklist(void* addr, kh_dynablocks_t* dynablocks)
|
||||
@@ -267,8 +225,8 @@ dynablock_t* FindDynablockDynablocklist(void* addr, kh_dynablocks_t* dynablocks)
|
||||
return NULL;
|
||||
dynablock_t* db;
|
||||
kh_foreach_value(dynablocks, db,
|
||||
uintptr_t s = (uintptr_t)db->block;
|
||||
uintptr_t e = (uintptr_t)db->block+db->size;
|
||||
const uintptr_t s = (uintptr_t)db->block;
|
||||
const uintptr_t e = (uintptr_t)db->block+db->size;
|
||||
if((uintptr_t)addr>=s && (uintptr_t)addr<e)
|
||||
return db->father?db->father:db;
|
||||
)
|
||||
@@ -278,7 +236,7 @@ dynablock_t* FindDynablockDynablocklist(void* addr, kh_dynablocks_t* dynablocks)
|
||||
static dynablocklist_t* getDBFromAddress(uintptr_t addr)
|
||||
{
|
||||
const int idx = (addr>>DYNAMAP_SHIFT);
|
||||
return (my_context->dynmap[idx])?my_context->dynmap[idx]:NULL;
|
||||
return getDB(idx);
|
||||
}
|
||||
|
||||
dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* created)
|
||||
@@ -309,13 +267,17 @@ dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* c
|
||||
if (!*created)
|
||||
return block;
|
||||
|
||||
if(!dynablocks->direct)
|
||||
dynablocks->direct = (dynablock_t**)calloc(dynablocks->textsz, sizeof(dynablock_t*));
|
||||
if(!dynablocks->direct) {
|
||||
dynablock_t** p = (dynablock_t**)calloc(dynablocks->textsz, sizeof(dynablock_t*));
|
||||
if(arm_lock_storeifnull(&dynablocks->direct, p)!=p)
|
||||
free(p); // someone already create the direct array, too late...
|
||||
}
|
||||
|
||||
// create and add new block
|
||||
dynarec_log(LOG_DUMP, "Ask for DynaRec Block creation @%p\n", (void*)addr);
|
||||
|
||||
block = (dynablock_t*)calloc(1, sizeof(dynablock_t));
|
||||
block->parent = dynablocks;
|
||||
dynablock_t* tmp = (dynablock_t*)arm_lock_storeifnull(&dynablocks->direct[addr-dynablocks->text], block);
|
||||
if(tmp != block) {
|
||||
// a block appeard!
|
||||
@@ -324,8 +286,6 @@ dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* c
|
||||
return tmp;
|
||||
}
|
||||
|
||||
block->parent = dynablocks;
|
||||
|
||||
*created = 1;
|
||||
return block;
|
||||
}
|
||||
@@ -363,19 +323,49 @@ static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, uintptr_t
|
||||
if(!created)
|
||||
return block; // existing block...
|
||||
|
||||
#if 0
|
||||
if(box86_dynarec_dump)
|
||||
pthread_mutex_lock(&my_context->mutex_dyndump);
|
||||
#endif
|
||||
// fill the block
|
||||
block->x86_addr = (void*)addr;
|
||||
if(!FillBlock(block, filladdr)) {
|
||||
dynablocks->direct[addr-dynablocks->text] = NULL;
|
||||
pthread_mutex_lock(&my_context->mutex_dyndump);
|
||||
void* ret = FillBlock(block, filladdr);
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
if(!ret) {
|
||||
dynarec_log(LOG_DEBUG, "Fillblock of block %p for %p returned an error\n", block, (void*)addr);
|
||||
void* old = (void*)arm_lock_storeifref(&dynablocks->direct[addr-dynablocks->text], 0, block);
|
||||
if(old!=block && old) { // put it back in place, strange things are happening here!
|
||||
dynarec_log(LOG_INFO, "Warning, a wild block appeared at %p: %p\n", (void*)addr, old);
|
||||
// Doing nothing else, the block has not been written
|
||||
}
|
||||
free(block);
|
||||
block = NULL;
|
||||
}
|
||||
#if 0
|
||||
if(box86_dynarec_dump)
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
#endif
|
||||
// check size
|
||||
if(block && block->x86_size) {
|
||||
int blocksz = block->x86_size;
|
||||
if(dynablocks->maxsz<blocksz) {
|
||||
dynablocks->maxsz = blocksz;
|
||||
for(int idx=(addr>>DYNAMAP_SHIFT)+1; idx<=((addr+blocksz)>>DYNAMAP_SHIFT); ++idx) {
|
||||
dynablocklist_t* dblist;
|
||||
if((dblist = getDB(idx)))
|
||||
if(dblist->maxsz<blocksz)
|
||||
dblist->maxsz = blocksz;
|
||||
}
|
||||
}
|
||||
protectDB((uintptr_t)block->x86_addr, block->x86_size);
|
||||
// fill-in jumptable
|
||||
addJumpTableIfDefault(block->x86_addr, block->block);
|
||||
for(int i=0; i<block->sons_size; ++i)
|
||||
addJumpTableIfDefault(block->sons[i]->x86_addr, block->sons[i]->block);
|
||||
}
|
||||
|
||||
dynarec_log(LOG_DEBUG, " --- DynaRec Block %s @%p:%p (%p, 0x%x bytes, with %d son(s))\n", created?"created":"recycled", (void*)addr, (void*)(addr-((block)?block->x86_size:0)), (block)?block->block:0, (block)?block->size:0, (block)?block->sons_size:0);
|
||||
dynarec_log(LOG_DEBUG, " --- DynaRec Block %s @%p:%p (%p, 0x%x bytes, with %d son(s))\n", created?"created":"recycled", (void*)addr, (void*)(addr+((block)?block->x86_size:0)), (block)?block->block:0, (block)?block->size:0, (block)?block->sons_size:0);
|
||||
|
||||
return block;
|
||||
}
|
||||
@@ -383,11 +373,11 @@ static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, uintptr_t
|
||||
dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t** current)
|
||||
{
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, *current);
|
||||
if(db && (db->need_test || (db->father && db->father->need_test))) {
|
||||
if(db && db->done && db->block && (db->need_test || (db->father && db->father->need_test))) {
|
||||
dynablock_t *father = db->father?db->father:db;
|
||||
uint32_t hash = father->nolinker?X31_hash_code(father->x86_addr, father->x86_size):0;
|
||||
uint32_t hash = X31_hash_code(father->x86_addr, father->x86_size);
|
||||
if(hash!=father->hash) {
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) with %d son(s)\n", father, father->x86_addr, father->x86_addr+father->x86_size, hash, father->hash, father->sons_size);
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x86_addr, father->x86_addr+father->x86_size, hash, father->hash, father->sons_size, (void*)addr);
|
||||
// no more current if it gets invalidated too
|
||||
if(*current && father->x86_addr>=(*current)->x86_addr && (father->x86_addr+father->x86_size)<(*current)->x86_addr)
|
||||
*current = NULL;
|
||||
@@ -398,6 +388,10 @@ dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t**
|
||||
} else {
|
||||
father->need_test = 0;
|
||||
protectDB((uintptr_t)father->x86_addr, father->x86_size);
|
||||
// fill back jumptable
|
||||
addJumpTableIfDefault(father->x86_addr, father->block);
|
||||
for(int i=0; i<father->sons_size; ++i)
|
||||
addJumpTableIfDefault(father->sons[i]->x86_addr, father->sons[i]->block);
|
||||
}
|
||||
}
|
||||
return db;
|
||||
@@ -408,11 +402,11 @@ dynablock_t* DBAlternateBlock(x86emu_t* emu, uintptr_t addr, uintptr_t filladdr)
|
||||
dynarec_log(LOG_DEBUG, "Creating AlternateBlock at %p for %p\n", (void*)addr, (void*)filladdr);
|
||||
int create = 1;
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, NULL);
|
||||
if(db && (db->need_test || (db->father && db->father->need_test))) {
|
||||
if(db && db->done && db->block && (db->need_test || (db->father && db->father->need_test))) {
|
||||
dynablock_t *father = db->father?db->father:db;
|
||||
uint32_t hash = father->nolinker?X31_hash_code(father->x86_addr, father->x86_size):0;
|
||||
uint32_t hash = X31_hash_code(father->x86_addr, father->x86_size);
|
||||
if(hash!=father->hash) {
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) with %d son(s)\n", father, father->x86_addr, father->x86_addr+father->x86_size, hash, father->hash, father->sons_size);
|
||||
dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x86_addr, father->x86_addr+father->x86_size, hash, father->hash, father->sons_size, (void*)addr);
|
||||
// Free father, it's now invalid!
|
||||
FreeDynablock(father);
|
||||
// start again... (will create a new block)
|
||||
@@ -420,6 +414,10 @@ dynablock_t* DBAlternateBlock(x86emu_t* emu, uintptr_t addr, uintptr_t filladdr)
|
||||
} else {
|
||||
father->need_test = 0;
|
||||
protectDB((uintptr_t)father->x86_addr, father->x86_size);
|
||||
// fill back jumptable
|
||||
addJumpTableIfDefault(father->x86_addr, father->block);
|
||||
for(int i=0; i<father->sons_size; ++i)
|
||||
addJumpTableIfDefault(father->sons[i]->x86_addr, father->sons[i]->block);
|
||||
}
|
||||
}
|
||||
return db;
|
||||
|
||||
@@ -13,14 +13,12 @@ typedef struct dynablock_s {
|
||||
void* block;
|
||||
int size;
|
||||
void* x86_addr;
|
||||
int x86_size;
|
||||
uintptr_t x86_size;
|
||||
uint32_t hash;
|
||||
uintptr_t* table;
|
||||
int tablesz;
|
||||
uint8_t need_test;
|
||||
uint8_t done;
|
||||
uint8_t gone;
|
||||
uint8_t nolinker;
|
||||
uint8_t dummy;
|
||||
int isize;
|
||||
dynablock_t** sons; // sons (kind-of dummy dynablock...)
|
||||
int sons_size;
|
||||
@@ -31,9 +29,8 @@ typedef struct dynablock_s {
|
||||
typedef struct dynablocklist_s {
|
||||
uintptr_t text;
|
||||
int textsz;
|
||||
uintptr_t base;
|
||||
int nolinker; // in case this dynablock can disapear (also, block memory are allocated with a temporary scheme)
|
||||
dynablock_t** direct; // direct mapping (waste of space, so not always there)
|
||||
int maxsz; // maxblock size (for this block or previous block)
|
||||
dynablock_t** direct; // direct mapping (waste of space, so the array is created at first write)
|
||||
} dynablocklist_t;
|
||||
|
||||
#endif //__DYNABLOCK_PRIVATE_H_
|
||||
+43
-52
@@ -25,64 +25,43 @@
|
||||
void arm_prolog(x86emu_t* emu, void* addr) EXPORTDYN;
|
||||
void arm_epilog() EXPORTDYN;
|
||||
void arm_epilog_fast() EXPORTDYN;
|
||||
void arm_linker() EXPORTDYN;
|
||||
int arm_tableupdate(void* jump, uintptr_t addr, void** table) EXPORTDYN;
|
||||
#endif
|
||||
|
||||
void tableupdate(void* jumpto, uintptr_t ref, void** table)
|
||||
{
|
||||
#ifdef ARM
|
||||
if(arm_tableupdate(jumpto, ref, table))
|
||||
#endif
|
||||
{
|
||||
table[0] = jumpto;
|
||||
table[1] = (void*)ref;
|
||||
}
|
||||
}
|
||||
|
||||
void resettable(void** table)
|
||||
{
|
||||
void* p = table[1];
|
||||
#ifdef ARM
|
||||
tableupdate(arm_linker, (uintptr_t)p, table);
|
||||
#endif
|
||||
//table[2] = own_dynablock // unchanged
|
||||
table[3] = NULL; // removed "linked" information
|
||||
}
|
||||
|
||||
#ifdef DYNAREC
|
||||
void* UpdateLinkTable(x86emu_t* emu, void** table, uintptr_t addr)
|
||||
#ifdef HAVE_TRACE
|
||||
uintptr_t getX86Address(dynablock_t* db, uintptr_t arm_addr);
|
||||
#endif
|
||||
void* LinkNext(x86emu_t* emu, uintptr_t addr, void* x2)
|
||||
{
|
||||
dynablock_t* current = (dynablock_t*)table[2];
|
||||
if(current->father)
|
||||
current = current->father;
|
||||
#ifdef HAVE_TRACE
|
||||
if(!addr) {
|
||||
x2-=8; // actual PC is 2 instructions ahead
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2);
|
||||
printf_log(LOG_NONE, "Warning, jumping to NULL address from %p (db=%p, x86addr=%p)\n", x2, db, db?(void*)getX86Address(db, (uintptr_t)x2):NULL);
|
||||
}
|
||||
#endif
|
||||
dynablock_t* current = NULL;
|
||||
void * jblock;
|
||||
dynablock_t* block = DBGetBlock(emu, addr, 1, ¤t);
|
||||
if(!current) { // current has been invalidated, stop running it...
|
||||
//dynarec_log(LOG_DEBUG, "--- Current invalidated while linking.\n");
|
||||
return arm_epilog_fast;
|
||||
}
|
||||
if(!block) {
|
||||
// no block, let link table as is...
|
||||
#ifdef HAVE_TRACE
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2);
|
||||
printf_log(LOG_INFO, "Warning, jumping to a no-block address from %p (db=%p, x86addr=%p)\n", x2, db, db?(void*)getX86Address(db, (uintptr_t)x2):NULL);
|
||||
#endif
|
||||
//tableupdate(arm_epilog, addr, table);
|
||||
return arm_epilog_fast;
|
||||
return arm_epilog;
|
||||
}
|
||||
if(!block->done) {
|
||||
// not finished yet... leave linker
|
||||
//tableupdate(arm_linker, addr, table);
|
||||
return arm_epilog_fast;
|
||||
return arm_epilog;
|
||||
}
|
||||
if(!(jblock=block->block)) {
|
||||
// null block, but done: go to epilog, no linker here
|
||||
tableupdate(arm_epilog, addr, table);
|
||||
return arm_epilog_fast;
|
||||
return arm_epilog;
|
||||
}
|
||||
//dynablock_t *father = block->father?block->father:block;
|
||||
if(!block->parent->nolinker) {
|
||||
//dynarec_log(LOG_DEBUG, "--- Linking %p/%p to %p (table=%p[%p/%p/%p/%p])\n", block, block->block, current, table, table[0], table[1], table[2], table[3]);
|
||||
// only update block if linker is allowed
|
||||
tableupdate(jblock, addr, table);
|
||||
}
|
||||
return jblock;
|
||||
}
|
||||
#endif
|
||||
@@ -98,9 +77,12 @@ void DynaCall(x86emu_t* emu, uintptr_t addr)
|
||||
ejb->emu = emu;
|
||||
ejb->jmpbuf_ok = 1;
|
||||
jmpbuf_reset = 1;
|
||||
if(setjmp((struct __jmp_buf_tag*)ejb->jmpbuf)) {
|
||||
printf_log(LOG_DEBUG, "Setjmp DynaCall, fs=0x%x\n", ejb->emu->segs[_FS]);
|
||||
int a;
|
||||
if((a=sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))) {
|
||||
printf_log(LOG_DEBUG, "Setjmp DynaCall %d, fs=0x%x\n", a, ejb->emu->segs[_FS]);
|
||||
addr = R_EIP; // not sure if it should still be inside DynaCall!
|
||||
if(a==2)
|
||||
Run(emu, 1); // "single step" next instruction that is doing auto-smc
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,14 +105,14 @@ void DynaCall(x86emu_t* emu, uintptr_t addr)
|
||||
dynablock_t* current = NULL;
|
||||
while(!emu->quit) {
|
||||
block = DBGetBlock(emu, R_EIP, 1, ¤t);
|
||||
current = (block && !block->parent->nolinker)?block:NULL;
|
||||
current = block;
|
||||
if(!block || !block->block || !block->done) {
|
||||
// no block, of block doesn't have DynaRec content (yet, temp is not null)
|
||||
// Use interpreter (should use single instruction step...)
|
||||
dynarec_log(LOG_DEBUG, "Calling Interpretor @%p, emu=%p\n", (void*)R_EIP, emu);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling Interpretor @%p, emu=%p\n", GetTID(), (void*)R_EIP, emu);
|
||||
Run(emu, 1);
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "Calling DynaRec Block @%p (%p) of %d x86 instructions (nolinker=%d, father=%p) emu=%p\n", (void*)R_EIP, block->block, block->isize ,block->parent->nolinker, block->father, emu);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling DynaRec Block @%p (%p) of %d x86 instructions (father=%p) emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize ,block->father, emu);
|
||||
CHECK_FLAGS(emu);
|
||||
// block is here, let's run it!
|
||||
#ifdef ARM
|
||||
@@ -147,7 +129,7 @@ void DynaCall(x86emu_t* emu, uintptr_t addr)
|
||||
ejb->emu = emu;
|
||||
ejb->jmpbuf_ok = 1;
|
||||
jmpbuf_reset = 1;
|
||||
if(setjmp((struct __jmp_buf_tag*)ejb->jmpbuf)) {
|
||||
if(sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1)) {
|
||||
printf_log(LOG_DEBUG, "Setjmp inner DynaCall, fs=0x%x\n", ejb->emu->segs[_FS]);
|
||||
addr = R_EIP;
|
||||
}
|
||||
@@ -177,15 +159,24 @@ int DynaRun(x86emu_t* emu)
|
||||
{
|
||||
// prepare setjump for signal handling
|
||||
emu_jmpbuf_t *ejb = NULL;
|
||||
#ifdef DYNAREC
|
||||
int jmpbuf_reset = 1;
|
||||
#endif
|
||||
if(emu->type == EMUTYPE_MAIN) {
|
||||
ejb = GetJmpBuf();
|
||||
if(!ejb->jmpbuf_ok) {
|
||||
ejb->emu = emu;
|
||||
ejb->jmpbuf_ok = 1;
|
||||
int a;
|
||||
#ifdef DYNAREC
|
||||
jmpbuf_reset = 1;
|
||||
if(setjmp((struct __jmp_buf_tag*)ejb->jmpbuf))
|
||||
printf_log(LOG_DEBUG, "Setjmp DynaRun, fs=0x%x\n", ejb->emu->segs[_FS]);
|
||||
#endif
|
||||
if((a=sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))) {
|
||||
printf_log(LOG_DEBUG, "Setjmp DynaRun %d, fs=0x%x\n", a, ejb->emu->segs[_FS]);
|
||||
if(a==2)
|
||||
Run(emu, 1); // "single step" next instruction that is doing auto-smc
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef DYNAREC
|
||||
@@ -198,14 +189,14 @@ int DynaRun(x86emu_t* emu)
|
||||
dynablock_t* current = NULL;
|
||||
while(!emu->quit) {
|
||||
block = DBGetBlock(emu, R_EIP, 1, ¤t);
|
||||
current = (block && !block->parent->nolinker)?block:NULL;
|
||||
current = block;
|
||||
if(!block || !block->block || !block->done) {
|
||||
// no block, of block doesn't have DynaRec content (yet, temp is not null)
|
||||
// Use interpreter (should use single instruction step...)
|
||||
dynarec_log(LOG_DEBUG, "Running Interpretor @%p, emu=%p\n", (void*)R_EIP, emu);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running Interpretor @%p, emu=%p\n", GetTID(), (void*)R_EIP, emu);
|
||||
Run(emu, 1);
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "Running DynaRec Block @%p (%p) of %d x86 insts (nolinker=%d, father=%p) emu=%p\n", (void*)R_EIP, block->block, block->isize, block->parent->nolinker, block->father, emu);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x86 insts (father=%p) emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize, block->father, emu);
|
||||
// block is here, let's run it!
|
||||
#ifdef ARM
|
||||
arm_prolog(emu, block->block);
|
||||
@@ -221,7 +212,7 @@ int DynaRun(x86emu_t* emu)
|
||||
ejb->emu = emu;
|
||||
ejb->jmpbuf_ok = 1;
|
||||
jmpbuf_reset = 1;
|
||||
if(setjmp((struct __jmp_buf_tag*)ejb->jmpbuf))
|
||||
if(sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))
|
||||
printf_log(LOG_DEBUG, "Setjmp inner DynaRun, fs=0x%x\n", ejb->emu->segs[_FS]);
|
||||
}
|
||||
}
|
||||
|
||||
+150
-25
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86context.h"
|
||||
#include "custommem.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x86emu_private.h"
|
||||
#include "tools/bridge_private.h"
|
||||
@@ -19,6 +20,7 @@
|
||||
#include "dynablock_private.h"
|
||||
#include "dynarec_arm.h"
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "elfloader.h"
|
||||
|
||||
void printf_x86_instruction(zydis_dec_t* dec, instruction_x86_t* inst, const char* name) {
|
||||
@@ -81,9 +83,9 @@ uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr) {
|
||||
}
|
||||
return best;
|
||||
}
|
||||
#define PK(A) (*((uint8_t*)(addr+(A))))
|
||||
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n)
|
||||
{
|
||||
#define PK(A) (*((uint8_t*)(addr+(A))))
|
||||
if(!n)
|
||||
return 1;
|
||||
if(PK(0)==0x90)
|
||||
@@ -109,7 +111,122 @@ int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n)
|
||||
if(n>7 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x84 && PK(3)==0x00 && PK(4)==0x00 && PK(5)==0x00 && PK(6)==0x00 && PK(7)==0x00)
|
||||
return is_nops(dyn, addr+8, n-8);
|
||||
return 0;
|
||||
#undef PK
|
||||
}
|
||||
|
||||
// return size of next instuciton, -1 is unknown
|
||||
// not all instrction are setup
|
||||
int next_instruction(dynarec_arm_t *dyn, uintptr_t addr)
|
||||
{
|
||||
uint8_t opcode = PK(0);
|
||||
uint8_t nextop;
|
||||
switch (opcode) {
|
||||
case 0x66:
|
||||
opcode = PK(1);
|
||||
switch(opcode) {
|
||||
case 0x90:
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
case 0x81:
|
||||
nextop = PK(1);
|
||||
return fakeed(dyn, addr+2, 0, nextop)-addr + 4;
|
||||
case 0x83:
|
||||
nextop = PK(1);
|
||||
return fakeed(dyn, addr+2, 0, nextop)-addr + 1;
|
||||
case 0x84:
|
||||
case 0x85:
|
||||
case 0x88:
|
||||
case 0x89:
|
||||
case 0x8A:
|
||||
case 0x8B:
|
||||
case 0x8C:
|
||||
case 0x8D:
|
||||
case 0x8E:
|
||||
case 0x8F:
|
||||
nextop = PK(1);
|
||||
return fakeed(dyn, addr+2, 0, nextop)-addr;
|
||||
case 0x50:
|
||||
case 0x51:
|
||||
case 0x52:
|
||||
case 0x53:
|
||||
case 0x54:
|
||||
case 0x55:
|
||||
case 0x56:
|
||||
case 0x57:
|
||||
case 0x58:
|
||||
case 0x59:
|
||||
case 0x5A:
|
||||
case 0x5B:
|
||||
case 0x5C:
|
||||
case 0x5D:
|
||||
case 0x5E:
|
||||
case 0x5F:
|
||||
case 0x90:
|
||||
case 0x91:
|
||||
case 0x92:
|
||||
case 0x93:
|
||||
case 0x94:
|
||||
case 0x95:
|
||||
case 0x96:
|
||||
case 0x97:
|
||||
case 0x98:
|
||||
case 0x99:
|
||||
case 0x9B:
|
||||
case 0x9C:
|
||||
case 0x9D:
|
||||
case 0x9E:
|
||||
case 0x9F:
|
||||
return 1;
|
||||
case 0xA0:
|
||||
case 0xA1:
|
||||
case 0xA2:
|
||||
case 0xA3:
|
||||
return 5;
|
||||
case 0xB0:
|
||||
case 0xB1:
|
||||
case 0xB2:
|
||||
case 0xB3:
|
||||
case 0xB4:
|
||||
case 0xB5:
|
||||
case 0xB6:
|
||||
case 0xB7:
|
||||
return 2;
|
||||
case 0xB8:
|
||||
case 0xB9:
|
||||
case 0xBA:
|
||||
case 0xBB:
|
||||
case 0xBC:
|
||||
case 0xBD:
|
||||
case 0xBE:
|
||||
case 0xBF:
|
||||
return 5;
|
||||
case 0xFF:
|
||||
nextop = PK(1);
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: // INC Ed
|
||||
case 1: //DEC Ed
|
||||
case 2: // CALL Ed
|
||||
case 4: // JMP Ed
|
||||
case 6: // Push Ed
|
||||
return fakeed(dyn, addr+2, 0, nextop)-addr;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#undef PK
|
||||
|
||||
int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n)
|
||||
{
|
||||
int i = 0;
|
||||
while(i<n) {
|
||||
int j=next_instruction(dyn, addr+i);
|
||||
if(j<=0) return 0;
|
||||
i+=j;
|
||||
}
|
||||
return (i==n)?1:0;
|
||||
}
|
||||
|
||||
uint32_t needed_flags(dynarec_arm_t *dyn, int ninst, uint32_t setf, int recurse)
|
||||
@@ -188,17 +305,26 @@ instsize_t* addInst(instsize_t* insts, size_t* size, size_t* cap, int x86_size,
|
||||
return insts;
|
||||
}
|
||||
|
||||
void arm_pass0(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
void arm_pass1(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
void arm_pass2(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
void arm_pass3(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
uintptr_t arm_pass0(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
uintptr_t arm_pass1(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
uintptr_t arm_pass2(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
uintptr_t arm_pass3(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
|
||||
void* FillBlock(dynablock_t* block, uintptr_t addr) {
|
||||
dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
if(addr>=box86_nodynarec_start && addr<box86_nodynarec_end) {
|
||||
dynarec_log(LOG_DEBUG, "Asked to fill a block in fobidden zone\n");
|
||||
return NULL;
|
||||
}
|
||||
if(!isJumpTableDefault((void*)addr)) {
|
||||
dynarec_log(LOG_DEBUG, "Asked to fill a block at %p, but JumpTable is not default\n", (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
// init the helper
|
||||
dynarec_arm_t helper = {0};
|
||||
helper.nolinker = box86_dynarec_linker?(block->parent->nolinker):1;
|
||||
helper.start = addr;
|
||||
arm_pass0(&helper, addr);
|
||||
uintptr_t start = addr;
|
||||
uintptr_t end = arm_pass0(&helper, addr);
|
||||
if(!helper.size) {
|
||||
dynarec_log(LOG_DEBUG, "Warning, null-sized dynarec block (%p)\n", (void*)addr);
|
||||
block->done = 1;
|
||||
@@ -207,11 +333,12 @@ void* FillBlock(dynablock_t* block, uintptr_t addr) {
|
||||
}
|
||||
helper.cap = helper.size+3; // needs epilog handling
|
||||
helper.insts = (instruction_arm_t*)calloc(helper.cap, sizeof(instruction_arm_t));
|
||||
// already protect the block and compute hash signature
|
||||
protectDB(addr, end-addr+1);
|
||||
uint32_t hash = X31_hash_code((void*)addr, end-addr+1);
|
||||
// pass 1, addresses, x86 jump addresses, flags
|
||||
arm_pass1(&helper, addr);
|
||||
// calculate barriers
|
||||
uintptr_t start = helper.insts[0].x86.addr;
|
||||
uintptr_t end = helper.insts[helper.size].x86.addr+helper.insts[helper.size].x86.size;
|
||||
for(int i=0; i<helper.size; ++i)
|
||||
if(helper.insts[i].x86.jmp) {
|
||||
uintptr_t j = helper.insts[i].x86.jmp;
|
||||
@@ -249,16 +376,13 @@ void* FillBlock(dynablock_t* block, uintptr_t addr) {
|
||||
}
|
||||
helper.block = p;
|
||||
helper.arm_start = (uintptr_t)p;
|
||||
helper.tablesz = helper.tablei;
|
||||
if(helper.tablesz)
|
||||
helper.table = (uintptr_t*)calloc(helper.tablesz, sizeof(uintptr_t));
|
||||
if(helper.sons_size) {
|
||||
helper.sons_x86 = (uintptr_t*)calloc(helper.sons_size, sizeof(uintptr_t));
|
||||
helper.sons_arm = (void**)calloc(helper.sons_size, sizeof(void*));
|
||||
}
|
||||
// pass 3, emit (log emit arm opcode)
|
||||
if(box86_dynarec_dump) {
|
||||
dynarec_log(LOG_NONE, "%sEmitting %d bytes for %d x86 bytes", (box86_dynarec_dump>1)?"\e[01;36m":"", helper.arm_size, helper.isize);
|
||||
dynarec_log(LOG_NONE, "%s%04d|Emitting %d bytes for %d x86 bytes", (box86_dynarec_dump>1)?"\e[01;36m":"", GetTID(), helper.arm_size, helper.isize);
|
||||
printFunctionAddr(helper.start, " => ");
|
||||
dynarec_log(LOG_NONE, "%s\n", (box86_dynarec_dump>1)?"\e[m":"");
|
||||
}
|
||||
@@ -292,20 +416,23 @@ void* FillBlock(dynablock_t* block, uintptr_t addr) {
|
||||
// ok, free the helper now
|
||||
free(helper.insts);
|
||||
free(helper.next);
|
||||
block->table = helper.table;
|
||||
block->tablesz = helper.tablesz;
|
||||
for (int i=0; i<helper.tablesz/4; ++i)
|
||||
block->table[i*4+2] = (uintptr_t)block;
|
||||
block->size = sz;
|
||||
block->isize = helper.size;
|
||||
block->block = p;
|
||||
block->nolinker = helper.nolinker;
|
||||
block->need_test = 0;
|
||||
//block->x86_addr = (void*)start;
|
||||
block->x86_size = end-start;
|
||||
block->x86_size = end-start+1;
|
||||
if(box86_dynarec_largest<block->x86_size)
|
||||
box86_dynarec_largest = block->x86_size;
|
||||
block->hash = (helper.nolinker)?X31_hash_code(block->x86_addr, block->x86_size):0;
|
||||
block->hash = X31_hash_code(block->x86_addr, block->x86_size);
|
||||
// Check if something changed, to abbort if it as
|
||||
if(block->hash != hash) {
|
||||
dynarec_log(LOG_INFO, "Warning, a block changed while beeing processed hash(%p:%d)=%x/%x\n", block->x86_addr, block->x86_size, block->hash, hash);
|
||||
free(helper.sons_x86);
|
||||
free(helper.sons_arm);
|
||||
FreeDynarecMap(block, (uintptr_t)p, sz);
|
||||
return NULL;
|
||||
}
|
||||
// fill sons if any
|
||||
dynablock_t** sons = NULL;
|
||||
int sons_size = 0;
|
||||
@@ -314,10 +441,10 @@ void* FillBlock(dynablock_t* block, uintptr_t addr) {
|
||||
for (int i=0; i<helper.sons_size; ++i) {
|
||||
int created = 1;
|
||||
dynablock_t *son = AddNewDynablock(block->parent, helper.sons_x86[i], &created);
|
||||
if(created || !son->parent) { // avoid breaking a working block! also, block could be outside this parent...
|
||||
if(created) { // avoid breaking a working block!
|
||||
son->block = helper.sons_arm[i];
|
||||
son->x86_addr = (void*)helper.sons_x86[i];
|
||||
son->x86_size = end-helper.sons_x86[i];
|
||||
son->x86_size = end-helper.sons_x86[i]+1;
|
||||
if(!son->x86_size) {printf_log(LOG_NONE, "Warning, son with null x86 size! (@%p / ARM=%p)", son->x86_addr, son->block);}
|
||||
son->father = block;
|
||||
son->done = 1;
|
||||
@@ -332,8 +459,6 @@ void* FillBlock(dynablock_t* block, uintptr_t addr) {
|
||||
} else
|
||||
free(sons);
|
||||
}
|
||||
if(block->parent->nolinker)
|
||||
protectDB((uintptr_t)block->x86_addr, block->x86_size);
|
||||
free(helper.sons_x86);
|
||||
free(helper.sons_arm);
|
||||
block->done = 1;
|
||||
|
||||
+326
-382
File diff suppressed because it is too large.
Load diff
+258
-300
File diff suppressed because it is too large.
Load diff
@@ -38,41 +38,41 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0x03:
|
||||
INST_NAME("ADD Gd, FS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
grab_fsdata(dyn, addr, ninst, x12);
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x12);
|
||||
emit_add32(dyn, ninst, gd, ed, x3, x12);
|
||||
GETEDO(x14);
|
||||
emit_add32(dyn, ninst, gd, ed, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x2B:
|
||||
INST_NAME("SUB Gd, FS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
grab_fsdata(dyn, addr, ninst, x12);
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x12);
|
||||
emit_sub32(dyn, ninst, gd, ed, x3, x12);
|
||||
GETEDO(x14);
|
||||
emit_sub32(dyn, ninst, gd, ed, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x33:
|
||||
INST_NAME("XOR Gd, FS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
grab_fsdata(dyn, addr, ninst, x12);
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x12);
|
||||
emit_xor32(dyn, ninst, gd, ed, x3, x12);
|
||||
GETEDO(x14);
|
||||
emit_xor32(dyn, ninst, gd, ed, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x3B:
|
||||
INST_NAME("CMP Gd, FS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
grab_fsdata(dyn, addr, ninst, x12);
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x12);
|
||||
emit_cmp32(dyn, ninst, gd, ed, x3, x12);
|
||||
GETEDO(x14);
|
||||
emit_cmp32(dyn, ninst, gd, ed, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x67:
|
||||
@@ -82,7 +82,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0x89:
|
||||
INST_NAME("MOV FS:Ew16, Gw");
|
||||
nextop = F8;
|
||||
grab_fsdata(dyn, addr, ninst, x12);
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
GETGD; // don't need GETGW here
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
@@ -91,33 +91,33 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
} else {
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
STRH_REG(gd, x12, ed);
|
||||
STRH_REG(gd, x14, ed);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, FS:Ew16");
|
||||
nextop=F8;
|
||||
grab_fsdata(dyn, addr, ninst, x12);
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
MOV_REG(gd, xEAX+(nextop&7));
|
||||
} else { // mem <= reg
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
LDR_REG_LSL_IMM5(gd, ed, x12, 0);
|
||||
LDR_REG_LSL_IMM5(gd, ed, x14, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8F:
|
||||
INST_NAME("POP FS:Ew16");
|
||||
nextop=F8;
|
||||
grab_fsdata(dyn, addr, ninst, x12);
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
POP(xESP, (1<<(xEAX+(nextop&7)))); // 67 ignored
|
||||
POP1(xEAX+(nextop&7)); // 67 ignored
|
||||
} else {
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
POP(xESP, (1<<x2));
|
||||
STR_REG_LSL_IMM5(x2, x1, x12, 0);
|
||||
POP1(x2);
|
||||
STR_REG_LSL_IMM5(x2, x1, x14, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -145,7 +145,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
grab_fsdata(dyn, addr, ninst, x12);
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
switch((nextop>>3)&7) {
|
||||
case 6: // Push Ed
|
||||
INST_NAME("PUSH FS:Ew");
|
||||
@@ -153,8 +153,8 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
DEFAULT;
|
||||
} else { // mem <= i32
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
LDR_REG_LSL_IMM5(x3, ed, x12, 0);
|
||||
PUSH(xESP, 1<<x3);
|
||||
LDR_REG_LSL_IMM5(x3, ed, x14, 0);
|
||||
PUSH1(x3);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -168,40 +168,40 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
|
||||
case 0x89:
|
||||
INST_NAME("MOV FS:Ed, Gd");
|
||||
grab_fsdata(dyn, addr, ninst, x12);
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
MOV_REG(xEAX+(nextop&7), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
STR_REG_LSL_IMM5(gd, ed, x12, 0);
|
||||
STR_REG_LSL_IMM5(gd, ed, x14, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, FS:Ed");
|
||||
grab_fsdata(dyn, addr, ninst, x12);
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
MOV_REG(gd, xEAX+(nextop&7));
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
LDR_REG_LSL_IMM5(gd, ed, x12, 0);
|
||||
LDR_REG_LSL_IMM5(gd, ed, x14, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8F:
|
||||
INST_NAME("POP FS:Ed");
|
||||
grab_fsdata(dyn, addr, ninst, x12);
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
POP(xESP, (1<<(xEAX+(nextop&7))));
|
||||
POP1(xEAX+(nextop&7));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
POP(xESP, (1<<x2));
|
||||
STR_REG_LSL_IMM5(x2, ed, x12, 0);
|
||||
POP1(x2);
|
||||
STR_REG_LSL_IMM5(x2, ed, x14, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -252,7 +252,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
|
||||
case 0xC7:
|
||||
INST_NAME("MOV FS:Ed, Id");
|
||||
grab_fsdata(dyn, addr, ninst, x12);
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
nextop=F8;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= i32
|
||||
i32 = F32S;
|
||||
@@ -262,7 +262,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
i32 = F32S;
|
||||
MOV32(x3, i32);
|
||||
STR_REG_LSL_IMM5(x3, ed, x12, 0);
|
||||
STR_REG_LSL_IMM5(x3, ed, x14, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -274,10 +274,10 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
grab_fsdata(dyn, addr, ninst, x12);
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
switch((nextop>>3)&7) {
|
||||
case 2: // CALL Ed
|
||||
INST_NAME("CALL Ed");
|
||||
INST_NAME("CALL FS:Ed");
|
||||
PASS2IF(ninst && dyn->insts && dyn->insts[ninst-1].x86.set_flags, 1) {
|
||||
READFLAGS(X_PEND); // that's suspicious
|
||||
} else {
|
||||
@@ -287,20 +287,18 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV_REG(xEIP, xEAX+(nextop&7));
|
||||
} else { // mem
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
LDR_REG_LSL_IMM5(xEIP, ed, x12, 0);
|
||||
LDR_REG_LSL_IMM5(xEIP, ed, x14, 0);
|
||||
}
|
||||
BARRIER(1);
|
||||
BARRIER_NEXT(1);
|
||||
if(!dyn->nolinker && (!dyn->insts || ninst!=dyn->size-1)) {
|
||||
PASS2(cstack_push(dyn, ninst, addr, dyn->insts[ninst+1].address, x1, x2);)
|
||||
if(!dyn->insts || ninst!=dyn->size-1) {
|
||||
} else {
|
||||
PASS2(cstack_push(dyn, ninst, 0, 0, x1, x2);)
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
MOV32(x2, addr);
|
||||
}
|
||||
PUSH(xESP, 1<<x2);
|
||||
jump_to_linker(dyn, 0, xEIP, ninst); // smart linker
|
||||
MOV32(x2, addr);
|
||||
PUSH1(x2);
|
||||
jump_to_next(dyn, 0, xEIP, ninst);
|
||||
break;
|
||||
case 6: // Push Ed
|
||||
INST_NAME("PUSH FS:Ed");
|
||||
@@ -308,8 +306,8 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
DEFAULT;
|
||||
} else { // mem <= i32
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
LDR_REG_LSL_IMM5(x3, ed, x12, 0);
|
||||
PUSH(xESP, 1<<x3);
|
||||
LDR_REG_LSL_IMM5(x3, ed, x14, 0);
|
||||
PUSH1(x3);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
+142
-35
@@ -41,41 +41,60 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0x03:
|
||||
INST_NAME("ADD Gd, GS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
grab_tlsdata(dyn, addr, ninst, x12);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x12);
|
||||
emit_add32(dyn, ninst, gd, ed, x3, x12);
|
||||
GETEDO(x14);
|
||||
emit_add32(dyn, ninst, gd, ed, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x2B:
|
||||
INST_NAME("SUB Gd, GS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
grab_tlsdata(dyn, addr, ninst, x12);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x12);
|
||||
emit_sub32(dyn, ninst, gd, ed, x3, x12);
|
||||
GETEDO(x14);
|
||||
emit_sub32(dyn, ninst, gd, ed, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x33:
|
||||
INST_NAME("XOR Gd, GS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
grab_tlsdata(dyn, addr, ninst, x12);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x12);
|
||||
emit_xor32(dyn, ninst, gd, ed, x3, x12);
|
||||
GETEDO(x14);
|
||||
emit_xor32(dyn, ninst, gd, ed, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x3B:
|
||||
INST_NAME("CMP Gd, GS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
grab_tlsdata(dyn, addr, ninst, x12);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x12);
|
||||
emit_cmp32(dyn, ninst, gd, ed, x3, x12);
|
||||
GETEDO(x14);
|
||||
emit_cmp32(dyn, ninst, gd, ed, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x69:
|
||||
INST_NAME("IMUL Gd, GS:Ed, Id");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x14);
|
||||
i32 = F32S;
|
||||
MOV32(x14, i32);
|
||||
UFLAG_IF {
|
||||
SMULL(x3, gd, x14, ed);
|
||||
UFLAG_OP1(x3);
|
||||
UFLAG_RES(gd);
|
||||
UFLAG_DF(x3, d_imul32);
|
||||
} else {
|
||||
MUL(gd, ed, x14);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x80:
|
||||
@@ -88,7 +107,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
grab_tlsdata(dyn, addr, ninst, x1);
|
||||
GETEBO(x1);
|
||||
u8 = F8;
|
||||
emit_add8c(dyn, ninst, x1, u8, x2, x12);
|
||||
emit_add8c(dyn, ninst, x1, u8, x2, x14);
|
||||
EBBACK;
|
||||
break;
|
||||
case 1: //OR
|
||||
@@ -97,7 +116,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
grab_tlsdata(dyn, addr, ninst, x1);
|
||||
GETEBO(x1);
|
||||
u8 = F8;
|
||||
emit_or8c(dyn, ninst, x1, u8, x2, x12);
|
||||
emit_or8c(dyn, ninst, x1, u8, x2, x14);
|
||||
EBBACK;
|
||||
break;
|
||||
case 2: //ADC
|
||||
@@ -107,7 +126,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
grab_tlsdata(dyn, addr, ninst, x1);
|
||||
GETEBO(x1);
|
||||
u8 = F8;
|
||||
emit_adc8c(dyn, ninst, x1, u8, x2, x12);
|
||||
emit_adc8c(dyn, ninst, x1, u8, x2, x14);
|
||||
EBBACK;
|
||||
break;
|
||||
case 3: //SBB
|
||||
@@ -117,7 +136,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
grab_tlsdata(dyn, addr, ninst, x1);
|
||||
GETEBO(x1);
|
||||
u8 = F8;
|
||||
emit_sbb8c(dyn, ninst, x1, u8, x2, x12);
|
||||
emit_sbb8c(dyn, ninst, x1, u8, x2, x14);
|
||||
EBBACK;
|
||||
break;
|
||||
case 4: //AND
|
||||
@@ -126,7 +145,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
grab_tlsdata(dyn, addr, ninst, x1);
|
||||
GETEBO(x1);
|
||||
u8 = F8;
|
||||
emit_and8c(dyn, ninst, x1, u8, x2, x12);
|
||||
emit_and8c(dyn, ninst, x1, u8, x2, x14);
|
||||
EBBACK;
|
||||
break;
|
||||
case 5: //SUB
|
||||
@@ -135,7 +154,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
grab_tlsdata(dyn, addr, ninst, x1);
|
||||
GETEBO(x1);
|
||||
u8 = F8;
|
||||
emit_sub8c(dyn, ninst, x1, u8, x2, x12);
|
||||
emit_sub8c(dyn, ninst, x1, u8, x2, x14);
|
||||
EBBACK;
|
||||
break;
|
||||
case 6: //XOR
|
||||
@@ -144,7 +163,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
grab_tlsdata(dyn, addr, ninst, x1);
|
||||
GETEBO(x1);
|
||||
u8 = F8;
|
||||
emit_xor8c(dyn, ninst, x1, u8, x2, x12);
|
||||
emit_xor8c(dyn, ninst, x1, u8, x2, x14);
|
||||
EBBACK;
|
||||
break;
|
||||
case 7: //CMP
|
||||
@@ -155,50 +174,138 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
u8 = F8;
|
||||
if(u8) {
|
||||
MOVW(x2, u8);
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x12);
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x14);
|
||||
} else {
|
||||
emit_cmp8_0(dyn, ninst, x1, x3, x12);
|
||||
emit_cmp8_0(dyn, ninst, x1, x3, x14);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: //ADD
|
||||
if(opcode==0x81) {
|
||||
INST_NAME("ADD Ed, Id");
|
||||
} else {
|
||||
INST_NAME("ADD Ed, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
GETEDO2(x14);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
emit_add32c(dyn, ninst, ed, i32, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 1: //OR
|
||||
if(opcode==0x81) {INST_NAME("OR Ed, Id");} else {INST_NAME("OR Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
GETEDO2(x14);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
emit_or32c(dyn, ninst, ed, i32, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 2: //ADC
|
||||
if(opcode==0x81) {INST_NAME("ADC Ed, Id");} else {INST_NAME("ADC Ed, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
GETEDO2(x14);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
emit_adc32c(dyn, ninst, ed, i32, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 3: //SBB
|
||||
if(opcode==0x81) {INST_NAME("SBB Ed, Id");} else {INST_NAME("SBB Ed, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
GETEDO2(x14);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
emit_sbb32c(dyn, ninst, ed, i32, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 4: //AND
|
||||
if(opcode==0x81) {INST_NAME("AND Ed, Id");} else {INST_NAME("AND Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
GETEDO2(x14);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
emit_and32c(dyn, ninst, ed, i32, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 5: //SUB
|
||||
if(opcode==0x81) {INST_NAME("SUB Ed, Id");} else {INST_NAME("SUB Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
GETEDO2(x14);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
emit_sub32c(dyn, ninst, ed, i32, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 6: //XOR
|
||||
if(opcode==0x81) {INST_NAME("XOR Ed, Id");} else {INST_NAME("XOR Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
GETEDO2(x14);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
emit_xor32c(dyn, ninst, ed, i32, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 7: //CMP
|
||||
if(opcode==0x81) {INST_NAME("CMP Ed, Id");} else {INST_NAME("CMP Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
GETEDO2(x14);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
if(i32) {
|
||||
MOV32(x2, i32);
|
||||
emit_cmp32(dyn, ninst, ed, x2, x3, x14);
|
||||
} else {
|
||||
emit_cmp32_0(dyn, ninst, ed, x3, x14);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x89:
|
||||
INST_NAME("MOV GS:Ed, Gd");
|
||||
grab_tlsdata(dyn, addr, ninst, x12);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
MOV_REG(xEAX+(nextop&7), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
STR_REG_LSL_IMM5(gd, ed, x12, 0);
|
||||
STR_REG_LSL_IMM5(gd, ed, x14, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, GS:Ed");
|
||||
grab_tlsdata(dyn, addr, ninst, x12);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
MOV_REG(gd, xEAX+(nextop&7));
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
LDR_REG_LSL_IMM5(gd, ed, x12, 0);
|
||||
LDR_REG_LSL_IMM5(gd, ed, x14, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8F:
|
||||
INST_NAME("POP GS:Ed");
|
||||
grab_tlsdata(dyn, addr, ninst, x12);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
POP(xESP, (1<<(xEAX+(nextop&7))));
|
||||
POP1((xEAX+(nextop&7)));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
POP(xESP, (1<<x2));
|
||||
STR_REG_LSL_IMM5(x2, ed, x12, 0);
|
||||
POP1(x2);
|
||||
STR_REG_LSL_IMM5(x2, ed, x14, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -226,7 +333,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
|
||||
case 0xC7:
|
||||
INST_NAME("MOV GS:Ed, Id");
|
||||
grab_tlsdata(dyn, addr, ninst, x12);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop=F8;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= i32
|
||||
i32 = F32S;
|
||||
@@ -236,7 +343,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
i32 = F32S;
|
||||
MOV32(x3, i32);
|
||||
STR_REG_LSL_IMM5(x3, ed, x12, 0);
|
||||
STR_REG_LSL_IMM5(x3, ed, x14, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -248,7 +355,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
grab_tlsdata(dyn, addr, ninst, x12);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
switch((nextop>>3)&7) {
|
||||
case 6: // Push Ed
|
||||
INST_NAME("PUSH GS:Ed");
|
||||
@@ -256,8 +363,8 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
DEFAULT;
|
||||
} else { // mem <= i32
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
LDR_REG_LSL_IMM5(x3, ed, x12, 0);
|
||||
PUSH(xESP, 1<<x3);
|
||||
LDR_REG_LSL_IMM5(x3, ed, x14, 0);
|
||||
PUSH1(x3);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -47,7 +47,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1);
|
||||
emit_add16(dyn, ninst, x1, x2, x12, x3, (wb1 && (wback==x3))?1:0);
|
||||
emit_add16(dyn, ninst, x1, x2, x14, x3, (wb1 && (wback==x3))?1:0);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x03:
|
||||
@@ -56,7 +56,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2);
|
||||
emit_add16(dyn, ninst, x1, x2, x3, x12, 0);
|
||||
emit_add16(dyn, ninst, x1, x2, x3, x14, 0);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x05:
|
||||
@@ -64,7 +64,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
i32 = F16;
|
||||
UXTH(x1, xEAX, 0);
|
||||
emit_add16c(dyn, ninst, x1, i32, x3, x12);
|
||||
emit_add16c(dyn, ninst, x1, i32, x3, x14);
|
||||
BFI(xEAX, x1, 0, 16);
|
||||
break;
|
||||
case 0x06:
|
||||
@@ -92,7 +92,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1);
|
||||
emit_or16(dyn, ninst, x1, x2, x12, x3, (wb1 && (wback==x3))?1:0);
|
||||
emit_or16(dyn, ninst, x1, x2, x14, x2);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x0B:
|
||||
@@ -101,7 +101,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2);
|
||||
emit_or16(dyn, ninst, x1, x2, x12, x3, 0);
|
||||
emit_or16(dyn, ninst, x1, x2, x14, x3);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x0D:
|
||||
@@ -109,7 +109,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
i32 = F16;
|
||||
UXTH(x1, xEAX, 0);
|
||||
emit_or16c(dyn, ninst, x1, i32, x3, x12);
|
||||
emit_or16c(dyn, ninst, x1, i32, x3, x14);
|
||||
BFI(xEAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
@@ -123,7 +123,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1);
|
||||
emit_adc16(dyn, ninst, x1, x2, x12, x3, (wb1 && (wback==x3))?1:0);
|
||||
emit_adc16(dyn, ninst, x1, x2, x14, x3, (wb1 && (wback==x3))?1:0);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x13:
|
||||
@@ -133,7 +133,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2);
|
||||
emit_adc16(dyn, ninst, x1, x2, x12, x3, 0);
|
||||
emit_adc16(dyn, ninst, x1, x2, x14, x3, 0);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x15:
|
||||
@@ -142,7 +142,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
i32 = F16;
|
||||
UXTH(x1, xEAX, 0);
|
||||
emit_adc16c(dyn, ninst, x1, i32, x3, x12);
|
||||
emit_adc16c(dyn, ninst, x1, i32, x3, x14);
|
||||
BFI(xEAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
@@ -153,7 +153,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1);
|
||||
emit_sbb16(dyn, ninst, x1, x2, x12, x3, (wb1 && (wback==x3))?1:0);
|
||||
emit_sbb16(dyn, ninst, x1, x2, x14, x3, (wb1 && (wback==x3))?1:0);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x1B:
|
||||
@@ -163,7 +163,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2);
|
||||
emit_sbb16(dyn, ninst, x1, x2, x12, x3, 0);
|
||||
emit_sbb16(dyn, ninst, x1, x2, x14, x3, 0);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x1D:
|
||||
@@ -172,7 +172,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
i16 = F16;
|
||||
UXTH(x1, xEAX, 0);
|
||||
emit_sbb16c(dyn, ninst, x1, i16, x3, x12);
|
||||
emit_sbb16c(dyn, ninst, x1, i16, x3, x14);
|
||||
BFI(xEAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
@@ -182,7 +182,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1);
|
||||
emit_and16(dyn, ninst, x1, x2, x12, x3, (wb1 && (wback==x3))?1:0);
|
||||
emit_and16(dyn, ninst, x1, x2, x14, x2);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x23:
|
||||
@@ -191,7 +191,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2);
|
||||
emit_and16(dyn, ninst, x1, x2, x3, x12, 0);
|
||||
emit_and16(dyn, ninst, x1, x2, x3, x14);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x25:
|
||||
@@ -199,7 +199,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
i32 = F16;
|
||||
UXTH(x1, xEAX, 0);
|
||||
emit_and16c(dyn, ninst, x1, i32, x3, x12);
|
||||
emit_and16c(dyn, ninst, x1, i32, x3, x14);
|
||||
BFI(xEAX, x1, 0, 16);
|
||||
break;
|
||||
case 0x26:
|
||||
@@ -213,7 +213,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1);
|
||||
emit_sub16(dyn, ninst, x1, x2, x12, x3, (wb1 && (wback==x3))?1:0);
|
||||
emit_sub16(dyn, ninst, x1, x2, x14, x3, (wb1 && (wback==x3))?1:0);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x2B:
|
||||
@@ -222,7 +222,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2);
|
||||
emit_sub16(dyn, ninst, x1, x2, x3, x12, 0);
|
||||
emit_sub16(dyn, ninst, x1, x2, x3, x14, 0);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x2D:
|
||||
@@ -230,7 +230,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
i32 = F16;
|
||||
UXTH(x1, xEAX, 0);
|
||||
emit_sub16c(dyn, ninst, x1, i32, x3, x12);
|
||||
emit_sub16c(dyn, ninst, x1, i32, x3, x14);
|
||||
BFI(xEAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
@@ -240,7 +240,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1);
|
||||
emit_xor16(dyn, ninst, x1, x2, x12, x3, (wb1 && (wback==x3))?1:0);
|
||||
emit_xor16(dyn, ninst, x1, x2, x14, x2);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x33:
|
||||
@@ -249,7 +249,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2);
|
||||
emit_xor16(dyn, ninst, x1, x2, x3, x12, 0);
|
||||
emit_xor16(dyn, ninst, x1, x2, x3, x14);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x35:
|
||||
@@ -257,7 +257,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
i32 = F16;
|
||||
UXTH(x1, xEAX, 0);
|
||||
emit_xor16c(dyn, ninst, x1, i32, x3, x12);
|
||||
emit_xor16c(dyn, ninst, x1, i32, x3, x14);
|
||||
BFI(xEAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
@@ -267,7 +267,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x12);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x14);
|
||||
break;
|
||||
case 0x3B:
|
||||
INST_NAME("CMP Gw, Ew");
|
||||
@@ -275,7 +275,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x12);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x14);
|
||||
break;
|
||||
case 0x3D:
|
||||
INST_NAME("CMP AX, Iw");
|
||||
@@ -283,7 +283,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
i32 = F16;
|
||||
MOVW(x2, i32);
|
||||
UXTH(x1, xEAX, 0);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x12);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x40:
|
||||
@@ -298,7 +298,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
gd = xEAX+(opcode&7);
|
||||
UXTH(x1, gd, 0);
|
||||
emit_inc16(dyn, ninst, x1, x3, x12);
|
||||
emit_inc16(dyn, ninst, x1, x3, x14);
|
||||
BFI(gd, x1, 0, 16);
|
||||
break;
|
||||
case 0x48:
|
||||
@@ -313,7 +313,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
gd = xEAX+(opcode&7);
|
||||
UXTH(x1, gd, 0);
|
||||
emit_dec16(dyn, ninst, x1, x3, x12);
|
||||
emit_dec16(dyn, ninst, x1, x3, x14);
|
||||
BFI(gd, x1, 0, 16);
|
||||
break;
|
||||
case 0x50:
|
||||
@@ -420,7 +420,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEW(x1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
emit_add16c(dyn, ninst, ed, i16, x2, x12);
|
||||
emit_add16c(dyn, ninst, ed, i16, x2, x14);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1: //OR
|
||||
@@ -428,7 +428,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEW(x1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
emit_or16c(dyn, ninst, x1, i16, x2, x12);
|
||||
emit_or16c(dyn, ninst, x1, i16, x2, x14);
|
||||
EWBACK;
|
||||
break;
|
||||
case 2: //ADC
|
||||
@@ -437,7 +437,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEW(x1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
emit_adc16c(dyn, ninst, x1, i16, x2, x12);
|
||||
emit_adc16c(dyn, ninst, x1, i16, x2, x14);
|
||||
EWBACK;
|
||||
break;
|
||||
case 3: //SBB
|
||||
@@ -446,7 +446,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEW(x1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
emit_sbb16c(dyn, ninst, x1, i16, x2, x12);
|
||||
emit_sbb16c(dyn, ninst, x1, i16, x2, x14);
|
||||
EWBACK;
|
||||
break;
|
||||
case 4: //AND
|
||||
@@ -454,7 +454,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEW(x1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
emit_and16c(dyn, ninst, x1, i16, x2, x12);
|
||||
emit_and16c(dyn, ninst, x1, i16, x2, x14);
|
||||
EWBACK;
|
||||
break;
|
||||
case 5: //SUB
|
||||
@@ -462,7 +462,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEW(x1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
emit_sub16c(dyn, ninst, x1, i16, x2, x12);
|
||||
emit_sub16c(dyn, ninst, x1, i16, x2, x14);
|
||||
EWBACK;
|
||||
break;
|
||||
case 6: //XOR
|
||||
@@ -470,7 +470,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEW(x1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
emit_xor16c(dyn, ninst, x1, i16, x2, x12);
|
||||
emit_xor16c(dyn, ninst, x1, i16, x2, x14);
|
||||
EWBACK;
|
||||
break;
|
||||
case 7: //CMP
|
||||
@@ -480,9 +480,9 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
if(i16) {
|
||||
MOVW(x2, i16);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x12);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x14);
|
||||
} else
|
||||
emit_cmp16_0(dyn, ninst, x1, x3, x12);
|
||||
emit_cmp16_0(dyn, ninst, x1, x3, x14);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -493,7 +493,36 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETEW(x1);
|
||||
GETGW(x2);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x12);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x87:
|
||||
INST_NAME("XCHG Ew, Gw");
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
GETGW(x14);
|
||||
ed = xEAX + (nextop&7);
|
||||
UXTH(x1, ed, 0);
|
||||
// do the swap 14 -> ed, 1 -> gd
|
||||
BFI(gd, x1, 0, 16);
|
||||
BFI(ed, x14, 0, 16);
|
||||
} else {
|
||||
GETGW(x14);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
#if 0
|
||||
MARKLOCK;
|
||||
// do the swap with exclusive locking
|
||||
LDREXH(x1, ed);
|
||||
// do the swap 14 -> strb(ed), 1 -> gd
|
||||
STREXH(x3, x14, ed);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
#else
|
||||
LDRH_IMM8(x1, ed, fixedaddress);
|
||||
STRH_IMM8(x14, ed, fixedaddress);
|
||||
#endif
|
||||
BFI(gd, x1, 0, 16);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x89:
|
||||
@@ -580,23 +609,24 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0x99:
|
||||
INST_NAME("CWD");
|
||||
SXTH(x1, xEAX, 0);
|
||||
BFI(xEDX, x1, 16, 16);
|
||||
MOV_REG_LSR_IMM5(x1, x1, 16);
|
||||
BFI(xEDX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x9C:
|
||||
INST_NAME("PUSHF (16b)");
|
||||
READFLAGS(X_ALL);
|
||||
CALL(PackFlags, -1, 0);
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, packed_eflags.x32));
|
||||
STRHB_IMM8(x1, xESP, -2);
|
||||
STRHB_IMM8(xFlags, xESP, -2);
|
||||
break;
|
||||
case 0x9D:
|
||||
INST_NAME("POPF (16b)");
|
||||
SETFLAGS(X_ALL, SF_SET); // lower 16bits is all flags handled in dynarec
|
||||
LDRHA_IMM8(x1, xESP, 2);
|
||||
CALL(arm_popf16, -1, 0);
|
||||
MOVW(x1, d_none);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, df));
|
||||
LDRHA_IMM8(x2, xESP, 2);
|
||||
MOV32(x1, 0x7FD7);
|
||||
AND_REG_LSL_IMM5(x2, x2, x1, 0);
|
||||
ORR_IMM8(x2, x2, 2, 0);
|
||||
BFI(xFlags, x2, 0, 16);
|
||||
SET_DFNONE(x1);
|
||||
break;
|
||||
|
||||
case 0xA1:
|
||||
@@ -633,7 +663,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
u16 = F16;
|
||||
MOVW(x2, u16);
|
||||
UBFX(x1, xEAX, 0, 16);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x12);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x14);
|
||||
break;
|
||||
|
||||
case 0xAB:
|
||||
@@ -818,15 +848,15 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 6:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("SHL Ew, 1");
|
||||
MOVW(x12, 1);
|
||||
MOVW(x14, 1);
|
||||
} else {
|
||||
INST_NAME("SHL Ew, CL");
|
||||
AND_IMM8(x12, xECX, 0x1f);
|
||||
AND_IMM8(x14, xECX, 0x1f);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1);
|
||||
UFLAG_OP12(ed, x12)
|
||||
MOV_REG_LSL_REG(ed, ed, x12);
|
||||
UFLAG_OP12(ed, x14)
|
||||
MOV_REG_LSL_REG(ed, ed, x14);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shl16);
|
||||
@@ -834,15 +864,15 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 5:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("SHR Ew, 1");
|
||||
MOVW(x12, 1);
|
||||
MOVW(x14, 1);
|
||||
} else {
|
||||
INST_NAME("SHR Ew, CL");
|
||||
AND_IMM8(x12, xECX, 0x1f);
|
||||
AND_IMM8(x14, xECX, 0x1f);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1);
|
||||
UFLAG_OP12(ed, x12)
|
||||
MOV_REG_LSR_REG(ed, ed, x12);
|
||||
UFLAG_OP12(ed, x14)
|
||||
MOV_REG_LSR_REG(ed, ed, x14);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shr16);
|
||||
@@ -850,15 +880,15 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 7:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("SAR Ew, 1");
|
||||
MOVW(x12, 1);
|
||||
MOVW(x14, 1);
|
||||
} else {
|
||||
INST_NAME("SAR Ew, CL");
|
||||
AND_IMM8(x12, xECX, 0x1f);
|
||||
AND_IMM8(x14, xECX, 0x1f);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETSEW(x1);
|
||||
UFLAG_OP12(ed, x12)
|
||||
MOV_REG_ASR_REG(ed, ed, x12);
|
||||
UFLAG_OP12(ed, x14)
|
||||
MOV_REG_ASR_REG(ed, ed, x14);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_sar16);
|
||||
@@ -916,7 +946,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MARK2;
|
||||
SUB_IMM8(xECX, xECX, 1);
|
||||
MARK3;
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x12);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x14);
|
||||
break;
|
||||
|
||||
case 0xAB:
|
||||
@@ -952,7 +982,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MARK2;
|
||||
SUB_IMM8(xECX, xECX, 1);
|
||||
MARK3;
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x12);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x14);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -969,7 +999,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETEW(x1);
|
||||
u16 = F16;
|
||||
MOVW(x2, u16);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x12);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x14);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("NOT Ew");
|
||||
@@ -981,7 +1011,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("NEG Ew");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEW(x1);
|
||||
emit_neg16(dyn, ninst, ed, x2, x12);
|
||||
emit_neg16(dyn, ninst, ed, x2, x14);
|
||||
EWBACK;
|
||||
break;
|
||||
case 4:
|
||||
@@ -1026,23 +1056,19 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
i32 = dyn->state_flags; //TODO: find a better way to do this
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
if(i32!=SF_SET) {
|
||||
MOVW(x1, d_none);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, df));
|
||||
} else {
|
||||
MOVW(x1, 0);
|
||||
}
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
SET_DFNONE(x1);
|
||||
}
|
||||
BFC(xFlags, F_CF, 1);
|
||||
break;
|
||||
case 0xF9:
|
||||
INST_NAME("STC");
|
||||
i32 = dyn->state_flags; //TODO: find a better way to do this
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
if(i32!=SF_SET) {
|
||||
MOVW(x1, d_none);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, df));
|
||||
SET_DFNONE(x1);
|
||||
}
|
||||
MOVW(x1, 1);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
BFI(xFlags, x1, F_CF, 1);
|
||||
break;
|
||||
|
||||
case 0xFF:
|
||||
@@ -1052,14 +1078,14 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("INC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
GETEW(x1);
|
||||
emit_inc16(dyn, ninst, x1, x2, x12);
|
||||
emit_inc16(dyn, ninst, x1, x2, x14);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("DEC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SET);
|
||||
GETEW(x1);
|
||||
emit_dec16(dyn, ninst, x1, x2, x12);
|
||||
emit_dec16(dyn, ninst, x1, x2, x14);
|
||||
EWBACK;
|
||||
break;
|
||||
default:
|
||||
|
||||
+231
-84
@@ -107,8 +107,16 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
DEFAULT;
|
||||
return addr;
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
|
||||
VLDR_64(v0, ed, fixedaddress);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
|
||||
VLDR_64(v0, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-8, 0);
|
||||
LDR_IMM9(x2, ed, fixedaddress);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVtoV_D(v0, x2, x3);
|
||||
}
|
||||
break;
|
||||
case 0x13:
|
||||
INST_NAME("MOVLPD Eq, Gx");
|
||||
@@ -457,107 +465,93 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
|
||||
case 0x40:
|
||||
INST_NAME("CMOVO Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
CMPS_IMM8(x2, 1)
|
||||
, cNE, cEQ, X_OF)
|
||||
GO( TSTS_IMM8_ROR(xFlags, 0b10, 0x0b)
|
||||
, cEQ, cNE, X_OF)
|
||||
break;
|
||||
case 0x41:
|
||||
INST_NAME("CMOVNO Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
CMPS_IMM8(x2, 1)
|
||||
, cEQ, cNE, X_OF)
|
||||
GO( TSTS_IMM8_ROR(xFlags, 0b10, 0x0b)
|
||||
, cNE, cEQ, X_OF)
|
||||
break;
|
||||
case 0x42:
|
||||
INST_NAME("CMOVC Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
CMPS_IMM8(x2, 1)
|
||||
, cNE, cEQ, X_CF)
|
||||
GO( TSTS_IMM8(xFlags, 1<<F_CF)
|
||||
, cEQ, cNE, X_CF)
|
||||
break;
|
||||
case 0x43:
|
||||
INST_NAME("CMOVNC Gw, Ew");
|
||||
GO( LDR_IMM9(2, 0, offsetof(x86emu_t, flags[F_CF]));
|
||||
CMPS_IMM8(2, 1)
|
||||
, cEQ, cNE, X_CF)
|
||||
GO( TSTS_IMM8(xFlags, 1<<F_CF)
|
||||
, cNE, cEQ, X_CF)
|
||||
break;
|
||||
case 0x44:
|
||||
INST_NAME("CMOVZ Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
CMPS_IMM8(x2, 1)
|
||||
, cNE, cEQ, X_ZF)
|
||||
GO( TSTS_IMM8(xFlags, 1<<F_ZF)
|
||||
, cEQ, cNE, X_ZF)
|
||||
break;
|
||||
case 0x45:
|
||||
INST_NAME("CMOVNZ Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
CMPS_IMM8(x2, 1)
|
||||
, cEQ, cNE, X_ZF)
|
||||
GO( TSTS_IMM8(xFlags, 1<<F_ZF)
|
||||
, cNE, cEQ, X_ZF)
|
||||
break;
|
||||
case 0x46:
|
||||
INST_NAME("CMOVBE Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
LDR_IMM9(x3, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
ORRS_REG_LSL_IMM5(x2, x2, x3, 0);
|
||||
GO( TSTS_IMM8(xFlags, (1<<F_CF)|(1<<F_ZF))
|
||||
, cEQ, cNE, X_CF|X_ZF)
|
||||
break;
|
||||
case 0x47:
|
||||
INST_NAME("CMOVNBE Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
LDR_IMM9(x3, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
ORRS_REG_LSL_IMM5(x2, x2, x3, 0);
|
||||
GO( TSTS_IMM8(xFlags, (1<<F_CF)|(1<<F_ZF))
|
||||
, cNE, cEQ, X_CF|X_ZF)
|
||||
break;
|
||||
case 0x48:
|
||||
INST_NAME("CMOVS Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
CMPS_IMM8(x2, 1)
|
||||
, cNE, cEQ, X_SF)
|
||||
GO( TSTS_IMM8(xFlags, 1<<F_SF)
|
||||
, cEQ, cNE, X_SF)
|
||||
break;
|
||||
case 0x49:
|
||||
INST_NAME("CMOVNS Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
CMPS_IMM8(x2, 1)
|
||||
, cEQ, cNE, X_SF)
|
||||
GO( TSTS_IMM8(xFlags, 1<<F_SF)
|
||||
, cNE, cEQ, X_SF)
|
||||
break;
|
||||
case 0x4A:
|
||||
INST_NAME("CMOVP Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
CMPS_IMM8(x2, 1)
|
||||
, cNE, cEQ, X_PF)
|
||||
GO( TSTS_IMM8(xFlags, 1<<F_PF)
|
||||
, cEQ, cNE, X_PF)
|
||||
break;
|
||||
case 0x4B:
|
||||
INST_NAME("CMOVNP Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
CMPS_IMM8(x2, 1)
|
||||
, cEQ, cNE, X_PF)
|
||||
GO( TSTS_IMM8(xFlags, 1<<F_PF)
|
||||
, cNE, cEQ, X_PF)
|
||||
break;
|
||||
case 0x4C:
|
||||
INST_NAME("CMOVL Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
GO( UBFX(x2, xFlags, F_SF, 1);
|
||||
UBFX(x1, xFlags, F_OF, 1);
|
||||
CMPS_REG_LSL_IMM5(x1, x2, 0)
|
||||
, cEQ, cNE, X_OF|X_SF)
|
||||
break;
|
||||
case 0x4D:
|
||||
INST_NAME("CMOVGE Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
GO( UBFX(x2, xFlags, F_SF, 1);
|
||||
UBFX(x1, xFlags, F_OF, 1);
|
||||
CMPS_REG_LSL_IMM5(x1, x2, 0)
|
||||
, cNE, cEQ, X_OF|X_SF)
|
||||
break;
|
||||
case 0x4E:
|
||||
INST_NAME("CMOVLE Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
GO( UBFX(x2, xFlags, F_SF, 1);
|
||||
UBFX(x1, xFlags, F_OF, 1);
|
||||
XOR_REG_LSL_IMM5(x1, x1, x2, 0);
|
||||
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
UBFX(x2, xFlags, F_ZF, 1);
|
||||
ORRS_REG_LSL_IMM5(x2, x1, x2, 0);
|
||||
, cEQ, cNE, X_OF|X_SF|X_ZF)
|
||||
break;
|
||||
case 0x4F:
|
||||
INST_NAME("CMOVG Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
GO( UBFX(x2, xFlags, F_SF, 1);
|
||||
UBFX(x1, xFlags, F_OF, 1);
|
||||
XOR_REG_LSL_IMM5(x1, x1, x2, 0);
|
||||
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
UBFX(x2, xFlags, F_ZF, 1);
|
||||
ORRS_REG_LSL_IMM5(x2, x1, x2, 0);
|
||||
, cNE, cEQ, X_OF|X_SF|X_ZF)
|
||||
break;
|
||||
@@ -638,6 +632,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(v1);
|
||||
// need rounding?
|
||||
VCVTQ_S32_F32(v0, v1);
|
||||
break;
|
||||
case 0x5C:
|
||||
@@ -656,10 +651,10 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
// MINPD: if any input is NaN, or Ex[i]<Gx[i], copy Ex[i] -> Gx[i]
|
||||
VCMP_F64(v0, q0);
|
||||
VMRS_APSR();
|
||||
VMOVcond_64(cPL, v0, q0);
|
||||
VMOVcond_64(cCS, v0, q0);
|
||||
VCMP_F64(v0+1, q0+1);
|
||||
VMRS_APSR();
|
||||
VMOVcond_64(cPL, v0+1, q0+1);
|
||||
VMOVcond_64(cCS, v0+1, q0+1);
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVPD Gx, Ex");
|
||||
@@ -677,10 +672,10 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
// MAXPD: if any input is NaN, or Ex[i]>Gx[i], copy Ex[i] -> Gx[i]
|
||||
VCMP_F64(q0, v0);
|
||||
VMRS_APSR();
|
||||
VMOVcond_64(cPL, v0, q0);
|
||||
VMOVcond_64(cCS, v0, q0);
|
||||
VCMP_F64(q0+1, v0+1);
|
||||
VMRS_APSR();
|
||||
VMOVcond_64(cPL, v0+1, q0+1);
|
||||
VMOVcond_64(cCS, v0+1, q0+1);
|
||||
break;
|
||||
case 0x60:
|
||||
INST_NAME("PUNPCKLBW Gx,Ex");
|
||||
@@ -1186,8 +1181,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
GETEW(x1);
|
||||
AND_IMM8(x2, gd, 15);
|
||||
MOV_REG_LSR_REG(x1, ed, x2);
|
||||
AND_IMM8(x1, x1, 1);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
BFI(xFlags, x1, F_CF, 1);
|
||||
break;
|
||||
case 0xA4:
|
||||
case 0xA5:
|
||||
@@ -1199,7 +1193,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
UXTB(x3, xECX, 0);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEWW(x12, x1);
|
||||
GETEWW(x14, x1);
|
||||
GETGW(x2);
|
||||
if(opcode==0xA4) {
|
||||
u8 = F8;
|
||||
@@ -1214,11 +1208,11 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
SETFLAGS(X_CF, SF_SET);
|
||||
nextop = F8;
|
||||
GETGD; // there is an AND below, to 32bits is the same
|
||||
GETEW(x12);
|
||||
GETEW(x14);
|
||||
AND_IMM8(x2, gd, 15);
|
||||
MOV_REG_LSR_REG(x1, ed, x2);
|
||||
ANDS_IMM8(x1, x1, 1);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
BFI(xFlags, x1, F_CF, 1);
|
||||
B_NEXT(cNE);
|
||||
MOVW(x1, 1);
|
||||
ORR_REG_LSL_REG(ed, ed, x1, x2);
|
||||
@@ -1234,7 +1228,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
UXTB(x3, xECX, 0);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEWW(x12, x1);
|
||||
GETEWW(x14, x1);
|
||||
GETGW(x2);
|
||||
if(opcode==0xAC) {
|
||||
u8 = F8;
|
||||
@@ -1267,11 +1261,11 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
SETFLAGS(X_CF, SF_SET);
|
||||
nextop = F8;
|
||||
GETGD; // there is an AND below, to 32bits is the same
|
||||
GETEW(x12);
|
||||
GETEW(x14);
|
||||
AND_IMM8(x2, gd, 15);
|
||||
MOV_REG_LSR_REG(x1, ed, x2);
|
||||
ANDS_IMM8(x1, x1, 1);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
BFI(xFlags, x1, F_CF, 1);
|
||||
B_NEXT(cEQ);
|
||||
MOVW(x1, 1);
|
||||
XOR_REG_LSL_REG(ed, ed, x1, x2);
|
||||
@@ -1307,23 +1301,123 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
BFI(gd, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0xBA:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 4:
|
||||
INST_NAME("BT Ew, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
u8 = F8;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255-32, 0);
|
||||
u8 = F8;
|
||||
fixedaddress+=(u8>>4)*2;
|
||||
LDRH_IMM8(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
u8&=0x0f;
|
||||
if(u8) {
|
||||
MOV_REG_LSR_IMM5(x1, ed, u8);
|
||||
ed = x1;
|
||||
}
|
||||
BFI(xFlags, ed, F_CF, 1);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("BTS Ew, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
u8 = F8;
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255-32, 0);
|
||||
u8 = F8;
|
||||
fixedaddress+=(u8>>4)*2;
|
||||
LDRH_IMM8(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
MOV_REG_LSR_IMM5(x14, ed, u8&0x0f);
|
||||
ANDS_IMM8(x14, x14, 1);
|
||||
BFI(xFlags, x14, F_CF, 1);
|
||||
B_MARK3(cNE); // bit already set, jump to next instruction
|
||||
MOVW(x14, 1);
|
||||
XOR_REG_LSL_IMM5(ed, ed, x14, u8&0x0f);
|
||||
if(wback) {
|
||||
STRH_IMM8(ed, wback, fixedaddress);
|
||||
}
|
||||
MARK3;
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("BTR Ew, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
u8 = F8;
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255-32, 0);
|
||||
u8 = F8;
|
||||
fixedaddress+=(u8>>4)*2;
|
||||
LDRH_IMM8(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
MOV_REG_LSR_IMM5(x14, ed, u8&0x0f);
|
||||
ANDS_IMM8(x14, x14, 1);
|
||||
BFI(xFlags, x14, F_CF, 1);
|
||||
B_MARK3(cEQ); // bit already clear, jump to next instruction
|
||||
//MOVW(x14, 1); // already 0x01
|
||||
XOR_REG_LSL_IMM5(ed, ed, x14, u8&0x0f);
|
||||
if(wback) {
|
||||
STRH_IMM8(ed, wback, fixedaddress);
|
||||
}
|
||||
MARK3;
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("BTC Ew, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
u8 = F8;
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255-32, 0);
|
||||
u8 = F8;
|
||||
fixedaddress+=(u8>>4)*2;
|
||||
LDRH_IMM8(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
MOV_REG_LSR_IMM5(x14, ed, u8&0x0f);
|
||||
ANDS_IMM8(x14, x14, 1);
|
||||
BFI(xFlags, x14, F_CF, 1);
|
||||
MOVW_COND(cEQ, x14, 1); // may already 0x01
|
||||
XOR_REG_LSL_IMM5(ed, ed, x14, u8&0x0f);
|
||||
if(wback) {
|
||||
STRH_IMM8(ed, wback, fixedaddress);
|
||||
}
|
||||
MARK3;
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0xBB:
|
||||
INST_NAME("BTC Ew, Gw");
|
||||
SETFLAGS(X_CF, SF_SET);
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
nextop = F8;
|
||||
GETGD; // there is an AND below, to 32bits is the same
|
||||
GETEW(x12);
|
||||
GETEW(x14);
|
||||
AND_IMM8(x2, gd, 15);
|
||||
MOV_REG_LSR_REG(x1, ed, x2);
|
||||
AND_IMM8(x1, x1, 1);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
BFI(xFlags, x1, F_CF, 1);
|
||||
MOVW(x1, 1);
|
||||
XOR_REG_LSL_REG(ed, ed, x1, x2);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0xBC:
|
||||
INST_NAME("BSF Ew,Gw");
|
||||
SETFLAGS(X_ZF, SF_SET);
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
nextop = F8;
|
||||
GETEW(x1); // Get EW
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
@@ -1334,13 +1428,12 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
BFI(xEAX+((nextop&0x38)>>3), x2, 0, 16);
|
||||
XOR_REG_LSL_IMM5(x1, x1, x1, 0); //ZF not set
|
||||
MARK;
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
MOVW(x1, d_none);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, df));
|
||||
BFI(xFlags, x1, F_ZF, 1);
|
||||
SET_DFNONE(x1);
|
||||
break;
|
||||
case 0xBD:
|
||||
INST_NAME("BSR Ew,Gw");
|
||||
SETFLAGS(X_ZF, SF_SET);
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
nextop = F8;
|
||||
GETEW(x1); // Get EW
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
@@ -1352,9 +1445,8 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
BFI(xEAX+((nextop&0x38)>>3), x2, 0, 16);
|
||||
XOR_REG_LSL_IMM5(x1, x1, x1, 0); //ZF not set
|
||||
MARK;
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
MOVW(x1, d_none);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, df));
|
||||
BFI(xFlags, x1, F_ZF, 1);
|
||||
SET_DFNONE(x1);
|
||||
break;
|
||||
case 0xBE:
|
||||
INST_NAME("MOVSX Gw, Eb");
|
||||
@@ -1372,6 +1464,16 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
BFI(gd, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0xC1:
|
||||
INST_NAME("XADD Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2);
|
||||
BFI((xEAX+((nextop&0x38)>>3)), x2, 0, 16); // GW <- EW
|
||||
emit_add16(dyn, ninst, x1, x2, x14, x3, 1);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0xC2:
|
||||
INST_NAME("CMPPD Gx, Ex");
|
||||
nextop = F8;
|
||||
@@ -1380,32 +1482,40 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
GETEX(d0);
|
||||
u8 = F8;
|
||||
// 0
|
||||
VCMP_F64(v0, d0);
|
||||
if((u8&7)==6){
|
||||
VCMP_F64(d0, v0);
|
||||
} else {
|
||||
VCMP_F64(v0, d0);
|
||||
}
|
||||
VMRS_APSR();
|
||||
MOVW(x2, 0);
|
||||
switch(u8&7) {
|
||||
case 0: MVN_COND_REG_LSL_IMM5(cEQ, x2, x2, 0); break; // Equal
|
||||
case 1: MVN_COND_REG_LSL_IMM5(cCC, x2, x2, 0); break; // Less than
|
||||
case 2: MVN_COND_REG_LSL_IMM5(cLS, x2, x2, 0); break; // Less or equal
|
||||
case 1: MVN_COND_REG_LSL_IMM5(cMI, x2, x2, 0); break; // Less than
|
||||
case 2: MVN_COND_REG_LSL_IMM5(cLE, x2, x2, 0); break; // Less or equal
|
||||
case 3: MVN_COND_REG_LSL_IMM5(cVS, x2, x2, 0); break; // NaN
|
||||
case 4: MVN_COND_REG_LSL_IMM5(cNE, x2, x2, 0); break; // Not Equal (or unordered on ARM, not on X86...)
|
||||
case 5: MVN_COND_REG_LSL_IMM5(cPL, x2, x2, 0); break; // Greater or equal or unordered
|
||||
case 6: MVN_COND_REG_LSL_IMM5(cHI, x2, x2, 0); break; // Greater or unordered
|
||||
case 5: MVN_COND_REG_LSL_IMM5(cCS, x2, x2, 0); break; // Greater or equal or unordered
|
||||
case 6: MVN_COND_REG_LSL_IMM5(cLT, x2, x2, 0); break; // Greater or unordered, test inverted, N!=V so unordereded or less than (inverted)
|
||||
case 7: MVN_COND_REG_LSL_IMM5(cVC, x2, x2, 0); break; // not NaN
|
||||
}
|
||||
VMOVtoV_D(v0, x2, x2);
|
||||
// 1
|
||||
VCMP_F64(v0+1, d0+1);
|
||||
if((u8&7)==6){
|
||||
VCMP_F64(d0+1, v0+1);
|
||||
} else {
|
||||
VCMP_F64(v0+1, d0+1);
|
||||
}
|
||||
VMRS_APSR();
|
||||
MOVW(x2, 0);
|
||||
switch(u8&7) {
|
||||
case 0: MVN_COND_REG_LSL_IMM5(cEQ, x2, x2, 0); break; // Equal
|
||||
case 1: MVN_COND_REG_LSL_IMM5(cCC, x2, x2, 0); break; // Less than
|
||||
case 2: MVN_COND_REG_LSL_IMM5(cLS, x2, x2, 0); break; // Less or equal
|
||||
case 1: MVN_COND_REG_LSL_IMM5(cMI, x2, x2, 0); break; // Less than
|
||||
case 2: MVN_COND_REG_LSL_IMM5(cLE, x2, x2, 0); break; // Less or equal
|
||||
case 3: MVN_COND_REG_LSL_IMM5(cVS, x2, x2, 0); break; // NaN
|
||||
case 4: MVN_COND_REG_LSL_IMM5(cNE, x2, x2, 0); break; // Not Equal (or unordered on ARM, not on X86...)
|
||||
case 5: MVN_COND_REG_LSL_IMM5(cPL, x2, x2, 0); break; // Greater or equal or unordered
|
||||
case 6: MVN_COND_REG_LSL_IMM5(cHI, x2, x2, 0); break; // Greater or unordered
|
||||
case 5: MVN_COND_REG_LSL_IMM5(cCS, x2, x2, 0); break; // Greater or equal or unordered
|
||||
case 6: MVN_COND_REG_LSL_IMM5(cLT, x2, x2, 0); break; // Greater or unordered, test inverted, N!=V so unordereded or less than (inverted)
|
||||
case 7: MVN_COND_REG_LSL_IMM5(cVC, x2, x2, 0); break; // not NaN
|
||||
}
|
||||
VMOVtoV_D(v0+1, x2, x2);
|
||||
@@ -1460,6 +1570,27 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF: /* BSWAP reg */
|
||||
INST_NAME("BSWAP Reg");
|
||||
gd = xEAX+(opcode&7);
|
||||
REV16(x1, gd);
|
||||
BFI(gd, x1, 0, 16);
|
||||
break;
|
||||
case 0xD0:
|
||||
INST_NAME("ADDSUBPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(v1);
|
||||
VSUB_F64(v0+0, v0+0, v1+0);
|
||||
VADD_F64(v0+1, v0+1, v1+1);
|
||||
break;
|
||||
case 0xD1:
|
||||
INST_NAME("PSRLW Gx,Ex");
|
||||
nextop = F8;
|
||||
@@ -1853,12 +1984,28 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
GETGX(q0);
|
||||
GETEX(q1);
|
||||
VABDQ_U8(q0, q0, q1);
|
||||
VABDQ_U8(q0, q0, q1); // needs VABDLQ in fact
|
||||
VPADDLQ_U8(q0, q0);
|
||||
VPADDLQ_U16(q0, q0);
|
||||
VPADDLQ_U32(q0, q0);
|
||||
break;
|
||||
|
||||
case 0xF7:
|
||||
INST_NAME("MASKMOVDQU Gx, Ex")
|
||||
nextop = F8;
|
||||
GETGX(q0);
|
||||
GETEX(q1);
|
||||
v0 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_8(v0, xEDI); // hopefully it's always aligned?
|
||||
if((nextop&0xC0)==0xC0)
|
||||
v1 = fpu_get_scratch_quad(dyn); // need to preserve the register
|
||||
else
|
||||
v1 = q1;
|
||||
VCLTQ_0_8(v1, q1); // get the mask
|
||||
VBICQ(v0, v0, v1); // mask destination
|
||||
VANDQ(v1, q0, v1); // mask source
|
||||
VORRQ(v1, v1, v0); // combine
|
||||
VST1Q_8(v1, xEDI); // put back
|
||||
break;
|
||||
case 0xF8:
|
||||
INST_NAME("PSUBB Gx,Ex");
|
||||
nextop = F8;
|
||||
|
||||
@@ -45,7 +45,7 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0x89:
|
||||
INST_NAME("MOV FS:Ew16, Gw");
|
||||
nextop = F8;
|
||||
grab_fsdata(dyn, addr, ninst, x12);
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
GETGD; // don't need GETGW here
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
@@ -54,14 +54,14 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
} else {
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
STRH_REG(gd, x12, ed);
|
||||
STRH_REG(gd, x14, ed);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, FS:Ew16");
|
||||
nextop=F8;
|
||||
grab_fsdata(dyn, addr, ninst, x12);
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
ed = xEAX+(nextop&7);
|
||||
@@ -70,20 +70,20 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
} else { // mem <= reg
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
LDR_REG_LSL_IMM5(gd, x12, ed, 0);
|
||||
LDR_REG_LSL_IMM5(gd, x14, ed, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8F:
|
||||
INST_NAME("POP FS:Ew16");
|
||||
nextop=F8;
|
||||
grab_fsdata(dyn, addr, ninst, x12);
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
POP(xESP, (1<<(xEAX+(nextop&7)))); // 67 ignored
|
||||
POP1(xEAX+(nextop&7)); // 67 ignored
|
||||
} else {
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
POP(xESP, (1<<x2));
|
||||
STR_REG_LSL_IMM5(x2, x12, ed, 0);
|
||||
POP1(x2);
|
||||
STR_REG_LSL_IMM5(x2, x14, ed, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -111,7 +111,7 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
grab_fsdata(dyn, addr, ninst, x12);
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
switch((nextop>>3)&7) {
|
||||
case 6: // Push Ed
|
||||
INST_NAME("PUSH FS:Ew");
|
||||
@@ -119,8 +119,8 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
DEFAULT;
|
||||
} else { // mem <= i32
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
LDR_REG_LSL_IMM5(x3, ed, x12, 0);
|
||||
PUSH(xESP, 1<<x3);
|
||||
LDR_REG_LSL_IMM5(x3, ed, x14, 0);
|
||||
PUSH1(x3);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -140,7 +140,7 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst+1].address-(dyn->arm_size+8); \
|
||||
Bcond(NO, i32); \
|
||||
jump_to_linker(dyn, addr+i8, 0, ninst); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst); \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
|
||||
@@ -155,8 +155,7 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SUBS_IMM8(x1, x1, 1);
|
||||
BFI(xECX, x1, 0, 16);
|
||||
B_NEXT(cEQ); // CX is 0, no LOOP
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
TSTS_IMM8(xFlags, 1<<F_ZF);
|
||||
GO(cNE, cEQ);
|
||||
break;
|
||||
case 0xE1:
|
||||
@@ -167,8 +166,7 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SUBS_IMM8(x1, x1, 1);
|
||||
BFI(xECX, x1, 0, 16);
|
||||
B_NEXT(cEQ); // CX is 0, no LOOP
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
TSTS_IMM8(xFlags, 1<<F_ZF);
|
||||
GO(cEQ, cNE);
|
||||
break;
|
||||
case 0xE2:
|
||||
|
||||
@@ -94,7 +94,7 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
@@ -216,7 +216,7 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VCMP_F64(v1, d1);
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FSUB ST0, float[ED]");
|
||||
|
||||
@@ -23,13 +23,13 @@
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
static double d_1 = 1.0;
|
||||
static double d_l2t = L2T;
|
||||
static double d_l2e = L2E;
|
||||
static double d_pi = PI;
|
||||
static double d_lg2 = LG2;
|
||||
static double d_ln2 = LN2;
|
||||
static double d_0 = 0.0;
|
||||
static const double d_1 = 1.0;
|
||||
static const double d_l2t = L2T;
|
||||
static const double d_l2e = L2E;
|
||||
static const double d_pi = PI;
|
||||
static const double d_lg2 = LG2;
|
||||
static const double d_ln2 = LN2;
|
||||
static const double d_0 = 0.0;
|
||||
|
||||
uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
@@ -58,7 +58,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xC7:
|
||||
INST_NAME("FLD STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
v2 = x87_do_push(dyn, ninst);
|
||||
v2 = x87_do_push(dyn, ninst, x3);
|
||||
VMOV_64(v2, v1);
|
||||
break;
|
||||
|
||||
@@ -108,43 +108,43 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
|
||||
case 0xE8:
|
||||
INST_NAME("FLD1");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
v1 = x87_do_push(dyn, ninst, x1);
|
||||
MOV32(x2, (&d_1));
|
||||
VLDR_64(v1, x2, 0);
|
||||
break;
|
||||
case 0xE9:
|
||||
INST_NAME("FLDL2T");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
v1 = x87_do_push(dyn, ninst, x1);
|
||||
MOV32(x2, (&d_l2t));
|
||||
VLDR_64(v1, x2, 0);
|
||||
break;
|
||||
case 0xEA:
|
||||
INST_NAME("FLDL2E");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
v1 = x87_do_push(dyn, ninst, x1);
|
||||
MOV32(x2, (&d_l2e));
|
||||
VLDR_64(v1, x2, 0);
|
||||
break;
|
||||
case 0xEB:
|
||||
INST_NAME("FLDPI");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
v1 = x87_do_push(dyn, ninst, x1);
|
||||
MOV32(x2, (&d_pi));
|
||||
VLDR_64(v1, x2, 0);
|
||||
break;
|
||||
case 0xEC:
|
||||
INST_NAME("FLDLG2");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
v1 = x87_do_push(dyn, ninst, x1);
|
||||
MOV32(x2, (&d_lg2));
|
||||
VLDR_64(v1, x2, 0);
|
||||
break;
|
||||
case 0xED:
|
||||
INST_NAME("FLDLN2");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
v1 = x87_do_push(dyn, ninst, x1);
|
||||
MOV32(x2, (&d_ln2));
|
||||
VLDR_64(v1, x2, 0);
|
||||
break;
|
||||
case 0xEE:
|
||||
INST_NAME("FLDZ");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
v1 = x87_do_push(dyn, ninst, x1);
|
||||
MOV32(x2, (&d_0));
|
||||
VLDR_64(v1, x2, 0);
|
||||
break;
|
||||
@@ -182,13 +182,13 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fyl2x, -1, 0);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF2:
|
||||
INST_NAME("FTAN");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_ftan, -1, 0);
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
v1 = x87_do_push(dyn, ninst, x3);
|
||||
MOV32(x2, (&d_1));
|
||||
VLDR_64(v1, x2, 0);
|
||||
break;
|
||||
@@ -197,7 +197,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fpatan, -1, 0);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF4:
|
||||
INST_NAME("FXTRACT");
|
||||
@@ -238,7 +238,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fyl2xp1, -1, 0);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xFB:
|
||||
INST_NAME("FSINCOS");
|
||||
@@ -289,7 +289,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FLD ST0, float[ED]");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
v1 = x87_do_push(dyn, ninst, x1);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
@@ -331,7 +331,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VMOVfrV(x2, s0);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
}
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FLDENV Ed");
|
||||
|
||||
@@ -54,8 +54,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
READFLAGS(X_CF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
TSTS_IMM8(xFlags, 1<<F_CF);
|
||||
VMOVcond_64(cNE, v1, v2); // F_CF==1
|
||||
break;
|
||||
case 0xC8:
|
||||
@@ -70,8 +69,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
READFLAGS(X_ZF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
TSTS_IMM8(xFlags, 1<<F_ZF);
|
||||
VMOVcond_64(cNE, v1, v2); // F_ZF==1
|
||||
break;
|
||||
case 0xD0:
|
||||
@@ -86,9 +84,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
READFLAGS(X_CF|X_ZF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
ORRS_REG_LSL_IMM5(x1, x1, x2, 0);
|
||||
TSTS_IMM8(xFlags, (1<<F_CF)|(1<<F_ZF));
|
||||
VMOVcond_64(cNE, v1, v2); // F_CF==1 | F_ZF==1
|
||||
break;
|
||||
case 0xD8:
|
||||
@@ -103,8 +99,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
READFLAGS(X_PF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
TSTS_IMM8(xFlags, 1<<F_PF);
|
||||
VMOVcond_64(cNE, v1, v2); // F_PF==1
|
||||
break;
|
||||
case 0xE9:
|
||||
@@ -113,8 +108,8 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1);
|
||||
VCMP_F64(v1, v2);
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xE4:
|
||||
@@ -173,7 +168,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VCVT_F64_S32(d0, s0);
|
||||
VCMP_F64(v1, d0);
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FISUB ST0, Ed");
|
||||
|
||||
@@ -52,8 +52,7 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
READFLAGS(X_CF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
TSTS_IMM8(xFlags, 1<<F_CF);
|
||||
VMOVcond_64(cEQ, v1, v2); // F_CF==0
|
||||
break;
|
||||
case 0xC8:
|
||||
@@ -68,8 +67,7 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
READFLAGS(X_ZF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
TSTS_IMM8(xFlags, 1<<F_ZF);
|
||||
VMOVcond_64(cEQ, v1, v2); // F_ZF==0
|
||||
break;
|
||||
case 0xD0:
|
||||
@@ -84,10 +82,8 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
READFLAGS(X_CF|X_ZF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
ORRS_REG_LSL_IMM5(x1, x1, x2, 0);
|
||||
VMOVcond_64(cEQ, v1, v2); // F_CF==0 | F_ZF==0
|
||||
TSTS_IMM8(xFlags, (1<<F_CF)|(1<<F_ZF));
|
||||
VMOVcond_64(cEQ, v1, v2); // F_CF==0 & F_ZF==0
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
@@ -101,8 +97,7 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
READFLAGS(X_PF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
TSTS_IMM8(xFlags, 1<<F_PF);
|
||||
VMOVcond_64(cEQ, v1, v2); // F_PF==0
|
||||
break;
|
||||
case 0xE1:
|
||||
@@ -110,8 +105,8 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xE2:
|
||||
INST_NAME("FNCLEX");
|
||||
MOVW(x1, 0);
|
||||
LDRH_IMM8(x2, xEmu, offsetof(x86emu_t, sw));
|
||||
MOVW(x1, 0);
|
||||
BFI(x2, x1, 0, 8); // IE .. PE, SF, ES
|
||||
BFI(x2, x1, 15, 1); // B
|
||||
STRH_IMM8(x2, xEmu, offsetof(x86emu_t, sw));
|
||||
@@ -164,7 +159,7 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ed");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
v1 = x87_do_push(dyn, ninst, x1);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
@@ -188,8 +183,8 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
MSR_nzcvq_0();
|
||||
VMRS(x12); // Get FPCSR reg to clear exceptions flags
|
||||
ORR_IMM8(x3, x12, 0b001, 6); // enable exceptions
|
||||
VMRS(x14); // Get FPCSR reg to clear exceptions flags
|
||||
ORR_IMM8(x3, x14, 0b001, 6); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
VCVT_S32_F64(s0, v1);
|
||||
@@ -198,13 +193,13 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
MOV_IMM_COND(cNE, ed, 0b10, 1); // 0x80000000
|
||||
WBACK;
|
||||
VMSR(x12); // put back values
|
||||
x87_do_pop(dyn, ninst);
|
||||
VMSR(x14); // put back values
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FIST Ed, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x12); // x1 have the modified RPSCR reg
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14); // x1 have the modified RPSCR reg
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
@@ -229,7 +224,7 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 3:
|
||||
INST_NAME("FISTP Ed, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x12); // x1 have the modified RPSCR reg
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14); // x1 have the modified RPSCR reg
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
@@ -249,17 +244,32 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
MOV_IMM_COND(cNE, ed, 0b10, 1); // 0x80000000
|
||||
WBACK;
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FLD tbyte");
|
||||
x87_do_push_empty(dyn, ninst, x1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOV_REG(x1, ed);
|
||||
if(PK(0)==0xDB && ((PK(1)>>3)&7)==7) {
|
||||
// the FLD is immediatly followed by an FSTP
|
||||
LDR_IMM9(x2, ed, 0);
|
||||
LDR_IMM9(x3, ed, 4);
|
||||
LDRH_IMM8(x14, ed, 8);
|
||||
// no persistant scratch register, so unrool both instruction here...
|
||||
MESSAGE(LOG_DUMP, "\tHack: FSTP tbyte\n");
|
||||
nextop = F8; //0xDB
|
||||
nextop = F8; //modrm
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
STR_IMM9(x2, ed, 0);
|
||||
STR_IMM9(x3, ed, 4);
|
||||
STRH_IMM8(x14, ed, 8);
|
||||
} else {
|
||||
if(ed!=x1) {
|
||||
MOV_REG(x1, ed);
|
||||
}
|
||||
x87_do_push_empty(dyn, ninst, x3);
|
||||
CALL(arm_fld, -1, 0);
|
||||
}
|
||||
CALL(arm_fld, -1, 0);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FSTP tbyte");
|
||||
@@ -269,7 +279,7 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV_REG(x1, ed);
|
||||
}
|
||||
CALL(arm_fstp, -1, 0);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
|
||||
@@ -90,7 +90,7 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
@@ -211,7 +211,7 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
VCMP_F64(v1, d1);
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FSUB ST0, double[ED]");
|
||||
|
||||
@@ -61,7 +61,7 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xD8:
|
||||
INST_NAME("FSTP ST0, ST0");
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
@@ -74,7 +74,7 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VMOV_64(v2, v1);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xE0:
|
||||
@@ -104,7 +104,7 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
@@ -138,7 +138,7 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FLD double");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
v1 = x87_do_push(dyn, ninst, x1);
|
||||
#if 0
|
||||
// can bus error...
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
|
||||
@@ -161,8 +161,8 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(arm_fistp64, -1, 0);
|
||||
x87_do_pop(dyn, ninst);
|
||||
CALL(arm_fistt64, -1, 0);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FST double");
|
||||
@@ -191,7 +191,7 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
STR_IMM9(x3, ed, fixedaddress+4);
|
||||
}
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FRSTOR m108byte");
|
||||
@@ -210,7 +210,7 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 7:
|
||||
INST_NAME("FNSTSW m2byte");
|
||||
fpu_purgecache(dyn, ninst, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x12, &fixedaddress, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x14, &fixedaddress, 0, 0);
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, top));
|
||||
MOVW(x2, offsetof(x86emu_t, sw));
|
||||
ADD_REG_LSL_IMM5(x2, xEmu, x2, 0);
|
||||
|
||||
@@ -43,7 +43,7 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VADD_F64(v2, v2, v1);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
@@ -57,7 +57,7 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VMUL_F64(v2, v2, v1);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
@@ -72,7 +72,7 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xD9:
|
||||
@@ -81,8 +81,8 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1);
|
||||
VCMP_F64(v1, v2);
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
@@ -96,7 +96,7 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VSUB_F64(v2, v1, v2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
@@ -110,7 +110,7 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VSUB_F64(v2, v2, v1);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -124,7 +124,7 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VDIV_F64(v2, v1, v2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
@@ -138,7 +138,7 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VDIV_F64(v2, v2, v1);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xD8:
|
||||
|
||||
@@ -51,14 +51,13 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xC7:
|
||||
INST_NAME("FFREEP STx");
|
||||
// not handling Tag...
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xE0:
|
||||
INST_NAME("FNSTSW AX");
|
||||
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
AND_IMM8(x2, x2, 7);
|
||||
BFI(x1, x2, 11, 3); // inject top
|
||||
BFI(xEAX, x1, 0, 16);
|
||||
break;
|
||||
@@ -76,7 +75,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
FCOMI(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -92,7 +91,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
FCOMI(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
@@ -141,7 +140,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ew");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
v1 = x87_do_push(dyn, ninst, x1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0);
|
||||
LDRSH_IMM8(x1, wback, fixedaddress);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
@@ -155,8 +154,9 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
MSR_nzcvq_0();
|
||||
VMRS(x14); // get fpscr
|
||||
// x1 already have FPCSR reg to clear exceptions flags
|
||||
ORR_IMM8(x3, x1, 0b001, 6); // enable exceptions
|
||||
ORR_IMM8(x3, x14, 0b001, 6); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
VCVTR_S32_F64(s0, v1);
|
||||
@@ -167,12 +167,13 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
CMPS_REG_LSL_IMM5_COND(cEQ, ed, x3, 0);
|
||||
MOVW_COND(cNE, x3, 0x8000); // saturated
|
||||
STRH_IMM8(x3, wback, fixedaddress);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
VMSR(x14);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FIST Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x12);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
@@ -194,7 +195,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 3:
|
||||
INST_NAME("FISTP Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x12);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
@@ -211,7 +212,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
CMPS_REG_LSL_IMM5_COND(cEQ, ed, x3, 0);
|
||||
MOVW_COND(cNE, x3, 0x8000); // saturated
|
||||
STRH_IMM8(x3, wback, fixedaddress);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 4:
|
||||
@@ -234,7 +235,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(fpu_fbst, -1, 0);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 7: // could be inlined for most thing, but is it usefull?
|
||||
INST_NAME("FISTP i64, ST0");
|
||||
@@ -242,7 +243,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(arm_fistp64, -1, 0);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
+438
-821
File diff suppressed because it is too large.
Load diff
@@ -23,6 +23,63 @@
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
// emit SHL32 instruction, from s1 , shift s2, store result in s1 using s3 and s4 as scratch. s3 can be same as s2
|
||||
void emit_shl32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
int32_t j32;
|
||||
MAYUSE(j32);
|
||||
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_shl32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(F_OF) {
|
||||
CMPS_IMM8(s2, 0);
|
||||
IFX(F_OF) {
|
||||
BIC_IMM8_COND(cEQ, xFlags, xFlags, 0b10, 0x0b);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9_COND(cEQ, s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
}
|
||||
IFX(X_CF | X_OF) {
|
||||
RSB_IMM8(s4, s2, 32);
|
||||
MOV_REG_LSR_REG(s4, s1, s4);
|
||||
BFI(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
MOVS_REG_LSL_REG(s1, s1, s2);
|
||||
} else {
|
||||
MOV_REG_LSL_REG(s1, s1, s2);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 31);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPS_IMM8(s2, 1); // if s3==1
|
||||
IFX(X_SF) {} else {MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 31);}
|
||||
XOR_REG_LSL_IMM5_COND(cEQ, s4, s4, xFlags, 0); // CF is set if OF is asked
|
||||
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
|
||||
// else
|
||||
BFC_COND(cNE, xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHL32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shl32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
@@ -30,17 +87,13 @@ void emit_shl32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
MOVW(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
MOVW(s4, d_shl32);
|
||||
SET_DF(s4, d_shl32);
|
||||
} else IFX(X_ALL) {
|
||||
MOVW(s4, d_none);
|
||||
}
|
||||
IFX(X_PEND|X_ALL) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df));
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(c==0) {
|
||||
IFX(F_OF) {
|
||||
MOVW(s4, 0);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
@@ -48,10 +101,8 @@ void emit_shl32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
return;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
if(c<31) {
|
||||
UBFX(s3, s1, 32-c, 1);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
}
|
||||
MOV_REG_LSR_IMM5(s3, s1, 32-c);
|
||||
BFI(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
IFX(X_ZF|X_OF) {
|
||||
MOVS_REG_LSL_IMM5(s1, s1, c);
|
||||
@@ -62,33 +113,76 @@ void emit_shl32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
MOVW_COND(cNE, s3, 0);
|
||||
MOVW_COND(cEQ, s3, 1);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
UBFX(s3, s1, 31, 1);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
MOV_REG_LSR_IMM5(s3, s1, 31);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
IFX(X_SF) {} else {UBFX(s3, s1, 31, 1);}
|
||||
IFX(X_SF) {} else {MOV_REG_LSR_IMM5(s3, s1, 31);}
|
||||
XOR_IMM8_COND(cCS, s3, s3, 1);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
BFI(xFlags, s3, F_OF, 1);
|
||||
} else {
|
||||
MOVW(s4, 0);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
|
||||
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
AND_IMM8(s3, s1, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHR32 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s2 can be same as s3
|
||||
void emit_shr32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
int32_t j32;
|
||||
MAYUSE(j32);
|
||||
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_shr32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_ALL) {
|
||||
CMPS_IMM8(s2, 0); //if(!c)
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9_COND(cEQ, s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
}
|
||||
IFX(X_ZF|X_CF) {
|
||||
MOVS_REG_LSR_REG(s1, s1, s2);
|
||||
} else {
|
||||
MOV_REG_LSR_REG(s1, s1, s2);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF|X_CF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 31);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPS_IMM8(s2, 1);
|
||||
MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 30);
|
||||
XOR_REG_LSR_IMM8_COND(cEQ, s4, s4, s4, 1);
|
||||
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,12 +193,9 @@ void emit_shr32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
MOVW(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
MOVW(s4, d_shr32);
|
||||
SET_DF(s4, d_shr32);
|
||||
} else IFX(X_ALL) {
|
||||
MOVW(s4, d_none);
|
||||
}
|
||||
IFX(X_PEND|X_ALL) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df));
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
@@ -120,37 +211,28 @@ void emit_shr32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF|X_CF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
MOVW_COND(cNE, s3, 0);
|
||||
MOVW_COND(cEQ, s3, 1);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
MOVW_COND(cCC, s3, 0);
|
||||
MOVW_COND(cCS, s3, 1);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
UBFX(s3, s1, 31, 1);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
MOV_REG_LSR_IMM5(s3, s1, 31);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 30);
|
||||
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
BFI(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
|
||||
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
AND_IMM8(s3, s1, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,12 +243,9 @@ void emit_sar32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
MOVW(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
MOVW(s4, d_sar32);
|
||||
SET_DF(s4, d_sar32);
|
||||
} else IFX(X_ALL) {
|
||||
MOVW(s4, d_none);
|
||||
}
|
||||
IFX(X_PEND|X_ALL) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df));
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
@@ -182,29 +261,21 @@ void emit_sar32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF|X_CF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
MOVW_COND(cNE, s3, 0);
|
||||
MOVW_COND(cEQ, s3, 1);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
MOVW_COND(cCC, s3, 0);
|
||||
MOVW_COND(cCS, s3, 1);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
UBFX(s3, s1, 31, 1);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
MOV_REG_LSR_IMM5(s3, s1, 31);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
|
||||
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
AND_IMM8(s3, s1, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,12 +285,9 @@ void emit_rol32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, c);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
MOVW(s4, d_rol32);
|
||||
SET_DF(s4, d_rol32);
|
||||
} else IFX(X_ALL) {
|
||||
MOVW(s4, d_none);
|
||||
}
|
||||
IFX(X_PEND|X_ALL) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df));
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
@@ -232,14 +300,12 @@ void emit_rol32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
AND_IMM8(s3, s1, 1);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
BFI(xFlags, s1, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
ADD_REG_LSR_IMM5(s3, s1, s1, 31);
|
||||
AND_IMM8(s3, s3, 1);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
BFI(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -250,12 +316,9 @@ void emit_ror32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, c);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
MOVW(s4, d_ror32);
|
||||
SET_DF(s4, d_ror32);
|
||||
} else IFX(X_ALL) {
|
||||
MOVW(s4, d_none);
|
||||
}
|
||||
IFX(X_PEND|X_ALL) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df));
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
@@ -268,15 +331,132 @@ void emit_ror32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
UBFX(s3, s1, 31, 1);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
MOV_REG_LSR_IMM5(s3, s1, 31);
|
||||
BFI(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 30);
|
||||
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
BFI(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHRD32 instruction, from s1, fill s2 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shrd32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4)
|
||||
{
|
||||
c&=0x1f;
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
// same flags calc as shr32
|
||||
SET_DF(s4, d_shr32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
MOVS_REG_LSR_IMM5(s1, s1, c);
|
||||
} else {
|
||||
MOV_REG_LSR_IMM5(s1, s1, c);
|
||||
}
|
||||
IFX(X_ZF|X_CF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORRS_REG_LSL_IMM5(s1, s1, s2, 32-c);
|
||||
} else {
|
||||
ORR_REG_LSL_IMM5(s1, s1, s2, 32-c);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 31);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 30);
|
||||
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
|
||||
BFI(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
void emit_shld32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4)
|
||||
{
|
||||
c&=0x1f;
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
// same flags computation as with shl32
|
||||
SET_DF(s4, d_shl32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(c==0) {
|
||||
IFX(F_OF) {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 32-c);
|
||||
BFI(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
MOVS_REG_LSL_IMM5(s1, s1, c);
|
||||
} else {
|
||||
MOV_REG_LSL_IMM5(s1, s1, c);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
UBFX(s3, s2, 0, 1);
|
||||
XOR_IMM8_COND(cCS, s3, s3, 1);
|
||||
BFI(xFlags, s3, F_OF, 1);
|
||||
} else {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORRS_REG_LSR_IMM5(s1, s1, s2, 32-c);
|
||||
} else {
|
||||
ORR_REG_LSR_IMM5(s1, s1, s2, 32-c);
|
||||
}
|
||||
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 31);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
@@ -26,43 +26,34 @@
|
||||
// emit CMP32 instruction, from cmp s1 , s2, using s3 and s4 as scratch
|
||||
void emit_cmp32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
IFX_PENDOR0 {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
MOVW(s4, d_cmp32);
|
||||
SET_DF(s4, d_cmp32);
|
||||
} else {
|
||||
MOVW(s4, 0);
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
|
||||
SUBS_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 - s2
|
||||
IFX(X_PEND) {
|
||||
IFX_PENDOR0 {
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF|X_CF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
IFX(X_PEND) {
|
||||
MOVW(s4, 0);
|
||||
}
|
||||
// first the easy flag, also found on ARM
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
IFX(X_ZF|X_PEND) {
|
||||
MOVW(s4, 0);
|
||||
}
|
||||
MOVW_COND(cVS, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
ORR_IMM8_COND(cVS, xFlags, xFlags, 0b10, 0x0b);
|
||||
BIC_IMM8_COND(cVC, xFlags, xFlags, 0b10, 0x0b);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
IFX(X_ZF|X_OF|X_PEND) {
|
||||
MOVW(s4, 0);
|
||||
}
|
||||
MOVW_COND(cCC, s4, 1); // Carry flags on ARM is reversed compared to x86 one
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
// reversed carry
|
||||
ORR_IMM8_COND(cCC, xFlags, xFlags, 1<<F_CF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
UBFX(s4, s3, 31, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
MOV_REG_LSR_IMM5(s4, s3, 31);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// and now the tricky ones (and mostly unused), PF and AF
|
||||
IFX(X_AF) {
|
||||
@@ -73,8 +64,8 @@ void emit_cmp32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BIC_REG_LSL_IMM5(s3, s2, s1, 0); // loosing res... s3 = s & ~d
|
||||
ORR_REG_LSL_IMM5(s3, s4, s3, 0); // s3 = (res & (~d | s)) | (s & ~d)
|
||||
IFX(X_AF) {
|
||||
UBFX(s4, s3, 3, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_AF])); // AF: bc & 0x08
|
||||
MOV_REG_LSR_IMM5(s4, s3, 3);
|
||||
BFI(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
@@ -83,90 +74,71 @@ void emit_cmp32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
}
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
|
||||
MOV32(s4, GetParityTab());
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
AND_IMM8(s3, s3, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP32 instruction, from cmp s1 , 0, using s3 and s4 as scratch
|
||||
void emit_cmp32_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
MOVW(s4, 0);
|
||||
IFX(X_PEND) {
|
||||
IFX_PENDOR0 {
|
||||
MOVW(s4, 0);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, op2));
|
||||
MOVW(s4, d_cmp32);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
SET_DF(s4, d_cmp32);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
|
||||
SUBS_IMM8(s3, s1, 0); // res = s1 - 0
|
||||
IFX(X_PEND) {
|
||||
IFX(X_ZF|X_OF|X_CF|X_AF) {
|
||||
MOVW(s4, 0);
|
||||
}
|
||||
}
|
||||
// and now the tricky ones (and mostly unused), PF and AF
|
||||
// bc = (res & (~d | s)) | (~d & s) => is 0 here...
|
||||
IFX(X_CF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF])); // CF : bc & 0x80000000
|
||||
}
|
||||
IFX(X_AF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_AF])); // AF: bc & 0x08
|
||||
IFX(X_CF | X_AF | X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
// first the easy flags, also found on ARM
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
UBFX(s4, s3, 31, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
MOV_REG_LSR_IMM5(s4, s3, 31);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
|
||||
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
AND_IMM8(s3, s1, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP16 instruction, from cmp s1 , s2, using s3 and s4 as scratch
|
||||
void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
IFX_PENDOR0 {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
MOVW(s3, d_cmp16);
|
||||
SET_DF(s3, d_cmp16);
|
||||
} else {
|
||||
MOVW(s3, 0);
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, df)); // reset flags
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 - s2
|
||||
IFX(X_PEND) {
|
||||
IFX_PENDOR0 {
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
MOVW(s4, 0xffff);
|
||||
TSTS_REG_LSL_IMM5(s3, s4, 0);
|
||||
MOVW_COND(cNE, s4, 0);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
UBFX(s4, s3, 15, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
MOV_REG_LSR_IMM5(s4, s3, 15);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s)
|
||||
IFX(X_CF|X_AF|X_OF) {
|
||||
@@ -176,108 +148,87 @@ void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BIC_REG_LSL_IMM5(s3, s2, s1, 0); // loosing res... s3 = s & ~d
|
||||
ORR_REG_LSL_IMM5(s3, s4, s3, 0); // s3 = (res & (~d | s)) | (s & ~d)
|
||||
IFX(X_CF) {
|
||||
UBFX(s4, s3, 15, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF])); // CF : bc & 0x8000
|
||||
MOV_REG_LSR_IMM5(s4, s3, 15);
|
||||
BFI(xFlags, s4, F_CF, 1); // CF : bc & 0x8000
|
||||
}
|
||||
IFX(X_AF) {
|
||||
UBFX(s4, s3, 3, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_AF])); // AF: bc & 0x08
|
||||
MOV_REG_LSR_IMM5(s4, s3, 3);
|
||||
BFI(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_OF) {
|
||||
MOV_REG_LSR_IMM5(s4, s3, 14);
|
||||
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF])); // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
|
||||
BFI(xFlags, s4, F_OF, 1); // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
|
||||
}
|
||||
}
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
IFX(X_CF|X_AF|X_OF) {
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
}
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
|
||||
MOV32(s4, GetParityTab());
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
AND_IMM8(s3, s3, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP16 instruction, from cmp s1 , #0, using s3 and s4 as scratch
|
||||
void emit_cmp16_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
MOVW(s3, 0);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
IFX_PENDOR0 {
|
||||
MOVW(s3, 0);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
MOVW(s3, d_cmp16);
|
||||
}
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, df)); // reset flags
|
||||
IFX(X_OF|X_CF|X_AF) {
|
||||
MOVW(s4, 0);
|
||||
SET_DF(s3, d_cmp16);
|
||||
} else {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s) = 0
|
||||
IFX(X_CF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF])); // CF : bc & 0x8000
|
||||
}
|
||||
IFX(X_AF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_AF])); // AF: bc & 0x08
|
||||
IFX(X_CF | X_AF | X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF])); // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
MOVW(s4, 0xffff);
|
||||
TSTS_REG_LSL_IMM5(s1, s4, 0);
|
||||
MOVW(s4, 0);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
UBFX(s4, s1, 15, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
MOV_REG_LSR_IMM5(s4, s1, 15);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
|
||||
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
AND_IMM8(s3, s1, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
// emit CMP8 instruction, from cmp s1 , s2, using s3 and s4 as scratch
|
||||
void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOVW(s4, d_cmp8);
|
||||
IFX_PENDOR0 {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_cmp8);
|
||||
} else {
|
||||
MOVW(s4, 0);
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 - s2
|
||||
IFX(X_PEND) {
|
||||
IFX_PENDOR0 {
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
IFX(X_PEND) {
|
||||
MOVW(s4, 0);
|
||||
}
|
||||
TSTS_IMM8(s3, 0xff);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
UBFX(s4, s3, 7, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
MOV_REG_LSR_IMM5(s4, s3, 7);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s)
|
||||
IFX(X_CF|X_AF|X_OF) {
|
||||
@@ -287,198 +238,171 @@ void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BIC_REG_LSL_IMM5(s3, s2, s1, 0); // loosing res... s3 = s & ~d
|
||||
ORR_REG_LSL_IMM5(s3, s4, s3, 0); // s3 = (res & (~d | s)) | (s & ~d)
|
||||
IFX(X_CF) {
|
||||
UBFX(s4, s3, 7, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF])); // CF : bc & 0x80
|
||||
MOV_REG_LSR_IMM5(s4, s3, 7);
|
||||
BFI(xFlags, s4, F_CF, 1); // CF : bc & 0x80
|
||||
}
|
||||
IFX(X_AF) {
|
||||
UBFX(s4, s3, 3, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_AF])); // AF: bc & 0x08
|
||||
MOV_REG_LSR_IMM5(s4, s3, 3);
|
||||
BFI(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_OF) {
|
||||
MOV_REG_LSR_IMM5(s4, s3, 6);
|
||||
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF])); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
|
||||
BFI(xFlags, s4, F_OF, 1); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
|
||||
}
|
||||
}
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
IFX(X_CF|X_AF|X_OF) {
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
}
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
|
||||
MOV32(s4, GetParityTab());
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
AND_IMM8(s3, s3, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
}
|
||||
// emit CMP8 instruction, from cmp s1 , 0, using s3 and s4 as scratch
|
||||
void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
MOVW(s4, 0);
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, d_cmp8);
|
||||
IFX_PENDOR0 {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
MOVW(s4, 0);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, op2));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, df));
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
SET_DF(s3, d_cmp8);
|
||||
} else {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s) = 0
|
||||
IFX(X_CF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF])); // CF : bc & 0x80
|
||||
}
|
||||
IFX(X_AF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_AF])); // AF: bc & 0x08
|
||||
IFX(X_CF | X_AF | X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF])); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTS_IMM8(s1, 0xff);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
UBFX(s4, s1, 7, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
MOV_REG_LSR_IMM5(s4, s1, 7);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
|
||||
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
AND_IMM8(s3, s1, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST32 instruction, from test s1 , s2, using s3 and s4 as scratch
|
||||
void emit_test32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MOVW(s4, 0);
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, d_tst32);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, df));
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, d_tst32);
|
||||
} else {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
IFX(X_ZF|X_CF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
|
||||
}
|
||||
ANDS_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 & s2
|
||||
IFX(X_PEND) {
|
||||
IFX_PENDOR0 {
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
UBFX(s4, s3, 31, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
MOV_REG_LSR_IMM5(s4, s3, 31);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
|
||||
MOV32(s4, GetParityTab());
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
AND_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
AND_IMM8(s3, s3, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST16 instruction, from test s1 , s2, using s3 and s4 as scratch
|
||||
void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MOVW(s4, 0);
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, d_tst16);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, df));
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, d_tst16);
|
||||
} else {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
IFX(X_ZF|X_CF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
|
||||
}
|
||||
ANDS_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 & s2
|
||||
IFX(X_PEND) {
|
||||
IFX_PENDOR0 {
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
UBFX(s4, s3, 15, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
MOV_REG_LSR_IMM5(s4, s3, 15);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
|
||||
MOV32(s4, GetParityTab());
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
AND_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
AND_IMM8(s3, s3, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST8 instruction, from test s1 , s2, using s3 and s4 as scratch
|
||||
void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MOVW(s4, 0);
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, d_tst8);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, df));
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, d_tst8);
|
||||
} else {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
IFX(X_ZF|X_CF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
|
||||
}
|
||||
ANDS_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 & s2
|
||||
IFX(X_PEND) {
|
||||
IFX_PENDOR0 {
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
UBFX(s4, s3, 7, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
MOV_REG_LSR_IMM5(s4, s3, 7);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
|
||||
MOV32(s4, GetParityTab());
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
AND_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
AND_IMM8(s3, s3, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
}
|
||||
+182
-127
@@ -46,15 +46,15 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
wb2 = (wback>>2);
|
||||
wback = xEAX+(wback&3);
|
||||
UXTB(x1, wback, wb2);
|
||||
emit_add8(dyn, ninst, x1, x2, x12, x3, 0);
|
||||
emit_add8(dyn, ninst, x1, x2, x14, x3, 0);
|
||||
BFI(wback, ed, wb2*8, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0);
|
||||
MARKLOCK;
|
||||
LDREXB(x1, wback);
|
||||
emit_add8(dyn, ninst, x1, x2, x12, x3, (wback==x3)?1:0);
|
||||
STREXB(x12, x1, wback);
|
||||
CMPS_IMM8(x12, 0);
|
||||
emit_add8(dyn, ninst, x1, x2, x14, x3, (wback==x3)?1:0);
|
||||
STREXB(x14, x1, wback);
|
||||
CMPS_IMM8(x14, 0);
|
||||
B_MARKLOCK(cNE); // write failed, try again
|
||||
}
|
||||
break;
|
||||
@@ -65,12 +65,12 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_add32(dyn, ninst, ed, gd, x3, x12);
|
||||
emit_add32(dyn, ninst, ed, gd, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
emit_add32(dyn, ninst, x1, gd, x3, x12);
|
||||
emit_add32(dyn, ninst, x1, gd, x3, x14);
|
||||
STREX(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
@@ -80,21 +80,22 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("LOCK OR Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGB(x2);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
GETGB(x2);
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2);
|
||||
wback = xEAX+(wback&3);
|
||||
UXTB(x1, wback, wb2);
|
||||
emit_or8(dyn, ninst, x1, x2, x12, x3, 0);
|
||||
emit_or8(dyn, ninst, x1, x2, x14, x3);
|
||||
BFI(wback, ed, wb2*8, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0);
|
||||
MARKLOCK;
|
||||
GETGB(x2);
|
||||
LDREXB(x1, wback);
|
||||
emit_or8(dyn, ninst, x1, x2, x12, x3, (wback==x3)?1:0);
|
||||
STREXB(x12, x1, wback);
|
||||
CMPS_IMM8(x12, 0);
|
||||
emit_or8(dyn, ninst, x1, x2, x14, x2);
|
||||
STREXB(x14, x1, wback);
|
||||
CMPS_IMM8(x14, 0);
|
||||
B_MARKLOCK(cNE); // write failed, try again
|
||||
}
|
||||
break;
|
||||
@@ -105,12 +106,12 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_or32(dyn, ninst, ed, gd, x3, x12);
|
||||
emit_or32(dyn, ninst, ed, gd, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
emit_or32(dyn, ninst, x1, gd, x3, x12);
|
||||
emit_or32(dyn, ninst, x1, gd, x3, x14);
|
||||
STREX(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
@@ -126,15 +127,15 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
wb2 = (wback>>2);
|
||||
wback = xEAX+(wback&3);
|
||||
UXTB(x1, wback, wb2);
|
||||
emit_adc8(dyn, ninst, x1, x2, x12, x3, 0);
|
||||
emit_adc8(dyn, ninst, x1, x2, x14, x3, 0);
|
||||
BFI(wback, ed, wb2*8, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0);
|
||||
MARKLOCK;
|
||||
LDREXB(x1, wback);
|
||||
emit_adc8(dyn, ninst, x1, x2, x12, x3, (wback==x3)?1:0);
|
||||
STREXB(x12, x1, wback);
|
||||
CMPS_IMM8(x12, 0);
|
||||
emit_adc8(dyn, ninst, x1, x2, x14, x3, (wback==x3)?1:0);
|
||||
STREXB(x14, x1, wback);
|
||||
CMPS_IMM8(x14, 0);
|
||||
B_MARKLOCK(cNE); // write failed, try again
|
||||
}
|
||||
break;
|
||||
@@ -145,12 +146,12 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_adc32(dyn, ninst, ed, gd, x3, x12);
|
||||
emit_adc32(dyn, ninst, ed, gd, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
emit_adc32(dyn, ninst, x1, gd, x3, x12);
|
||||
emit_adc32(dyn, ninst, x1, gd, x3, x14);
|
||||
STREX(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
@@ -166,15 +167,15 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
wb2 = (wback>>2);
|
||||
wback = xEAX+(wback&3);
|
||||
UXTB(x1, wback, wb2);
|
||||
emit_sbb8(dyn, ninst, x1, x2, x12, x3, 0);
|
||||
emit_sbb8(dyn, ninst, x1, x2, x14, x3, 0);
|
||||
BFI(wback, ed, wb2*8, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0);
|
||||
MARKLOCK;
|
||||
LDREXB(x1, wback);
|
||||
emit_sbb8(dyn, ninst, x1, x2, x12, x3, (wback==x3)?1:0);
|
||||
STREXB(x12, x1, wback);
|
||||
CMPS_IMM8(x12, 0);
|
||||
emit_sbb8(dyn, ninst, x1, x2, x14, x3, (wback==x3)?1:0);
|
||||
STREXB(x14, x1, wback);
|
||||
CMPS_IMM8(x14, 0);
|
||||
B_MARKLOCK(cNE); // write failed, try again
|
||||
}
|
||||
break;
|
||||
@@ -185,12 +186,12 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_sbb32(dyn, ninst, ed, gd, x3, x12);
|
||||
emit_sbb32(dyn, ninst, ed, gd, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
emit_sbb32(dyn, ninst, x1, gd, x3, x12);
|
||||
emit_sbb32(dyn, ninst, x1, gd, x3, x14);
|
||||
STREX(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
@@ -200,21 +201,22 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("LOCK AND Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGB(x2);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
GETGB(x2);
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2);
|
||||
wback = xEAX+(wback&3);
|
||||
UXTB(x1, wback, wb2);
|
||||
emit_and8(dyn, ninst, x1, x2, x12, x3, 0);
|
||||
emit_and8(dyn, ninst, x1, x2, x14, x3);
|
||||
BFI(wback, ed, wb2*8, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0);
|
||||
MARKLOCK;
|
||||
GETGB(x2);
|
||||
LDREXB(x1, wback);
|
||||
emit_and8(dyn, ninst, x1, x2, x12, x3, (wback==x3)?1:0);
|
||||
STREXB(x12, x1, wback);
|
||||
CMPS_IMM8(x12, 0);
|
||||
emit_and8(dyn, ninst, x1, x2, x14, x2);
|
||||
STREXB(x14, x1, wback);
|
||||
CMPS_IMM8(x14, 0);
|
||||
B_MARKLOCK(cNE); // write failed, try again
|
||||
}
|
||||
break;
|
||||
@@ -225,12 +227,12 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_and32(dyn, ninst, ed, gd, x3, x12);
|
||||
emit_and32(dyn, ninst, ed, gd, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
emit_and32(dyn, ninst, x1, gd, x3, x12);
|
||||
emit_and32(dyn, ninst, x1, gd, x3, x14);
|
||||
STREX(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
@@ -246,15 +248,15 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
wb2 = (wback>>2);
|
||||
wback = xEAX+(wback&3);
|
||||
UXTB(x1, wback, wb2);
|
||||
emit_sub8(dyn, ninst, x1, x2, x12, x3, 0);
|
||||
emit_sub8(dyn, ninst, x1, x2, x14, x3, 0);
|
||||
BFI(wback, ed, wb2*8, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0);
|
||||
MARKLOCK;
|
||||
LDREXB(x1, wback);
|
||||
emit_sub8(dyn, ninst, x1, x2, x12, x3, (wback==x3)?1:0);
|
||||
STREXB(x12, x1, wback);
|
||||
CMPS_IMM8(x12, 0);
|
||||
emit_sub8(dyn, ninst, x1, x2, x14, x3, (wback==x3)?1:0);
|
||||
STREXB(x14, x1, wback);
|
||||
CMPS_IMM8(x14, 0);
|
||||
B_MARKLOCK(cNE); // write failed, try again
|
||||
}
|
||||
break;
|
||||
@@ -265,12 +267,12 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_sub32(dyn, ninst, ed, gd, x3, x12);
|
||||
emit_sub32(dyn, ninst, ed, gd, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
emit_sub32(dyn, ninst, x1, gd, x3, x12);
|
||||
emit_sub32(dyn, ninst, x1, gd, x3, x14);
|
||||
STREX(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
@@ -280,21 +282,22 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("LOCK XOR Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGB(x2);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
GETGB(x2);
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2);
|
||||
wback = xEAX+(wback&3);
|
||||
UXTB(x1, wback, wb2);
|
||||
emit_xor8(dyn, ninst, x1, x2, x12, x3, 0);
|
||||
emit_xor8(dyn, ninst, x1, x2, x14, x3);
|
||||
BFI(wback, ed, wb2*8, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0);
|
||||
MARKLOCK;
|
||||
GETGB(x2);
|
||||
LDREXB(x1, wback);
|
||||
emit_xor8(dyn, ninst, x1, x2, x12, x3, (wback==x3)?1:0);
|
||||
STREXB(x12, x1, wback);
|
||||
CMPS_IMM8(x12, 0);
|
||||
emit_xor8(dyn, ninst, x1, x2, x14, x2);
|
||||
STREXB(x14, x1, wback);
|
||||
CMPS_IMM8(x14, 0);
|
||||
B_MARKLOCK(cNE); // write failed, try again
|
||||
}
|
||||
break;
|
||||
@@ -305,12 +308,12 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_xor32(dyn, ninst, ed, gd, x3, x12);
|
||||
emit_xor32(dyn, ninst, ed, gd, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
emit_xor32(dyn, ninst, x1, gd, x3, x12);
|
||||
emit_xor32(dyn, ninst, x1, gd, x3, x14);
|
||||
STREX(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
@@ -331,7 +334,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_add32c(dyn, ninst, ed, i32, x3, x12);
|
||||
emit_add32c(dyn, ninst, ed, i32, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
@@ -339,16 +342,16 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
B_MARK(cNE);
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
emit_add32c(dyn, ninst, x1, i32, x3, x12);
|
||||
emit_add32c(dyn, ninst, x1, i32, x3, x14);
|
||||
STREX(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
B_NEXT(c__);
|
||||
MARK; // unaligned! also, not enough
|
||||
LDR_IMM9(x1, wback, 0);
|
||||
LDREXB(x12, wback);
|
||||
BFI(x1, x12, 0, 8); // re-inject
|
||||
emit_add32c(dyn, ninst, x1, i32, x3, x12);
|
||||
LDREXB(x14, wback);
|
||||
BFI(x1, x14, 0, 8); // re-inject
|
||||
emit_add32c(dyn, ninst, x1, i32, x3, x14);
|
||||
STREXB(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARK(cNE);
|
||||
@@ -361,13 +364,13 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_or32c(dyn, ninst, ed, i32, x3, x12);
|
||||
emit_or32c(dyn, ninst, ed, i32, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
emit_or32c(dyn, ninst, x1, i32, x3, x12);
|
||||
emit_or32c(dyn, ninst, x1, i32, x3, x14);
|
||||
STREX(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
@@ -380,13 +383,13 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_adc32c(dyn, ninst, ed, i32, x3, x12);
|
||||
emit_adc32c(dyn, ninst, ed, i32, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
emit_adc32c(dyn, ninst, x1, i32, x3, x12);
|
||||
emit_adc32c(dyn, ninst, x1, i32, x3, x14);
|
||||
STREX(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
@@ -399,13 +402,13 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_sbb32c(dyn, ninst, ed, i32, x3, x12);
|
||||
emit_sbb32c(dyn, ninst, ed, i32, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
emit_sbb32c(dyn, ninst, x1, i32, x3, x12);
|
||||
emit_sbb32c(dyn, ninst, x1, i32, x3, x14);
|
||||
STREX(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
@@ -417,13 +420,13 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_and32c(dyn, ninst, ed, i32, x3, x12);
|
||||
emit_and32c(dyn, ninst, ed, i32, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
emit_and32c(dyn, ninst, x1, i32, x3, x12);
|
||||
emit_and32c(dyn, ninst, x1, i32, x3, x14);
|
||||
STREX(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
@@ -435,7 +438,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_sub32c(dyn, ninst, ed, i32, x3, x12);
|
||||
emit_sub32c(dyn, ninst, ed, i32, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
@@ -443,16 +446,16 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
B_MARK(cNE);
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
emit_sub32c(dyn, ninst, x1, i32, x3, x12);
|
||||
emit_sub32c(dyn, ninst, x1, i32, x3, x14);
|
||||
STREX(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
B_NEXT(c__);
|
||||
MARK; // unaligned! also, not enough
|
||||
LDR_IMM9(x1, wback, 0);
|
||||
LDREXB(x12, wback);
|
||||
BFI(x1, x12, 0, 8); // re-inject
|
||||
emit_sub32c(dyn, ninst, x1, i32, x3, x12);
|
||||
LDREXB(x14, wback);
|
||||
BFI(x1, x14, 0, 8); // re-inject
|
||||
emit_sub32c(dyn, ninst, x1, i32, x3, x14);
|
||||
STREXB(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARK(cNE);
|
||||
@@ -465,13 +468,13 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_xor32c(dyn, ninst, ed, i32, x3, x12);
|
||||
emit_xor32c(dyn, ninst, ed, i32, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
emit_xor32c(dyn, ninst, x1, i32, x3, x12);
|
||||
emit_xor32c(dyn, ninst, x1, i32, x3, x14);
|
||||
STREX(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
@@ -485,9 +488,9 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
if(i32) {
|
||||
MOV32(x2, i32);
|
||||
emit_cmp32(dyn, ninst, ed, x2, x3, x12);
|
||||
emit_cmp32(dyn, ninst, ed, x2, x3, x14);
|
||||
} else {
|
||||
emit_cmp32_0(dyn, ninst, ed, x3, x12);
|
||||
emit_cmp32_0(dyn, ninst, ed, x3, x14);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -549,8 +552,8 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
// AL == Eb
|
||||
GETGB(x1);
|
||||
if(wb1) {
|
||||
STREXB(x12, x1, wback);
|
||||
CMPS_IMM8(x12, 0);
|
||||
STREXB(x14, x1, wback);
|
||||
CMPS_IMM8(x14, 0);
|
||||
B_MARKLOCK(cNE); // write failed, try again
|
||||
if(!(gb1==xEAX && gb2==0)) {
|
||||
UXTB(x1, xEAX, 0); // readback AL if needed
|
||||
@@ -565,7 +568,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
BFI(xEAX, ed, 0, 8);
|
||||
MARK3;
|
||||
// done, do the cmp now
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x12);
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x14);
|
||||
break;
|
||||
case 0xB1:
|
||||
INST_NAME("LOCK CMPXCHG Ed, Gd");
|
||||
@@ -589,22 +592,22 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
// EAX == Ed
|
||||
if(wback) {
|
||||
TSTS_IMM8(wback, 3);
|
||||
STREX_COND(cEQ, x12, gd, wback);
|
||||
STREXB_COND(cNE, x12, gd, wback);
|
||||
CMPS_IMM8(x12, 0);
|
||||
STREX_COND(cEQ, x14, gd, wback);
|
||||
STREXB_COND(cNE, x14, gd, wback);
|
||||
CMPS_IMM8(x14, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
TSTS_IMM8(wback, 3); // anoying, all those test
|
||||
STR_IMM9_COND(cNE, gd, wback, 0);
|
||||
emit_cmp32(dyn, ninst, xEAX, ed, x1, x12);
|
||||
emit_cmp32(dyn, ninst, xEAX, ed, x1, x14);
|
||||
} else {
|
||||
emit_cmp32(dyn, ninst, xEAX, ed, x1, x12);
|
||||
emit_cmp32(dyn, ninst, xEAX, ed, x1, x14);
|
||||
MOV_REG(ed, gd);
|
||||
}
|
||||
// done
|
||||
B_MARK3(c__); // not next, in case its called with a LOCK prefix
|
||||
MARK;
|
||||
// EAX != Ed
|
||||
emit_cmp32(dyn, ninst, xEAX, ed, x3, x12);
|
||||
emit_cmp32(dyn, ninst, xEAX, ed, x3, x14);
|
||||
MOV_REG(xEAX, ed);
|
||||
MARK3
|
||||
break;
|
||||
@@ -626,15 +629,15 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = x1;
|
||||
}
|
||||
AND_IMM8(x2, gd, 0x1f);
|
||||
MOV_REG_LSR_REG(x12, ed, x2);
|
||||
ANDS_IMM8(x12, x12, 1);
|
||||
STR_IMM9(x12, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
MOV_REG_LSR_REG(x14, ed, x2);
|
||||
ANDS_IMM8(x14, x14, 1);
|
||||
BFI(xFlags, x14, F_CF, 1);
|
||||
B_MARK3(cEQ); // bit already clear, jump to end of instruction
|
||||
MOVW(x12, 1);
|
||||
XOR_REG_LSL_REG(ed, ed, x12, x2);
|
||||
MOVW(x14, 1);
|
||||
XOR_REG_LSL_REG(ed, ed, x14, x2);
|
||||
if(wback) {
|
||||
STREX(x12, ed, wback);
|
||||
CMPS_IMM8(x12, 0);
|
||||
STREX(x14, ed, wback);
|
||||
CMPS_IMM8(x14, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
}
|
||||
MARK3;
|
||||
@@ -662,8 +665,41 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV_REG_LSR_IMM5(x1, ed, u8);
|
||||
ed = x1;
|
||||
}
|
||||
AND_IMM8(x1, ed, 1);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
BFI(xFlags, ed, F_CF, 1);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("LOCK BTS Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
gd = x2;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
u8 = F8;
|
||||
MOVW(gd, u8);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, 0, 0);
|
||||
u8 = F8;
|
||||
MOVW(gd, u8);
|
||||
UBFX(x1, gd, 5, 3); // r1 = (gd>>5);
|
||||
ADD_REG_LSL_IMM5(x3, ed, x1, 2); //(&ed)+=r1*4;
|
||||
MARKLOCK;
|
||||
LDREX(x1, x3);
|
||||
ed = x1;
|
||||
wback = x3;
|
||||
}
|
||||
AND_IMM8(x2, gd, 0x1f);
|
||||
MOV_REG_LSR_REG(x14, ed, x2);
|
||||
ANDS_IMM8(x14, x14, 1);
|
||||
BFI(xFlags, x14, F_CF, 1);
|
||||
B_MARK3(cNE); // bit already set, jump to next instruction
|
||||
MOVW(x14, 1);
|
||||
XOR_REG_LSL_REG(ed, ed, x14, x2);
|
||||
if(wback) {
|
||||
STREX(x14, ed, wback);
|
||||
CMPS_IMM8(x14, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
}
|
||||
MARK3;
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("LOCK BTR Ed, Ib");
|
||||
@@ -686,15 +722,15 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
wback = x3;
|
||||
}
|
||||
AND_IMM8(x2, gd, 0x1f);
|
||||
MOV_REG_LSR_REG(x12, ed, x2);
|
||||
ANDS_IMM8(x12, x12, 1);
|
||||
STR_IMM9(x12, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
MOV_REG_LSR_REG(x14, ed, x2);
|
||||
ANDS_IMM8(x14, x14, 1);
|
||||
BFI(xFlags, x14, F_CF, 1);
|
||||
B_MARK3(cEQ); // bit already clear, jump to next instruction
|
||||
//MOVW(x12, 1); // already 0x01
|
||||
XOR_REG_LSL_REG(ed, ed, x12, x2);
|
||||
//MOVW(x14, 1); // already 0x01
|
||||
XOR_REG_LSL_REG(ed, ed, x14, x2);
|
||||
if(wback) {
|
||||
STREX(x12, ed, wback);
|
||||
CMPS_IMM8(x12, 0);
|
||||
STREX(x14, ed, wback);
|
||||
CMPS_IMM8(x14, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
}
|
||||
MARK3;
|
||||
@@ -721,14 +757,13 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
wback = x3;
|
||||
}
|
||||
AND_IMM8(x2, gd, 0x1f);
|
||||
MOV_REG_LSR_REG(x12, ed, x2);
|
||||
AND_IMM8(x12, x12, 1);
|
||||
STR_IMM9(x12, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
MOVW(x12, 1);
|
||||
XOR_REG_LSL_REG(ed, ed, x12, x2);
|
||||
MOV_REG_LSR_REG(x14, ed, x2);
|
||||
BFI(xFlags, x14, F_CF, 1);
|
||||
MOVW(x14, 1);
|
||||
XOR_REG_LSL_REG(ed, ed, x14, x2);
|
||||
if(wback) {
|
||||
STREX(x12, ed, wback);
|
||||
CMPS_IMM8(x12, 0);
|
||||
STREX(x14, ed, wback);
|
||||
CMPS_IMM8(x14, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
}
|
||||
break;
|
||||
@@ -753,10 +788,10 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = x2;
|
||||
}
|
||||
BFI(gb1, ed, gb2*8, 8); // gb <- eb
|
||||
emit_add8(dyn, ninst, ed, gd, x12, x3, 1);
|
||||
emit_add8(dyn, ninst, ed, gd, x14, x3, 1);
|
||||
if(wb1) {
|
||||
STREXB(x12, ed, wback);
|
||||
CMPS_IMM8(x12, 0);
|
||||
STREXB(x14, ed, wback);
|
||||
CMPS_IMM8(x14, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
} else {
|
||||
BFI(wback, ed, wb2*8, 8);
|
||||
@@ -774,35 +809,31 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
XOR_REG_LSL_IMM5(ed, gd, ed, 0);
|
||||
XOR_REG_LSL_IMM5(gd, gd, ed, 0);
|
||||
}
|
||||
emit_add32(dyn, ninst, ed, gd, x3, x12);
|
||||
emit_add32(dyn, ninst, ed, gd, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
|
||||
TSTS_IMM8(wback, 3);
|
||||
B_MARK(cNE); // unaligned
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
ADD_REG_LSL_IMM5(x12, x1, gd, 0);
|
||||
STREX(x3, x12, wback);
|
||||
ADD_REG_LSL_IMM5(x14, x1, gd, 0);
|
||||
STREX(x3, x14, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
IFX(X_ALL|X_PEND) {
|
||||
MOV_REG(x2, x1);
|
||||
emit_add32(dyn, ninst, x2, gd, x3, x12);
|
||||
}
|
||||
MOV_REG(gd, x1);
|
||||
B_NEXT(c__);
|
||||
B_MARK2(c__);
|
||||
MARK;
|
||||
LDR_IMM9(x1, wback, 0);
|
||||
LDREXB(x12, wback);
|
||||
BFI(x1, x12, 0, 8);
|
||||
ADD_REG_LSL_IMM5(x12, x1, gd, 0);
|
||||
STREXB(x3, x12, wback);
|
||||
LDREXB(x14, wback);
|
||||
BFI(x1, x14, 0, 8);
|
||||
ADD_REG_LSL_IMM5(x14, x1, gd, 0);
|
||||
STREXB(x3, x14, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARK(cNE);
|
||||
STR_IMM9(x12, wback, 0);
|
||||
STR_IMM9(x14, wback, 0);
|
||||
MARK2;
|
||||
IFX(X_ALL|X_PEND) {
|
||||
MOV_REG(x2, x1);
|
||||
emit_add32(dyn, ninst, x2, gd, x3, x12);
|
||||
emit_add32(dyn, ninst, x2, gd, x3, x14);
|
||||
}
|
||||
MOV_REG(gd, x1);
|
||||
}
|
||||
@@ -825,9 +856,9 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV_REG(x2, xEBX);
|
||||
MOV_REG(x3, xECX);
|
||||
TSTS_IMM8(wback, 7);
|
||||
STREXD_COND(cEQ, x12, x2, wback);
|
||||
STREX_COND(cNE, x12, x2, wback);
|
||||
CMPS_IMM8(x12, 0);
|
||||
STREXD_COND(cEQ, x14, x2, wback);
|
||||
STREX_COND(cNE, x14, x2, wback);
|
||||
CMPS_IMM8(x14, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
TSTS_IMM8(wback, 7);
|
||||
STR_IMM9_COND(cNE, x3, wback, 4);
|
||||
@@ -838,7 +869,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV_REG(xEDX, x3);
|
||||
MOVW(x1, 0);
|
||||
MARK3;
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
BFI(xFlags, x1, F_ZF, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -856,15 +887,27 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_inc32(dyn, ninst, ed, x3, x12);
|
||||
emit_inc32(dyn, ninst, ed, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
|
||||
TSTS_IMM8(wback, 3);
|
||||
B_MARK(cNE); // unaligned
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
emit_inc32(dyn, ninst, x1, x3, x12);
|
||||
emit_inc32(dyn, ninst, x1, x3, x14);
|
||||
STREX(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
B_NEXT(c__);
|
||||
MARK;
|
||||
LDR_IMM9(x1, wback, 0);
|
||||
LDREXB(x3, wback);
|
||||
BFI(x1, x3, 0, 8);
|
||||
emit_inc32(dyn, ninst, x1, x3, x14);
|
||||
STREXB(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARK(cNE);
|
||||
STR_IMM9(x1, wback, 0);
|
||||
}
|
||||
break;
|
||||
case 1: //DEC Ed
|
||||
@@ -872,25 +915,37 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_dec32(dyn, ninst, ed, x3, x12);
|
||||
emit_dec32(dyn, ninst, ed, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
|
||||
TSTS_IMM8(wback, 3);
|
||||
B_MARK(cNE); // unaligned
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
emit_dec32(dyn, ninst, x1, x3, x12);
|
||||
emit_dec32(dyn, ninst, x1, x3, x14);
|
||||
STREX(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
B_NEXT(c__);
|
||||
MARK;
|
||||
LDR_IMM9(x1, wback, 0);
|
||||
LDREXB(x3, wback);
|
||||
BFI(x1, x3, 0, 8);
|
||||
emit_dec32(dyn, ninst, x1, x3, x14);
|
||||
STREXB(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARK(cNE);
|
||||
STR_IMM9(x1, wback, 0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// dafault to NO LOCK
|
||||
// default to NO LOCK
|
||||
addr-=2;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// dafault to NO LOCK
|
||||
// default to NO LOCK
|
||||
--addr;
|
||||
}
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("CVTSD2SI Gd, Ex");
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x12);
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
@@ -209,7 +209,7 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
// MINSD: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
|
||||
VCMP_F64(v0, d0);
|
||||
VMRS_APSR();
|
||||
VMOVcond_64(cPL, v0, d0);
|
||||
VMOVcond_64(cCS, v0, d0); // move v0 <- d0 if v0 or d0 unordered or v0 >= d0
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVSD Gx, Ex");
|
||||
@@ -228,7 +228,7 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
// MAXSD: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
|
||||
VCMP_F64(d0, v0);
|
||||
VMRS_APSR();
|
||||
VMOVcond_64(cPL, v0, d0);
|
||||
VMOVcond_64(cCS, v0, d0); // move v0 <- d0 if v0 or d0 is unordered or d0 >= v0
|
||||
break;
|
||||
|
||||
case 0x70:
|
||||
@@ -292,18 +292,22 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(d0);
|
||||
VCMP_F64(v0, d0);
|
||||
u8 = F8;
|
||||
if((u8&7)==6){
|
||||
VCMP_F64(d0, v0);
|
||||
} else {
|
||||
VCMP_F64(v0, d0);
|
||||
}
|
||||
VMRS_APSR();
|
||||
MOVW(x2, 0);
|
||||
u8 = F8;
|
||||
switch(u8&7) {
|
||||
case 0: MVN_COND_REG_LSL_IMM5(cEQ, x2, x2, 0); break; // Equal
|
||||
case 1: MVN_COND_REG_LSL_IMM5(cCC, x2, x2, 0); break; // Less than
|
||||
case 2: MVN_COND_REG_LSL_IMM5(cLS, x2, x2, 0); break; // Less or equal
|
||||
case 1: MVN_COND_REG_LSL_IMM5(cMI, x2, x2, 0); break; // Less than
|
||||
case 2: MVN_COND_REG_LSL_IMM5(cLE, x2, x2, 0); break; // Less or equal
|
||||
case 3: MVN_COND_REG_LSL_IMM5(cVS, x2, x2, 0); break; // NaN
|
||||
case 4: MVN_COND_REG_LSL_IMM5(cNE, x2, x2, 0); break; // Not Equal (or unordered on ARM, not on X86...)
|
||||
case 5: MVN_COND_REG_LSL_IMM5(cPL, x2, x2, 0); break; // Greater or equal or unordered
|
||||
case 6: MVN_COND_REG_LSL_IMM5(cHI, x2, x2, 0); break; // Greater or unordered
|
||||
case 5: MVN_COND_REG_LSL_IMM5(cCS, x2, x2, 0); break; // Greater or equal or unordered
|
||||
case 6: MVN_COND_REG_LSL_IMM5(cLT, x2, x2, 0); break; // Greater or unordered, test inverted, N!=V so unordereded or less than (inverted)
|
||||
case 7: MVN_COND_REG_LSL_IMM5(cVC, x2, x2, 0); break; // not NaN
|
||||
}
|
||||
VMOVtoV_D(v0, x2, x2);
|
||||
|
||||
@@ -227,7 +227,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("CVTSS2SI Gd, Ex");
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x12);
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
@@ -426,7 +426,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
// MINSS: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
|
||||
VCMP_F32(s0, s1);
|
||||
VMRS_APSR();
|
||||
VMOVcond_32(cPL, s0, s1);
|
||||
VMOVcond_32(cCS, s0, s1); // move s0 <- s1 if s0 or s1 unordered or s0 >= s1
|
||||
if(v0!=d0) {
|
||||
VMOV_64(v0, d0);
|
||||
}
|
||||
@@ -469,7 +469,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
// MAXSS: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
|
||||
VCMP_F32(s1, s0);
|
||||
VMRS_APSR();
|
||||
VMOVcond_32(cPL, s0, s1);
|
||||
VMOVcond_32(cCS, s0, s1); // move s0 <- s1 if s0 or s1 is unordered or s1 >= s0
|
||||
if(v0!=d0) {
|
||||
VMOV_64(v0, d0);
|
||||
}
|
||||
@@ -507,7 +507,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
VLD1Q_64(v1, ed);
|
||||
}
|
||||
u8 = F8;
|
||||
// only high part need to be suffled. VTBL only handle 8bits value, so the 16bits suffles need to be changed in 8bits
|
||||
// only high part need to be shuffled. VTBL only handle 8bits value, so the 16bits shuffles need to be changed in 8bits
|
||||
u32 = 0;
|
||||
for (int i=0; i<2; ++i) {
|
||||
u32 |= (((u8>>(i*2))&3)*2+0)<<(i*16+0);
|
||||
@@ -570,16 +570,17 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
GETED;
|
||||
GETGD;
|
||||
SET_DFNONE(x3);
|
||||
TSTS_REG_LSL_IMM5(ed, ed, 0);
|
||||
RBIT(x1, ed); // reverse
|
||||
CLZ(gd, x1); // x2 gets leading 0 == TZCNT
|
||||
MOVW_COND(cEQ, x1, 1);
|
||||
MOVW_COND(cNE, x1, 0);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
RSB_IMM8(x1, x1, 1);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
MOVW(x1, d_none);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, df));
|
||||
MOVW_COND(cEQ, x3, 1);
|
||||
MOVW_COND(cNE, x3, 0);
|
||||
BFI(xFlags, x3, F_CF, 1); // CF = is source 0?
|
||||
RBIT(x3, ed); // reverse
|
||||
CLZ(gd, x3); // x2 gets leading 0 == TZCNT
|
||||
TSTS_REG_LSL_IMM5(gd, gd, 0);
|
||||
MOVW_COND(cEQ, x3, 1);
|
||||
MOVW_COND(cNE, x3, 0);
|
||||
BFI(xFlags, x3, F_ZF, 1); // ZF = is dest 0?
|
||||
break;
|
||||
|
||||
case 0xC2:
|
||||
@@ -597,18 +598,22 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
VMOV_64(d0, v0);
|
||||
}
|
||||
s0 = d0*2;
|
||||
VCMP_F32(s0, s1);
|
||||
u8 = F8;
|
||||
if((u8&7)==6){
|
||||
VCMP_F32(s1, s0);
|
||||
} else {
|
||||
VCMP_F32(s0, s1);
|
||||
}
|
||||
VMRS_APSR();
|
||||
MOVW(x2, 0);
|
||||
u8 = F8;
|
||||
switch(u8&7) {
|
||||
case 0: MVN_COND_REG_LSL_IMM5(cEQ, x2, x2, 0); break; // Equal
|
||||
case 1: MVN_COND_REG_LSL_IMM5(cCC, x2, x2, 0); break; // Less than
|
||||
case 2: MVN_COND_REG_LSL_IMM5(cLS, x2, x2, 0); break; // Less or equal
|
||||
case 1: MVN_COND_REG_LSL_IMM5(cMI, x2, x2, 0); break; // Less than
|
||||
case 2: MVN_COND_REG_LSL_IMM5(cLE, x2, x2, 0); break; // Less or equal
|
||||
case 3: MVN_COND_REG_LSL_IMM5(cVS, x2, x2, 0); break; // NaN
|
||||
case 4: MVN_COND_REG_LSL_IMM5(cNE, x2, x2, 0); break; // Not Equal (or unordered on ARM, not on X86...)
|
||||
case 5: MVN_COND_REG_LSL_IMM5(cPL, x2, x2, 0); break; // Greater or equal or unordered
|
||||
case 6: MVN_COND_REG_LSL_IMM5(cHI, x2, x2, 0); break; // Greater or unordered
|
||||
case 5: MVN_COND_REG_LSL_IMM5(cCS, x2, x2, 0); break; // Greater or equal or unordered
|
||||
case 6: MVN_COND_REG_LSL_IMM5(cLT, x2, x2, 0); break; // Greater or unordered, test inverted, N!=V so unordereded or less than (inverted)
|
||||
case 7: MVN_COND_REG_LSL_IMM5(cVC, x2, x2, 0); break; // not NaN
|
||||
}
|
||||
VMOVtoDx_32(v0, 0, x2);
|
||||
|
||||
@@ -21,28 +21,14 @@
|
||||
#include "emu/x86run_private.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "x86trace.h"
|
||||
#include "signals.h"
|
||||
#include "dynarec_arm.h"
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "dynarec_arm_functions.h"
|
||||
|
||||
void arm_popf(x86emu_t* emu, uint32_t f)
|
||||
{
|
||||
emu->packed_eflags.x32 = (f & 0x3F7FD7) | 0x2; // mask off res2 and res3 and on res1
|
||||
UnpackFlags(emu);
|
||||
RESET_FLAGS(emu);
|
||||
}
|
||||
|
||||
void arm_popf16(x86emu_t* emu, uint32_t f)
|
||||
{
|
||||
emu->packed_eflags.x32 &= 0xffff0000;
|
||||
emu->packed_eflags.x32 |= (f & 0x7FD7) | 0x2; // mask off res2 and res3 and on res1
|
||||
UnpackFlags(emu);
|
||||
RESET_FLAGS(emu);
|
||||
}
|
||||
|
||||
void arm_fstp(x86emu_t* emu, void* p)
|
||||
{
|
||||
if(ST0.ll!=STld(0).ref)
|
||||
if(ST0.q!=STld(0).ref)
|
||||
D2LD(&ST0.d, p);
|
||||
else
|
||||
memcpy(p, &STld(0).ld, 10);
|
||||
@@ -71,7 +57,7 @@ void arm_fpatan(x86emu_t* emu)
|
||||
}
|
||||
void arm_fxtract(x86emu_t* emu)
|
||||
{
|
||||
int32_t tmp32s = (ST1.ll&0x7ff0000000000000LL)>>52;
|
||||
int32_t tmp32s = (ST1.q&0x7ff0000000000000LL)>>52;
|
||||
tmp32s -= 1023;
|
||||
ST1.d /= exp2(tmp32s);
|
||||
ST0.d = tmp32s;
|
||||
@@ -121,7 +107,7 @@ void arm_fild64(x86emu_t* emu, int64_t* ed)
|
||||
memcpy(&tmp, ed, sizeof(tmp));
|
||||
ST0.d = tmp;
|
||||
STll(0).ll = tmp;
|
||||
STll(0).ref = ST0.ll;
|
||||
STll(0).ref = ST0.q;
|
||||
}
|
||||
|
||||
void arm_fbstp(x86emu_t* emu, uint8_t* ed)
|
||||
@@ -132,7 +118,7 @@ void arm_fbstp(x86emu_t* emu, uint8_t* ed)
|
||||
void arm_fistp64(x86emu_t* emu, int64_t* ed)
|
||||
{
|
||||
// used of memcpy to avoid aligments issues
|
||||
if(STll(0).ref==ST(0).ll) {
|
||||
if(STll(0).ref==ST(0).q) {
|
||||
memcpy(ed, &STll(0).ll, sizeof(int64_t));
|
||||
} else {
|
||||
int64_t tmp;
|
||||
@@ -144,16 +130,23 @@ void arm_fistp64(x86emu_t* emu, int64_t* ed)
|
||||
}
|
||||
}
|
||||
|
||||
void arm_fistt64(x86emu_t* emu, int64_t* ed)
|
||||
{
|
||||
// used of memcpy to avoid aligments issues
|
||||
int64_t tmp = ST0.d;
|
||||
memcpy(ed, &tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
void arm_fld(x86emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
memcpy(&STld(0).ld, ed, 10);
|
||||
LD2D(&STld(0), &ST(0).d);
|
||||
STld(0).ref = ST0.ll;
|
||||
STld(0).ref = ST0.q;
|
||||
}
|
||||
|
||||
void arm_ud(x86emu_t* emu)
|
||||
{
|
||||
kill(getpid(), SIGILL);
|
||||
emit_signal(emu, SIGILL, (void*)R_EIP, 0);
|
||||
}
|
||||
|
||||
void arm_fsave(x86emu_t* emu, uint8_t* ed)
|
||||
@@ -266,11 +259,11 @@ void fpu_reset_reg(dynarec_arm_t* dyn)
|
||||
dyn->fpuused[i]=0;
|
||||
}
|
||||
|
||||
#define F8 *(uint8_t*)(addr++)
|
||||
#define F32 *(uint32_t*)(addr+=4, addr-4)
|
||||
// Get if ED will have the correct parity. Not emiting anything. Parity is 2 for DWORD or 3 for QWORD
|
||||
int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity)
|
||||
{
|
||||
#define F8 *(uint8_t*)(addr++)
|
||||
#define F32 *(uint32_t*)(addr+=4, addr-4)
|
||||
|
||||
uint32_t tested = (1<<parity)-1;
|
||||
if((nextop&0xC0)==0xC0)
|
||||
@@ -289,7 +282,7 @@ int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, i
|
||||
return (tmp&tested)?0:1;
|
||||
}
|
||||
} else {
|
||||
if(sib_reg==4)
|
||||
if(sib_reg==4 && parity<3)
|
||||
return 0; // simple [reg]
|
||||
// don't try [reg1 + reg2<<N], unless reg1 is ESP
|
||||
return ((sib&0x7)==4 && (sib>>6)>=parity)?1:0;
|
||||
@@ -303,9 +296,36 @@ int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, i
|
||||
} else {
|
||||
return 0; //Form [reg1 + reg2<<N + XXXXXX]
|
||||
}
|
||||
}
|
||||
|
||||
// Do the GETED, but don't emit anything...
|
||||
uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop)
|
||||
{
|
||||
if((nextop&0xC0)==0xC0)
|
||||
return addr;
|
||||
if(!(nextop&0xC0)) {
|
||||
if((nextop&7)==4) {
|
||||
uint8_t sib = F8;
|
||||
if((sib&0x7)==5) {
|
||||
addr+=4;
|
||||
}
|
||||
} else if((nextop&7)==5) {
|
||||
addr+=4;
|
||||
}
|
||||
} else {
|
||||
if((nextop&7)==4) {
|
||||
++addr;
|
||||
}
|
||||
if(nextop&0x80) {
|
||||
addr+=4;
|
||||
} else {
|
||||
++addr;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
#undef F8
|
||||
#undef F32
|
||||
}
|
||||
|
||||
int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn)
|
||||
{
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
|
||||
void arm_popf(x86emu_t* emu, uint32_t f);
|
||||
void arm_popf16(x86emu_t* emu, uint32_t f);
|
||||
void arm_fstp(x86emu_t* emu, void* p);
|
||||
|
||||
void arm_print_armreg(x86emu_t* emu, uintptr_t reg, uintptr_t n);
|
||||
@@ -25,6 +23,7 @@ void arm_fbld(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_fild64(x86emu_t* emu, int64_t* ed);
|
||||
void arm_fbstp(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_fistp64(x86emu_t* emu, int64_t* ed);
|
||||
void arm_fistt64(x86emu_t* emu, int64_t* ed);
|
||||
void arm_fld(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_fsave(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_frstor(x86emu_t* emu, uint8_t* ed);
|
||||
@@ -53,6 +52,8 @@ void fpu_reset_reg(dynarec_arm_t* dyn);
|
||||
|
||||
// Get if ED will have the correct parity. Not emiting anything. Parity is 2 for DWORD or 3 for QWORD
|
||||
int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity);
|
||||
// Do the GETED, but don't emit anything...
|
||||
uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop);
|
||||
|
||||
// Is what pointed at addr a native call? And if yes, to what function?
|
||||
int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn);
|
||||
|
||||
+159
-253
@@ -20,6 +20,7 @@
|
||||
#include "dynablock_private.h"
|
||||
#include "arm_printer.h"
|
||||
#include "../tools/bridge_private.h"
|
||||
#include "custommem.h"
|
||||
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
@@ -153,31 +154,6 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
return addr;
|
||||
}
|
||||
|
||||
// Do the GETED, but don't emit anything...
|
||||
uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop)
|
||||
{
|
||||
if(!(nextop&0xC0)) {
|
||||
if((nextop&7)==4) {
|
||||
uint8_t sib = F8;
|
||||
if((sib&0x7)==5) {
|
||||
addr+=4;
|
||||
}
|
||||
} else if((nextop&7)==5) {
|
||||
addr+=4;
|
||||
}
|
||||
} else {
|
||||
if((nextop&7)==4) {
|
||||
++addr;
|
||||
}
|
||||
if(nextop&0x80) {
|
||||
addr+=4;
|
||||
} else {
|
||||
++addr;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
/* setup r2 to address pointed by ED, r3 as scratch also fixaddress is an optionnal delta in the range [-absmax, +absmax], with delta&mask==0 to be added to ed for LDR/STR */
|
||||
uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int* fixaddress, uint32_t absmax, uint32_t mask)
|
||||
{
|
||||
@@ -268,181 +244,101 @@ void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
BX(2);
|
||||
}
|
||||
|
||||
void jump_to_linker(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
{
|
||||
MESSAGE(LOG_DUMP, "Jump to linker (#%d) nolinker=%d\n", dyn->tablei, dyn->nolinker);
|
||||
int j32;
|
||||
MAYUSE(j32);
|
||||
if(dyn->nolinker==2) {
|
||||
jump_to_epilog(dyn, ip, reg, ninst);
|
||||
MESSAGE(LOG_DUMP, "Jump to next\n");
|
||||
|
||||
if(reg) {
|
||||
if(reg!=xEIP) {
|
||||
MOV_REG(xEIP, reg);
|
||||
}
|
||||
MOV32(x2, getJumpTable());
|
||||
MOV_REG_LSR_IMM5(x3, xEIP, JMPTABL_SHIFT);
|
||||
LDR_REG_LSL_IMM5(x2, x2, x3, 2); // shiftsizeof(uintptr_t)
|
||||
UBFX(x3, xEIP, 0, JMPTABL_SHIFT);
|
||||
LDR_REG_LSL_IMM5(x3, x2, x3, 2); // shiftsizeof(uintptr_t)
|
||||
} else {
|
||||
if(reg) {
|
||||
if(reg!=xEIP) {
|
||||
MOV_REG(xEIP, reg);
|
||||
}
|
||||
} else {
|
||||
MOV32_(xEIP, ip);
|
||||
}
|
||||
uintptr_t* table = 0;
|
||||
if(dyn->tablesz) {
|
||||
table = &dyn->table[dyn->tablei];
|
||||
table[0] = (uintptr_t)arm_linker;
|
||||
table[1] = ip;
|
||||
}
|
||||
dyn->tablei+=4; // smart linker or not, we keep table correctly alligned for LDREXD/STREXD access
|
||||
MOV32_(x1, (uintptr_t)table);
|
||||
// TODO: This is not thread safe.
|
||||
if(!ip) { // no IP, jump address in a reg, so need smart linker
|
||||
#if 0
|
||||
//version thread safe
|
||||
MARK;
|
||||
LDREXD(x2, x1); // load dest address in x2 and planned ip in x3
|
||||
CMPS_REG_LSL_IMM5(xEIP, x3, 0);
|
||||
BXcond(cEQ, x2);
|
||||
MOV32_(x2, (uintptr_t)arm_linker);
|
||||
MOV_REG(x3, x12);
|
||||
STREXD(x12, x2, x1); // nope, putting back linker & IP in place
|
||||
// x12 now contain success / falure for write
|
||||
CMPS_IMM8(x12, 1);
|
||||
MOV_REG(x12, x3); // put back IP in place...
|
||||
B_MARK(cEQ);
|
||||
BX(x2); // go to linker
|
||||
#else
|
||||
// not thread safe, is that still ok?
|
||||
LDRD_IMM8(x2, x1, 0);
|
||||
CMPS_REG_LSL_IMM5(xEIP, x3, 0);
|
||||
BXcond(cEQ, x2);
|
||||
MOV32_(x2, (uintptr_t)arm_linker);
|
||||
MOV_REG(x3, x12);
|
||||
STRD_IMM8(x2, x1, 0);
|
||||
BX(x2);
|
||||
#endif
|
||||
} else {
|
||||
LDR_IMM9(x2, x1, 0);
|
||||
BX(x2); // jump
|
||||
}
|
||||
uintptr_t p = getJumpTableAddress(ip);
|
||||
MOV32(x2, p);
|
||||
MOV32_(xEIP, ip);
|
||||
LDR_IMM9(x3, x2, 0);
|
||||
}
|
||||
MOV_REG(x1, xEIP);
|
||||
#ifdef HAVE_TRACE
|
||||
MOV_REG(x2, 15); // move current PC to x2, for tracing
|
||||
#endif
|
||||
BX(x3);
|
||||
}
|
||||
|
||||
void ret_to_epilog(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
// using linker here doesn't seem to bring any significant speed improvment. To much change in the jump table probably
|
||||
#if 0
|
||||
int i32;
|
||||
MAYUSE(i32);
|
||||
if(dyn->nolinker) {
|
||||
#endif
|
||||
MESSAGE(LOG_DUMP, "Ret epilog\n");
|
||||
POP(xESP, 1<<xEIP);
|
||||
cstack_pop(dyn, ninst, xEIP, x1, x2);
|
||||
PASS3(void* epilog = arm_epilog);
|
||||
MOV32_(x2, (uintptr_t)epilog);
|
||||
BX(x2);
|
||||
#if 0
|
||||
} else {
|
||||
MESSAGE(LOG_DUMP, "Ret epilog with linker\n");
|
||||
POP(xESP, 1<<xEIP);
|
||||
uintptr_t* table = 0;
|
||||
if(dyn->tablesz) {
|
||||
table = &dyn->table[dyn->tablei];
|
||||
table[0] = (uintptr_t)arm_linker;
|
||||
table[1] = 0;
|
||||
}
|
||||
dyn->tablei+=4; // smart linker
|
||||
MOV32_(x1, (uintptr_t)table);
|
||||
MARK;
|
||||
LDREXD(x2, x1); // load dest address in x2 and planned ip in x3
|
||||
CMPS_REG_LSL_IMM5(xEIP, x3, 0);
|
||||
BXcond(cEQ, x2);
|
||||
MOV32_(x2, (uintptr_t)arm_linker);
|
||||
MOV_REG(x3, x12);
|
||||
STREXD(x12, x2, x1); // nope, putting back linker & IP in place
|
||||
// x12 now contain success / falure for write
|
||||
CMPS_IMM8(x12, 1);
|
||||
MOV_REG(x12, x3); // put back IP in place...
|
||||
B_MARK(cEQ);
|
||||
BX(x2); // go to linker
|
||||
}
|
||||
#endif
|
||||
MESSAGE(LOG_DUMP, "Ret next\n");
|
||||
POP1(xEIP);
|
||||
MOV32(x2, getJumpTable());
|
||||
MOV_REG_LSR_IMM5(x3, xEIP, JMPTABL_SHIFT);
|
||||
LDR_REG_LSL_IMM5(x2, x2, x3, 2); // shiftsizeof(uintptr_t)
|
||||
UBFX(x3, xEIP, 0, JMPTABL_SHIFT);
|
||||
LDR_REG_LSL_IMM5(x3, x2, x3, 2); // shiftsizeof(uintptr_t)
|
||||
MOV_REG(x1, xEIP);
|
||||
#ifdef HAVE_TRACE
|
||||
MOV_REG(x2, 15); // move current PC to x2, for tracing
|
||||
#endif
|
||||
BX(x3);
|
||||
}
|
||||
|
||||
void retn_to_epilog(dynarec_arm_t* dyn, int ninst, int n)
|
||||
{
|
||||
#if 0
|
||||
int i32;
|
||||
MAYUSE(i32);
|
||||
if(dyn->nolinker) {
|
||||
#endif
|
||||
MESSAGE(LOG_DUMP, "Retn epilog\n");
|
||||
POP(xESP, 1<<xEIP);
|
||||
POP1(xEIP);
|
||||
if(n>0xff) {
|
||||
MOVW(x1, n);
|
||||
ADD_REG_LSL_IMM5(xESP, xESP, x1, 0);
|
||||
} else {
|
||||
ADD_IMM8(xESP, xESP, n);
|
||||
}
|
||||
cstack_pop(dyn, ninst, xEIP, x1, x2);
|
||||
PASS3(void* epilog = arm_epilog);
|
||||
MOV32_(x2, (uintptr_t)epilog);
|
||||
BX(x2);
|
||||
#if 0
|
||||
} else {
|
||||
MESSAGE(LOG_DUMP, "Retn epilog with linker\n");
|
||||
POP(xESP, 1<<xEIP);
|
||||
ADD_IMM8(xESP, xESP, n);
|
||||
uintptr_t* table = 0;
|
||||
if(dyn->tablesz) {
|
||||
table = &dyn->table[dyn->tablei];
|
||||
table[0] = (uintptr_t)arm_linker;
|
||||
table[1] = 0;
|
||||
}
|
||||
dyn->tablei+=4; // smart linker
|
||||
MOV32_(x1, (uintptr_t)table);
|
||||
MARK;
|
||||
LDREXD(x2, x1); // load dest address in x2 and planned ip in x3
|
||||
CMPS_REG_LSL_IMM5(xEIP, x3, 0);
|
||||
BXcond(cEQ, x2);
|
||||
MOV32_(x2, (uintptr_t)arm_linker);
|
||||
MOV_REG(x3, x12);
|
||||
STREXD(x12, x2, x1); // nope, putting back linker & IP in place
|
||||
// x12 now contain success / falure for write
|
||||
CMPS_IMM8(x12, 1);
|
||||
MOV_REG(x12, x3); // put back IP in place...
|
||||
B_MARK(cEQ);
|
||||
BX(x2); // go to linker
|
||||
}
|
||||
#endif
|
||||
MOV32(x2, getJumpTable());
|
||||
MOV_REG_LSR_IMM5(x3, xEIP, JMPTABL_SHIFT);
|
||||
LDR_REG_LSL_IMM5(x2, x2, x3, 2); // shiftsizeof(uintptr_t)
|
||||
UBFX(x3, xEIP, 0, JMPTABL_SHIFT);
|
||||
LDR_REG_LSL_IMM5(x3, x2, x3, 2); // shiftsizeof(uintptr_t)
|
||||
MOV_REG(x1, xEIP);
|
||||
#ifdef HAVE_TRACE
|
||||
MOV_REG(x2, 15); // move current PC to x2, for tracing
|
||||
#endif
|
||||
BX(x3);
|
||||
}
|
||||
|
||||
void iret_to_epilog(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
MESSAGE(LOG_DUMP, "IRet epilog\n");
|
||||
// POP IP
|
||||
POP(xESP, 1<<xEIP);
|
||||
POP1(xEIP);
|
||||
// POP CS
|
||||
MOVW(x1, offsetof(x86emu_t, segs[_CS]));
|
||||
POP(xESP, 1<<x2);
|
||||
POP1(x2);
|
||||
STRH_REG(x2, xEmu, x1);
|
||||
MOVW(x1, 0);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, segs_serial[_CS]));
|
||||
// POP EFLAGS
|
||||
POP(xESP, (1<<x1));
|
||||
CALL(arm_popf, -1, (1<<xEIP));
|
||||
MOVW(x1, d_none);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, df));
|
||||
POP1(xFlags);
|
||||
MOV32(x1, 0x3F7FD7);
|
||||
AND_REG_LSL_IMM5(xFlags, xFlags, x1, 0);
|
||||
ORR_IMM8(xFlags, xFlags, 2, 0);
|
||||
SET_DFNONE(x1);
|
||||
// Ret....
|
||||
cstack_pop(dyn, ninst, xEIP, x1, x2);
|
||||
PASS3(void* epilog = arm_epilog);
|
||||
MOV32_(x2, (uintptr_t)epilog);
|
||||
MOV32_(x2, (uintptr_t)arm_epilog); // epilog on purpose, CS might have changed!
|
||||
BX(x2);
|
||||
}
|
||||
|
||||
void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, uint32_t mask)
|
||||
void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, uint32_t mask, int saveflags)
|
||||
{
|
||||
if(ret!=-2) {
|
||||
PUSH(xSP, (1<<xEmu) | mask);
|
||||
}
|
||||
fpu_pushcache(dyn, ninst, reg);
|
||||
if(saveflags) {
|
||||
STR_IMM9(xFlags, xEmu, offsetof(x86emu_t, eflags));
|
||||
}
|
||||
MOV32(reg, (uintptr_t)fnc);
|
||||
BLX(reg);
|
||||
fpu_popcache(dyn, ninst, reg);
|
||||
@@ -452,6 +348,10 @@ void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, uint32_t
|
||||
if(ret!=-2) {
|
||||
POP(xSP, (1<<xEmu) | mask);
|
||||
}
|
||||
if(saveflags) {
|
||||
LDR_IMM9(xFlags, xEmu, offsetof(x86emu_t, eflags));
|
||||
}
|
||||
SET_NODF();
|
||||
}
|
||||
|
||||
void grab_tlsdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg)
|
||||
@@ -460,13 +360,13 @@ void grab_tlsdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg)
|
||||
int32_t j32;
|
||||
MAYUSE(j32);
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, context));
|
||||
LDR_IMM9(x12, xEmu, offsetof(x86emu_t, segs_serial[_GS])); // complete check here
|
||||
LDR_IMM9(x14, xEmu, offsetof(x86emu_t, segs_serial[_GS])); // complete check here
|
||||
LDR_IMM9(x1, x1, offsetof(box86context_t, sel_serial));
|
||||
CMPS_REG_LSL_IMM5(x12, x1, 0);
|
||||
CMPS_REG_LSL_IMM5(x14, x1, 0);
|
||||
LDR_IMM9_COND(cEQ, reg, xEmu, offsetof(x86emu_t, segs_offs[_GS]));
|
||||
B_MARKSEG(cEQ);
|
||||
MOVW(x1, _GS);
|
||||
call_c(dyn, ninst, GetSegmentBaseEmu, 12, reg, 0);
|
||||
call_c(dyn, ninst, GetSegmentBaseEmu, x14, reg, 0, 1);
|
||||
MARKSEG;
|
||||
MESSAGE(LOG_DUMP, "----TLSData\n");
|
||||
}
|
||||
@@ -476,12 +376,12 @@ void grab_fsdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg)
|
||||
int32_t j32;
|
||||
MAYUSE(j32);
|
||||
MESSAGE(LOG_DUMP, "Get FS: Offset\n");
|
||||
LDR_IMM9(x12, xEmu, offsetof(x86emu_t, segs_serial[_FS]));// fast check here
|
||||
CMPS_IMM8(x12, 0);
|
||||
LDR_IMM9(x14, xEmu, offsetof(x86emu_t, segs_serial[_FS]));// fast check here
|
||||
CMPS_IMM8(x14, 0);
|
||||
LDR_IMM9_COND(cNE, reg, xEmu, offsetof(x86emu_t, segs_offs[_FS]));
|
||||
B_MARKSEG(cNE);
|
||||
MOVW(x1, _FS);
|
||||
call_c(dyn, ninst, GetSegmentBaseEmu, 12, reg, 0);
|
||||
call_c(dyn, ninst, GetSegmentBaseEmu, x14, reg, 0, 1);
|
||||
MARKSEG;
|
||||
MESSAGE(LOG_DUMP, "----FS: Offset\n");
|
||||
}
|
||||
@@ -490,6 +390,7 @@ void grab_fsdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg)
|
||||
static void x87_reset(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
#if STEP > 1
|
||||
dyn->x87count = 0;
|
||||
for (int i=0; i<8; ++i)
|
||||
dyn->x87cache[i] = -1;
|
||||
dyn->x87stack = 0;
|
||||
@@ -501,6 +402,8 @@ void x87_stackcount(dynarec_arm_t* dyn, int ninst, int scratch)
|
||||
#if STEP > 1
|
||||
if(!dyn->x87stack)
|
||||
return;
|
||||
if(dyn->mmxcount)
|
||||
mmx_purgecache(dyn, ninst, scratch);
|
||||
MESSAGE(LOG_DUMP, "\tSynch x87 Stackcount (%d)\n", dyn->x87stack);
|
||||
int a = dyn->x87stack;
|
||||
// Add x87stack to emu fpu_stack
|
||||
@@ -526,9 +429,12 @@ void x87_stackcount(dynarec_arm_t* dyn, int ninst, int scratch)
|
||||
#endif
|
||||
}
|
||||
|
||||
int x87_do_push(dynarec_arm_t* dyn, int ninst)
|
||||
int x87_do_push(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
#if STEP > 1
|
||||
if(dyn->mmxcount)
|
||||
mmx_purgecache(dyn, ninst, s1);
|
||||
++dyn->x87count;
|
||||
dyn->x87stack+=1;
|
||||
// move all regs in cache, and find a free one
|
||||
int ret = -1;
|
||||
@@ -547,6 +453,9 @@ int x87_do_push(dynarec_arm_t* dyn, int ninst)
|
||||
void x87_do_push_empty(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
#if STEP > 1
|
||||
if(dyn->mmxcount)
|
||||
mmx_purgecache(dyn, ninst, s1);
|
||||
++dyn->x87count;
|
||||
dyn->x87stack+=1;
|
||||
// move all regs in cache
|
||||
for(int i=0; i<8; ++i)
|
||||
@@ -556,9 +465,11 @@ void x87_do_push_empty(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
x87_stackcount(dyn, ninst, s1);
|
||||
#endif
|
||||
}
|
||||
void x87_do_pop(dynarec_arm_t* dyn, int ninst)
|
||||
void x87_do_pop(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
#if STEP > 1
|
||||
if(dyn->mmxcount)
|
||||
mmx_purgecache(dyn, ninst, s1);
|
||||
dyn->x87stack-=1;
|
||||
// move all regs in cache, poping ST0
|
||||
for(int i=0; i<8; ++i)
|
||||
@@ -569,12 +480,14 @@ void x87_do_pop(dynarec_arm_t* dyn, int ninst)
|
||||
dyn->x87reg[i] = -1;
|
||||
}
|
||||
}
|
||||
--dyn->x87count;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void x87_purgecache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
void x87_purgecache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
#if STEP > 1
|
||||
dyn->x87count = 0;
|
||||
int ret = 0;
|
||||
for (int i=0; i<8 && !ret; ++i)
|
||||
if(dyn->x87cache[i] != -1)
|
||||
@@ -635,10 +548,10 @@ static void x87_purgecache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3
|
||||
if(ret!=0) {
|
||||
// --- set values
|
||||
// prepare offset to fpu => s1
|
||||
if(offsetof(x86emu_t, fpu)<256) {
|
||||
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, fpu));
|
||||
if(offsetof(x86emu_t, mmx87)<256) {
|
||||
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, mmx87));
|
||||
} else {
|
||||
MOVW(s1, offsetof(x86emu_t, fpu));
|
||||
MOVW(s1, offsetof(x86emu_t, mmx87));
|
||||
ADD_REG_LSL_IMM5(s1, xEmu, s1, 0);
|
||||
}
|
||||
// Get top
|
||||
@@ -669,10 +582,10 @@ static void x87_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
if(!ret) // nothing to do
|
||||
return;
|
||||
// prepare offset to fpu => s1
|
||||
if(offsetof(x86emu_t, fpu)<256) {
|
||||
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, fpu));
|
||||
if(offsetof(x86emu_t, mmx87)<256) {
|
||||
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, mmx87));
|
||||
} else {
|
||||
MOVW(s1, offsetof(x86emu_t, fpu));
|
||||
MOVW(s1, offsetof(x86emu_t, mmx87));
|
||||
ADD_REG_LSL_IMM5(s1, xEmu, s1, 0);
|
||||
}
|
||||
// Get top
|
||||
@@ -692,6 +605,8 @@ static void x87_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
int x87_get_cache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
{
|
||||
#if STEP > 1
|
||||
if(dyn->mmxcount)
|
||||
mmx_purgecache(dyn, ninst, s1);
|
||||
// search in cache first
|
||||
for (int i=0; i<8; ++i)
|
||||
if(dyn->x87cache[i]==st)
|
||||
@@ -705,10 +620,11 @@ int x87_get_cache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
// found, setup and grab the value
|
||||
dyn->x87cache[ret] = st;
|
||||
dyn->x87reg[ret] = fpu_get_reg_double(dyn);
|
||||
if(offsetof(x86emu_t, fpu)<256) {
|
||||
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, fpu));
|
||||
++dyn->x87count;
|
||||
if(offsetof(x86emu_t, mmx87)<256) {
|
||||
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, mmx87));
|
||||
} else {
|
||||
MOVW(s1, offsetof(x86emu_t, fpu));
|
||||
MOVW(s1, offsetof(x86emu_t, mmx87));
|
||||
ADD_REG_LSL_IMM5(s1, xEmu, s1, 0);
|
||||
}
|
||||
LDR_IMM9(s2, xEmu, offsetof(x86emu_t, top));
|
||||
@@ -753,10 +669,10 @@ void x87_refresh(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
return;
|
||||
MESSAGE(LOG_DUMP, "\tRefresh x87 Cache for ST%d\n", st);
|
||||
// prepare offset to fpu => s1
|
||||
if(offsetof(x86emu_t, fpu)<256) {
|
||||
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, fpu));
|
||||
if(offsetof(x86emu_t, mmx87)<256) {
|
||||
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, mmx87));
|
||||
} else {
|
||||
MOVW(s1, offsetof(x86emu_t, fpu));
|
||||
MOVW(s1, offsetof(x86emu_t, mmx87));
|
||||
ADD_REG_LSL_IMM5(s1, xEmu, s1, 0);
|
||||
}
|
||||
// Get top
|
||||
@@ -784,10 +700,10 @@ void x87_forget(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
return;
|
||||
MESSAGE(LOG_DUMP, "\tForget x87 Cache for ST%d\n", st);
|
||||
// prepare offset to fpu => s1
|
||||
if(offsetof(x86emu_t, fpu)<256) {
|
||||
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, fpu));
|
||||
if(offsetof(x86emu_t, mmx87)<256) {
|
||||
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, mmx87));
|
||||
} else {
|
||||
MOVW(s1, offsetof(x86emu_t, fpu));
|
||||
MOVW(s1, offsetof(x86emu_t, mmx87));
|
||||
ADD_REG_LSL_IMM5(s1, xEmu, s1, 0);
|
||||
}
|
||||
// Get top
|
||||
@@ -804,21 +720,24 @@ void x87_forget(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
fpu_free_reg_double(dyn, dyn->x87reg[ret]);
|
||||
dyn->x87cache[ret] = -1;
|
||||
dyn->x87reg[ret] = -1;
|
||||
--dyn->x87count;
|
||||
#endif
|
||||
}
|
||||
|
||||
void x87_reget_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
{
|
||||
#if STEP > 1
|
||||
if(dyn->mmxcount)
|
||||
mmx_purgecache(dyn, ninst, s1);
|
||||
// search in cache first
|
||||
for (int i=0; i<8; ++i)
|
||||
if(dyn->x87cache[i]==st) {
|
||||
// refresh the value
|
||||
MESSAGE(LOG_DUMP, "\tRefresh x87 Cache for ST%d\n", st);
|
||||
if(offsetof(x86emu_t, fpu)<256) {
|
||||
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, fpu));
|
||||
if(offsetof(x86emu_t, mmx87)<256) {
|
||||
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, mmx87));
|
||||
} else {
|
||||
MOVW(s1, offsetof(x86emu_t, fpu));
|
||||
MOVW(s1, offsetof(x86emu_t, mmx87));
|
||||
ADD_REG_LSL_IMM5(s1, xEmu, s1, 0);
|
||||
}
|
||||
LDR_IMM9(s2, xEmu, offsetof(x86emu_t, top));
|
||||
@@ -845,10 +764,11 @@ void x87_reget_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
// found, setup and grab the value
|
||||
dyn->x87cache[ret] = st;
|
||||
dyn->x87reg[ret] = fpu_get_reg_double(dyn);
|
||||
if(offsetof(x86emu_t, fpu)<256) {
|
||||
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, fpu));
|
||||
++dyn->x87count;
|
||||
if(offsetof(x86emu_t, mmx87)<256) {
|
||||
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, mmx87));
|
||||
} else {
|
||||
MOVW(s1, offsetof(x86emu_t, fpu));
|
||||
MOVW(s1, offsetof(x86emu_t, mmx87));
|
||||
ADD_REG_LSL_IMM5(s1, xEmu, s1, 0);
|
||||
}
|
||||
LDR_IMM9(s2, xEmu, offsetof(x86emu_t, top));
|
||||
@@ -881,6 +801,20 @@ int x87_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
return s3;
|
||||
}
|
||||
|
||||
// Set rounding according to mxcsr flags, return reg to restore flags
|
||||
int sse_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
LDRH_IMM8(s1, xEmu, offsetof(x86emu_t, mxcsr));
|
||||
UBFX(s2, s1, 13, 2); // extract round...
|
||||
MOV32(s1, round_map);
|
||||
LDR_REG_LSL_IMM5(s2, s1, s2, 2);
|
||||
VMRS(s1); // get fpscr
|
||||
MOV_REG(s3, s1);
|
||||
BFI(s1, s2, 22, 2); // inject new round
|
||||
VMSR(s1); // put new fpscr
|
||||
return s3;
|
||||
}
|
||||
|
||||
// Restore round flag
|
||||
void x87_restoreround(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
@@ -891,18 +825,22 @@ void x87_restoreround(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
static void mmx_reset(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
#if STEP > 1
|
||||
dyn->mmxcount = 0;
|
||||
for (int i=0; i<8; ++i)
|
||||
dyn->mmxcache[i] = -1;
|
||||
#endif
|
||||
}
|
||||
// get neon register for a MMX reg, create the entry if needed
|
||||
int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a)
|
||||
int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a)
|
||||
{
|
||||
#if STEP > 1
|
||||
if(dyn->x87count)
|
||||
x87_purgecache(dyn, ninst, s1, s2, s3);
|
||||
if(dyn->mmxcache[a]!=-1)
|
||||
return dyn->mmxcache[a];
|
||||
++dyn->mmxcount;
|
||||
int ret = dyn->mmxcache[a] = fpu_get_reg_double(dyn);
|
||||
int offs = offsetof(x86emu_t, mmx[a]);
|
||||
int offs = offsetof(x86emu_t, mmx87[a]);
|
||||
if(!(offs&3) && (offs>>2)<256) {
|
||||
ADD_IMM8_ROR(s1, xEmu, offs>>2, 15);
|
||||
} else {
|
||||
@@ -916,11 +854,14 @@ int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a)
|
||||
#endif
|
||||
}
|
||||
// get neon register for a MMX reg, but don't try to synch it if it needed to be created
|
||||
int mmx_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a)
|
||||
int mmx_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a)
|
||||
{
|
||||
#if STEP > 1
|
||||
if(dyn->x87count)
|
||||
x87_purgecache(dyn, ninst, s1, s2, s3);
|
||||
if(dyn->mmxcache[a]!=-1)
|
||||
return dyn->mmxcache[a];
|
||||
++dyn->mmxcount;
|
||||
int ret = dyn->mmxcache[a] = fpu_get_reg_double(dyn);
|
||||
return ret;
|
||||
#else
|
||||
@@ -928,15 +869,18 @@ int mmx_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a)
|
||||
#endif
|
||||
}
|
||||
// purge the MMX cache only(needs 3 scratch registers)
|
||||
static void mmx_purgecache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
void mmx_purgecache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
#if STEP > 1
|
||||
if(!dyn->mmxcount)
|
||||
return;
|
||||
dyn->mmxcount = 0;
|
||||
int old = -1;
|
||||
for (int i=0; i<8; ++i)
|
||||
if(dyn->mmxcache[i]!=-1) {
|
||||
if (old==-1) {
|
||||
MESSAGE(LOG_DUMP, "\tPurge MMX Cache ------\n");
|
||||
int offs = offsetof(x86emu_t, mmx[i]);
|
||||
int offs = offsetof(x86emu_t, mmx87[i]);
|
||||
if(!(offs&3) && (offs>>2)<256) {
|
||||
ADD_IMM8_ROR(s1, xEmu, offs>>2, 15);
|
||||
} else {
|
||||
@@ -967,7 +911,7 @@ static void mmx_reflectcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
for (int i=0; i<8; ++i)
|
||||
if(dyn->mmxcache[i]!=-1) {
|
||||
if (old==-1) {
|
||||
int offs = offsetof(x86emu_t, mmx[i]);
|
||||
int offs = offsetof(x86emu_t, mmx87[i]);
|
||||
if(!(offs&3) && (offs>>2)<256) {
|
||||
ADD_IMM8_ROR(s1, xEmu, offs>>2, 15);
|
||||
} else {
|
||||
@@ -1093,8 +1037,8 @@ void fpu_pushcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
#if STEP > 1
|
||||
// only need to push 16-31...
|
||||
int n=0;
|
||||
for (int i=8; i<24; i++)
|
||||
if(dyn->fpuused[i])
|
||||
for (int i=16; i<32; i++)
|
||||
if(dyn->fpuused[i-8])
|
||||
++n;
|
||||
if(!n)
|
||||
return;
|
||||
@@ -1106,10 +1050,9 @@ void fpu_pushcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
SUB_IMM8(xSP, xSP, n*8);
|
||||
}
|
||||
MOV_REG(s1, xSP);
|
||||
for (int i=0; i<n; ++i) { // should use VSTM?
|
||||
if(dyn->fpuused[i+8]) {
|
||||
PASS3(int a = 16+i);
|
||||
VST1_32_W(a, s1);
|
||||
for (int i=16; i<32; ++i) { // should use VSTM?
|
||||
if(dyn->fpuused[i-8]) {
|
||||
VST1_32_W(i, s1);
|
||||
}
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "\t------- Push FPU Cache (%d)\n", n);
|
||||
@@ -1121,17 +1064,16 @@ void fpu_popcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
#if STEP > 1
|
||||
// only need to push 16-31...
|
||||
int n=0;
|
||||
for (int i=8; i<24; i++)
|
||||
if(dyn->fpuused[i])
|
||||
for (int i=16; i<32; i++)
|
||||
if(dyn->fpuused[i-8])
|
||||
++n;
|
||||
if(!n)
|
||||
return;
|
||||
MESSAGE(LOG_DUMP, "\tPop FPU Cache (%d)------\n", n);
|
||||
MOV_REG(s1, xSP);
|
||||
for (int i=0; i<n; ++i) {
|
||||
if(dyn->fpuused[i+8]) {
|
||||
PASS3(int a = 16+i);
|
||||
VLD1_32_W(a, s1);
|
||||
for (int i=16; i<32; ++i) {
|
||||
if(dyn->fpuused[i-8]) {
|
||||
VLD1_32_W(i, s1);
|
||||
}
|
||||
}
|
||||
if(n>=8) {
|
||||
@@ -1192,49 +1134,13 @@ void fpu_putback_single_reg(dynarec_arm_t* dyn, int ninst, int reg, int idx, int
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// PUSH a x86/native couple of address in cstack, using s1, s2, s2+1
|
||||
void cstack_push(dynarec_arm_t* dyn, int ninst, uintptr_t x86ip, uintptr_t armip, int s1, int s2)
|
||||
void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
if(x86ip)
|
||||
armip+=dyn->arm_start;
|
||||
MESSAGE(LOG_DUMP, "CStack PUSH %p/%p-----\n", (void*)x86ip, (void*)armip);
|
||||
// load current indice
|
||||
LDR_IMM9(s2, xEmu, offsetof(x86emu_t, cstacki));
|
||||
// calcule offset in the cstack
|
||||
MOV32(s1, offsetof(x86emu_t, cstack));
|
||||
TSTS_IMM8(xEmu, 0x04); // test if x86emu_t struct is not 0x8 aligned
|
||||
ADD_IMM8_cond(cNE, s1, s1, 4); // align...
|
||||
ADD_REG_LSL_IMM5(s1, s1, s2, 3); //*8, because it's a pair of address
|
||||
// increment (mod mask) and save back index
|
||||
ADD_IMM8(s2, s2, 1);
|
||||
AND_IMM8(s2, s2, CSTACKMASK);
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, cstacki));
|
||||
// push the pair of address
|
||||
MOV32(s2, x86ip);
|
||||
MOV32_(s2+1, armip);
|
||||
STRD_REG(s2, xEmu, s1);
|
||||
MESSAGE(LOG_DUMP, "--------------CStack PUSH\n");
|
||||
}
|
||||
|
||||
// POP a x86/native couple of address from cstack, and generate the jump is x86 address is s0, use s1, s2 and s2+1 as scratch
|
||||
void cstack_pop(dynarec_arm_t* dyn, int ninst, int s0, int s1, int s2)
|
||||
{
|
||||
MESSAGE(LOG_DUMP, "CStack POP----------------\n");
|
||||
// load current indice
|
||||
LDR_IMM9(s1, xEmu, offsetof(x86emu_t, cstacki));
|
||||
// decrement (mod mask) and save back index
|
||||
SUB_IMM8(s1, s1, 1);
|
||||
AND_IMM8(s1, s1, CSTACKMASK);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, cstacki));
|
||||
// calcule offset in the cstack
|
||||
MOV32(s2, offsetof(x86emu_t, cstack));
|
||||
TSTS_IMM8(xEmu, 0x04); // test if x86emu_t struct is not 0x8 aligned
|
||||
ADD_IMM8_cond(cNE, s2, s2, 4); // align...
|
||||
ADD_REG_LSL_IMM5(s1, s2, s1, 3); //*8, because it's a pair of address
|
||||
// pop the pair of address
|
||||
LDRD_REG(s2, xEmu, s1);
|
||||
CMPS_REG_LSL_IMM5(s0, s2, 0);
|
||||
BXcond(cEQ, s2+1);
|
||||
MESSAGE(LOG_DUMP, "----------------CStack POP\n");
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
|
||||
MOV32(s4, GetParityTab());
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
AND_IMM8(s3, s1, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
@@ -69,6 +69,16 @@
|
||||
LDR_REG_LSL_IMM5(x1, wback, O, 0); \
|
||||
ed = x1; \
|
||||
}
|
||||
//GETEDO can use r1 for ed, and r2 for wback. wback is 0 if ed is xEAX..xEDI, else O is added to wback
|
||||
#define GETEDO2(O) if((nextop&0xC0)==0xC0) { \
|
||||
ed = xEAX+(nextop&7); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0); \
|
||||
ADD_REG_LSL_IMM5(wback, wback, O, 0);\
|
||||
LDR_IMM9(x1, wback, 0); \
|
||||
ed = x1; \
|
||||
}
|
||||
#define WBACKO(O) if(wback) {STR_REG_LSL_IMM5(ed, wback, O, 0);}
|
||||
//FAKEELike GETED, but doesn't get anything
|
||||
#define FAKEED if((nextop&0xC0)!=0xC0) { \
|
||||
@@ -179,18 +189,22 @@
|
||||
#define GBBACK BFI(gb1, gd, gb2*8, 8);
|
||||
|
||||
// Get Direction with size Z and based of F_DF flag, on register r ready for LDR/STR fetching
|
||||
// F_DF is 1<<10, so 1 ROR 11*2 (so F_OF)
|
||||
#define GETDIR(r, A) \
|
||||
LDR_IMM9(r, xEmu, offsetof(x86emu_t, flags[F_DF])); \
|
||||
CMPS_IMM8(r, 1); \
|
||||
MOVW(r, A); \
|
||||
RSB_COND_IMM8(cEQ, r, r, 0)
|
||||
TSTS_IMM8_ROR(xFlags, 1, 0x0b); \
|
||||
MOVW(r, A); \
|
||||
RSB_COND_IMM8(cNE, r, r, 0)
|
||||
|
||||
// CALL will use x12 for the call address. Return value can be put in ret (unless ret is -1)
|
||||
// CALL will use x14 for the call address. Return value can be put in ret (unless ret is -1)
|
||||
// R0 will not be pushed/popd if ret is -2
|
||||
#define CALL(F, ret, M) call_c(dyn, ninst, F, x12, ret, M)
|
||||
#define CALL(F, ret, M) call_c(dyn, ninst, F, x14, ret, M, 1)
|
||||
// CALL_ will use x3 for the call address. Return value can be put in ret (unless ret is -1)
|
||||
// R0 will not be pushed/popd if ret is -2
|
||||
#define CALL_(F, ret, M) call_c(dyn, ninst, F, x3, ret, M)
|
||||
#define CALL_(F, ret, M) call_c(dyn, ninst, F, x3, ret, M, 1)
|
||||
// CALL_S will use x3 for the call address. Return value can be put in ret (unless ret is -1)
|
||||
// R0 will not be pushed/popd if ret is -2. Flags are not save/restored
|
||||
#define CALL_S(F, ret, M) call_c(dyn, ninst, F, x3, ret, M, 0)
|
||||
|
||||
#define MARK if(dyn->insts) {dyn->insts[ninst].mark = (uintptr_t)dyn->arm_size;}
|
||||
#define GETMARK ((dyn->insts)?dyn->insts[ninst].mark:(dyn->arm_size+4))
|
||||
#define MARK2 if(dyn->insts) {dyn->insts[ninst].mark2 = (uintptr_t)dyn->arm_size;}
|
||||
@@ -230,6 +244,7 @@
|
||||
Bcond(cond, j32)
|
||||
|
||||
#define IFX(A) if(dyn->insts && (dyn->insts[ninst].x86.need_flags&(A)))
|
||||
#define IFX_PENDOR0 if(dyn->insts && (dyn->insts[ninst].x86.need_flags&(X_PEND) || !dyn->insts[ninst].x86.need_flags))
|
||||
#define IFXX(A) if(dyn->insts && (dyn->insts[ninst].x86.need_flags==(A)))
|
||||
#define IFX2X(A, B) if(dyn->insts && (dyn->insts[ninst].x86.need_flags==(A) || dyn->insts[ninst].x86.need_flags==(B) || dyn->insts[ninst].x86.need_flags==((A)|(B))))
|
||||
#define IFXN(A, B) if(dyn->insts && (dyn->insts[ninst].x86.need_flags&(A) && !(dyn->insts[ninst].x86.need_flags&(B))))
|
||||
@@ -237,49 +252,40 @@
|
||||
// Generate FCOM with s1 and s2 scratch regs (the VCMP is already done)
|
||||
#define FCOM(s1, s2) \
|
||||
VMRS_APSR(); /* 0b0100011100000000 */ \
|
||||
LDRH_IMM8(s2, xEmu, offsetof(x86emu_t, sw)); /*offset is 8bits right?*/ \
|
||||
MOVW(s1, 0b0100011100000000); \
|
||||
BIC_REG_LSL_IMM5(s2, s2, s1, 0); \
|
||||
MOVW_COND(cVS, s1, 0b0100010100000000); /* unordered */ \
|
||||
MOVW_COND(cEQ, s1, 0b0100000000000000); /* zero */ \
|
||||
MOVW_COND(cGT, s1, 0b0000000000000000); /* greater than */ \
|
||||
MOVW_COND(cLO, s1, 0b0000000100000000); /* less than */ \
|
||||
ORR_REG_LSL_IMM5(s2, s2, s1, 0); \
|
||||
STRH_IMM8(s2, xEmu, offsetof(x86emu_t, sw))
|
||||
LDRH_IMM8(s1, xEmu, offsetof(x86emu_t, sw)); /*offset is 8bits right?*/ \
|
||||
BIC_IMM8(s1, s1, 0b01000111, 12); \
|
||||
ORR_IMM8_COND(cVS, s1, s1, 0b01000101, 12); /* unordered */ \
|
||||
ORR_IMM8_COND(cEQ, s1, s1, 0b01000000, 12); /* equal */ \
|
||||
ORR_IMM8_COND(cMI, s1, s1, 0b00000001, 12); /* less than */ \
|
||||
/* greater than leave 0 */ \
|
||||
STRH_IMM8(s1, xEmu, offsetof(x86emu_t, sw))
|
||||
|
||||
// Generate FCOMI with s1 and s2 scratch regs (the VCMP is already done)
|
||||
#define FCOMI(s1, s2) \
|
||||
VMRS_APSR(); /* 0b111 */ \
|
||||
XOR_REG_LSL_IMM5(s2, s2, s2, 0); \
|
||||
MOVW_COND(cVS, s1, 0b111); /* unordered */ \
|
||||
MOVW_COND(cEQ, s1, 0b100); /* zero */ \
|
||||
MOVW_COND(cGT, s1, 0b000); /* greater than */ \
|
||||
MOVW_COND(cLO, s1, 0b001); /* less than */ \
|
||||
IFX(X_CF|X_PEND) { \
|
||||
UBFX(s2, s1, 0, 1); \
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_CF]));\
|
||||
} \
|
||||
IFX(X_PF|X_PEND) { \
|
||||
UBFX(s2, s1, 1, 1); \
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_PF]));\
|
||||
} \
|
||||
IFX(X_ZF|X_PEND) { \
|
||||
UBFX(s2, s1, 2, 1); \
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_ZF]));\
|
||||
} \
|
||||
MOVW(s2, d_none); \
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, df)); \
|
||||
IFX(X_OF|X_PEND) { \
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_OF]));\
|
||||
} \
|
||||
IFX(X_AF|X_PEND) { \
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_AF]));\
|
||||
} \
|
||||
IFX(X_SF|X_PEND) { \
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_SF]));\
|
||||
} \
|
||||
IFX(X_CF|X_PF|X_ZF|X_PEND) { \
|
||||
VMRS_APSR(); /* 0b111 */ \
|
||||
BIC_IMM8(xFlags, xFlags, 0b1000101, 0); \
|
||||
ORR_IMM8_COND(cVS, xFlags, xFlags, 0b01000101, 0); /* unordered */ \
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 0b01000000, 0); /* zero */ \
|
||||
ORR_IMM8_COND(cMI, xFlags, xFlags, 0b00000001, 0); /* less than */ \
|
||||
/* greater than leave 0 */ \
|
||||
} \
|
||||
SET_DFNONE(s1); \
|
||||
IFX(X_OF|X_PEND) { \
|
||||
BFC(xFlags, F_OF, 1); \
|
||||
} \
|
||||
IFX(X_AF|X_PEND) { \
|
||||
BFC(xFlags, F_AF, 1); \
|
||||
} \
|
||||
IFX(X_SF|X_PEND) { \
|
||||
BFC(xFlags, F_SF, 1); \
|
||||
} \
|
||||
|
||||
|
||||
#define SET_DFNONE(S) if(!dyn->dfnone) {MOVW(S, d_none); STR_IMM9(S, xEmu, offsetof(x86emu_t, df)); dyn->dfnone=1;}
|
||||
#define SET_DF(S, N) if(N) {MOVW(S, N); STR_IMM9(S, xEmu, offsetof(x86emu_t, df)); dyn->dfnone=0;} else SET_DFNONE(S)
|
||||
#define SET_NODF() dyn->dfnone = 0
|
||||
#define SET_DFOK() dyn->dfnone = 1
|
||||
|
||||
#ifndef READFLAGS
|
||||
#define READFLAGS(A) \
|
||||
@@ -293,6 +299,7 @@
|
||||
CALL_(UpdateFlags, -1, 0); \
|
||||
MARKF; \
|
||||
dyn->state_flags = SF_SET; \
|
||||
SET_DFOK(); \
|
||||
}
|
||||
#endif
|
||||
#ifndef SETFLAGS
|
||||
@@ -310,11 +317,11 @@
|
||||
#ifndef BARRIER_NEXT
|
||||
#define BARRIER_NEXT(A)
|
||||
#endif
|
||||
#define UFLAG_OP1(A) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, 0, offsetof(x86emu_t, op1));}
|
||||
#define UFLAG_OP2(A) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, 0, offsetof(x86emu_t, op2));}
|
||||
#define UFLAG_OP12(A1, A2) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {STR_IMM9(A1, 0, offsetof(x86emu_t, op1));STR_IMM9(A2, 0, offsetof(x86emu_t, op2));}
|
||||
#define UFLAG_RES(A) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, 0, offsetof(x86emu_t, res));}
|
||||
#define UFLAG_DF(r, A) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {MOVW(r, A); STR_IMM9(r, 0, offsetof(x86emu_t, df));}
|
||||
#define UFLAG_OP1(A) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, xEmu, offsetof(x86emu_t, op1));}
|
||||
#define UFLAG_OP2(A) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, xEmu, offsetof(x86emu_t, op2));}
|
||||
#define UFLAG_OP12(A1, A2) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {STR_IMM9(A1, xEmu, offsetof(x86emu_t, op1));STR_IMM9(A2, 0, offsetof(x86emu_t, op2));}
|
||||
#define UFLAG_RES(A) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, xEmu, offsetof(x86emu_t, res));}
|
||||
#define UFLAG_DF(r, A) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {SET_DF(r, A)}
|
||||
#define UFLAG_IF if(dyn->insts && dyn->insts[ninst].x86.need_flags)
|
||||
#ifndef DEFAULT
|
||||
#define DEFAULT *ok = -1; BARRIER(2)
|
||||
@@ -332,7 +339,7 @@
|
||||
#endif
|
||||
|
||||
void arm_epilog();
|
||||
void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
|
||||
void* arm_next(x86emu_t* emu, uintptr_t addr);
|
||||
|
||||
#ifndef STEPNAME
|
||||
#define STEPNAME3(N,M) N##M
|
||||
@@ -362,10 +369,9 @@ void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
|
||||
#define dynarecF30F STEPNAME(dynarecF30F)
|
||||
|
||||
#define geted STEPNAME(geted_)
|
||||
#define fakeed STEPNAME(fakeed_)
|
||||
#define geted16 STEPNAME(geted16_)
|
||||
#define jump_to_epilog STEPNAME(jump_to_epilog_)
|
||||
#define jump_to_linker STEPNAME(jump_to_linker_)
|
||||
#define jump_to_next STEPNAME(jump_to_next_)
|
||||
#define ret_to_epilog STEPNAME(ret_to_epilog_)
|
||||
#define retn_to_epilog STEPNAME(retn_to_epilog_)
|
||||
#define iret_to_epilog STEPNAME(iret_to_epilog_)
|
||||
@@ -432,11 +438,17 @@ void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
|
||||
#define emit_neg32 STEPNAME(emit_neg32)
|
||||
#define emit_neg16 STEPNAME(emit_neg16)
|
||||
#define emit_neg8 STEPNAME(emit_neg8)
|
||||
#define emit_shl32 STEPNAME(emit_shl32)
|
||||
#define emit_shl32c STEPNAME(emit_shl32c)
|
||||
#define emit_shr32 STEPNAME(emit_shr32)
|
||||
#define emit_shr32c STEPNAME(emit_shr32c)
|
||||
#define emit_sar32c STEPNAME(emit_sar32c)
|
||||
#define emit_rol32c STEPNAME(emit_rol32c)
|
||||
#define emit_ror32c STEPNAME(emit_ror32c)
|
||||
#define emit_shrd32c STEPNAME(emit_shrd32c)
|
||||
#define emit_shld32c STEPNAME(emit_shld32c)
|
||||
|
||||
#define emit_pf STEPNAME(emit_pf)
|
||||
|
||||
#define x87_do_push STEPNAME(x87_do_push)
|
||||
#define x87_do_push_empty STEPNAME(x87_do_push_empty)
|
||||
@@ -449,6 +461,7 @@ void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
|
||||
#define x87_stackcount STEPNAME(x87_stackcount)
|
||||
#define x87_setround STEPNAME(x87_setround)
|
||||
#define x87_restoreround STEPNAME(x87_restoreround)
|
||||
#define sse_setround STEPNAME(sse_setround)
|
||||
#define mmx_get_reg STEPNAME(mmx_get_reg)
|
||||
#define mmx_get_reg_empty STEPNAME(mmx_get_reg_empty)
|
||||
#define sse_get_reg STEPNAME(sse_get_reg)
|
||||
@@ -458,12 +471,11 @@ void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
|
||||
#define fpu_popcache STEPNAME(fpu_popcache)
|
||||
#define fpu_reset STEPNAME(fpu_reset)
|
||||
#define fpu_purgecache STEPNAME(fpu_purgecache)
|
||||
#define x87_purgecache STEPNAME(x87_purgecache)
|
||||
#define mmx_purgecache STEPNAME(mmx_purgecache)
|
||||
#ifdef HAVE_TRACE
|
||||
#define fpu_reflectcache STEPNAME(fpu_reflectcache)
|
||||
#endif
|
||||
#define cstack_push STEPNAME(cstack_push)
|
||||
#define cstack_pop STEPNAME(cstack_pop)
|
||||
|
||||
|
||||
// get the single reg that from the double "reg" (so Dx[idx])
|
||||
#define fpu_get_single_reg STEPNAME(fpu_get_single_reg)
|
||||
@@ -473,20 +485,17 @@ void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
|
||||
/* setup r2 to address pointed by */
|
||||
uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int* fixedaddress, uint32_t absmax, uint32_t mask);
|
||||
|
||||
// Do the GETED, but don't emit anything...
|
||||
uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop);
|
||||
|
||||
/* setup r2 to address pointed by */
|
||||
uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int* fixedaddress, uint32_t absmax, uint32_t mask);
|
||||
|
||||
|
||||
// generic x86 helper
|
||||
void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst);
|
||||
void jump_to_linker(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst);
|
||||
void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst);
|
||||
void ret_to_epilog(dynarec_arm_t* dyn, int ninst);
|
||||
void retn_to_epilog(dynarec_arm_t* dyn, int ninst, int n);
|
||||
void iret_to_epilog(dynarec_arm_t* dyn, int ninst);
|
||||
void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, uint32_t mask);
|
||||
void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, uint32_t mask, int saveflags);
|
||||
void grab_fsdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg);
|
||||
void grab_tlsdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg);
|
||||
void emit_lock(dynarec_arm_t* dyn, uintptr_t addr, int ninst);
|
||||
@@ -514,21 +523,21 @@ void emit_xor32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_xor32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_and32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_and32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
|
||||
void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_or8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
|
||||
void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_xor8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
|
||||
void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_and8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_add16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
|
||||
void emit_add16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_sub16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
|
||||
void emit_sub16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
|
||||
void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_or16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
|
||||
void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_xor16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
|
||||
void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_and16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_inc32(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_inc16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
@@ -551,21 +560,27 @@ void emit_sbb16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
void emit_neg32(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_neg16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_neg8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_shl32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_shl32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_shr32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_shr32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_sar32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_rol32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_ror32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_shrd32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4);
|
||||
void emit_shld32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4);
|
||||
|
||||
void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
|
||||
// x87 helper
|
||||
// cache of the local stack counter, to avoid upadte at every call
|
||||
void x87_stackcount(dynarec_arm_t* dyn, int ninst, int scratch);
|
||||
// fpu push. Return the Dd value to be used
|
||||
int x87_do_push(dynarec_arm_t* dyn, int ninst);
|
||||
int x87_do_push(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
// fpu push. Do not allocate a cache register. Needs a scratch register to do x87stack synch (or 0 to not do it)
|
||||
void x87_do_push_empty(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
// fpu pop. All previous returned Dd should be considered invalid
|
||||
void x87_do_pop(dynarec_arm_t* dyn, int ninst);
|
||||
void x87_do_pop(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
// get cache index for a x87 reg, create the entry if needed
|
||||
int x87_get_cache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a);
|
||||
// get vfpu register for a x87 reg, create the entry if needed
|
||||
@@ -580,12 +595,14 @@ void x87_reget_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st);
|
||||
int x87_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
// Restore round flag
|
||||
void x87_restoreround(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
// Set rounding according to mxcsr flags, return reg to restore flags
|
||||
int sse_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
|
||||
//MMX helpers
|
||||
// get neon register for a MMX reg, create the entry if needed
|
||||
int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a);
|
||||
int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a);
|
||||
// get neon register for a MMX reg, but don't try to synch it if it needed to be created
|
||||
int mmx_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a);
|
||||
int mmx_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a);
|
||||
|
||||
//SSE/SSE2 helpers
|
||||
// get neon register for a SSE reg, create the entry if needed
|
||||
@@ -598,6 +615,8 @@ int sse_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a);
|
||||
void fpu_reset(dynarec_arm_t* dyn, int ninst);
|
||||
// purge the FPU cache (needs 3 scratch registers)
|
||||
void fpu_purgecache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
void x87_purgecache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
void mmx_purgecache(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
#ifdef HAVE_TRACE
|
||||
void fpu_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
#endif
|
||||
@@ -628,11 +647,6 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
|
||||
// PUSH a x86/native couple of address in cstack, using s1, s2, s2+1
|
||||
void cstack_push(dynarec_arm_t* dyn, int ninst, uintptr_t x86ip, uintptr_t armip, int s1, int s2);
|
||||
// POP a x86/native couple of address from cstack, and generate the jump is x86 address is s0, use s1, s2 and s2+1 as scratch
|
||||
void cstack_pop(dynarec_arm_t* dyn, int ninst, int s0, int s1, int s2);
|
||||
|
||||
#if STEP < 2
|
||||
#define PASS2(A)
|
||||
#else
|
||||
|
||||
@@ -19,26 +19,27 @@
|
||||
#include "arm_printer.h"
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
#include "custommem.h"
|
||||
|
||||
#ifndef STEP
|
||||
#error No STEP defined
|
||||
#endif
|
||||
|
||||
void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
{
|
||||
int ok = 1;
|
||||
int ninst = 0;
|
||||
uintptr_t ip = addr;
|
||||
uintptr_t init_addr = addr;
|
||||
int need_epilog = 1;
|
||||
dyn->tablei = 0;
|
||||
dyn->sons_size = 0;
|
||||
// Clean up (because there are multiple passes)
|
||||
dyn->state_flags = 0;
|
||||
dyn->dfnone = 0;
|
||||
fpu_reset(dyn, ninst);
|
||||
// ok, go now
|
||||
INIT;
|
||||
while(ok) {
|
||||
if(dyn->insts && (ninst>dyn->size)) {dynarec_log(LOG_NONE, "Warning, too many inst treated (%d / %d)\n",ninst, dyn->size);}
|
||||
ip = addr;
|
||||
if(dyn->insts && (dyn->insts[ninst].x86.barrier==1)) {
|
||||
NEW_BARRIER_INST;
|
||||
@@ -52,7 +53,7 @@ void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
MESSAGE(LOG_DUMP, "TRACE ----\n");
|
||||
fpu_reflectcache(dyn, ninst, x1, x2, x3);
|
||||
MOV32(x1, ip);
|
||||
STM(xEmu, (1<<4)|(1<<5)|(1<<6)|(1<<7)|(1<<8)|(1<<9)|(1<<10)|(1<<11));
|
||||
STM(xEmu, (1<<xEAX)|(1<<xEBX)|(1<<xECX)|(1<<xEDX)|(1<<xESI)|(1<<xEDI)|(1<<xESP)|(1<<xEBP));
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, ip));
|
||||
MOVW(x2, 1);
|
||||
CALL(PrintTrace, -1, 0);
|
||||
@@ -67,23 +68,43 @@ void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
|
||||
if(dyn->insts && dyn->insts[ninst+1].x86.barrier) {
|
||||
fpu_purgecache(dyn, ninst, x1, x2, x3);
|
||||
if(dyn->insts[ninst+1].x86.barrier!=2)
|
||||
if(dyn->insts[ninst+1].x86.barrier!=2) {
|
||||
dyn->state_flags = 0;
|
||||
dyn->dfnone = 0;
|
||||
}
|
||||
}
|
||||
if(!ok && !need_epilog && dyn->insts && (addr < (dyn->start+dyn->isize))) {
|
||||
ok = 1;
|
||||
}
|
||||
if(!ok && !need_epilog && !dyn->insts) { // check if need to continue
|
||||
uintptr_t next = get_closest_next(dyn, addr);
|
||||
if(next && ((next-addr)<15) && is_nops(dyn, addr, next-addr)) {
|
||||
dynarec_log(LOG_DEBUG, "Extend block %p, %p -> %p (ninst=%d)\n", dyn, (void*)addr, (void*)next, ninst);
|
||||
ok = 1;
|
||||
} else if(next && (next-addr)<15) {
|
||||
dynarec_log(LOG_DEBUG, "Cannot extend block %p -> %p (%02X %02X %02X %02X %02X)\n", (void*)addr, (void*)next, PK(0), PK(1), PK(2), PK(3), PK(4));
|
||||
if(!ok && !need_epilog && !dyn->insts && getProtection(addr+3))
|
||||
if(*(uint32_t*)addr!=0) { // check if need to continue (but is next 4 bytes are 0, stop)
|
||||
uintptr_t next = get_closest_next(dyn, addr);
|
||||
if(next && (
|
||||
(((next-addr)<15) && is_nops(dyn, addr, next-addr))
|
||||
||(((next-addr)<30) && is_instructions(dyn, addr, next-addr)) ))
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "Extend block %p, %p -> %p (ninst=%d)\n", dyn, (void*)addr, (void*)next, ninst);
|
||||
ok = 1;
|
||||
} else if(next && (next-addr)<30) {
|
||||
dynarec_log(LOG_DEBUG, "Cannot extend block %p -> %p (%02X %02X %02X %02X %02X %02X %02X %02x)\n", (void*)addr, (void*)next, PK(0), PK(1), PK(2), PK(3), PK(4), PK(5), PK(6), PK(7));
|
||||
}
|
||||
}
|
||||
}
|
||||
if(ok<0) {ok = 0; need_epilog=1;}
|
||||
++ninst;
|
||||
#if STEP == 0
|
||||
if(ok && !isJumpTableDefault((void*)addr))
|
||||
#else
|
||||
if(ok && dyn->insts && (ninst==dyn->size))
|
||||
#endif
|
||||
{
|
||||
#if STEP == 3
|
||||
dynarec_log(LOG_DEBUG, "Stopping block %p (%d / %d)\n",(void*)init_addr, ninst, dyn->size);
|
||||
#endif
|
||||
BARRIER(2);
|
||||
fpu_purgecache(dyn, ninst, x1, x2, x3);
|
||||
jump_to_next(dyn, addr, 0, ninst);
|
||||
ok=0; need_epilog=0;
|
||||
}
|
||||
}
|
||||
if(need_epilog) {
|
||||
fpu_purgecache(dyn, ninst, x1, x2, x3);
|
||||
@@ -91,4 +112,5 @@ void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
}
|
||||
FINI;
|
||||
MESSAGE(LOG_DUMP, "---- END OF BLOCK ---- (%d, %d sons)\n", dyn->size, dyn->sons_size);
|
||||
return addr;
|
||||
}
|
||||
@@ -29,9 +29,6 @@ typedef struct dynarec_arm_s {
|
||||
void* block; // memory pointer where next instruction is emited
|
||||
uintptr_t arm_start; // start of the arm code
|
||||
int arm_size; // size of emitted arm code
|
||||
uintptr_t* table; // jump table
|
||||
int tablesz; // size of the jump table
|
||||
int tablei; // index
|
||||
int state_flags;// actual state for on-demand flags
|
||||
int x87cache[8];// cache status for the 8 x87 register behind the fpu stack
|
||||
int x87reg[8]; // reg used for x87cache entry
|
||||
@@ -39,10 +36,12 @@ typedef struct dynarec_arm_s {
|
||||
int ssecache[8];// cache status for the 8 SSE(2) registers
|
||||
int fpuused[24];// all 8..31 double reg from fpu, used by x87, sse and mmx
|
||||
int x87stack; // cache stack counter
|
||||
int x87count; // number of x87 register used
|
||||
int mmxcount; // number of mmx register used (not both mmx and x87 at the same time)
|
||||
int fpu_scratch;// scratch counter
|
||||
int fpu_extra_qscratch; // some opcode need an extra quad scratch register
|
||||
int fpu_reg; // x87/sse/mmx reg counter
|
||||
int nolinker; // disable use of (smart) linker in the block
|
||||
int dfnone; // if defered flags is already set to df_none
|
||||
uintptr_t* next; // variable array of "next" jump address
|
||||
int next_sz;
|
||||
int next_cap;
|
||||
@@ -54,5 +53,6 @@ typedef struct dynarec_arm_s {
|
||||
void add_next(dynarec_arm_t *dyn, uintptr_t addr);
|
||||
uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr);
|
||||
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n);
|
||||
int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n);
|
||||
|
||||
#endif //__DYNAREC_ARM_PRIVATE_H_
|
||||
@@ -31,7 +31,5 @@ typedef struct instruction_x86_s {
|
||||
} instruction_x86_t;
|
||||
|
||||
void printf_x86_instruction(zydis_dec_t* dec, instruction_x86_t* inst, const char* name);
|
||||
void tableupdate(void* jumpto, uintptr_t ref, void** table);
|
||||
void resettable(void** table);
|
||||
|
||||
#endif //__DYNAREC_PRIVATE_H_
|
||||
@@ -289,6 +289,7 @@ ARM_ cond 0 0 0 1 0 0 1 0 (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) 0 0 1
|
||||
ARM_ cond/=1110 0 0 0 1 0 0 1 0 imm12 0 1 1 1 imm4 BKPT #<imm16>
|
||||
ARMS cond 0 0 0 1 0 0 1 1 Rn (0) (0) (0) (0) imm5 type 0 Rm TEQ<c> <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 1 0 1 0 0 Rn Rt (0) (0) (0) (0) 1 0 0 1 Rm SWPB<c> <Rt>, <Rm>, [<Rn>]
|
||||
ARM_ cond 0 0 0 1 0 1 1 0 (1) (1) (1) (1) Rd (1) (1) (1) (1) 0 0 0 1 Rm CLZ<c> <Rd>, <Rm>
|
||||
ARM_ cond 0 0 0 1 U 1 W 0 Rn Rt imm4H 1 0 1 1 imm4L STRH<c> <Rt>, [<Rn>, #+/-<imm8>]{!}
|
||||
ARM_ cond 0 0 0 1 U 1 W 0 Rn Rt imm4H 1 1 0 1 imm4L LDRD<c> <Rt>, <Rt2>, [<Rn>, #+/-<imm8>]{!}
|
||||
ARM_ cond 0 0 0 1 U 1 W 0 Rn Rt imm4H 1 1 1 1 imm4L STRD<c> <Rt>, <Rt2>, [<Rn>, #+/-<imm8>]{!}
|
||||
@@ -375,6 +376,7 @@ ARMs cond 0 1 1 0 1 1 1 sat_imm Rd imm5 sh 0 1 Rn USAT<c> <Rd>, #<imm>, <Rn>{, <
|
||||
ARM_ cond 0 1 1 0 1 1 1 0 sat_imm Rd (1) (1) (1) (1) 0 0 1 1 Rn USAT16<c> <Rd>, #<imm>, <Rn>
|
||||
ARM_ cond 0 1 1 0 1 1 1 0 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm UXTB<c> <Rd>, <Rm>{, <rotation>}
|
||||
ARM_ cond 0 1 1 0 1 1 1 0 Rn Rd rotate (0) (0) 0 1 1 1 Rm UXTAB<c> <Rd>, <Rn>, <Rm>{, <rotation>}
|
||||
ARM_ cond 0 1 1 0 1 1 1 1 (1) (1) (1) (1) Rd (1) (1) (1) (1) 0 0 1 1 Rm RBIT<c> <Rd>, <Rm>
|
||||
ARM_ cond 0 1 1 0 1 1 1 1 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm UXTH<c> <Rd>, <Rm>{, <rotation>}
|
||||
ARM_ cond 0 1 1 0 1 1 1 1 (1) (1) (1) (1) Rd (1) (1) (1) (1) 1 0 1 1 Rm REVSH<c> <Rd>, <Rm>
|
||||
ARM_ cond 0 1 1 0 1 1 1 1 Rn Rd rotate (0) (0) 0 1 1 1 Rm UXTAH<c> <Rd>, <Rn>, <Rm>{, <rotation>}
|
||||
|
||||
@@ -40,7 +40,7 @@ const char* DumpSection(Elf32_Shdr *s, char* SST) {
|
||||
GO(SHT_HIPROC);
|
||||
GO(SHT_LOUSER);
|
||||
GO(SHT_HIUSER);
|
||||
#ifdef SHT_GNU_versym
|
||||
#if defined(SHT_GNU_versym) && defined(SHT_GNU_ATTRIBUTES)
|
||||
GO(SHT_GNU_versym);
|
||||
GO(SHT_GNU_ATTRIBUTES);
|
||||
GO(SHT_GNU_HASH);
|
||||
@@ -100,7 +100,7 @@ const char* DumpDynamic(Elf32_Dyn *s) {
|
||||
GO(DT_RUNPATH, 0);
|
||||
GO(DT_FLAGS, 0);
|
||||
GO(DT_ENCODING, 0);
|
||||
#ifdef DT_NUM
|
||||
#if defined(DT_NUM) && defined(DT_TLSDESC_PLT)
|
||||
GO(DT_NUM, 0);
|
||||
GO(DT_VALRNGLO, 0);
|
||||
GO(DT_GNU_PRELINKED, 0);
|
||||
@@ -193,6 +193,7 @@ const char* DumpRelType(int t)
|
||||
GO(R_386_TLS_GD_32);
|
||||
GO(R_386_TLS_DTPMOD32);
|
||||
GO(R_386_TLS_DTPOFF32);
|
||||
GO(R_386_TLS_TPOFF32);
|
||||
#undef GO
|
||||
default: sprintf(buff, "type: 0x%x (unknown)", t); break;
|
||||
}
|
||||
|
||||
+214
-71
@@ -10,6 +10,7 @@
|
||||
#include <link.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "box86version.h"
|
||||
#include "elfloader.h"
|
||||
@@ -27,6 +28,8 @@
|
||||
#include "callback.h"
|
||||
#include "dynarec.h"
|
||||
#include "box86stack.h"
|
||||
#include "custommem.h"
|
||||
#include "wine_tools.h"
|
||||
#ifdef DYNAREC
|
||||
#include "dynablock.h"
|
||||
#endif
|
||||
@@ -64,10 +67,10 @@ void FreeElfHeader(elfheader_t** head)
|
||||
return;
|
||||
elfheader_t *h = *head;
|
||||
#ifdef DYNAREC
|
||||
if(h->text) {
|
||||
/*if(h->text) {
|
||||
dynarec_log(LOG_INFO, "Free Dynarec block for %s\n", h->path);
|
||||
cleanDBFromAddressRange(my_context, h->text, h->textsz, 1);
|
||||
}
|
||||
}*/ // will be free at the end, no need to free it now
|
||||
#endif
|
||||
free(h->name);
|
||||
free(h->path);
|
||||
@@ -180,7 +183,9 @@ int AllocElfMemory(box86context_t* context, elfheader_t* head, int mainbin)
|
||||
uintptr_t start = head->multiblock_offs[j];
|
||||
uintptr_t end = head->multiblock_offs[j] + head->multiblock_size[j];
|
||||
start &= ~balign;
|
||||
if(((bstart>=start) && (bstart<=end)) || ((bend>=start) && (bend<=end)) || ((bstart<start) && (bend>end))) {
|
||||
if( (head->e_type == ET_DYN) ||
|
||||
(((bstart>=start) && (bstart<=end)) || ((bend>=start) && (bend<=end)) || ((bstart<start) && (bend>end))))
|
||||
{
|
||||
// merge
|
||||
ok = 1;
|
||||
if(bstart<start)
|
||||
@@ -195,17 +200,36 @@ int AllocElfMemory(box86context_t* context, elfheader_t* head, int mainbin)
|
||||
++n;
|
||||
}
|
||||
}
|
||||
head->multiblock_n = n; // might be less in fact
|
||||
for (int i=0; i<head->multiblock_n; ++i) {
|
||||
|
||||
printf_log(LOG_DEBUG, "Allocating 0x%x memory @%p for Elf \"%s\"\n", head->multiblock_size[i], (void*)head->multiblock_offs[i], head->name);
|
||||
void* p = mmap((void*)head->multiblock_offs[i], head->multiblock_size[i]
|
||||
, PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED
|
||||
, MAP_PRIVATE | MAP_ANONYMOUS /*| ((wine_preloaded)?MAP_FIXED:0)*/
|
||||
, -1, 0);
|
||||
if(p==MAP_FAILED) {
|
||||
printf_log(LOG_NONE, "Cannot create memory map (@%p 0x%x/0x%x) for elf \"%s\"\n", (void*)head->multiblock_offs[i], head->multiblock_size[i], head->align, head->name);
|
||||
return 1;
|
||||
}
|
||||
if(head->multiblock_offs[i] &&( p!=(void*)head->multiblock_offs[i])) {
|
||||
if((head->e_type!=ET_DYN)) {
|
||||
printf_log(LOG_NONE, "Error, memory map (@%p 0x%x/0x%x) for elf \"%s\" allocated @%p\n", (void*)head->multiblock_offs[i], head->multiblock_size[i], head->align, head->name, p);
|
||||
return 1;
|
||||
} else {
|
||||
printf_log(LOG_INFO, "Allocated memory is not at hinted %p but %p (size %p) \"%s\"\n", (void*)head->multiblock_offs[i], p, (void*)head->multiblock_size[i], head->name);
|
||||
// need to adjust vaddr!
|
||||
for (int i=0; i<head->numPHEntries; ++i)
|
||||
if(head->PHEntries[i].p_type == PT_LOAD) {
|
||||
Elf32_Phdr * e = &head->PHEntries[i];
|
||||
if(e->p_vaddr>=head->multiblock_offs[i] && e->p_vaddr<(head->multiblock_offs[i]+head->multiblock_size[i])) {
|
||||
e->p_vaddr = e->p_vaddr - head->multiblock_offs[i] + (uintptr_t)p;
|
||||
if(!head->delta) head->delta = (intptr_t)p - (intptr_t)head->multiblock_offs[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setProtection((uintptr_t)p, head->multiblock_size[i], PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
head->multiblock[i] = p;
|
||||
if(p<(void*)head->memory)
|
||||
head->memory = (char*)p;
|
||||
@@ -215,12 +239,17 @@ int AllocElfMemory(box86context_t* context, elfheader_t* head, int mainbin)
|
||||
printf_log(LOG_DEBUG, "Allocating 0x%x memory @%p for Elf \"%s\"\n", head->memsz, (void*)offs, head->name);
|
||||
void* p = mmap((void*)offs, head->memsz
|
||||
, PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
, MAP_PRIVATE | MAP_ANONYMOUS | (((offs)?MAP_FIXED:0))
|
||||
, MAP_PRIVATE | MAP_ANONYMOUS /*| (((offs&&wine_preloaded)?MAP_FIXED:0))*/
|
||||
, -1, 0);
|
||||
if(p==MAP_FAILED) {
|
||||
printf_log(LOG_NONE, "Cannot create memory map (@%p 0x%x/0x%x) for elf \"%s\"\n", (void*)offs, head->memsz, head->align, head->name);
|
||||
return 1;
|
||||
}
|
||||
if(offs && (p!=(void*)offs) && (head->e_type!=ET_DYN)) {
|
||||
printf_log(LOG_NONE, "Error, memory map (@%p 0x%x/0x%x) for elf \"%s\" allocated @%p\n", (void*)offs, head->memsz, head->align, head->name, p);
|
||||
return 1;
|
||||
}
|
||||
setProtection((uintptr_t)p, head->memsz, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
head->memory = p;
|
||||
memset(p, 0, head->memsz);
|
||||
head->delta = (intptr_t)p - (intptr_t)head->vaddr;
|
||||
@@ -264,13 +293,14 @@ int LoadElfMemory(FILE* f, box86context_t* context, elfheader_t* head)
|
||||
printf_log(LOG_NONE, "Fail to read PT_LOAD part #%d (size=%d)\n", i, e->p_filesz);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#ifdef DYNAREC
|
||||
if(e->p_flags & PF_X) {
|
||||
dynarec_log(LOG_DEBUG, "Add ELF eXecutable Memory %p:%p\n", dest, (void*)e->p_memsz);
|
||||
addDBFromAddressRange(context, (uintptr_t)dest, e->p_memsz, 0);
|
||||
}
|
||||
if(e->p_flags & PF_X) {
|
||||
dynarec_log(LOG_DEBUG, "Add ELF eXecutable Memory %p:%p\n", dest, (void*)e->p_memsz);
|
||||
addDBFromAddressRange((uintptr_t)dest, e->p_memsz);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// zero'd difference between filesz and memsz
|
||||
/*if(e->p_filesz != e->p_memsz)
|
||||
memset(dest+e->p_filesz, 0, e->p_memsz - e->p_filesz);*/ //block is already 0'd at creation
|
||||
@@ -303,11 +333,13 @@ int ReloadElfMemory(FILE* f, box86context_t* context, elfheader_t* head)
|
||||
printf_log(LOG_DEBUG, "Re-loading block #%i @%p (0x%x/0x%x)\n", i, dest, e->p_filesz, e->p_memsz);
|
||||
int ret = fseeko64(f, e->p_offset, SEEK_SET);
|
||||
if(ret==-1) {printf_log(LOG_NONE, "Fail to (re)seek PT_LOAD part #%d (offset=%d, errno=%d/%s)\n", i, e->p_offset, errno, strerror(errno)); return 1;}
|
||||
#ifdef DYNAREC
|
||||
cleanDBFromAddressRange((uintptr_t)dest, e->p_memsz, 0);
|
||||
#endif
|
||||
mprotect(dest, e->p_memsz, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
setProtection((uintptr_t)dest, e->p_memsz, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
if(e->p_filesz) {
|
||||
ssize_t r = -1;
|
||||
#ifdef DYNAREC
|
||||
unprotectDB((uintptr_t)dest, e->p_memsz);
|
||||
#endif
|
||||
if((r=fread(dest, e->p_filesz, 1, f))!=1) {
|
||||
printf_log(LOG_NONE, "Fail to (re)read PT_LOAD part #%d (dest=%p, size=%d, return=%d, feof=%d/ferror=%d/%s)\n", i, dest, e->p_filesz, r, feof(f), ferror(f), strerror(ferror(f)));
|
||||
return 1;
|
||||
@@ -321,6 +353,26 @@ int ReloadElfMemory(FILE* f, box86context_t* context, elfheader_t* head)
|
||||
// TLS data are just a copy, no need to re-load it
|
||||
return 0;
|
||||
}
|
||||
int FindR386COPYRel(elfheader_t* h, const char* name, uintptr_t *offs, uint32_t** p)
|
||||
{
|
||||
if(!h)
|
||||
return 0;
|
||||
Elf32_Rel * rel = (Elf32_Rel *)(h->rel + h->delta);
|
||||
if(!h->rel)
|
||||
return 0;
|
||||
int cnt = h->relsz / h->relent;
|
||||
for (int i=0; i<cnt; ++i) {
|
||||
int t = ELF32_R_TYPE(rel[i].r_info);
|
||||
Elf32_Sym *sym = &h->DynSym[ELF32_R_SYM(rel[i].r_info)];
|
||||
const char* symname = SymName(h, sym);
|
||||
if(!strcmp(symname, name) && t==R_386_COPY) {
|
||||
*offs = sym->st_value + h->delta;
|
||||
*p = (uint32_t*)(rel[i].r_offset + h->delta);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int cnt, Elf32_Rel *rel)
|
||||
{
|
||||
@@ -334,6 +386,14 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int cn
|
||||
uintptr_t offs = 0;
|
||||
uintptr_t end = 0;
|
||||
uintptr_t tmp = 0;
|
||||
int version = head->VerSym?((Elf32_Half*)((uintptr_t)head->VerSym+head->delta))[ELF32_R_SYM(rel[i].r_info)]:0;
|
||||
const char* ver = GetSymbolVersion(head, version);
|
||||
char SymbolVersionned[501];
|
||||
strncpy(SymbolVersionned, symname, 500);
|
||||
if(ver) {
|
||||
strncat(SymbolVersionned, "@", 500);
|
||||
strncat(SymbolVersionned, ver, 500);
|
||||
}
|
||||
elfheader_t* h_tls = head;
|
||||
if(bind==STB_LOCAL) {
|
||||
offs = sym->st_value + head->delta;
|
||||
@@ -345,16 +405,23 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int cn
|
||||
offs = sym->st_value + head->delta;
|
||||
end = offs + sym->st_size;
|
||||
}
|
||||
// so weak symbol are the one left
|
||||
// so weak symbol are the one left, and try versionned symbol first
|
||||
if(!offs && !end) {
|
||||
h_tls = NULL;
|
||||
if(local_maplib)
|
||||
GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end);
|
||||
if(!offs && !end)
|
||||
GetGlobalSymbolStartEnd(maplib, symname, &offs, &end);
|
||||
if(local_maplib) {
|
||||
GetGlobalSymbolStartEnd(local_maplib, SymbolVersionned, &offs, &end);
|
||||
if(!offs && !end)
|
||||
GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end);
|
||||
}
|
||||
if(!offs && !end) {
|
||||
GetGlobalSymbolStartEnd(maplib, SymbolVersionned, &offs, &end);
|
||||
if(!offs && !end)
|
||||
GetGlobalSymbolStartEnd(maplib, symname, &offs, &end);
|
||||
}
|
||||
}
|
||||
}
|
||||
uintptr_t globoffs, globend;
|
||||
uint32_t* globp;
|
||||
int delta;
|
||||
switch(t) {
|
||||
case R_386_NONE:
|
||||
@@ -381,6 +448,26 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int cn
|
||||
}
|
||||
}
|
||||
break;
|
||||
case R_386_TLS_TPOFF32:
|
||||
// Non-negated offset in static TLS block???
|
||||
{
|
||||
if(h_tls)
|
||||
offs = sym->st_value;
|
||||
else {
|
||||
if(local_maplib)
|
||||
h_tls = GetGlobalSymbolElf(local_maplib, symname);
|
||||
if(!h_tls)
|
||||
h_tls = GetGlobalSymbolElf(maplib, symname);
|
||||
}
|
||||
if(h_tls) {
|
||||
delta = *(int*)p;
|
||||
printf_log(LOG_DUMP, "Applying %s %s on %s @%p (%d -> %d)\n", (bind==STB_LOCAL)?"Local":"Global", DumpRelType(t), symname, p, delta, (int32_t)offs + h_tls->tlsbase);
|
||||
*p = (uint32_t)(-((int32_t)offs + h_tls->tlsbase));
|
||||
} else {
|
||||
printf_log(LOG_INFO, "Warning, cannot apply %s %s on %s @%p (%d), no elf_header found\n", (bind==STB_LOCAL)?"Local":"Global", DumpRelType(t), symname, p, (int32_t)offs);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case R_386_PC32:
|
||||
if (!offs) {
|
||||
printf_log(LOG_NONE, "Error: Global Symbol %s not found, cannot apply R_386_PC32 @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
|
||||
@@ -391,18 +478,59 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int cn
|
||||
*p += offs;
|
||||
break;
|
||||
case R_386_GLOB_DAT:
|
||||
// Look for same symbol already loaded but not in self (so no need for local_maplib here)
|
||||
if (GetGlobalNoWeakSymbolStartEnd(maplib, symname, &globoffs, &globend)) {
|
||||
offs = globoffs;
|
||||
end = globend;
|
||||
}
|
||||
if (!offs) {
|
||||
if(strcmp(symname, "__gmon_start__"))
|
||||
printf_log(LOG_NONE, "Error: Global Symbol %s not found, cannot apply R_386_GLOB_DAT @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
|
||||
// return -1;
|
||||
if(head!=my_context->elfs[0] && !IsGlobalNoWeakSymbolInNative(maplib, symname) && FindR386COPYRel(my_context->elfs[0], symname, &globoffs, &globp)) {
|
||||
// set global offs / size for the symbol
|
||||
offs = sym->st_value + head->delta;
|
||||
end = offs + sym->st_size;
|
||||
if(sym->st_size) {
|
||||
printf_log(LOG_DUMP, "Apply %s R_386_GLOB_DAT with R_386_COPY @%p/%p (%p/%p -> %p/%p) size=%d on sym=%s \n", (bind==STB_LOCAL)?"Local":"Global", p, globp, (void*)(p?(*p):0), (void*)(globp?(*globp):0), (void*)offs, (void*)globoffs, sym->st_size, symname);
|
||||
memmove((void*)globoffs, (void*)offs, sym->st_size); // preapply to copy part from lib to main elf
|
||||
AddWeakSymbol(GetGlobalData(maplib), symname, offs, sym->st_size);
|
||||
} else {
|
||||
printf_log(LOG_DUMP, "Apply %s R_386_GLOB_DAT with R_386_COPY @%p/%p (%p/%p -> %p/%p) null sized on sym=%s \n", (bind==STB_LOCAL)?"Local":"Global", p, globp, (void*)(p?(*p):0), (void*)(globp?(*globp):0), (void*)offs, (void*)globoffs, symname);
|
||||
}
|
||||
*p = globoffs;
|
||||
} else {
|
||||
printf_log(LOG_DUMP, "Apply %s R_386_GLOB_DAT @%p (%p -> %p) on sym=%s\n", (bind==STB_LOCAL)?"Local":"Global", p, (void*)(p?(*p):0), (void*)offs, symname);
|
||||
*p = offs;
|
||||
// Look for same symbol already loaded but not in self (so no need for local_maplib here)
|
||||
if (GetGlobalNoWeakSymbolStartEnd(maplib, symname, &globoffs, &globend)) {
|
||||
offs = globoffs;
|
||||
end = globend;
|
||||
}
|
||||
if (!offs) {
|
||||
if(strcmp(symname, "__gmon_start__"))
|
||||
printf_log(LOG_NONE, "Error: Global Symbol %s not found, cannot apply R_386_GLOB_DAT @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
|
||||
} else {
|
||||
printf_log(LOG_DUMP, "Apply %s R_386_GLOB_DAT @%p (%p -> %p) on sym=%s\n", (bind==STB_LOCAL)?"Local":"Global", p, (void*)(p?(*p):0), (void*)offs, symname);
|
||||
*p = offs;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case R_386_COPY:
|
||||
if(offs) {
|
||||
uintptr_t old_offs = offs;
|
||||
uintptr_t old_end = end;
|
||||
offs = 0;
|
||||
GetSymbolStartEnd(GetGlobalData(maplib), symname, &offs, &end); // try globaldata symbols first
|
||||
if(offs==0) {
|
||||
if(local_maplib)
|
||||
GetNoSelfSymbolStartEnd(local_maplib, symname, &offs, &end, head);
|
||||
if(!offs)
|
||||
GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head); // get original copy if any
|
||||
}
|
||||
if(!offs) {
|
||||
offs = old_offs;
|
||||
end = old_end;
|
||||
}
|
||||
printf_log(LOG_DUMP, "Apply %s R_386_COPY @%p with sym=%s, @%p size=%d (", (bind==STB_LOCAL)?"Local":"Global", p, symname, (void*)offs, sym->st_size);
|
||||
memmove(p, (void*)offs, sym->st_size);
|
||||
if(LOG_DUMP<=box86_log) {
|
||||
uint32_t*k = (uint32_t*)p;
|
||||
for (int i=0; i<((sym->st_size>128)?128:sym->st_size); i+=4, ++k)
|
||||
printf_log(LOG_DUMP, "%s0x%08X", i?" ":"", *k);
|
||||
printf_log(LOG_DUMP, "%s)\n", (sym->st_size>128)?" ...":"");
|
||||
}
|
||||
} else {
|
||||
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_COPY @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
|
||||
}
|
||||
break;
|
||||
case R_386_RELATIVE:
|
||||
@@ -464,6 +592,7 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int cn
|
||||
tmp = (uintptr_t)(*p);
|
||||
if (bind==STB_LOCAL
|
||||
|| ((symname && strstr(symname, "g_cclosure_marshal_")==symname))
|
||||
|| ((symname && strstr(symname, "__pthread_unwind_next")==symname))
|
||||
|| !tmp
|
||||
|| !((tmp>=head->plt && tmp<head->plt_end) || (tmp>=head->gotplt && tmp<head->gotplt_end))
|
||||
) {
|
||||
@@ -476,38 +605,19 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int cn
|
||||
// return -1;
|
||||
} else {
|
||||
if(p) {
|
||||
printf_log(LOG_DUMP, "Apply %s R_386_JMP_SLOT @%p with sym=%s (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)offs);
|
||||
printf_log(LOG_DUMP, "Apply %s R_386_JMP_SLOT @%p with sym=%s(%s) (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, SymbolVersionned, *(void**)p, (void*)offs);
|
||||
*p = offs;
|
||||
} else {
|
||||
printf_log(LOG_NONE, "Warning, Symbol %s found, but Jump Slot Offset is NULL \n", symname);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printf_log(LOG_DUMP, "Preparing (if needed) %s R_386_JMP_SLOT @%p (0x%x->0x%0x) with sym=%s to be apply later\n", (bind==STB_LOCAL)?"Local":"Global", p, *p, *p+head->delta, symname);
|
||||
printf_log(LOG_DUMP, "Preparing (if needed) %s R_386_JMP_SLOT @%p (0x%x->0x%0x) with sym=%s(%s/version %d) to be apply later\n", (bind==STB_LOCAL)?"Local":"Global", p, *p, *p+head->delta, symname, SymbolVersionned, version);
|
||||
*p += head->delta;
|
||||
}
|
||||
break;
|
||||
case R_386_COPY:
|
||||
if(offs) {
|
||||
offs = 0;
|
||||
if(local_maplib)
|
||||
GetNoSelfSymbolStartEnd(local_maplib, symname, &offs, &end, head);
|
||||
if(!offs)
|
||||
GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head); // get original copy if any
|
||||
printf_log(LOG_DUMP, "Apply %s R_386_COPY @%p with sym=%s, @%p size=%d (", (bind==STB_LOCAL)?"Local":"Global", p, symname, (void*)offs, sym->st_size);
|
||||
memmove(p, (void*)offs, sym->st_size);
|
||||
if(LOG_DUMP<=box86_log) {
|
||||
uint32_t*k = (uint32_t*)p;
|
||||
for (int i=0; i<((sym->st_size>128)?128:sym->st_size); i+=4, ++k)
|
||||
printf_log(LOG_DUMP, "%s0x%08X", i?" ":"", *k);
|
||||
printf_log(LOG_DUMP, "%s)\n", (sym->st_size>128)?" ...":"");
|
||||
}
|
||||
} else {
|
||||
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_COPY @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf_log(LOG_INFO, "Warning, don't know of to handle rel #%d %s (%p)\n", i, DumpRelType(ELF32_R_TYPE(rel[i].r_info)), p);
|
||||
printf_log(LOG_INFO, "Warning, don't know of to handle rel #%d %s (%p) for %s\n", i, DumpRelType(ELF32_R_TYPE(rel[i].r_info)), p, symname?symname:"(nil)");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -581,7 +691,7 @@ int RelocateElfPlt(lib_t *maplib, lib_t *local_maplib, elfheader_t* head)
|
||||
return -1;
|
||||
}
|
||||
if(pltResolver==~0) {
|
||||
pltResolver = AddBridge(my_context->system, my_context, vFE, PltResolver, 0);
|
||||
pltResolver = AddBridge(my_context->system, vFE, PltResolver, 0);
|
||||
}
|
||||
if(head->pltgot) {
|
||||
*(uintptr_t*)(head->pltgot+head->delta+8) = pltResolver;
|
||||
@@ -610,7 +720,7 @@ Elf32_Sym* GetFunction(elfheader_t* h, const char* name)
|
||||
// TODO: create a hash on named to avoid this loop
|
||||
for (int i=0; i<h->numSymTab; ++i) {
|
||||
int type = ELF32_ST_TYPE(h->SymTab[i].st_info);
|
||||
if(/*h->SymTab[i].st_info == 18*/type==STT_FUNC) { // TODO: this "18" is probably defined somewhere
|
||||
if(type==STT_FUNC) {
|
||||
const char * symname = h->StrTab+h->SymTab[i].st_name;
|
||||
if(strcmp(symname, name)==0) {
|
||||
return h->SymTab+i;
|
||||
@@ -624,7 +734,7 @@ Elf32_Sym* GetElfObject(elfheader_t* h, const char* name)
|
||||
{
|
||||
for (int i=0; i<h->numSymTab; ++i) {
|
||||
int type = ELF32_ST_TYPE(h->SymTab[i].st_info);
|
||||
if(/*h->SymTab[i].st_info == 16*/type==STT_OBJECT) {
|
||||
if(type==STT_OBJECT) {
|
||||
const char * symname = h->StrTab+h->SymTab[i].st_name;
|
||||
if(strcmp(symname, name)==0) {
|
||||
return h->SymTab+i;
|
||||
@@ -688,7 +798,7 @@ void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* wea
|
||||
int vis = h->SymTab[i].st_other&0x3;
|
||||
if((type==STT_OBJECT || type==STT_FUNC || type==STT_COMMON || type==STT_TLS || type==STT_NOTYPE)
|
||||
&& (vis==STV_DEFAULT || vis==STV_PROTECTED) && (h->SymTab[i].st_shndx!=0)) {
|
||||
if(bind==10/*STB_GNU_UNIQUE*/ && FindGlobalSymbol(maplib, symname))
|
||||
if((bind==STB_GNU_UNIQUE /*|| (bind==STB_GLOBAL && type==STT_FUNC)*/) && FindGlobalSymbol(maplib, symname))
|
||||
continue;
|
||||
uintptr_t offs = (type==STT_TLS)?h->SymTab[i].st_value:(h->SymTab[i].st_value + h->delta);
|
||||
uint32_t sz = h->SymTab[i].st_size;
|
||||
@@ -713,7 +823,7 @@ void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* wea
|
||||
//st_shndx==65521 means ABS value
|
||||
if((type==STT_OBJECT || type==STT_FUNC || type==STT_COMMON || type==STT_TLS || type==STT_NOTYPE)
|
||||
&& (vis==STV_DEFAULT || vis==STV_PROTECTED) && (h->DynSym[i].st_shndx!=0 && h->DynSym[i].st_shndx<=65521)) {
|
||||
if(bind==10/*STB_GNU_UNIQUE*/ && FindGlobalSymbol(maplib, symname))
|
||||
if((bind==STB_GNU_UNIQUE || (bind==STB_GLOBAL && type==STT_FUNC)) && FindGlobalSymbol(maplib, symname))
|
||||
continue;
|
||||
uintptr_t offs = (type==STT_TLS)?h->DynSym[i].st_value:(h->DynSym[i].st_value + h->delta);
|
||||
uint32_t sz = h->DynSym[i].st_size;
|
||||
@@ -745,7 +855,7 @@ $PLATFORM – Expands to the processor type of the current machine (see the
|
||||
uname(1) man page description of the -i option). For more details of this token
|
||||
expansion, see “System Specific Shared Objects”
|
||||
*/
|
||||
int LoadNeededLibs(elfheader_t* h, lib_t *maplib, needed_libs_t* neededlibs, int local, box86context_t *box86, x86emu_t* emu)
|
||||
int LoadNeededLibs(elfheader_t* h, lib_t* maplib, needed_libs_t* neededlibs, library_t* deplib, int local, box86context_t* box86, x86emu_t* emu)
|
||||
{
|
||||
DumpDynamicRPath(h);
|
||||
// update RPATH first
|
||||
@@ -765,6 +875,21 @@ int LoadNeededLibs(elfheader_t* h, lib_t *maplib, needed_libs_t* neededlibs, int
|
||||
if(rpath!=rpathref)
|
||||
free(rpath);
|
||||
rpath = tmp;
|
||||
free(origin);
|
||||
}
|
||||
while(strstr(rpath, "${ORIGIN}")) {
|
||||
char* origin = strdup(h->path);
|
||||
char* p = strrchr(origin, '/');
|
||||
if(p) *p = '\0'; // remove file name to have only full path, without last '/'
|
||||
char* tmp = (char*)calloc(1, strlen(rpath)-strlen("${ORIGIN}")+strlen(origin)+1);
|
||||
p = strstr(rpath, "${ORIGIN}");
|
||||
memcpy(tmp, rpath, p-rpath);
|
||||
strcat(tmp, origin);
|
||||
strcat(tmp, p+strlen("${ORIGIN}"));
|
||||
if(rpath!=rpathref)
|
||||
free(rpath);
|
||||
rpath = tmp;
|
||||
free(origin);
|
||||
}
|
||||
if(strchr(rpath, '$')) {
|
||||
printf_log(LOG_INFO, "BOX86: Warning, RPATH with $ variable not supported yet (%s)\n", rpath);
|
||||
@@ -783,8 +908,8 @@ int LoadNeededLibs(elfheader_t* h, lib_t *maplib, needed_libs_t* neededlibs, int
|
||||
for (int i=0; i<h->numDynamic; ++i)
|
||||
if(h->Dynamic[i].d_tag==DT_NEEDED) {
|
||||
char *needed = h->DynStrTab+h->delta+h->Dynamic[i].d_un.d_val;
|
||||
// TODO: Add LD_LIBRARY_PATH and RPATH Handling
|
||||
if(AddNeededLib(maplib, neededlibs, local, needed, box86, emu)) {
|
||||
// TODO: Add LD_LIBRARY_PATH and RPATH handling
|
||||
if(AddNeededLib(maplib, neededlibs, deplib, local, needed, box86, emu)) {
|
||||
printf_log(LOG_INFO, "Error loading needed lib: \"%s\"\n", needed);
|
||||
if(!allow_missing_libs)
|
||||
return 1; //error...
|
||||
@@ -862,9 +987,13 @@ void RunElfFini(elfheader_t* h, x86emu_t *emu)
|
||||
if(!h || h->fini_done)
|
||||
return;
|
||||
h->fini_done = 1;
|
||||
#ifdef ANDROID
|
||||
// TODO: Fix .fini_array on Android
|
||||
printf_log(LOG_DEBUG, "Android does not support Fini for %s\n", ElfName(h));
|
||||
#else
|
||||
// first check fini array
|
||||
Elf32_Addr *addr = (Elf32_Addr*)(h->finiarray + h->delta);
|
||||
for (int i=0; i<h->finiarray_sz; ++i) {
|
||||
for (int i=h->finiarray_sz-1; i>=0; --i) {
|
||||
printf_log(LOG_DEBUG, "Calling Fini[%d] for %s @%p\n", i, ElfName(h), (void*)addr[i]);
|
||||
RunFunctionWithEmu(emu, 0, (uintptr_t)addr[i], 0);
|
||||
}
|
||||
@@ -875,7 +1004,7 @@ void RunElfFini(elfheader_t* h, x86emu_t *emu)
|
||||
RunFunctionWithEmu(emu, 0, p, 0);
|
||||
}
|
||||
h->init_done = 0; // can be re-inited again...
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
uintptr_t GetElfInit(elfheader_t* h)
|
||||
@@ -1007,8 +1136,8 @@ dynablocklist_t* GetDynablocksFromAddress(box86context_t *context, uintptr_t add
|
||||
return ret;
|
||||
}*/
|
||||
if(box86_dynarec_forced) {
|
||||
addDBFromAddressRange(my_context, addr, 1, 1);
|
||||
return my_context->dynmap[addr>>DYNAMAP_SHIFT];
|
||||
addDBFromAddressRange(addr, 1);
|
||||
return getDB(addr>>DYNAMAP_SHIFT);
|
||||
}
|
||||
//check if address is in an elf... if yes, grant a block (should I warn)
|
||||
Dl_info info;
|
||||
@@ -1159,34 +1288,48 @@ EXPORT void PltResolver(x86emu_t* emu)
|
||||
uintptr_t addr = Pop32(emu);
|
||||
int slot = (int)Pop32(emu);
|
||||
elfheader_t *h = (elfheader_t*)addr;
|
||||
printf_log(LOG_DEBUG, "PltResolver: Addr=%p, Slot=%d Return=%p: elf is %s\n", (void*)addr, slot, *(void**)(R_ESP), h->name);
|
||||
printf_log(LOG_DEBUG, "PltResolver: Addr=%p, Slot=%d Return=%p: elf is %s (VerSym=%p)\n", (void*)addr, slot, *(void**)(R_ESP), h->name, h->VerSym);
|
||||
|
||||
Elf32_Rel * rel = (Elf32_Rel *)(h->jmprel + h->delta + slot);
|
||||
|
||||
Elf32_Sym *sym = &h->DynSym[ELF32_R_SYM(rel->r_info)];
|
||||
int bind = ELF32_ST_BIND(sym->st_info);
|
||||
const char* symname = SymName(h, sym);
|
||||
int version = h->VerSym?((Elf32_Half*)((uintptr_t)h->VerSym+h->delta))[ELF32_R_SYM(rel->r_info)]:0;
|
||||
const char* ver = GetSymbolVersion(h, version);
|
||||
char symnameversionned[501];
|
||||
strncpy(symnameversionned, symname, 500);
|
||||
if(ver) {
|
||||
strncat(symnameversionned, "@", 500);
|
||||
strncat(symnameversionned, ver, 500);
|
||||
}
|
||||
uint32_t *p = (uint32_t*)(rel->r_offset + h->delta);
|
||||
uintptr_t offs = 0;
|
||||
uintptr_t end = 0;
|
||||
|
||||
library_t* lib = h->lib;
|
||||
lib_t* local_maplib = GetMaplib(lib);
|
||||
if(local_maplib)
|
||||
GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end);
|
||||
if(!offs && !end)
|
||||
GetGlobalSymbolStartEnd(my_context->maplib, symname, &offs, &end);
|
||||
if(local_maplib) {
|
||||
GetGlobalSymbolStartEnd(local_maplib, symnameversionned, &offs, &end);
|
||||
if(!offs && !end)
|
||||
GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end);
|
||||
}
|
||||
if(!offs && !end) {
|
||||
GetGlobalSymbolStartEnd(my_context->maplib, symnameversionned, &offs, &end);
|
||||
if(!offs && !end)
|
||||
GetGlobalSymbolStartEnd(my_context->maplib, symname, &offs, &end);
|
||||
}
|
||||
|
||||
if (!offs) {
|
||||
printf_log(LOG_NONE, "Error: PltReolver: Symbol %s not found, cannot apply R_386_JMP_SLOT @%p (%p) in %s\n", symname, p, *(void**)p, h->name);
|
||||
printf_log(LOG_NONE, "Error: PltReolver: Symbol %s(%s) not found, cannot apply R_386_JMP_SLOT @%p (%p) in %s\n", symname, symnameversionned, p, *(void**)p, h->name);
|
||||
emu->quit = 1;
|
||||
return;
|
||||
} else {
|
||||
if(p) {
|
||||
printf_log(LOG_DEBUG, "PltReolver: Apply %s R_386_JMP_SLOT @%p with sym=%s (%p -> %p / %s)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)offs, ElfName(FindElfAddress(my_context, offs)));
|
||||
printf_log(LOG_DEBUG, "PltReolver: Apply %s R_386_JMP_SLOT @%p with sym=%s(%s) (%p -> %p / %s)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, symnameversionned,*(void**)p, (void*)offs, ElfName(FindElfAddress(my_context, offs)));
|
||||
*p = offs;
|
||||
} else {
|
||||
printf_log(LOG_NONE, "PltReolver: Warning, Symbol %s found, but Jump Slot Offset is NULL \n", symname);
|
||||
printf_log(LOG_NONE, "PltReolver: Warning, Symbol %s(%s) found, but Jump Slot Offset is NULL \n", symname, symnameversionned);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,10 @@ struct elfheader_s {
|
||||
int numDynamic;
|
||||
char* DynStrTab;
|
||||
int szDynStrTab;
|
||||
Elf32_Half* VerSym;
|
||||
Elf32_Verneed* VerNeed;
|
||||
int szVerNeed;
|
||||
int e_type;
|
||||
|
||||
intptr_t delta; // should be 0
|
||||
|
||||
|
||||
+95
-48
@@ -120,6 +120,7 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
h->numPHEntries = header.e_phnum;
|
||||
h->numSHEntries = header.e_shnum;
|
||||
h->SHIdx = header.e_shstrndx;
|
||||
h->e_type = header.e_type;
|
||||
if(header.e_shentsize && header.e_shnum) {
|
||||
// special cases for nums
|
||||
if(h->numSHEntries == 0) {
|
||||
@@ -188,30 +189,79 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
// also grab the DT_STRTAB string table
|
||||
{
|
||||
for (int i=0; i<h->numDynamic; ++i) {
|
||||
if(h->Dynamic[i].d_tag == DT_REL)
|
||||
h->rel = h->Dynamic[i].d_un.d_ptr;
|
||||
else if(h->Dynamic[i].d_tag == DT_RELSZ)
|
||||
h->relsz = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_RELENT)
|
||||
h->relent = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_RELA)
|
||||
h->rela = h->Dynamic[i].d_un.d_ptr;
|
||||
else if(h->Dynamic[i].d_tag == DT_RELASZ)
|
||||
h->relasz = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_RELAENT)
|
||||
h->relaent = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_PLTGOT)
|
||||
h->pltgot = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_PLTREL)
|
||||
h->pltrel = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_PLTRELSZ)
|
||||
h->pltsz = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_JMPREL)
|
||||
h->jmprel = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_STRTAB)
|
||||
h->DynStrTab = (char*)(h->Dynamic[i].d_un.d_ptr);
|
||||
else if(h->Dynamic[i].d_tag == DT_STRSZ)
|
||||
h->szDynStrTab = h->Dynamic[i].d_un.d_val;
|
||||
Elf32_Dyn d = h->Dynamic[i];
|
||||
Elf32_Word val = d.d_un.d_val;
|
||||
Elf32_Addr ptr = d.d_un.d_ptr;
|
||||
switch (d.d_tag) {
|
||||
case DT_REL:
|
||||
h->rel = ptr;
|
||||
break;
|
||||
case DT_RELSZ:
|
||||
h->relsz = val;
|
||||
break;
|
||||
case DT_RELENT:
|
||||
h->relent = val;
|
||||
break;
|
||||
case DT_RELA:
|
||||
h->rela = ptr;
|
||||
break;
|
||||
case DT_RELASZ:
|
||||
h->relasz = val;
|
||||
break;
|
||||
case DT_RELAENT:
|
||||
h->relaent = val;
|
||||
break;
|
||||
case DT_PLTGOT:
|
||||
h->pltgot = val;
|
||||
break;
|
||||
case DT_PLTREL:
|
||||
h->pltrel = val;
|
||||
break;
|
||||
case DT_PLTRELSZ:
|
||||
h->pltsz = val;
|
||||
break;
|
||||
case DT_JMPREL:
|
||||
h->jmprel = val;
|
||||
break;
|
||||
case DT_STRTAB:
|
||||
h->DynStrTab = (char *)(ptr);
|
||||
break;
|
||||
case DT_STRSZ:
|
||||
h->szDynStrTab = val;
|
||||
break;
|
||||
case DT_INIT: // Entry point
|
||||
h->initentry = ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_INIT is at address %p\n", (void*)h->initentry);
|
||||
break;
|
||||
case DT_INIT_ARRAY:
|
||||
h->initarray = ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_INIT_ARRAY is at address %p\n", (void*)h->initarray);
|
||||
break;
|
||||
case DT_INIT_ARRAYSZ:
|
||||
h->initarray_sz = val / sizeof(Elf32_Addr);
|
||||
printf_log(LOG_DEBUG, "The DT_INIT_ARRAYSZ is %d\n", h->initarray_sz);
|
||||
break;
|
||||
case DT_FINI: // Exit hook
|
||||
h->finientry = ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_FINI is at address %p\n", (void*)h->finientry);
|
||||
break;
|
||||
case DT_FINI_ARRAY:
|
||||
h->finiarray = ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_FINI_ARRAY is at address %p\n", (void*)h->finiarray);
|
||||
break;
|
||||
case DT_FINI_ARRAYSZ:
|
||||
h->finiarray_sz = val / sizeof(Elf32_Addr);
|
||||
printf_log(LOG_DEBUG, "The DT_FINI_ARRAYSZ is %d\n", h->finiarray_sz);
|
||||
break;
|
||||
case DT_VERNEEDNUM:
|
||||
h->szVerNeed = val / sizeof(Elf32_Verneed);
|
||||
printf_log(LOG_DEBUG, "The DT_VERNEEDNUM is %d\n", h->szVerNeed);
|
||||
break;
|
||||
case DT_VERNEED:
|
||||
h->VerNeed = (Elf32_Verneed*)ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_VERNEED is at address %p\n", h->VerNeed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(h->rel) {
|
||||
if(h->relent != sizeof(Elf32_Rel)) {
|
||||
@@ -269,31 +319,11 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
h->plt_end = h->plt + h->SHEntries[ii].sh_size;
|
||||
printf_log(LOG_DEBUG, "The PLT Table is at address %p..%p\n", (void*)h->plt, (void*)h->plt_end);
|
||||
}
|
||||
// look for .init entry point
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".init");
|
||||
// grab version of symbols
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".gnu.version");
|
||||
if(ii) {
|
||||
h->initentry = h->SHEntries[ii].sh_addr;
|
||||
printf_log(LOG_DEBUG, "The .init is at address %p\n", (void*)h->initentry);
|
||||
}
|
||||
// and .init_array
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".init_array");
|
||||
if(ii) {
|
||||
h->initarray_sz = h->SHEntries[ii].sh_size / sizeof(Elf32_Addr);
|
||||
h->initarray = (uintptr_t)(h->SHEntries[ii].sh_addr);
|
||||
printf_log(LOG_DEBUG, "The .init_array is at address %p, and have %d elements\n", (void*)h->initarray, h->initarray_sz);
|
||||
}
|
||||
// look for .fini entry point
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".fini");
|
||||
if(ii) {
|
||||
h->finientry = h->SHEntries[ii].sh_addr;
|
||||
printf_log(LOG_DEBUG, "The .fini is at address %p\n", (void*)h->finientry);
|
||||
}
|
||||
// and .fini_array
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".fini_array");
|
||||
if(ii) {
|
||||
h->finiarray_sz = h->SHEntries[ii].sh_size / sizeof(Elf32_Addr);
|
||||
h->finiarray = (uintptr_t)(h->SHEntries[ii].sh_addr);
|
||||
printf_log(LOG_DEBUG, "The .fini_array is at address %p, and have %d elements\n", (void*)h->finiarray, h->finiarray_sz);
|
||||
h->VerSym = (Elf32_Half*)(h->SHEntries[ii].sh_addr);
|
||||
printf_log(LOG_DEBUG, "The .gnu.version is at address %p\n", h->VerSym);
|
||||
}
|
||||
// grab .text for main code
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".text");
|
||||
@@ -310,3 +340,20 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
const char* GetSymbolVersion(elfheader_t* h, int version)
|
||||
{
|
||||
if(!h->VerNeed || (version<2))
|
||||
return NULL;
|
||||
Elf32_Verneed *ver = (Elf32_Verneed*)((uintptr_t)h->VerNeed + h->delta);
|
||||
while(ver) {
|
||||
Elf32_Vernaux *aux = (Elf32_Vernaux*)((uintptr_t)ver + ver->vn_aux);
|
||||
for(int j=0; j<ver->vn_cnt; ++j) {
|
||||
if(aux->vna_other==version)
|
||||
return h->DynStr+aux->vna_name;
|
||||
aux = (Elf32_Vernaux*)((uintptr_t)aux + aux->vna_next);
|
||||
}
|
||||
ver = ver->vn_next?((Elf32_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
+4
-3
@@ -111,8 +111,8 @@
|
||||
} else getecommono(A, reg32_t, O)
|
||||
#define getem(A) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = &emu->mmx[(nextop&7)]; \
|
||||
} else getecommon(A, mmx_regs_t)
|
||||
A = &emu->mmx87[(nextop&7)]; \
|
||||
} else getecommon(A, mmx87_regs_t)
|
||||
#define getex(A) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = &emu->xmm[(nextop&7)]; \
|
||||
@@ -141,10 +141,11 @@
|
||||
#define EX opex
|
||||
#define GB emu->regs[(nextop>>3)&3].byte[(nextop>>5)&0x1]
|
||||
#define GD emu->regs[((nextop&0x38)>>3)]
|
||||
#define GM emu->mmx[((nextop&0x38)>>3)]
|
||||
#define GM emu->mmx87[((nextop&0x38)>>3)]
|
||||
#define GX emu->xmm[((nextop&0x38)>>3)]
|
||||
|
||||
// Alias
|
||||
#define GET_EW GET_ED
|
||||
#define GET_EW_OFFS GET_ED_OFFS
|
||||
#define EW ED
|
||||
#define GW GD
|
||||
+59
-34
@@ -29,7 +29,12 @@
|
||||
NEXT;
|
||||
|
||||
_0f_0x0B: /* UD2 */
|
||||
kill(getpid(), SIGILL); // this is undefined instruction
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip-2;
|
||||
emit_signal(emu, SIGILL, (void*)R_EIP, 0);
|
||||
ip = R_EIP;
|
||||
if(emu->quit) goto fini;
|
||||
STEP;
|
||||
NEXT;
|
||||
_0f_0x10: /* MOVUPS Gx,Ex */
|
||||
nextop = F8;
|
||||
@@ -144,7 +149,7 @@
|
||||
// rounding should be done; and indefinite integer should also be assigned if overflow or NaN/Inf
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
switch(emu->round) {
|
||||
switch((emu->mxcsr>>13)&3) {
|
||||
case ROUND_Nearest:
|
||||
GM.sd[1] = floorf(EX->f[1]+0.5f);
|
||||
GM.sd[0] = floorf(EX->f[0]+0.5f);
|
||||
@@ -244,6 +249,15 @@
|
||||
goto _default;
|
||||
}
|
||||
NEXT;
|
||||
|
||||
_0f_0x3F:
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip-2;
|
||||
emit_signal(emu, SIGILL, (void*)R_EIP, 0);
|
||||
ip = R_EIP;
|
||||
if(emu->quit) goto fini;
|
||||
STEP;
|
||||
NEXT;
|
||||
|
||||
#define GOCOND(BASE, PREFIX, CONDITIONAL) \
|
||||
_0f_##BASE##_0: \
|
||||
@@ -478,10 +492,14 @@
|
||||
GM.sb[1] = (GM.sw[1] > 127) ? 127 : ((GM.sw[1] < -128) ? -128 : GM.sw[1]);
|
||||
GM.sb[2] = (GM.sw[2] > 127) ? 127 : ((GM.sw[2] < -128) ? -128 : GM.sw[2]);
|
||||
GM.sb[3] = (GM.sw[3] > 127) ? 127 : ((GM.sw[3] < -128) ? -128 : GM.sw[3]);
|
||||
GM.sb[4] = (EM->sw[0] > 127) ? 127 : ((EM->sw[0] < -128) ? -128 : EM->sw[0]);
|
||||
GM.sb[5] = (EM->sw[1] > 127) ? 127 : ((EM->sw[1] < -128) ? -128 : EM->sw[1]);
|
||||
GM.sb[6] = (EM->sw[2] > 127) ? 127 : ((EM->sw[2] < -128) ? -128 : EM->sw[2]);
|
||||
GM.sb[7] = (EM->sw[3] > 127) ? 127 : ((EM->sw[3] < -128) ? -128 : EM->sw[3]);
|
||||
if(EM==&GM)
|
||||
GM.ud[1] = GM.ud[0];
|
||||
else {
|
||||
GM.sb[4] = (EM->sw[0] > 127) ? 127 : ((EM->sw[0] < -128) ? -128 : EM->sw[0]);
|
||||
GM.sb[5] = (EM->sw[1] > 127) ? 127 : ((EM->sw[1] < -128) ? -128 : EM->sw[1]);
|
||||
GM.sb[6] = (EM->sw[2] > 127) ? 127 : ((EM->sw[2] < -128) ? -128 : EM->sw[2]);
|
||||
GM.sb[7] = (EM->sw[3] > 127) ? 127 : ((EM->sw[3] < -128) ? -128 : EM->sw[3]);
|
||||
}
|
||||
NEXT;
|
||||
_0f_0x64: /* PCMPGTB Gm,Em */
|
||||
nextop = F8;
|
||||
@@ -509,33 +527,42 @@
|
||||
GET_EM;
|
||||
for(int i=0; i<4; ++i)
|
||||
GM.ub[i] = (GM.sw[i]<0)?0:((GM.sw[i]>0xff)?0xff:GM.sw[i]);
|
||||
for(int i=0; i<4; ++i)
|
||||
GM.ub[4+i] = (EM->sw[i]<0)?0:((EM->sw[i]>0xff)?0xff:EM->sw[i]);
|
||||
if(EM==&GM)
|
||||
GM.ud[1] = GM.ud[0];
|
||||
else
|
||||
for(int i=0; i<4; ++i)
|
||||
GM.ub[4+i] = (EM->sw[i]<0)?0:((EM->sw[i]>0xff)?0xff:EM->sw[i]);
|
||||
NEXT;
|
||||
_0f_0x68: /* PUNPCKHBW Gm,Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
if(EM==&GM) {eam1 = GM; EM = &eam1;} // copy is needed
|
||||
for(int i=0; i<4; ++i)
|
||||
GM.ub[2 * i] = GM.ub[i + 4];
|
||||
for(int i=0; i<4; ++i)
|
||||
GM.ub[2 * i + 1] = EM->ub[i + 4];
|
||||
if(EM==&GM)
|
||||
for(int i=0; i<4; ++i)
|
||||
GM.ub[2 * i + 1] = GM.ub[2 * i];
|
||||
else
|
||||
for(int i=0; i<4; ++i)
|
||||
GM.ub[2 * i + 1] = EM->ub[i + 4];
|
||||
NEXT;
|
||||
_0f_0x69: /* PUNPCKHWD Gm,Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
if(EM==&GM) {eam1 = GM; EM = &eam1;} // copy is needed
|
||||
for(int i=0; i<2; ++i)
|
||||
GM.uw[2 * i] = GM.uw[i + 2];
|
||||
for(int i=0; i<2; ++i)
|
||||
GM.uw[2 * i + 1] = EM->uw[i + 2];
|
||||
if(EM==&GM)
|
||||
for(int i=0; i<2; ++i)
|
||||
GM.uw[2 * i + 1] = GM.uw[2 * i];
|
||||
else
|
||||
for(int i=0; i<2; ++i)
|
||||
GM.uw[2 * i + 1] = EM->uw[i + 2];
|
||||
NEXT;
|
||||
_0f_0x6A: /* PUNPCKHDQ Gm,Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
if(EM==&GM) {eam1 = GM; EM = &eam1;} // copy is needed
|
||||
GM.ud[0] = GM.ud[1];
|
||||
GM.ud[1] = EM->ud[1];
|
||||
if(EM!=&GM)
|
||||
GM.ud[1] = EM->ud[1];
|
||||
NEXT;
|
||||
_0f_0x6B: /* PACKSSDW Gm,Em */
|
||||
nextop = F8;
|
||||
@@ -543,8 +570,11 @@
|
||||
if(EM==&GM) {eam1 = GM; EM = &eam1;} // copy is needed
|
||||
for(int i=0; i<2; ++i)
|
||||
GM.sw[i] = (GM.sd[i]<-32768)?-32768:((GM.sd[i]>32767)?32767:GM.sd[i]);
|
||||
for(int i=0; i<2; ++i)
|
||||
GM.sw[2+i] = (EM->sd[i]<-32768)?-32768:((EM->sd[i]>32767)?32767:EM->sd[i]);
|
||||
if(EM==&GM)
|
||||
GM.ud[1] = GM.ud[0];
|
||||
else
|
||||
for(int i=0; i<2; ++i)
|
||||
GM.sw[2+i] = (EM->sd[i]<-32768)?-32768:((EM->sd[i]>32767)?32767:EM->sd[i]);
|
||||
NEXT;
|
||||
|
||||
_0f_0x6E: /* MOVD Gm, Ed */
|
||||
@@ -762,22 +792,17 @@
|
||||
// should save flags & all
|
||||
// copy MMX regs...
|
||||
for(int i=0; i<8; ++i)
|
||||
memcpy(((void*)(ED))+32+i*16, &emu->mmx[0], sizeof(emu->mmx[0]));
|
||||
memcpy(((void*)(ED))+32+i*16, &emu->mmx87[0], sizeof(emu->mmx87[0]));
|
||||
// copy SSE regs
|
||||
memcpy(((void*)(ED))+160, &emu->xmm[0], sizeof(emu->xmm));
|
||||
// put also FPU regs in a reserved area...
|
||||
for(int i=0; i<8; ++i)
|
||||
memcpy(((void*)(ED))+416+i*8, &emu->fpu[0], sizeof(emu->fpu[0]));
|
||||
break;
|
||||
case 1: /* FXRSTOR m512byte */
|
||||
// should restore flags & all
|
||||
// copy back MMX regs...
|
||||
for(int i=0; i<8; ++i)
|
||||
memcpy(&emu->mmx[i], ((void*)(ED))+32+i*16, sizeof(emu->mmx[0]));
|
||||
memcpy(&emu->mmx87[i], ((void*)(ED))+32+i*16, sizeof(emu->mmx87[0]));
|
||||
// copy SSE regs
|
||||
memcpy(&emu->xmm[0], ((void*)(ED))+160/4, sizeof(emu->xmm));
|
||||
for(int i=0; i<8; ++i)
|
||||
memcpy(&emu->fpu[0], ((void*)(ED))+416+i*8, sizeof(emu->fpu[0]));
|
||||
break;
|
||||
case 2: /* LDMXCSR Md */
|
||||
emu->mxcsr = ED->dword[0];
|
||||
@@ -795,7 +820,6 @@
|
||||
GD.dword[0] = imul32(emu, GD.dword[0], ED->dword[0]);
|
||||
NEXT;
|
||||
_0f_0xB0: /* CMPXCHG Eb,Gb */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GET_EB;
|
||||
cmp8(emu, R_AL, EB->byte[0]);
|
||||
@@ -1192,20 +1216,17 @@
|
||||
GM.sd[i] >>= tmp8u;
|
||||
}
|
||||
NEXT;
|
||||
_0f_0xE3: /* PSRAQ Gm, Em */
|
||||
_0f_0xE3: /* PAVGW Gm, Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
if(EM->q>63)
|
||||
tmp8u = 64;
|
||||
else
|
||||
tmp8u = EM->ub[0];
|
||||
GM.sq >>= tmp8u;
|
||||
for(int i=0; i<4; ++i)
|
||||
GM.uw[i] = ((uint32_t)GM.uw[i]+EM->uw[i]+1)>>1;
|
||||
NEXT;
|
||||
_0f_0xE4: /* PMULHUW Gm, Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
for(int i=0; i<4; ++i) {
|
||||
tmp32u = (int32_t)GM.uw[i] * EM->uw[i];
|
||||
tmp32u = (uint32_t)GM.uw[i] * EM->uw[i];
|
||||
GM.uw[i] = (tmp32u>>16)&0xffff;
|
||||
}
|
||||
NEXT;
|
||||
@@ -1358,7 +1379,11 @@
|
||||
for(int i=0; i<2; ++i)
|
||||
GM.sd[i] -= EM->sd[i];
|
||||
NEXT;
|
||||
|
||||
_0f_0xFB: /* PSUBQ Gm,Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
GM.sq -= EM->sq;
|
||||
NEXT;
|
||||
_0f_0xFC: /* PADDB Gm, Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
|
||||
+45
-7
@@ -2,16 +2,29 @@
|
||||
goto *opcodes66[opcode];
|
||||
|
||||
#define GO(B, OP) \
|
||||
_66_##B##_0: \
|
||||
nextop = F8; \
|
||||
GET_EB; \
|
||||
EB->byte[0] = OP##8(emu, EB->byte[0], GB); \
|
||||
NEXT; \
|
||||
_66_##B##_1: \
|
||||
nextop = F8; \
|
||||
GET_EW; \
|
||||
EW->word[0] = OP##16(emu, EW->word[0], GW.word[0]); \
|
||||
NEXT; \
|
||||
_66_##B##_2: \
|
||||
nextop = F8; \
|
||||
GET_EB; \
|
||||
GB = OP##8(emu, GB, EB->byte[0]); \
|
||||
NEXT; \
|
||||
_66_##B##_3: \
|
||||
nextop = F8; \
|
||||
GET_EW; \
|
||||
GW.word[0] = OP##16(emu, GW.word[0], EW->word[0]); \
|
||||
NEXT; \
|
||||
_66_##B##_4: \
|
||||
R_AL = OP##8(emu, R_AL, F8); \
|
||||
NEXT; \
|
||||
_66_##B##_5: \
|
||||
R_AX = OP##16(emu, R_AX, F16); \
|
||||
NEXT;
|
||||
@@ -41,6 +54,11 @@
|
||||
if(emu->quit) goto fini;
|
||||
STEP
|
||||
NEXT;
|
||||
|
||||
_66_0x1F: /* POP DS */
|
||||
emu->segs[_DS] = Pop16(emu); // no check, no use....
|
||||
emu->segs_serial[_DS] = 0;
|
||||
NEXT;
|
||||
|
||||
_66_0x26: /* ES: */
|
||||
// ignored
|
||||
@@ -135,6 +153,13 @@
|
||||
R_AX = Pop16(emu);
|
||||
NEXT;
|
||||
|
||||
_66_0x64:
|
||||
R_EIP = ip-2;
|
||||
RunFS66(emu, GetFSBaseEmu(emu));
|
||||
ip = R_EIP;
|
||||
STEP;
|
||||
NEXT;
|
||||
|
||||
_66_0x66:
|
||||
goto _0x66; // 0x66 0x66 => can remove one 0x66
|
||||
|
||||
@@ -247,15 +272,12 @@
|
||||
|
||||
_66_0x9C: /* PUSHFW */
|
||||
CHECK_FLAGS(emu);
|
||||
PackFlags(emu);
|
||||
Push16(emu, (uint16_t)emu->packed_eflags.x32);
|
||||
Push16(emu, (uint16_t)emu->eflags.x32);
|
||||
NEXT;
|
||||
_66_0x9D: /* POPFW */
|
||||
CHECK_FLAGS(emu);
|
||||
PackFlags(emu);
|
||||
emu->packed_eflags.x32 &=0xffff0000;
|
||||
emu->packed_eflags.x32 |= (Pop16(emu) & 0x3F7FD7) | 0x2;
|
||||
UnpackFlags(emu);
|
||||
emu->eflags.x32 &=0xffff0000;
|
||||
emu->eflags.x32 |= (Pop16(emu) & 0x3F7FD7) | 0x2;
|
||||
NEXT;
|
||||
|
||||
_66_0xA1: /* MOV AX,Ow */
|
||||
@@ -333,6 +355,22 @@
|
||||
EW->word[0] = F16;
|
||||
NEXT;
|
||||
|
||||
_66_0xCB: /* FAR RET */
|
||||
ip = Pop(emu);
|
||||
emu->segs[_CS] = Pop(emu); // no check, no use....
|
||||
emu->segs_serial[_CS] = 0;
|
||||
// need to check status of CS register!
|
||||
STEP
|
||||
NEXT;
|
||||
_66_0xCC: /* INT3 */
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip-1;
|
||||
if(my_context->signals[SIGTRAP])
|
||||
raise(SIGTRAP);
|
||||
ip = R_EIP;
|
||||
if(emu->quit) goto fini;
|
||||
STEP
|
||||
NEXT;
|
||||
_66_0xD1: /* GRP2 Ew,1 */
|
||||
_66_0xD3: /* GRP2 Ew,CL */
|
||||
nextop = F8;
|
||||
@@ -370,7 +408,7 @@
|
||||
|
||||
_66_0xF0: /* LOCK prefix */
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip;
|
||||
R_EIP = ip - 2;
|
||||
RunLock66(emu);
|
||||
ip = R_EIP;
|
||||
if(emu->quit) goto fini;
|
||||
|
||||
+5
-5
@@ -8,9 +8,9 @@
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7: /* FLD STx */
|
||||
ll = ST(nextop&7).ll;
|
||||
ll = ST(nextop&7).q;
|
||||
fpu_do_push(emu);
|
||||
ST0.ll = ll;
|
||||
ST0.q = ll;
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
@@ -20,9 +20,9 @@
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF: /* FXCH STx */
|
||||
ll = ST(nextop&7).ll;
|
||||
ST(nextop&7).ll = ST0.ll;
|
||||
ST0.ll = ll;
|
||||
ll = ST(nextop&7).q;
|
||||
ST(nextop&7).q = ST0.q;
|
||||
ST0.q = ll;
|
||||
break;
|
||||
|
||||
case 0xD0: /* FNOP */
|
||||
|
||||
+4
-4
@@ -11,7 +11,7 @@
|
||||
case 0xC7:
|
||||
CHECK_FLAGS(emu);
|
||||
if(ACCESS_FLAG(F_CF))
|
||||
ST0.ll = ST(nextop&7).ll;
|
||||
ST0.q = ST(nextop&7).q;
|
||||
break;
|
||||
case 0xC8: /* FCMOVE ST(0), ST(i) */
|
||||
case 0xC9:
|
||||
@@ -23,7 +23,7 @@
|
||||
case 0xCF:
|
||||
CHECK_FLAGS(emu);
|
||||
if(ACCESS_FLAG(F_ZF))
|
||||
ST0.ll = ST(nextop&7).ll;
|
||||
ST0.q = ST(nextop&7).q;
|
||||
break;
|
||||
case 0xD0: /* FCMOVBE ST(0), ST(i) */
|
||||
case 0xD1:
|
||||
@@ -35,7 +35,7 @@
|
||||
case 0xD7:
|
||||
CHECK_FLAGS(emu);
|
||||
if(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF))
|
||||
ST0.ll = ST(nextop&7).ll;
|
||||
ST0.q = ST(nextop&7).q;
|
||||
break;
|
||||
case 0xD8: /* FCMOVU ST(0), ST(i) */
|
||||
case 0xD9:
|
||||
@@ -47,7 +47,7 @@
|
||||
case 0xDF:
|
||||
CHECK_FLAGS(emu);
|
||||
if(ACCESS_FLAG(F_PF))
|
||||
ST0.ll = ST(nextop&7).ll;
|
||||
ST0.q = ST(nextop&7).q;
|
||||
break;
|
||||
|
||||
case 0xE9: /* FUCOMPP */
|
||||
|
||||
+6
-6
@@ -10,7 +10,7 @@
|
||||
case 0xC7:
|
||||
CHECK_FLAGS(emu);
|
||||
if(!ACCESS_FLAG(F_CF))
|
||||
ST0.ll = ST(nextop&7).ll;
|
||||
ST0.q = ST(nextop&7).q;
|
||||
break;
|
||||
case 0xC8: /* FCMOVNE ST(0), ST(i) */
|
||||
case 0xC9:
|
||||
@@ -22,7 +22,7 @@
|
||||
case 0xCF:
|
||||
CHECK_FLAGS(emu);
|
||||
if(!ACCESS_FLAG(F_ZF))
|
||||
ST0.ll = ST(nextop&7).ll;
|
||||
ST0.q = ST(nextop&7).q;
|
||||
break;
|
||||
case 0xD0: /* FCMOVNBE ST(0), ST(i) */
|
||||
case 0xD1:
|
||||
@@ -34,7 +34,7 @@
|
||||
case 0xD7:
|
||||
CHECK_FLAGS(emu);
|
||||
if(!(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF)))
|
||||
ST0.ll = ST(nextop&7).ll;
|
||||
ST0.q = ST(nextop&7).q;
|
||||
break;
|
||||
case 0xD8: /* FCMOVNU ST(0), ST(i) */
|
||||
case 0xD9:
|
||||
@@ -46,7 +46,7 @@
|
||||
case 0xDF:
|
||||
CHECK_FLAGS(emu);
|
||||
if(!ACCESS_FLAG(F_PF))
|
||||
ST0.ll = ST(nextop&7).ll;
|
||||
ST0.q = ST(nextop&7).q;
|
||||
break;
|
||||
|
||||
case 0xE1: /* FDISI8087_NOP */
|
||||
@@ -133,11 +133,11 @@
|
||||
fpu_do_push(emu);
|
||||
memcpy(&STld(0).ld, ED, 10);
|
||||
LD2D(&STld(0), &ST(0).d);
|
||||
STld(0).ref = ST0.ll;
|
||||
STld(0).ref = ST0.q;
|
||||
break;
|
||||
case 7: /* FSTP tbyte */
|
||||
GET_ED;
|
||||
if(ST0.ll!=STld(0).ref)
|
||||
if(ST0.q!=STld(0).ref)
|
||||
D2LD(&ST0.d, ED);
|
||||
else
|
||||
memcpy(ED, &STld(0).ld, 10);
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF: /* FCOMP */
|
||||
fpu_fcom(emu, ST(nextop&7).d); // TODO: is this ok?
|
||||
fpu_fcom(emu, ST(nextop&7).d);
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xE0:
|
||||
|
||||
+2
-2
@@ -20,7 +20,7 @@
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
ST(nextop&7).ll = ST0.ll;
|
||||
ST(nextop&7).q = ST0.q;
|
||||
break;
|
||||
case 0xD8: /* FSTP ST0, STx */
|
||||
case 0xD9:
|
||||
@@ -30,7 +30,7 @@
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
ST(nextop&7).ll = ST0.ll;
|
||||
ST(nextop&7).q = ST0.q;
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xE0: /* FUCOM ST0, STx */
|
||||
|
||||
+15
-11
@@ -12,6 +12,18 @@
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
|
||||
case 0xD0: /* FSTP STx, ST0 */
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
ST(nextop&7).q = ST0.q;
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
|
||||
case 0xE0: /* FNSTSW AX */
|
||||
emu->sw.f.F87_TOP = emu->top&7;
|
||||
R_AX = emu->sw.x16;
|
||||
@@ -49,14 +61,6 @@
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
@@ -122,7 +126,7 @@
|
||||
fpu_do_push(emu);
|
||||
ST0.d = tmp64s;
|
||||
STll(0).ll = tmp64s;
|
||||
STll(0).ref = ST0.ll;
|
||||
STll(0).ref = ST0.q;
|
||||
break;
|
||||
case 6: /* FBSTP tbytes, ST0 */
|
||||
GET_ED;
|
||||
@@ -133,7 +137,7 @@
|
||||
GET_ED;
|
||||
if((uintptr_t)ED & 0x7) {
|
||||
// un-aligned!
|
||||
if(STll(0).ref==ST(0).ll)
|
||||
if(STll(0).ref==ST(0).q)
|
||||
memcpy(ED, &STll(0).ll, sizeof(int64_t));
|
||||
else {
|
||||
int64_t i64;
|
||||
@@ -144,7 +148,7 @@
|
||||
memcpy(ED, &i64, sizeof(int64_t));
|
||||
}
|
||||
} else {
|
||||
if(STll(0).ref==ST(0).ll)
|
||||
if(STll(0).ref==ST(0).q)
|
||||
*(int64_t*)ED = STll(0).ll;
|
||||
else {
|
||||
if(isgreater(ST0.d, (double)(int64_t)0x7fffffffffffffffLL) || isless(ST0.d, -(double)(int64_t)0x7fffffffffffffffLL) || !isfinite(ST0.d))
|
||||
|
||||
+19
-4
@@ -35,7 +35,7 @@
|
||||
case 0x2D: /* CVTSD2SI Gd, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
switch(emu->round) {
|
||||
switch((emu->mxcsr>>13)&3) {
|
||||
case ROUND_Nearest:
|
||||
GD.sdword[0] = floor(EX->d[0]+0.5);
|
||||
break;
|
||||
@@ -66,7 +66,6 @@
|
||||
GET_EX;
|
||||
GX.d[0] *= EX->d[0];
|
||||
break;
|
||||
|
||||
case 0x5A: /* CVTSD2SS Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
@@ -248,8 +247,24 @@
|
||||
case 0xE6: /* CVTPD2DQ Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GX.sd[0] = EX->d[0];
|
||||
GX.sd[1] = EX->d[1];
|
||||
switch((emu->mxcsr>>13)&3) {
|
||||
case ROUND_Nearest:
|
||||
GX.sd[0] = floor(EX->d[0]+0.5);
|
||||
GX.sd[1] = floor(EX->d[1]+0.5);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
GX.sd[0] = floor(EX->d[0]);
|
||||
GX.sd[1] = floor(EX->d[1]);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
GX.sd[0] = ceil(EX->d[0]);
|
||||
GX.sd[1] = ceil(EX->d[1]);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
GX.sd[0] = EX->d[0];
|
||||
GX.sd[1] = EX->d[1];
|
||||
break;
|
||||
}
|
||||
GX.q[1] = 0;
|
||||
break;
|
||||
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@
|
||||
case 0x2D: /* CVTSS2SI Gd, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
switch(emu->round) {
|
||||
switch((emu->mxcsr>>13)&3) {
|
||||
case ROUND_Nearest:
|
||||
GD.sdword[0] = floor(EX->f[0]+0.5);
|
||||
break;
|
||||
|
||||
+53
-35
@@ -5,6 +5,7 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
@@ -15,6 +16,13 @@
|
||||
#include "x86run.h"
|
||||
#include "x86run_private.h"
|
||||
#include "callback.h"
|
||||
#include "bridge.h"
|
||||
#ifdef HAVE_TRACE
|
||||
#include "x86trace.h"
|
||||
#endif
|
||||
#ifdef DYNAREC
|
||||
#include "custommem.h"
|
||||
#endif
|
||||
|
||||
typedef struct cleanup_s {
|
||||
void* f;
|
||||
@@ -34,22 +42,20 @@ static uint32_t x86emu_parity_tab[8] =
|
||||
0x69969669,
|
||||
};
|
||||
|
||||
static uint8_t EndEmuMarker[] = {0xcc, 'S', 'C', 0, 0, 0, 0};
|
||||
#ifdef DYNAREC
|
||||
void DynablockEmuMarker(box86context_t* context)
|
||||
uint32_t* GetParityTab()
|
||||
{
|
||||
dynarec_log(LOG_DUMP, "Create bridge memory map for PushExit\n");
|
||||
addDBFromAddressRange(context, (uintptr_t)&EndEmuMarker[0], sizeof(EndEmuMarker), 0);
|
||||
return x86emu_parity_tab;
|
||||
}
|
||||
#endif
|
||||
|
||||
void PushExit(x86emu_t* emu)
|
||||
{
|
||||
Push(emu, (uint32_t)&EndEmuMarker);
|
||||
uintptr_t endMarker = AddCheckBridge(my_context->system, NULL, NULL, 0);
|
||||
Push(emu, endMarker);
|
||||
}
|
||||
|
||||
void* GetExit()
|
||||
{
|
||||
return &EndEmuMarker;
|
||||
return (void*)AddCheckBridge(my_context->system, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
static void internalX86Setup(x86emu_t* emu, box86context_t *context, uintptr_t start, uintptr_t stack, int stacksize, int ownstack)
|
||||
@@ -60,8 +66,7 @@ static void internalX86Setup(x86emu_t* emu, box86context_t *context, uintptr_t s
|
||||
emu->sbiidx[i] = &emu->regs[i];
|
||||
emu->sbiidx[4] = &emu->zero;
|
||||
emu->x86emu_parity_tab = x86emu_parity_tab;
|
||||
emu->packed_eflags.x32 = 0x202; // default flags?
|
||||
UnpackFlags(emu);
|
||||
emu->eflags.x32 = 0x202; // default flags?
|
||||
// own stack?
|
||||
emu->stack2free = (ownstack)?(void*)stack:NULL;
|
||||
emu->init_stack = (void*)stack;
|
||||
@@ -76,6 +81,7 @@ static void internalX86Setup(x86emu_t* emu, box86context_t *context, uintptr_t s
|
||||
emu->segs[_GS] = 0x33;
|
||||
// setup fpu regs
|
||||
reset_fpu(emu);
|
||||
emu->mxcsr = 0x1f80;
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
@@ -165,11 +171,14 @@ void CallAllCleanup(x86emu_t *emu)
|
||||
RunFunctionWithEmu(emu, 0, (uintptr_t)(my_context->cleanups[i].f), my_context->cleanups[i].arg, my_context->cleanups[i].a );
|
||||
}
|
||||
my_context->clean_sz = 0;
|
||||
free(my_context->cleanups);
|
||||
my_context->cleanups = NULL;
|
||||
}
|
||||
|
||||
static void internalFreeX86(x86emu_t* emu)
|
||||
{
|
||||
free(emu->stack2free);
|
||||
if(emu->stack2free)
|
||||
munmap(emu->stack2free, emu->size_stack);
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
@@ -177,7 +186,7 @@ void FreeX86Emu(x86emu_t **emu)
|
||||
{
|
||||
if(!emu)
|
||||
return;
|
||||
printf_log(LOG_DEBUG, "Free a X86 Emu (%p)\n", *emu);
|
||||
printf_log(LOG_DEBUG, "%04d|Free a X86 Emu (%p)\n", GetTID(), *emu);
|
||||
|
||||
internalFreeX86(*emu);
|
||||
|
||||
@@ -189,7 +198,7 @@ void FreeX86EmuFromStack(x86emu_t **emu)
|
||||
{
|
||||
if(!emu)
|
||||
return;
|
||||
printf_log(LOG_DEBUG, "Free a X86 Emu from stack (%p)\n", *emu);
|
||||
printf_log(LOG_DEBUG, "%04d|Free a X86 Emu from stack (%p)\n", GetTID(), *emu);
|
||||
|
||||
internalFreeX86(*emu);
|
||||
}
|
||||
@@ -198,12 +207,11 @@ void CloneEmu(x86emu_t *newemu, const x86emu_t* emu)
|
||||
{
|
||||
memcpy(newemu->regs, emu->regs, sizeof(emu->regs));
|
||||
memcpy(&newemu->ip, &emu->ip, sizeof(emu->ip));
|
||||
memcpy(&newemu->packed_eflags, &emu->packed_eflags, sizeof(emu->packed_eflags));
|
||||
memcpy(&newemu->flags, &emu->flags, sizeof(emu->flags));
|
||||
memcpy(&newemu->eflags, &emu->eflags, sizeof(emu->eflags));
|
||||
newemu->old_ip = emu->old_ip;
|
||||
memcpy(newemu->segs, emu->segs, sizeof(emu->segs));
|
||||
memset(newemu->segs_serial, 0, sizeof(newemu->segs_serial));
|
||||
memcpy(newemu->fpu, emu->fpu, sizeof(emu->fpu));
|
||||
memcpy(newemu->mmx87, emu->mmx87, sizeof(emu->mmx87));
|
||||
memcpy(newemu->fpu_ld, emu->fpu_ld, sizeof(emu->fpu_ld));
|
||||
memcpy(newemu->fpu_ll, emu->fpu_ll, sizeof(emu->fpu_ll));
|
||||
memcpy(newemu->p_regs, emu->p_regs, sizeof(emu->p_regs));
|
||||
@@ -213,7 +221,6 @@ void CloneEmu(x86emu_t *newemu, const x86emu_t* emu)
|
||||
newemu->top = emu->top;
|
||||
newemu->fpu_stack = emu->fpu_stack;
|
||||
memcpy(&newemu->round, &emu->round, sizeof(emu->round));
|
||||
memcpy(newemu->mmx, emu->mmx, sizeof(emu->mmx));
|
||||
memcpy(newemu->xmm, emu->xmm, sizeof(emu->xmm));
|
||||
newemu->mxcsr = emu->mxcsr;
|
||||
newemu->quit = emu->quit;
|
||||
@@ -301,7 +308,7 @@ const char* DumpCPURegs(x86emu_t* emu, uintptr_t ip)
|
||||
if(trace_emm) {
|
||||
// do emm reg is needed
|
||||
for(int i=0; i<8; ++i) {
|
||||
sprintf(tmp, "mm%d:%016llx", i, emu->mmx[i].q);
|
||||
sprintf(tmp, "mm%d:%016llx", i, emu->mmx87[i].q);
|
||||
strcat(buff, tmp);
|
||||
if ((i&3)==3) strcat(buff, "\n"); else strcat(buff, " ");
|
||||
}
|
||||
@@ -317,7 +324,7 @@ const char* DumpCPURegs(x86emu_t* emu, uintptr_t ip)
|
||||
// start with FPU regs...
|
||||
if(emu->fpu_stack) {
|
||||
for (int i=0; i<emu->fpu_stack; i++) {
|
||||
sprintf(tmp, "ST%d=%f", i, emu->fpu[(emu->top+i)&7].d);
|
||||
sprintf(tmp, "ST%d=%f", i, emu->mmx87[(emu->top+i)&7].d);
|
||||
strcat(buff, tmp);
|
||||
int c = 10-strlen(tmp);
|
||||
if(c<1) c=1;
|
||||
@@ -351,8 +358,19 @@ void StopEmu(x86emu_t* emu, const char* reason)
|
||||
emu->quit = 1;
|
||||
printf_log(LOG_NONE, "%s", reason);
|
||||
// dump stuff...
|
||||
printf_log(LOG_NONE, "CPU Regs=%s\n", DumpCPURegs(emu, R_EIP));
|
||||
// TODO: stack, memory/instruction around EIP, etc..
|
||||
printf_log(LOG_NONE, "\n==== CPU Registers ====\n%s\n", DumpCPURegs(emu, R_EIP));
|
||||
printf_log(LOG_NONE, "\n======== Stack ========\nStack is from 0x%x to 0x%0x\n", R_EBP, R_ESP);
|
||||
if (R_EBP == R_ESP) {
|
||||
printf_log(LOG_NONE, "EBP = ESP: leaf function detected; next 128 bytes should be either data or random.\n");
|
||||
} else {
|
||||
// TODO: display stack if operation should be allowed (to avoid crashes)
|
||||
/* for (uint32_t *sp = R_EBP; sp >= R_ESP; --sp) {
|
||||
} */
|
||||
}
|
||||
printf_log(LOG_NONE, "\n====== Past data ======\nOld IP: %tX\n", emu->old_ip);
|
||||
#ifdef HAVE_TRACE
|
||||
printf_log(LOG_NONE, "%s\n", DecodeX86Trace(my_context->dec, emu->old_ip));
|
||||
#endif
|
||||
}
|
||||
|
||||
void UnimpOpcode(x86emu_t* emu)
|
||||
@@ -360,8 +378,8 @@ void UnimpOpcode(x86emu_t* emu)
|
||||
R_EIP = emu->old_ip;
|
||||
|
||||
int tid = syscall(SYS_gettid);
|
||||
printf_log(LOG_NONE, "%04d|%p: Unimplemented Opcode %02X %02X %02X %02X %02X %02X %02X %02X\n",
|
||||
tid, (void*)emu->old_ip,
|
||||
printf_log(LOG_NONE, "%04d|%p: Unimplemented Opcode (%02X) %02X %02X %02X %02X %02X %02X %02X %02X\n",
|
||||
tid, (void*)emu->old_ip, Peek(emu, -1),
|
||||
Peek(emu, 0), Peek(emu, 1), Peek(emu, 2), Peek(emu, 3),
|
||||
Peek(emu, 4), Peek(emu, 5), Peek(emu, 6), Peek(emu, 7));
|
||||
emu->quit=1;
|
||||
@@ -436,11 +454,11 @@ static inline void init_perfcounters (int32_t do_reset, int32_t enable_divider)
|
||||
uint64_t ReadTSC(x86emu_t* emu)
|
||||
{
|
||||
// Read the TimeStamp Counter as 64bits.
|
||||
// this is supposed to be the number of instrunctions executed since last reset
|
||||
// this is supposed to be the number of instructions executed since last reset
|
||||
#if defined(__i386__)
|
||||
uint64_t ret;
|
||||
__asm__ volatile("rdtsc" : "=A"(ret));
|
||||
return ret;
|
||||
uint64_t ret;
|
||||
__asm__ volatile("rdtsc" : "=A"(ret));
|
||||
return ret;
|
||||
#if 0
|
||||
#elif defined(__ARM_ARCH)
|
||||
#if (__ARM_ARCH >= 6)
|
||||
@@ -456,15 +474,15 @@ uint64_t ReadTSC(x86emu_t* emu)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
// fall back to gettime...
|
||||
// fall back to gettime...
|
||||
#ifndef NOGETCLOCK
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
|
||||
return (uint64_t)(ts.tv_sec) * 1000000000LL + ts.tv_nsec;
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
|
||||
return (uint64_t)(ts.tv_sec) * 1000000000LL + ts.tv_nsec;
|
||||
#else
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return (uint64_t)(tv.tv_sec) * 1000000 + tv.tv_usec;
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return (uint64_t)(tv.tv_sec) * 1000000 + tv.tv_usec;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -473,4 +491,4 @@ void ResetSegmentsCache(x86emu_t *emu)
|
||||
if(!emu)
|
||||
return;
|
||||
memset(emu->segs_serial, 0, sizeof(emu->segs_serial));
|
||||
}
|
||||
}
|
||||
@@ -25,22 +25,20 @@ typedef struct forkpty_s {
|
||||
|
||||
typedef struct x86emu_s {
|
||||
// cpu
|
||||
reg32_t regs[8],ip;
|
||||
int flags[F_LAST];
|
||||
x86flags_t packed_eflags;
|
||||
reg32_t regs[8];
|
||||
x86flags_t eflags;
|
||||
reg32_t ip;
|
||||
uintptr_t old_ip;
|
||||
// fpu
|
||||
fpu_reg_t fpu[9];
|
||||
// fpu / mmx
|
||||
mmx87_regs_t mmx87[8];
|
||||
uint16_t cw,cw_mask_all;
|
||||
x87flags_t sw;
|
||||
uint32_t top; // top is part of sw, but it's faster to have it separatly
|
||||
int fpu_stack;
|
||||
fpu_round_t round;
|
||||
fpu_ld_t fpu_ld[9]; // for long double emulation / 80bits fld fst
|
||||
fpu_ll_t fpu_ll[9]; // for 64bits fild / fist sequence
|
||||
fpu_p_reg_t p_regs[9];
|
||||
// mmx
|
||||
mmx_regs_t mmx[8];
|
||||
fpu_ld_t fpu_ld[8]; // for long double emulation / 80bits fld fst
|
||||
fpu_ll_t fpu_ll[8]; // for 64bits fild / fist sequence
|
||||
fpu_p_reg_t p_regs[8];
|
||||
// sse
|
||||
sse_regs_t xmm[8];
|
||||
uint32_t mxcsr;
|
||||
@@ -67,11 +65,6 @@ typedef struct x86emu_s {
|
||||
int longjmp; // if quit because of longjmp
|
||||
// parent context
|
||||
box86context_t *context;
|
||||
#ifdef DYNAREC
|
||||
// virtual return stack
|
||||
int cstacki; // current index
|
||||
uint64_t cstack[CSTACK+1]; // pair of x86 address / native address for call/ret, using uint64_t for alignement, +1 for allignment
|
||||
#endif
|
||||
// cpu helpers
|
||||
reg32_t zero;
|
||||
reg32_t *sbiidx[8];
|
||||
|
||||
+42
-21
@@ -9,6 +9,7 @@
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
@@ -120,7 +121,7 @@ void x86Int3(x86emu_t* emu)
|
||||
} else if(!strcmp(s, "opendir")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4));
|
||||
perr = 1;
|
||||
} else if(strstr(s, "__open")==s || strcmp(s, "open")==0) {
|
||||
} else if(strstr(s, "__open")==s || !strcmp(s, "open") || !strcmp(s, "my_open64")) {
|
||||
tmp = *(char**)(R_ESP+4);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %d (,%d))", tid, *(void**)(R_ESP), s, (tmp)?tmp:"(nil)", *(int*)(R_ESP+8), *(int*)(R_ESP+12));
|
||||
perr = 1;
|
||||
@@ -155,31 +156,34 @@ void x86Int3(x86emu_t* emu)
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p(\"%s\"), %i(%c))", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+4), *(int32_t*)(R_ESP+8), *(int32_t*)(R_ESP+8));
|
||||
} else if(strstr(s, "rindex")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p(\"%s\"), %i(%c))", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+4), *(int32_t*)(R_ESP+8), *(int32_t*)(R_ESP+8));
|
||||
} else if(strstr(s, "__xstat64")==s) {
|
||||
} else if(strstr(s, "my___xstat64")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p(\"%s\"), %p)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(char**)(R_ESP+8), *(char**)(R_ESP+8), *(void**)(R_ESP+12));
|
||||
perr = 1;
|
||||
} else if(strcmp(s, "__xstat")==0) {
|
||||
} else if(strcmp(s, "my___xstat")==0) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p(\"%s\"), %p)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(char**)(R_ESP+8), *(char**)(R_ESP+8), *(void**)(R_ESP+12));
|
||||
perr = 1;
|
||||
} else if(strstr(s, "__lxstat64")==s) {
|
||||
} else if(strstr(s, "my___lxstat64")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p(\"%s\"), %p)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(char**)(R_ESP+8), *(char**)(R_ESP+8), *(void**)(R_ESP+12));
|
||||
perr = 1;
|
||||
} else if(strstr(s, "sem_timedwait")==s) {
|
||||
pu32 = *(uint32_t**)(R_ESP+8);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, %p[%d sec %d ns])", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(void**)(R_ESP+8), pu32?pu32[0]:-1, pu32?pu32[1]:-1);
|
||||
perr = 1;
|
||||
} else if(strstr(s, "waitpid")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p, 0x%x)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(void**)(R_ESP+8), *(uint32_t*)(R_ESP+12));
|
||||
perr = 1;
|
||||
} else if(strstr(s, "clock_gettime")==s || strstr(s, "__clock_gettime")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(void**)(R_ESP+8));
|
||||
post = 1;
|
||||
pu32 = *(uint32_t**)(R_ESP+8);
|
||||
} else if(strstr(s, "semop")==s) {
|
||||
int16_t* p16 = *(int16_t**)(R_ESP+8);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p[%u/%d/%d], %d)", tid, *(void**)(R_ESP), s, *(int*)(R_ESP+4), p16, p16[0], p16[1], p16[2], *(int*)(R_ESP+12));
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p[%u/%d/0x%x], %d)", tid, *(void**)(R_ESP), s, *(int*)(R_ESP+4), p16, p16[0], p16[1], p16[2], *(int*)(R_ESP+12));
|
||||
perr = 1;
|
||||
} else if(!strcmp(s, "mmap64")) {
|
||||
} else if(!strcmp(s, "my_mmap64")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, 0x%x, %d, 0x%x, %d, %lld)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(size_t*)(R_ESP+8), *(int*)(R_ESP+12), *(int*)(R_ESP+16), *(int*)(R_ESP+20), *(int64_t*)(R_ESP+24));
|
||||
perr = 1;
|
||||
} else if(!strcmp(s, "mmap")) {
|
||||
} else if(!strcmp(s, "my_mmap")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, 0x%x, %d, 0x%x, %d, %d)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(size_t*)(R_ESP+8), *(int*)(R_ESP+12), *(int*)(R_ESP+16), *(int*)(R_ESP+20), *(int*)(R_ESP+24));
|
||||
perr = 1;
|
||||
} else if(strstr(s, "strcasecmp")==s || strstr(s, "__strcasecmp")==s) {
|
||||
@@ -192,40 +196,54 @@ void x86Int3(x86emu_t* emu)
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%.127s\", \"%.127s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(strstr(s, "strlen")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p(\"%s\"))", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), ((R_ESP+4))?(*(char**)(R_ESP+4)):"nil");
|
||||
} else if(strstr(s, "vsnprintf")==s) {
|
||||
} else if(strstr(s, "my_vsnprintf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, %u, %08X...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(uint32_t*)(R_ESP+8), *(uint32_t*)(R_ESP+12));
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
post = 3;
|
||||
} else if(strstr(s, "vsprintf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, \"%s\"...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(strstr(s, "my_vsprintf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\", %p)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(char**)(R_ESP+8), *(void**)(R_ESP+12));
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
post = 3;
|
||||
} else if(strstr(s, "snprintf")==s) {
|
||||
} else if(strstr(s, "my___vsprintf_chk")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, %d, %zu, \"%s\", %p)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(int*)(R_ESP+8), *(size_t*)(R_ESP+12), *(char**)(R_ESP+16), *(void**)(R_ESP+20));
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
post = 3;
|
||||
} else if(strstr(s, "my_snprintf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, %u, %08X...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(uint32_t*)(R_ESP+8), *(uint32_t*)(R_ESP+12));
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
post = 3;
|
||||
} else if(strstr(s, "sprintf")==s) {
|
||||
} else if(strstr(s, "my_sprintf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, %08X...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(uint32_t*)(R_ESP+8));
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
post = 3;
|
||||
} else if(strstr(s, "printf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\"...)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4));
|
||||
} else if(strstr(s, "my_printf")==s) {
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
if(((uintptr_t)pu32)<0x5) // probably a _chk function
|
||||
pu32 = *(uint32_t**)(R_ESP+8);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\"...)", tid, *(void**)(R_ESP), s, pu32?((char*)(pu32)):"nil");
|
||||
} else if(strstr(s, "puts")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\"...)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4));
|
||||
} else if(strstr(s, "fputs")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, \"%s\"...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(strstr(s, "fprintf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %p...)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(void**)(R_ESP+8));
|
||||
} else if(strstr(s, "my_fprintf")==s) {
|
||||
pu32 = *(uint32_t**)(R_ESP+8);
|
||||
if(((uintptr_t)pu32)<0x5) // probably a __fprint_chk
|
||||
pu32 = *(uint32_t**)(R_ESP+12);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, \"%s\", ...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), pu32?((char*)(pu32)):"nil");
|
||||
} else if(strstr(s, "vfprintf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, \"%s\", ...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(strstr(s, "my_vfprintf")==s) {
|
||||
pu32 = *(uint32_t**)(R_ESP+8);
|
||||
if(((uintptr_t)pu32)<0x5) // probably a _chk function
|
||||
pu32 = *(uint32_t**)(R_ESP+12);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, \"%s\", ...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), pu32?((char*)(pu32)):"nil");
|
||||
} else if(strstr(s, "vkGetInstanceProcAddr")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\")", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(strstr(s, "vkGetDeviceProcAddr")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\")", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(strstr(s, "sscanf")==s) {
|
||||
} else if(strstr(s, "my_glXGetProcAddress")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4));
|
||||
} else if(strstr(s, "my_sscanf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\", ...)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(!strcmp(s, "vsscanf")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\", ...)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(strstr(s, "XCreateWindow")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, %p, %d, %d, %u, %u, %u, %d, %u, %p, %u, %p)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(void**)(R_ESP+8), *(int*)(R_ESP+12), *(int*)(R_ESP+16), *(uint32_t*)(R_ESP+20), *(uint32_t*)(R_ESP+24), *(uint32_t*)(R_ESP+28), *(int32_t*)(R_ESP+32), *(uint32_t*)(R_ESP+36), *(void**)(R_ESP+40), *(uint32_t*)(R_ESP+44), *(void**)(R_ESP+48));
|
||||
@@ -245,7 +263,7 @@ void x86Int3(x86emu_t* emu)
|
||||
} else if(strstr(s, "udev_monitor_new_from_netlink")==s) {
|
||||
post = 5;
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\")", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(!strcmp(s, "syscall")) {
|
||||
} else if(!strcmp(s, "my_syscall")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p, %p, %p...)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(void**)(R_ESP+8), *(void**)(R_ESP+12), *(void**)(R_ESP+16));
|
||||
perr = 1;
|
||||
} else {
|
||||
@@ -285,7 +303,10 @@ void x86Int3(x86emu_t* emu)
|
||||
}
|
||||
return;
|
||||
}
|
||||
printf_log(LOG_INFO, "Warning, ignoring unsupported Int 3 call\n");
|
||||
if(0 && my_context->signals[SIGTRAP])
|
||||
raise(SIGTRAP);
|
||||
else
|
||||
printf_log(LOG_INFO, "%04d|Warning, ignoring unsupported Int 3 call @%p\n", GetTID(), (void*)R_EIP);
|
||||
//emu->quit = 1;
|
||||
}
|
||||
|
||||
|
||||
+60
-30
@@ -20,6 +20,7 @@
|
||||
#include "box86context.h"
|
||||
#include "my_cpuid.h"
|
||||
#include "bridge.h"
|
||||
#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
@@ -44,13 +45,13 @@ int Run(x86emu_t *emu, int step)
|
||||
float f;
|
||||
int64_t ll;
|
||||
sse_regs_t *opex, eax1;
|
||||
mmx_regs_t *opem, eam1;
|
||||
mmx87_regs_t *opem, eam1;
|
||||
|
||||
if(emu->quit)
|
||||
return 0;
|
||||
|
||||
//ref opcode: http://ref.x86asm.net/geek32.html#xA1
|
||||
printf_log(LOG_DEBUG, "Run X86 (%p), EIP=%p, Stack=%p\n", emu, (void*)R_EIP, emu->context->stack);
|
||||
printf_log(LOG_DEBUG, "Run X86 (%p), EIP=%p, Stack=%p\n", emu, (void*)R_EIP, (void*)R_ESP);
|
||||
#define F8 *(uint8_t*)(ip++)
|
||||
#define F8S *(int8_t*)(ip++)
|
||||
#define F16 *(uint16_t*)(ip+=2, ip-2)
|
||||
@@ -94,7 +95,7 @@ int Run(x86emu_t *emu, int step)
|
||||
&&_0xD8, &&_0xD9, &&_0xDA, &&_0xDB, &&_0xDC, &&_0xDD, &&_0xDE, &&_0xDF,
|
||||
&&_0xE0, &&_0xE1, &&_0xE2, &&_0xE3, &&_0xE4, &&_0xE5, &&_0xE6, &&_0xE7,
|
||||
&&_0xE8, &&_0xE9, &&_default, &&_0xEB, &&_0xEC, &&_0xED, &&_default, &&_default,
|
||||
&&_0xF0, &&_0xF1, &&_0xF2, &&_0xF3, &&_default, &&_0xF5, &&_0xF6, &&_0xF7,
|
||||
&&_0xF0, &&_0xF1, &&_0xF2, &&_0xF3, &&_0xF4, &&_0xF5, &&_0xF6, &&_0xF7,
|
||||
&&_0xF8, &&_0xF9, &&_0xFA, &&_0xFB, &&_0xFC, &&_0xFD, &&_0xFE, &&_0xFF
|
||||
};
|
||||
|
||||
@@ -106,7 +107,7 @@ int Run(x86emu_t *emu, int step)
|
||||
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x20-0x27
|
||||
&&_0f_0x28, &&_0f_0x29, &&_0f_0x2A, &&_0f_0x2B, &&_0f_0x2C, &&_0f_0x2D, &&_0f_0x2E, &&_0f_0x2F,
|
||||
&&_default, &&_0f_0x31, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x30-0x37
|
||||
&&_0f_0x38, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x38-0x3F
|
||||
&&_0f_0x38, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_0f_0x3F, //0x38-0x3F
|
||||
&&_0f_0x40_0, &&_0f_0x40_1, &&_0f_0x40_2, &&_0f_0x40_3, &&_0f_0x40_4, &&_0f_0x40_5, &&_0f_0x40_6, &&_0f_0x40_7,
|
||||
&&_0f_0x40_8, &&_0f_0x40_9, &&_0f_0x40_A, &&_0f_0x40_B, &&_0f_0x40_C, &&_0f_0x40_D, &&_0f_0x40_E, &&_0f_0x40_F,
|
||||
&&_0f_0x50, &&_0f_0x51, &&_0f_0x52, &&_0f_0x53, &&_0f_0x54, &&_0f_0x55, &&_0f_0x56, &&_0f_0x57, //0x50-0x57
|
||||
@@ -130,23 +131,23 @@ int Run(x86emu_t *emu, int step)
|
||||
&&_0f_0xE0, &&_0f_0xE1, &&_0f_0xE2, &&_0f_0xE3, &&_0f_0xE4 ,&&_0f_0xE5, &&_default, &&_0f_0xE7, //0xE0-0xE7
|
||||
&&_0f_0xE8, &&_0f_0xE9, &&_0f_0xEA, &&_0f_0xEB, &&_0f_0xEC ,&&_0f_0xED, &&_0f_0xEE, &&_0f_0xEF, //0xE8-0xEF
|
||||
&&_default, &&_0f_0xF1, &&_0f_0xF2, &&_0f_0xF3, &&_0f_0xF4 ,&&_0f_0xF5, &&_0f_0xF6, &&_0f_0xF7, //0xF0-0xF7
|
||||
&&_0f_0xF8, &&_0f_0xF9, &&_0f_0xFA, &&_default, &&_0f_0xFC ,&&_0f_0xFD, &&_0f_0xFE, &&_default //0xF8-0xFF
|
||||
&&_0f_0xF8, &&_0f_0xF9, &&_0f_0xFA, &&_0f_0xFB, &&_0f_0xFC ,&&_0f_0xFD, &&_0f_0xFE, &&_default //0xF8-0xFF
|
||||
};
|
||||
|
||||
static const void* opcodes66[256] = {
|
||||
&&_default, &&_66_0x00_1, &&_default, &&_66_0x00_3, &&_default ,&&_66_0x00_5, &&_66_0x06, &&_66_0x07, //0x00-0x07
|
||||
&&_default, &&_66_0x08_1, &&_default, &&_66_0x08_3, &&_default ,&&_66_0x08_5, &&_default, &&_66_0x0F, //0x08-0x0F
|
||||
&&_default, &&_66_0x10_1, &&_default, &&_66_0x10_3, &&_default ,&&_66_0x10_5, &&_default, &&_default, //0x10-0x17
|
||||
&&_default, &&_66_0x18_1, &&_default, &&_66_0x18_3, &&_default ,&&_66_0x18_5, &&_default, &&_default, //0x18-0x1F
|
||||
&&_default, &&_66_0x20_1, &&_default, &&_66_0x20_3, &&_default ,&&_66_0x20_5, &&_66_0x26, &&_default, //0x20-0x27
|
||||
&&_default, &&_66_0x28_1, &&_default, &&_66_0x28_3, &&_default ,&&_66_0x28_5, &&_66_0x2E, &&_default, //0x28-0x2F
|
||||
&&_default, &&_66_0x30_1, &&_default, &&_66_0x30_3, &&_default ,&&_66_0x30_5, &&_66_0x36, &&_default, //0x30-0x37
|
||||
&&_66_0x00_0, &&_66_0x00_1, &&_66_0x00_2, &&_66_0x00_3, &&_66_0x00_4 ,&&_66_0x00_5, &&_66_0x06, &&_66_0x07, //0x00-0x07
|
||||
&&_66_0x08_0, &&_66_0x08_1, &&_66_0x08_2, &&_66_0x08_3, &&_66_0x08_4 ,&&_66_0x08_5, &&_default, &&_66_0x0F, //0x08-0x0F
|
||||
&&_66_0x10_0, &&_66_0x10_1, &&_66_0x10_2, &&_66_0x10_3, &&_66_0x10_4 ,&&_66_0x10_5, &&_default, &&_default, //0x10-0x17
|
||||
&&_66_0x18_0, &&_66_0x18_1, &&_66_0x18_2, &&_66_0x18_3, &&_66_0x18_4 ,&&_66_0x18_5, &&_default, &&_66_0x1F, //0x18-0x1F
|
||||
&&_66_0x20_0, &&_66_0x20_1, &&_66_0x20_2, &&_66_0x20_3, &&_66_0x20_4 ,&&_66_0x20_5, &&_66_0x26, &&_default, //0x20-0x27
|
||||
&&_66_0x28_0, &&_66_0x28_1, &&_66_0x28_2, &&_66_0x28_3, &&_66_0x28_4 ,&&_66_0x28_5, &&_66_0x2E, &&_default, //0x28-0x2F
|
||||
&&_66_0x30_0, &&_66_0x30_1, &&_66_0x30_2, &&_66_0x30_3, &&_66_0x30_4 ,&&_66_0x30_5, &&_66_0x36, &&_default, //0x30-0x37
|
||||
&&_default, &&_66_0x39, &&_default, &&_66_0x3B, &&_default, &&_66_0x3D, &&_default, &&_default, //0x38-0x3F
|
||||
&&_66_0x40, &&_66_0x41, &&_66_0x42, &&_66_0x43, &&_66_0x44, &&_66_0x45, &&_66_0x46, &&_66_0x47,
|
||||
&&_66_0x48, &&_66_0x49, &&_66_0x4A, &&_66_0x4B, &&_66_0x4C, &&_66_0x4D, &&_66_0x4E, &&_66_0x4F,
|
||||
&&_66_0x50, &&_66_0x51, &&_66_0x52, &&_66_0x53, &&_66_0x54, &&_66_0x55, &&_66_0x56, &&_66_0x57, //0x50-0x57
|
||||
&&_66_0x58, &&_66_0x59, &&_66_0x5A, &&_66_0x5B, &&_66_0x5C, &&_66_0x5D, &&_66_0x5E, &&_66_0x5F, //0x58-0x5F
|
||||
&&_66_0x60, &&_66_0x61, &&_default, &&_default, &&_default ,&&_default, &&_66_0x66, &&_default, //0x60-0x67
|
||||
&&_66_0x60, &&_66_0x61, &&_default, &&_default, &&_66_0x64 ,&&_default, &&_66_0x66, &&_default, //0x60-0x67
|
||||
&&_66_0x68, &&_66_0x69, &&_66_0x6A, &&_66_0x6B, &&_default, &&_default, &&_default, &&_default, //0x68-0x6F
|
||||
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x70-0x77
|
||||
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x78-0x7F
|
||||
@@ -159,7 +160,7 @@ int Run(x86emu_t *emu, int step)
|
||||
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0xB0-0xB7
|
||||
&&_66_0xB8, &&_66_0xB9, &&_66_0xBA, &&_66_0xBB, &&_66_0xBC, &&_66_0xBD, &&_66_0xBE, &&_66_0xBF,
|
||||
&&_default, &&_66_0xC1, &&_default, &&_default, &&_default, &&_default, &&_default, &&_66_0xC7,
|
||||
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0xC8-0xCF
|
||||
&&_default, &&_default, &&_default, &&_66_0xCB, &&_66_0xCC ,&&_default, &&_default, &&_default, //0xC8-0xCF
|
||||
&&_default, &&_66_0xD1, &&_default, &&_66_0xD3, &&_default, &&_default, &&_default, &&_default, //0xD0-0xD7
|
||||
&&_default, &&_66_0xD9, &&_default, &&_default, &&_default ,&&_66_0xDD, &&_default, &&_default, //0xD8-0xDF
|
||||
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0xE0-0xE7
|
||||
@@ -170,7 +171,6 @@ int Run(x86emu_t *emu, int step)
|
||||
|
||||
x86emurun:
|
||||
ip = R_EIP;
|
||||
// UnpackFlags(emu);
|
||||
#ifdef HAVE_TRACE
|
||||
_trace:
|
||||
__builtin_prefetch((void*)ip, 0, 0);
|
||||
@@ -702,8 +702,15 @@ _trace:
|
||||
NEXT;
|
||||
_0x8F: /* POP Ed */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
ED->dword[0] = Pop(emu);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
emu->regs[(nextop&7)].dword[0] = Pop(emu);
|
||||
} else {
|
||||
tmp32u = Pop(emu); // this order allows handling POP [ESP] and variant
|
||||
GET_ED;
|
||||
R_ESP -= 4; // to prevent issue with SEGFAULT
|
||||
ED->dword[0] = tmp32u;
|
||||
R_ESP += 4;
|
||||
}
|
||||
NEXT;
|
||||
_0x90: /* NOP */
|
||||
NEXT;
|
||||
@@ -730,12 +737,10 @@ _trace:
|
||||
NEXT;
|
||||
_0x9C: /* PUSHF */
|
||||
CHECK_FLAGS(emu);
|
||||
PackFlags(emu);
|
||||
Push(emu, emu->packed_eflags.x32);
|
||||
Push(emu, emu->eflags.x32);
|
||||
NEXT;
|
||||
_0x9D: /* POPF */
|
||||
emu->packed_eflags.x32 = ((Pop(emu) & 0x3F7FD7)/* & (0xffff-40)*/ ) | 0x2; // mask off res2 and res3 and on res1
|
||||
UnpackFlags(emu);
|
||||
emu->eflags.x32 = ((Pop(emu) & 0x3F7FD7)/* & (0xffff-40)*/ ) | 0x2; // mask off res2 and res3 and on res1
|
||||
RESET_FLAGS(emu);
|
||||
NEXT;
|
||||
_0x9E: /* SAHF */
|
||||
@@ -749,8 +754,7 @@ _trace:
|
||||
NEXT;
|
||||
_0x9F: /* LAHF */
|
||||
CHECK_FLAGS(emu);
|
||||
PackFlags(emu);
|
||||
R_AH = (uint8_t)emu->packed_eflags.x32;
|
||||
R_AH = (uint8_t)emu->eflags.x32;
|
||||
NEXT;
|
||||
|
||||
_0xA0: /* MOV AL,Ob */
|
||||
@@ -917,7 +921,6 @@ _trace:
|
||||
GET_ED;
|
||||
ED->dword[0] = F32;
|
||||
NEXT;
|
||||
|
||||
_0xC8: /* ENTER Iw,Ib */
|
||||
tmp16u = F16;
|
||||
tmp8u = (F8) & 0x1f;
|
||||
@@ -933,7 +936,6 @@ _trace:
|
||||
}
|
||||
R_ESP -= tmp16u;
|
||||
NEXT;
|
||||
|
||||
_0xC9: /* LEAVE */
|
||||
R_ESP = R_EBP;
|
||||
R_EBP = Pop(emu);
|
||||
@@ -976,8 +978,7 @@ _trace:
|
||||
ip = Pop(emu);
|
||||
emu->segs[_CS] = Pop(emu);
|
||||
emu->segs_serial[_CS] = 0;
|
||||
emu->packed_eflags.x32 = ((Pop(emu) & 0x3F7FD7)/* & (0xffff-40)*/ ) | 0x2; // mask off res2 and res3 and on res1
|
||||
UnpackFlags(emu);
|
||||
emu->eflags.x32 = ((Pop(emu) & 0x3F7FD7)/* & (0xffff-40)*/ ) | 0x2; // mask off res2 and res3 and on res1
|
||||
RESET_FLAGS(emu);
|
||||
NEXT;
|
||||
_0xD0: /* GRP2 Eb,1 */
|
||||
@@ -1243,6 +1244,24 @@ _trace:
|
||||
case 0x4D:
|
||||
case 0x4E:
|
||||
case 0x4F:
|
||||
case 0x50:
|
||||
case 0x51:
|
||||
case 0x52:
|
||||
case 0x53:
|
||||
case 0x54:
|
||||
case 0x55:
|
||||
case 0x56:
|
||||
case 0x57:
|
||||
case 0x58:
|
||||
case 0x59:
|
||||
case 0x5A:
|
||||
case 0x5B:
|
||||
case 0x5C:
|
||||
case 0x5D:
|
||||
case 0x5E:
|
||||
case 0x5F:
|
||||
case 0x60:
|
||||
case 0x61:
|
||||
case 0x70:
|
||||
case 0x71:
|
||||
case 0x72:
|
||||
@@ -1259,12 +1278,17 @@ _trace:
|
||||
case 0x7D:
|
||||
case 0x7E:
|
||||
case 0x7F: /* BND / NOP */
|
||||
case 0x80:
|
||||
case 0x86: /* XACQUIRE/XRELEASE XCHG */
|
||||
case 0x87: /* XACQUIRE/XRELEASE XCHG */
|
||||
case 0x88: /* XRELEASE MOV... */
|
||||
case 0x89: /* XRELEASE MOV... ignoring acquire thingy */
|
||||
case 0x9C:
|
||||
case 0xA0:
|
||||
case 0xC0:
|
||||
case 0xC3: /* yup, repz ret is valid */
|
||||
case 0xD0:
|
||||
case 0xE0:
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
case 0xEB:
|
||||
@@ -1422,7 +1446,11 @@ _trace:
|
||||
R_ECX = tmp32u;
|
||||
} // else(nextop==0x0F)
|
||||
NEXT;
|
||||
|
||||
_0xF4: /* HLT */
|
||||
// this is a privilege opcode... should an error be called instead?
|
||||
sched_yield();
|
||||
STEP;
|
||||
NEXT;
|
||||
_0xF5: /* CMC */
|
||||
CHECK_FLAGS(emu);
|
||||
CONDITIONAL_SET_FLAG(!ACCESS_FLAG(F_CF), F_CF);
|
||||
@@ -1434,7 +1462,8 @@ _trace:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
case 1: /* TEST Eb,Ib */
|
||||
test8(emu, EB->byte[0], F8);
|
||||
tmp8u = F8;
|
||||
test8(emu, EB->byte[0], tmp8u);
|
||||
break;
|
||||
case 2: /* NOT Eb */
|
||||
EB->byte[0] = not8(emu, EB->byte[0]);
|
||||
@@ -1462,7 +1491,8 @@ _trace:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
case 1: /* TEST Ed,Id */
|
||||
test32(emu, ED->dword[0], F32);
|
||||
tmp32u = F32;
|
||||
test32(emu, ED->dword[0], tmp32u);
|
||||
break;
|
||||
case 2: /* NOT Ed */
|
||||
ED->dword[0] = not32(emu, ED->dword[0]);
|
||||
|
||||
+267
-32
@@ -11,6 +11,7 @@
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "box86context.h"
|
||||
#include "bridge.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
@@ -42,7 +43,7 @@ void Run6766(x86emu_t *emu)
|
||||
|
||||
|
||||
default:
|
||||
ip-=2; //unfetch
|
||||
ip-=3; //unfetch
|
||||
UnimpOpcode(emu);
|
||||
}
|
||||
R_EIP = ip;
|
||||
@@ -120,6 +121,14 @@ void Run67(x86emu_t *emu)
|
||||
R_DI+=1;
|
||||
break;
|
||||
|
||||
case 0xAC: /* LODSB */
|
||||
R_AL = *(int8_t*)(R_SI+GetDSBaseEmu(emu));
|
||||
if(ACCESS_FLAG(F_DF))
|
||||
R_SI-=1;
|
||||
else
|
||||
R_SI+=1;
|
||||
break;
|
||||
|
||||
case 0xE0: /* LOOPNZ */
|
||||
CHECK_FLAGS(emu);
|
||||
tmp8s = F8S;
|
||||
@@ -153,6 +162,7 @@ void Run67(x86emu_t *emu)
|
||||
break;
|
||||
|
||||
default:
|
||||
ip-=2;
|
||||
UnimpOpcode(emu);
|
||||
}
|
||||
R_EIP = ip;
|
||||
@@ -288,16 +298,32 @@ void RunLock(x86emu_t *emu)
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
#ifdef DYNAREC
|
||||
do {
|
||||
tmp32u = arm_lock_read_d(ED);
|
||||
cmp32(emu, R_EAX, tmp32u);
|
||||
if(ACCESS_FLAG(F_ZF)) {
|
||||
tmp32s = arm_lock_write_d(ED, GD.dword[0]);
|
||||
} else {
|
||||
R_EAX = tmp32u;
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
if(((uintptr_t)ED)&3) {
|
||||
do {
|
||||
tmp32u = ED->dword[0] & ~0xff;
|
||||
tmp32u |= arm_lock_read_b(ED);
|
||||
cmp32(emu, R_EAX, tmp32u);
|
||||
if(ACCESS_FLAG(F_ZF)) {
|
||||
tmp32s = arm_lock_write_b(ED, GD.dword[0] & 0xff);
|
||||
if(!tmp32s)
|
||||
ED->dword[0] = GD.dword[0];
|
||||
} else {
|
||||
R_EAX = tmp32u;
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
} else {
|
||||
do {
|
||||
tmp32u = arm_lock_read_d(ED);
|
||||
cmp32(emu, R_EAX, tmp32u);
|
||||
if(ACCESS_FLAG(F_ZF)) {
|
||||
tmp32s = arm_lock_write_d(ED, GD.dword[0]);
|
||||
} else {
|
||||
R_EAX = tmp32u;
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
}
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
cmp32(emu, R_EAX, ED->dword[0]);
|
||||
@@ -365,6 +391,38 @@ void RunLock(x86emu_t *emu)
|
||||
else
|
||||
CLEAR_FLAG(F_CF);
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
case 5: /* BTS Ed, Ib */
|
||||
CHECK_FLAGS(emu);
|
||||
GET_ED;
|
||||
tmp8u = F8;
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
{
|
||||
ED=(reg32_t*)(((uint32_t*)(ED))+(tmp8u>>5));
|
||||
}
|
||||
tmp8u&=31;
|
||||
#ifdef DYNAREC
|
||||
do {
|
||||
tmp32u = arm_lock_read_d(ED);
|
||||
if(tmp32u & (1<<tmp8u)) {
|
||||
SET_FLAG(F_CF);
|
||||
tmp32s = 0;
|
||||
} else {
|
||||
CLEAR_FLAG(F_CF);
|
||||
tmp32u ^= (1<<tmp8u);
|
||||
tmp32s = arm_lock_write_d(ED, tmp32u);
|
||||
}
|
||||
} while(tmp32s);
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
if(ED->dword[0] & (1<<tmp8u)) {
|
||||
SET_FLAG(F_CF);
|
||||
} else {
|
||||
CLEAR_FLAG(F_CF);
|
||||
ED->dword[0] ^= (1<<tmp8u);
|
||||
}
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
case 6: /* BTR Ed, Ib */
|
||||
@@ -400,7 +458,7 @@ void RunLock(x86emu_t *emu)
|
||||
break;
|
||||
|
||||
default:
|
||||
ip -= 2; //unfetchall 0F BA but not F0, continue normal without LOCK
|
||||
ip -= 3; //unfetchall 0F BA nextop but not F0, continue normal without LOCK
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -455,10 +513,19 @@ void RunLock(x86emu_t *emu)
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
#ifdef DYNAREC
|
||||
do {
|
||||
tmp32u = arm_lock_read_d(ED);
|
||||
tmp32u2 = add32(emu, tmp32u, GD.dword[0]);
|
||||
} while(arm_lock_write_d(ED, tmp32u2));
|
||||
if(((uintptr_t)ED)&3) {
|
||||
do {
|
||||
tmp32u = ED->dword[0] & ~0xff;
|
||||
tmp32u |= arm_lock_read_b(ED);
|
||||
tmp32u2 = add32(emu, tmp32u, GD.dword[0]);
|
||||
} while(arm_lock_write_b(ED, tmp32u2&0xff));
|
||||
ED->dword[0] = tmp32u2;
|
||||
} else {
|
||||
do {
|
||||
tmp32u = arm_lock_read_d(ED);
|
||||
tmp32u2 = add32(emu, tmp32u, GD.dword[0]);
|
||||
} while(arm_lock_write_d(ED, tmp32u2));
|
||||
}
|
||||
GD.dword[0] = tmp32u;
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
@@ -529,11 +596,16 @@ void RunLock(x86emu_t *emu)
|
||||
break;
|
||||
default:
|
||||
// trigger invalid lock?
|
||||
ip -= 1; // unfetch 0F but not F0
|
||||
ip -= 2; // unfetch 0F and nextop but not F0
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x66:
|
||||
RunLock66(emu);
|
||||
ip = R_EIP;
|
||||
break;
|
||||
|
||||
case 0x81: /* GRP Ed,Id */
|
||||
case 0x83: /* GRP Ed,Ib */
|
||||
nextop = F8;
|
||||
@@ -589,9 +661,19 @@ void RunLock(x86emu_t *emu)
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* INC Ed */
|
||||
#ifdef DYNAREC
|
||||
do {
|
||||
tmp32u = arm_lock_read_d(ED);
|
||||
} while(arm_lock_write_d(ED, inc32(emu, tmp32u)));
|
||||
if((uintptr_t)ED&3) {
|
||||
//meh.
|
||||
do {
|
||||
tmp32u = ED->dword[0];
|
||||
tmp32u &=~0xff;
|
||||
tmp32u |= arm_lock_read_b(ED);
|
||||
tmp32u = inc32(emu, tmp32u);
|
||||
} while(arm_lock_write_b(ED, tmp32u&0xff));
|
||||
ED->dword[0] = tmp32u;
|
||||
} else
|
||||
do {
|
||||
tmp32u = arm_lock_read_d(ED);
|
||||
} while(arm_lock_write_d(ED, inc32(emu, tmp32u)));
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
ED->dword[0] = inc32(emu, ED->dword[0]);
|
||||
@@ -600,9 +682,19 @@ void RunLock(x86emu_t *emu)
|
||||
break;
|
||||
case 1: /* DEC Ed */
|
||||
#ifdef DYNAREC
|
||||
do {
|
||||
tmp32u = arm_lock_read_d(ED);
|
||||
} while(arm_lock_write_d(ED, dec32(emu, tmp32u)));
|
||||
if((uintptr_t)ED&3) {
|
||||
//meh.
|
||||
do {
|
||||
tmp32u = ED->dword[0];
|
||||
tmp32u &=~0xff;
|
||||
tmp32u |= arm_lock_read_b(ED);
|
||||
tmp32u = dec32(emu, tmp32u);
|
||||
} while(arm_lock_write_b(ED, tmp32u&0xff));
|
||||
ED->dword[0] = tmp32u;
|
||||
} else
|
||||
do {
|
||||
tmp32u = arm_lock_read_d(ED);
|
||||
} while(arm_lock_write_d(ED, dec32(emu, tmp32u)));
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
ED->dword[0] = dec32(emu, ED->dword[0]);
|
||||
@@ -626,12 +718,16 @@ void RunLock(x86emu_t *emu)
|
||||
|
||||
void RunLock66(x86emu_t *emu)
|
||||
{
|
||||
uintptr_t ip = R_EIP+1;
|
||||
uintptr_t ip = R_EIP+2;
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
reg32_t *oped;
|
||||
uint16_t tmp16u;
|
||||
int16_t tmp16s;
|
||||
#ifdef DYNAREC
|
||||
uint16_t tmp16u2;
|
||||
int32_t tmp32s;
|
||||
#endif
|
||||
switch(opcode) {
|
||||
case 0x0f:
|
||||
opcode = F8;
|
||||
@@ -667,6 +763,41 @@ void RunLock66(x86emu_t *emu)
|
||||
UnimpOpcode(emu);
|
||||
}
|
||||
break;
|
||||
case 0x81: /* GRP Ed,Iw */
|
||||
case 0x83: /* GRP Ed,Ib */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
if(opcode==0x83) {
|
||||
tmp16s = F8S;
|
||||
tmp16u = (uint32_t)tmp16s;
|
||||
} else
|
||||
tmp16u = F16;
|
||||
#ifdef DYNAREC
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: do { tmp16u2 = arm_lock_read_h(EW);} while(arm_lock_write_h(EW, add16(emu, tmp16u2, tmp16u))); break;
|
||||
case 1: do { tmp16u2 = arm_lock_read_h(EW);} while(arm_lock_write_h(EW, or16(emu, tmp16u2, tmp16u))); break;
|
||||
case 2: do { tmp16u2 = arm_lock_read_h(EW);} while(arm_lock_write_h(EW, adc16(emu, tmp16u2, tmp16u))); break;
|
||||
case 3: do { tmp16u2 = arm_lock_read_h(EW);} while(arm_lock_write_h(EW, sbb16(emu, tmp16u2, tmp16u))); break;
|
||||
case 4: do { tmp16u2 = arm_lock_read_h(EW);} while(arm_lock_write_h(EW, and16(emu, tmp16u2, tmp16u))); break;
|
||||
case 5: do { tmp16u2 = arm_lock_read_h(EW);} while(arm_lock_write_h(EW, sub16(emu, tmp16u2, tmp16u))); break;
|
||||
case 6: do { tmp16u2 = arm_lock_read_h(EW);} while(arm_lock_write_h(EW, xor16(emu, tmp16u2, tmp16u))); break;
|
||||
case 7: cmp16(emu, ED->dword[0], tmp16u); break;
|
||||
}
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: EW->word[0] = add16(emu, EW->word[0], tmp16u); break;
|
||||
case 1: EW->word[0] = or16(emu, EW->word[0], tmp16u); break;
|
||||
case 2: EW->word[0] = adc16(emu, EW->word[0], tmp16u); break;
|
||||
case 3: EW->word[0] = sbb16(emu, EW->word[0], tmp16u); break;
|
||||
case 4: EW->word[0] = and16(emu, EW->word[0], tmp16u); break;
|
||||
case 5: EW->word[0] = sub16(emu, EW->word[0], tmp16u); break;
|
||||
case 6: EW->word[0] = xor16(emu, EW->word[0], tmp16u); break;
|
||||
case 7: cmp16(emu, EW->word[0], tmp16u); break;
|
||||
}
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
ip-=3; // unfetch nextop, F0 & 66
|
||||
UnimpOpcode(emu);
|
||||
@@ -698,11 +829,31 @@ void RunGS(x86emu_t *emu)
|
||||
GD.dword[0] = add32(emu, GD.dword[0], ED->dword[0]);
|
||||
break;
|
||||
|
||||
case 0x06: /* PUSH ES */
|
||||
Push(emu, emu->segs[_ES]);
|
||||
break;
|
||||
case 0x07: /* POP ES */
|
||||
emu->segs[_ES] = Pop(emu);
|
||||
emu->segs_serial[_ES] = 0;
|
||||
break;
|
||||
|
||||
case 0x0f:
|
||||
RunGS0F(emu, tlsdata);
|
||||
ip = R_EIP;
|
||||
break;
|
||||
|
||||
case 0x11: /* ADC GS:Ed, Gd */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
ED->dword[0] = adc32(emu, ED->dword[0], GD.dword[0]);
|
||||
break;
|
||||
|
||||
case 0x13: /* ADC Gd, GS:Ed */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
GD.dword[0] = adc32(emu, GD.dword[0], ED->dword[0]);
|
||||
break;
|
||||
|
||||
case 0x2B: /* SUB Gd, GS:Ed */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
@@ -715,6 +866,29 @@ void RunGS(x86emu_t *emu)
|
||||
GD.dword[0] = xor32(emu, GD.dword[0], ED->dword[0]);
|
||||
break;
|
||||
|
||||
case 0x40:
|
||||
case 0x41:
|
||||
case 0x42:
|
||||
case 0x43:
|
||||
case 0x44:
|
||||
case 0x45:
|
||||
case 0x46:
|
||||
case 0x47: /* INC Reg */
|
||||
tmp8u = opcode&7;
|
||||
emu->regs[tmp8u].dword[0] = inc32(emu, emu->regs[tmp8u].dword[0]);
|
||||
break;
|
||||
case 0x48:
|
||||
case 0x49:
|
||||
case 0x4A:
|
||||
case 0x4B:
|
||||
case 0x4C:
|
||||
case 0x4D:
|
||||
case 0x4E:
|
||||
case 0x4F: /* DEC Reg */
|
||||
tmp8u = opcode&7;
|
||||
emu->regs[tmp8u].dword[0] = dec32(emu, emu->regs[tmp8u].dword[0]);
|
||||
break;
|
||||
|
||||
case 0x64: /* FS: */
|
||||
// so just ignore that GS: prefix then
|
||||
--ip; // put FS back
|
||||
@@ -854,7 +1028,7 @@ void RunGS(x86emu_t *emu)
|
||||
ED->dword[0] = dec32(emu, ED->dword[0]);
|
||||
break;
|
||||
case 2: /* CALL NEAR Ed */
|
||||
R_EIP = ED->dword[0];
|
||||
R_EIP = (uintptr_t)getAlternate((void*)ED->dword[0]);
|
||||
Push(emu, ip);
|
||||
ip = R_EIP;
|
||||
break;
|
||||
@@ -871,7 +1045,7 @@ void RunGS(x86emu_t *emu)
|
||||
}
|
||||
break;
|
||||
case 4: /* JMP NEAR Ed */
|
||||
ip = ED->dword[0];
|
||||
ip = (uintptr_t)getAlternate((void*)ED->dword[0]);
|
||||
break;
|
||||
case 5: /* JMP FAR Ed */
|
||||
if(nextop>0xc0) {
|
||||
@@ -893,7 +1067,7 @@ void RunGS(x86emu_t *emu)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ip--;
|
||||
ip=R_EIP;
|
||||
UnimpOpcode(emu);
|
||||
}
|
||||
R_EIP = ip;
|
||||
@@ -964,9 +1138,19 @@ void RunFS(x86emu_t *emu)
|
||||
--ip; // so ignore prefix and continue
|
||||
break;
|
||||
|
||||
case 0x66:
|
||||
RunFS66(emu, tlsdata);
|
||||
ip = R_EIP;
|
||||
break;
|
||||
case 0x67:
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
case 0x3B: /* CMP GD, FS:Ed16 */
|
||||
nextop = F8;
|
||||
GET_EW16_OFFS(tlsdata);
|
||||
cmp32(emu, GD.dword[0], ED->dword[0]);
|
||||
break;
|
||||
|
||||
case 0x89: /* MOV ED16,Gd */
|
||||
nextop = F8;
|
||||
GET_EW16_OFFS(tlsdata);
|
||||
@@ -1001,12 +1185,12 @@ void RunFS(x86emu_t *emu)
|
||||
Push(emu, ED->dword[0]);
|
||||
break;
|
||||
default:
|
||||
ip-=2;
|
||||
ip-=3;
|
||||
UnimpOpcode(emu);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ip-=2;
|
||||
ip-=3;
|
||||
UnimpOpcode(emu);
|
||||
}
|
||||
break;
|
||||
@@ -1080,6 +1264,12 @@ void RunFS(x86emu_t *emu)
|
||||
GET_ED_OFFS(tlsdata);
|
||||
ED->dword[0] = Pop(emu);
|
||||
break;
|
||||
|
||||
case 0x9C: /* PUSHFD */
|
||||
// Segment override if for memory loc, no stack segment
|
||||
--ip; // so ignore prefix and continue
|
||||
break;
|
||||
|
||||
case 0xA0: /* MOV AL,Ob */
|
||||
tmp32s = F32S;
|
||||
R_AL = *(uint8_t*)((tlsdata) + tmp32s);
|
||||
@@ -1140,7 +1330,7 @@ void RunFS(x86emu_t *emu)
|
||||
ED->dword[0] = dec32(emu, ED->dword[0]);
|
||||
break;
|
||||
case 2: /* CALL NEAR Ed */
|
||||
R_EIP = ED->dword[0];
|
||||
R_EIP = (uintptr_t)getAlternate((void*)ED->dword[0]);
|
||||
Push(emu, ip);
|
||||
ip = R_EIP;
|
||||
break;
|
||||
@@ -1157,11 +1347,12 @@ void RunFS(x86emu_t *emu)
|
||||
}
|
||||
break;
|
||||
case 4: /* JMP NEAR Ed */
|
||||
ip = ED->dword[0];
|
||||
ip = (uintptr_t)getAlternate((void*)ED->dword[0]);
|
||||
break;
|
||||
case 5: /* JMP FAR Ed */
|
||||
if(nextop>0xc0) {
|
||||
printf_log(LOG_NONE, "Illegal Opcode 0x%02X 0x%02X\n", opcode, nextop);
|
||||
ip-=3;
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_ILLEGAL;
|
||||
} else {
|
||||
@@ -1180,8 +1371,52 @@ void RunFS(x86emu_t *emu)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ip--;
|
||||
ip = R_EIP;
|
||||
UnimpOpcode(emu);
|
||||
}
|
||||
R_EIP = ip;
|
||||
}
|
||||
|
||||
void RunFS66(x86emu_t *emu, uintptr_t tlsdata)
|
||||
{
|
||||
uintptr_t ip = R_EIP+2;
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
reg32_t *oped;
|
||||
switch(opcode) {
|
||||
case 0x03: /* ADD Gw, FS:Ew */
|
||||
nextop = F8;
|
||||
GET_EW_OFFS(tlsdata);
|
||||
GW.word[0] = add16(emu, GW.word[0], EW->word[0]);
|
||||
break;
|
||||
|
||||
case 0x8B: /* MOV Gw,FS:Ew */
|
||||
nextop = F8;
|
||||
GET_EW_OFFS(tlsdata);
|
||||
GW.word[0] = EW->word[0];
|
||||
break;
|
||||
default:
|
||||
ip=R_EIP;
|
||||
UnimpOpcode(emu);
|
||||
}
|
||||
R_EIP = ip;
|
||||
}
|
||||
|
||||
void RunGS0F(x86emu_t *emu, uintptr_t tlsdata)
|
||||
{
|
||||
uintptr_t ip = R_EIP+2;
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
reg32_t *oped;
|
||||
switch(opcode) {
|
||||
case 0xB6: /* MOVZX Gd,GS:Eb */
|
||||
nextop = F8;
|
||||
GET_EB_OFFS(tlsdata);
|
||||
GD.dword[0] = EB->byte[0];
|
||||
break;
|
||||
default:
|
||||
ip=R_EIP;
|
||||
UnimpOpcode(emu);
|
||||
}
|
||||
R_EIP = ip;
|
||||
}
|
||||
+352
-349
File diff suppressed because it is too large.
Load diff
+23
-63
@@ -27,10 +27,27 @@
|
||||
#define PARITY(x) (((emu->x86emu_parity_tab[(x) / 32] >> ((x) % 32)) & 1) == 0)
|
||||
#define XOR2(x) (((x) ^ ((x)>>1)) & 0x1)
|
||||
|
||||
#ifdef ANDROID
|
||||
void EXPORT my___libc_init(x86emu_t* emu, void* raw_args __unused, void (*onexit)(void) __unused, int (*main)(int, char**, char**), void const * const structors __unused)
|
||||
{
|
||||
//TODO: register fini
|
||||
// let's cheat and set all args...
|
||||
Push(emu, (uint32_t)my_context->envv);
|
||||
Push(emu, (uint32_t)my_context->argv);
|
||||
Push(emu, (uint32_t)my_context->argc);
|
||||
|
||||
printf_log(LOG_DEBUG, "Transfert to main(%d, %p, %p)=>%p from __libc_init\n", my_context->argc, my_context->argv, my_context->envv, main);
|
||||
// call main and finish
|
||||
PushExit(emu);
|
||||
R_EIP=(uint32_t)main;
|
||||
|
||||
DynaRun(emu);
|
||||
|
||||
emu->quit = 1; // finished!
|
||||
}
|
||||
#else
|
||||
int32_t EXPORT my___libc_start_main(x86emu_t* emu, int *(main) (int, char * *, char * *), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end))
|
||||
{
|
||||
//TODO: register rtld_fini
|
||||
//TODO: register fini
|
||||
// let's cheat and set all args...
|
||||
Push(emu, (uint32_t)my_context->envv);
|
||||
Push(emu, (uint32_t)my_context->argv);
|
||||
@@ -48,11 +65,13 @@ int32_t EXPORT my___libc_start_main(x86emu_t* emu, int *(main) (int, char * *, c
|
||||
// call main and finish
|
||||
PushExit(emu);
|
||||
R_EIP=(uint32_t)main;
|
||||
#ifdef DYNAREC
|
||||
|
||||
DynaRun(emu);
|
||||
#endif
|
||||
|
||||
emu->quit = 1; // finished!
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
const char* GetNativeName(void* p)
|
||||
{
|
||||
@@ -685,64 +704,6 @@ void UpdateFlags(x86emu_t *emu)
|
||||
RESET_FLAGS(emu);
|
||||
}
|
||||
|
||||
|
||||
void PackFlags(x86emu_t* emu)
|
||||
{
|
||||
#define GO(A) emu->packed_eflags.f.F__##A = emu->flags[F_##A];
|
||||
#define GOC(A, C) emu->packed_eflags.f.F__##A = C;
|
||||
GO(CF);
|
||||
GOC(res1, 1);
|
||||
GO(PF);
|
||||
GOC(res2, 0);
|
||||
GO(AF);
|
||||
GOC(res3, 0);
|
||||
GO(ZF);
|
||||
GO(SF);
|
||||
GO(TF);
|
||||
GO(IF);
|
||||
GO(DF);
|
||||
GO(OF);
|
||||
GO(IOPL);
|
||||
GO(NT);
|
||||
GOC(dummy, 0);
|
||||
GO(RF);
|
||||
GO(VM);
|
||||
GO(AC);
|
||||
GO(VIF);
|
||||
GO(VIP);
|
||||
GO(ID);
|
||||
#undef GO
|
||||
#undef GOC
|
||||
}
|
||||
void UnpackFlags(x86emu_t* emu)
|
||||
{
|
||||
#define GO(A) emu->flags[F_##A] = emu->packed_eflags.f.F__##A;
|
||||
#define GOC(A, C) emu->flags[F_##A] = C;
|
||||
GO(CF);
|
||||
GOC(res1, 1);
|
||||
GO(PF);
|
||||
GOC(res2, 0);
|
||||
GO(AF);
|
||||
GOC(res3, 0);
|
||||
GO(ZF);
|
||||
GO(SF);
|
||||
GO(TF);
|
||||
GO(IF);
|
||||
GO(DF);
|
||||
GO(OF);
|
||||
GO(IOPL);
|
||||
GO(NT);
|
||||
GOC(dummy, 0);
|
||||
GO(RF);
|
||||
GO(VM);
|
||||
GO(AC);
|
||||
GO(VIF);
|
||||
GO(VIP);
|
||||
GO(ID);
|
||||
#undef GO
|
||||
#undef GOC
|
||||
}
|
||||
|
||||
uintptr_t GetSegmentBaseEmu(x86emu_t* emu, int seg)
|
||||
{
|
||||
if(emu->segs_serial[seg] != emu->context->sel_serial) {
|
||||
@@ -807,7 +768,6 @@ void PrintTrace(x86emu_t* emu, uintptr_t ip, int dynarec)
|
||||
my_context->trace_tid = tid;
|
||||
}
|
||||
#endif
|
||||
trace_end = 0;
|
||||
printf_log(LOG_NONE, "%s", DumpCPURegs(emu, ip));
|
||||
if(PK(0)==0xcc && PK(1)=='S' && PK(2)=='C') {
|
||||
uint32_t a = *(uint32_t*)(ip+3);
|
||||
|
||||
@@ -149,12 +149,12 @@ static inline reg32_t* GetEw16off(x86emu_t *emu, uint32_t v, uintptr_t offset)
|
||||
}
|
||||
}
|
||||
|
||||
static inline mmx_regs_t* GetEm(x86emu_t *emu, uint32_t v)
|
||||
static inline mmx87_regs_t* GetEm(x86emu_t *emu, uint32_t v)
|
||||
{
|
||||
uint32_t m = v&0xC7; // filter Ed
|
||||
if(m>=0xC0) {
|
||||
return &emu->mmx[m&0x07];
|
||||
} else return (mmx_regs_t*)GetECommon(emu, m);
|
||||
return &emu->mmx87[m&0x07];
|
||||
} else return (mmx87_regs_t*)GetECommon(emu, m);
|
||||
}
|
||||
|
||||
static inline sse_regs_t* GetEx(x86emu_t *emu, uint32_t v)
|
||||
@@ -177,10 +177,10 @@ static inline reg32_t* GetGb(x86emu_t *emu, uint32_t v)
|
||||
return (reg32_t*)&emu->regs[m&3].byte[m>>2];
|
||||
}
|
||||
|
||||
static inline mmx_regs_t* GetGm(x86emu_t *emu, uint32_t v)
|
||||
static inline mmx87_regs_t* GetGm(x86emu_t *emu, uint32_t v)
|
||||
{
|
||||
uint8_t m = (v&0x38)>>3;
|
||||
return &emu->mmx[m&7];
|
||||
return &emu->mmx87[m&7];
|
||||
}
|
||||
|
||||
static inline sse_regs_t* GetGx(x86emu_t *emu, uint32_t v)
|
||||
@@ -200,7 +200,9 @@ void Run660F(x86emu_t *emu);
|
||||
void Run66D9(x86emu_t *emu); // x87
|
||||
void Run6766(x86emu_t *emu);
|
||||
void RunGS(x86emu_t *emu);
|
||||
void RunGS0F(x86emu_t *emu, uintptr_t tlsdata);
|
||||
void RunFS(x86emu_t *emu);
|
||||
void RunFS66(x86emu_t *emu, uintptr_t tlsdata);
|
||||
void RunLock(x86emu_t *emu);
|
||||
void RunLock66(x86emu_t *emu);
|
||||
|
||||
@@ -208,13 +210,11 @@ void x86Syscall(x86emu_t *emu);
|
||||
void x86Int3(x86emu_t* emu);
|
||||
x86emu_t* x86emu_fork(x86emu_t* e, int forktype);
|
||||
|
||||
void PackFlags(x86emu_t* emu);
|
||||
void UnpackFlags(x86emu_t* emu);
|
||||
|
||||
uintptr_t GetSegmentBaseEmu(x86emu_t* emu, int seg);
|
||||
#define GetGSBaseEmu(emu) GetSegmentBaseEmu(emu, _GS)
|
||||
#define GetFSBaseEmu(emu) GetSegmentBaseEmu(emu, _FS)
|
||||
#define GetESBaseEmu(emu) GetSegmentBaseEmu(emu, _ES)
|
||||
#define GetDSBaseEmu(emu) GetSegmentBaseEmu(emu, _DS)
|
||||
|
||||
const char* GetNativeName(void* p);
|
||||
|
||||
|
||||
+41
-5
@@ -68,6 +68,10 @@ int32_t my_epoll_wait(x86emu_t* emu, int32_t epfd, void* events, int32_t maxeven
|
||||
#endif
|
||||
int my_sigaction(x86emu_t* emu, int signum, const x86_sigaction_t *act, x86_sigaction_t *oldact);
|
||||
int32_t my_execve(x86emu_t* emu, const char* path, char* const argv[], char* const envp[]);
|
||||
void* my_mmap(x86emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, int offset);
|
||||
void* my_mmap64(x86emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, int64_t offset);
|
||||
int my_munmap(x86emu_t* emu, void* addr, unsigned long length);
|
||||
int my_mprotect(x86emu_t* emu, void *addr, unsigned long len, int prot);
|
||||
|
||||
// cannot include <fcntl.h>, it conflict with some asm includes...
|
||||
#ifndef O_NONBLOCK
|
||||
@@ -129,7 +133,7 @@ scwrap_t syscallwrap[] = {
|
||||
{ 82, __NR_select, 5 },
|
||||
#endif
|
||||
{ 85, __NR_readlink, 3 },
|
||||
{ 91, __NR_munmap, 2 },
|
||||
//{ 91, __NR_munmap, 2 },
|
||||
{ 94, __NR_fchmod, 2 },
|
||||
{ 99, __NR_statfs, 2 },
|
||||
#ifdef __NR_socketcall
|
||||
@@ -166,7 +170,7 @@ scwrap_t syscallwrap[] = {
|
||||
//{ 120, __NR_clone, 5 }, // need works
|
||||
//{ 122, __NR_uname, 1 },
|
||||
//{ 123, __NR_modify_ldt },
|
||||
{ 125, __NR_mprotect, 3 },
|
||||
//{ 125, __NR_mprotect, 3 },
|
||||
{ 136, __NR_personality, 1 },
|
||||
{ 140, __NR__llseek, 5 },
|
||||
{ 141, __NR_getdents, 3 },
|
||||
@@ -190,15 +194,24 @@ scwrap_t syscallwrap[] = {
|
||||
{ 183, __NR_getcwd, 2 },
|
||||
{ 186, __NR_sigaltstack, 2 }, // neeed wrap or something?
|
||||
{ 191, __NR_ugetrlimit, 2 },
|
||||
{ 192, __NR_mmap2, 6},
|
||||
// { 192, __NR_mmap2, 6},
|
||||
//{ 195, __NR_stat64, 2 }, // need proprer wrap because of structure size change
|
||||
//{ 196, __NR_lstat64, 2 }, // need proprer wrap because of structure size change
|
||||
//{ 197, __NR_fstat64, 2 }, // need proprer wrap because of structure size change
|
||||
#ifndef POWERPCLE
|
||||
{ 199, __NR_getuid32, 0 },
|
||||
{ 200, __NR_getgid32, 0 },
|
||||
{ 201, __NR_geteuid32, 0 },
|
||||
{ 202, __NR_getegid32, 0 },
|
||||
{ 208, __NR_setresuid32, 3 },
|
||||
#else
|
||||
// PowerPC uses the same syscalls for 32/64 bit processes.
|
||||
{ 199, __NR_getuid, 0 },
|
||||
{ 200, __NR_getgid, 0 },
|
||||
{ 201, __NR_geteuid, 0 },
|
||||
{ 202, __NR_getegid, 0 },
|
||||
{ 208, __NR_setresuid, 3 },
|
||||
#endif
|
||||
{ 220, __NR_getdents64, 3 },
|
||||
//{ 221, __NR_fcntl64, 3 },
|
||||
{ 224, __NR_gettid, 0 },
|
||||
@@ -215,11 +228,17 @@ scwrap_t syscallwrap[] = {
|
||||
{ 266, __NR_clock_getres, 2 },
|
||||
//{ 270, __NR_tgkill, 3 },
|
||||
{ 271, __NR_utimes, 2 },
|
||||
{ 291, __NR_inotify_init, 0},
|
||||
{ 292, __NR_inotify_add_watch, 3},
|
||||
{ 293, __NR_inotify_rm_watch, 2},
|
||||
{ 311, __NR_set_robust_list, 2 },
|
||||
{ 312, __NR_get_robust_list, 4 },
|
||||
{ 318, __NR_getcpu, 3},
|
||||
#ifdef NOALIGN
|
||||
{ 329, __NR_epoll_create1, 1 },
|
||||
#endif
|
||||
{ 331, __NR_pipe2, 2},
|
||||
{ 332, __NR_inotify_init1, 1},
|
||||
#ifdef __NR_getrandom
|
||||
{ 355, __NR_getrandom, 3 },
|
||||
#endif
|
||||
@@ -396,9 +415,12 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
case 90: // old_mmap
|
||||
{
|
||||
struct mmap_arg_struct *st = (struct mmap_arg_struct*)R_EBX;
|
||||
R_EAX = (uintptr_t)mmap((void*)st->addr, st->len, st->prot, st->flags, st->fd, st->offset);
|
||||
R_EAX = (uintptr_t)my_mmap(emu, (void*)st->addr, st->len, st->prot, st->flags, st->fd, st->offset);
|
||||
}
|
||||
break;
|
||||
case 91: // munmap
|
||||
R_EAX = my_munmap(emu, (void*)R_EBX, (unsigned long)R_ECX);
|
||||
break;
|
||||
#ifndef __NR_socketcall
|
||||
case 102: {
|
||||
unsigned long *args = (unsigned long *)R_ECX;
|
||||
@@ -459,6 +481,7 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
break;
|
||||
case 120: // clone
|
||||
{
|
||||
// should wrap that using a thread...
|
||||
//struct x86_pt_regs *regs = (struct x86_pt_regs *)R_EDI;
|
||||
// lets duplicate the emu
|
||||
void* stack_base = (void*)R_ECX;
|
||||
@@ -466,7 +489,8 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
if(!R_ECX) {
|
||||
// allocate a new stack...
|
||||
stack_size = 1024*1024;
|
||||
stack_base = malloc(stack_size); // why not 1M... (normal operation do copy on write, simpler to just copy)
|
||||
//stack_base = malloc(stack_size); // why not 1M... (normal operation do copy on write, simpler to just copy)
|
||||
stack_base = mmap(NULL, stack_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_GROWSDOWN, -1, 0);
|
||||
// copy value from old stack to new stack
|
||||
int size_to_copy = (uintptr_t)emu->init_stack + emu->size_stack - (R_ESP);
|
||||
memcpy(stack_base-size_to_copy, (void*)R_ESP, size_to_copy);
|
||||
@@ -510,6 +534,9 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
case 123: // SYS_modify_ldt
|
||||
R_EAX = my_modify_ldt(emu, R_EBX, (thread_area_t*)R_ECX, R_EDX);
|
||||
break;
|
||||
case 125: // mprotect
|
||||
R_EAX = my_mprotect(emu, (void*)R_EBX, (unsigned long)R_ECX, R_EDX);
|
||||
break;
|
||||
case 168: // sys_poll
|
||||
R_EAX = (uint32_t)poll((void*)R_EBX, R_ECX, (int)R_EDX);
|
||||
break;
|
||||
@@ -526,6 +553,9 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
R_EAX = r;
|
||||
}
|
||||
break;
|
||||
case 192: // mmap2
|
||||
R_EAX = (uint32_t)my_mmap64(emu, (void*)R_EBX, (unsigned long)R_ECX, R_EDX, R_ESI, R_EDI, R_EBP);
|
||||
break;
|
||||
case 195: // stat64
|
||||
{
|
||||
struct stat64 st;
|
||||
@@ -644,10 +674,16 @@ uint32_t EXPORT my_syscall(x86emu_t *emu)
|
||||
return (uint32_t)close(i32(4));
|
||||
case 11: // execve
|
||||
return (uint32_t)my_execve(emu, p(4), p(8), p(12));
|
||||
case 91: // munmap
|
||||
return (uint32_t)my_munmap(emu, p(4), u32(8));
|
||||
case 123: // SYS_modify_ldt
|
||||
return my_modify_ldt(emu, i32(4), (thread_area_t*)p(8), i32(12));
|
||||
case 125: // mprotect
|
||||
return (uint32_t)my_mprotect(emu, p(4), u32(8), i32(12));
|
||||
case 174: // sys_rt_sigaction
|
||||
return (uint32_t)my_sigaction(emu, i32(4), (x86_sigaction_t*)p(8), (x86_sigaction_t*)p(12));
|
||||
case 192: // mmap2
|
||||
return (uint32_t)my_mmap64(emu, p(4), u32(8), i32(12), i32(16), i32(20), u32(24));
|
||||
case 243: // set_thread_area
|
||||
return my_set_thread_area((thread_area_t*)p(4));
|
||||
#ifndef NOALIGN
|
||||
|
||||
+2
-1
@@ -186,8 +186,9 @@ static void* GetSeg33Base()
|
||||
if ((ptr = (tlsdatasize_t*)pthread_getspecific(my_context->tlskey)) == NULL) {
|
||||
ptr = (tlsdatasize_t*)fillTLSData(my_context);
|
||||
}
|
||||
if(ptr->tlssize != my_context->tlssize)
|
||||
if(ptr->tlssize != my_context->tlssize) {
|
||||
ptr = (tlsdatasize_t*)resizeTLSData(my_context, ptr);
|
||||
}
|
||||
return ptr->tlsdata+ptr->tlssize;
|
||||
}
|
||||
|
||||
|
||||
+304
-253
@@ -3018,109 +3018,121 @@ typedef struct ZydisDecodedOperand_
|
||||
} imm;
|
||||
} ZydisDecodedOperand;
|
||||
/**
|
||||
* @brief Defines the `ZydisCPUFlags` datatype.
|
||||
* Defines the `ZydisCPUFlags` data-type.
|
||||
*/
|
||||
typedef ZyanU32 ZydisCPUFlags;
|
||||
|
||||
typedef ZyanU8 ZydisCPUFlag;
|
||||
|
||||
/**
|
||||
* @brief Defines the `ZydisCPUFlag` enum.
|
||||
*/
|
||||
typedef enum ZydisCPUFlag_
|
||||
{
|
||||
/**
|
||||
* @brief Carry flag.
|
||||
*/
|
||||
ZYDIS_CPUFLAG_CF,
|
||||
/**
|
||||
* @brief Parity flag.
|
||||
*/
|
||||
ZYDIS_CPUFLAG_PF,
|
||||
/**
|
||||
* @brief Adjust flag.
|
||||
*/
|
||||
ZYDIS_CPUFLAG_AF,
|
||||
/**
|
||||
* @brief Zero flag.
|
||||
*/
|
||||
ZYDIS_CPUFLAG_ZF,
|
||||
/**
|
||||
* @brief Sign flag.
|
||||
*/
|
||||
ZYDIS_CPUFLAG_SF,
|
||||
/**
|
||||
* @brief Trap flag.
|
||||
*/
|
||||
ZYDIS_CPUFLAG_TF,
|
||||
/**
|
||||
* @brief Interrupt enable flag.
|
||||
*/
|
||||
ZYDIS_CPUFLAG_IF,
|
||||
/**
|
||||
* @brief Direction flag.
|
||||
*/
|
||||
ZYDIS_CPUFLAG_DF,
|
||||
/**
|
||||
* @brief Overflow flag.
|
||||
*/
|
||||
ZYDIS_CPUFLAG_OF,
|
||||
/**
|
||||
* @brief I/O privilege level flag.
|
||||
*/
|
||||
ZYDIS_CPUFLAG_IOPL,
|
||||
/**
|
||||
* @brief Nested task flag.
|
||||
*/
|
||||
ZYDIS_CPUFLAG_NT,
|
||||
/**
|
||||
* @brief Resume flag.
|
||||
*/
|
||||
ZYDIS_CPUFLAG_RF,
|
||||
/**
|
||||
* @brief Virtual 8086 mode flag.
|
||||
*/
|
||||
ZYDIS_CPUFLAG_VM,
|
||||
/**
|
||||
* @brief Alignment check.
|
||||
*/
|
||||
ZYDIS_CPUFLAG_AC,
|
||||
/**
|
||||
* @brief Virtual interrupt flag.
|
||||
*/
|
||||
ZYDIS_CPUFLAG_VIF,
|
||||
/**
|
||||
* @brief Virtual interrupt pending.
|
||||
*/
|
||||
ZYDIS_CPUFLAG_VIP,
|
||||
/**
|
||||
* @brief Able to use CPUID instruction.
|
||||
*/
|
||||
ZYDIS_CPUFLAG_ID,
|
||||
/**
|
||||
* @brief FPU condition-code flag 0.
|
||||
*/
|
||||
ZYDIS_CPUFLAG_C0,
|
||||
/**
|
||||
* @brief FPU condition-code flag 1.
|
||||
*/
|
||||
ZYDIS_CPUFLAG_C1,
|
||||
/**
|
||||
* @brief FPU condition-code flag 2.
|
||||
*/
|
||||
ZYDIS_CPUFLAG_C2,
|
||||
/**
|
||||
* @brief FPU condition-code flag 3.
|
||||
*/
|
||||
ZYDIS_CPUFLAG_C3,
|
||||
* Carry flag.
|
||||
*/
|
||||
#define ZYDIS_CPUFLAG_CF 0
|
||||
/**
|
||||
* Parity flag.
|
||||
*/
|
||||
#define ZYDIS_CPUFLAG_PF 2
|
||||
/**
|
||||
* Adjust flag.
|
||||
*/
|
||||
#define ZYDIS_CPUFLAG_AF 4
|
||||
/**
|
||||
* Zero flag.
|
||||
*/
|
||||
#define ZYDIS_CPUFLAG_ZF 6
|
||||
/**
|
||||
* Sign flag.
|
||||
*/
|
||||
#define ZYDIS_CPUFLAG_SF 7
|
||||
/**
|
||||
* Trap flag.
|
||||
*/
|
||||
#define ZYDIS_CPUFLAG_TF 8
|
||||
/**
|
||||
* Interrupt enable flag.
|
||||
*/
|
||||
#define ZYDIS_CPUFLAG_IF 9
|
||||
/**
|
||||
* Direction flag.
|
||||
*/
|
||||
#define ZYDIS_CPUFLAG_DF 10
|
||||
/**
|
||||
* Overflow flag.
|
||||
*/
|
||||
#define ZYDIS_CPUFLAG_OF 11
|
||||
/**
|
||||
* I/O privilege level flag.
|
||||
*/
|
||||
#define ZYDIS_CPUFLAG_IOPL 12
|
||||
/**
|
||||
* Nested task flag.
|
||||
*/
|
||||
#define ZYDIS_CPUFLAG_NT 14
|
||||
/**
|
||||
* Resume flag.
|
||||
*/
|
||||
#define ZYDIS_CPUFLAG_RF 16
|
||||
/**
|
||||
* Virtual 8086 mode flag.
|
||||
*/
|
||||
#define ZYDIS_CPUFLAG_VM 17
|
||||
/**
|
||||
* Alignment check.
|
||||
*/
|
||||
#define ZYDIS_CPUFLAG_AC 18
|
||||
/**
|
||||
* Virtual interrupt flag.
|
||||
*/
|
||||
#define ZYDIS_CPUFLAG_VIF 19
|
||||
/**
|
||||
* Virtual interrupt pending.
|
||||
*/
|
||||
#define ZYDIS_CPUFLAG_VIP 20
|
||||
/**
|
||||
* Able to use CPUID instruction.
|
||||
*/
|
||||
#define ZYDIS_CPUFLAG_ID 21
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* FPU condition-code flag 0.
|
||||
*
|
||||
* DEPRECATED. This flag is not actually part of `FLAGS/EFLAGS/RFLAGS` and will be removed in the
|
||||
* next major release. Please refer to the `fpu_flags_read`/`fpu_flags_written` field instead and
|
||||
* use one of the `ZYDIS_FPUFLAG_XXX` masks to check for specific a flag.
|
||||
*/
|
||||
#define ZYDIS_CPUFLAG_C0 22
|
||||
/**
|
||||
* FPU condition-code flag 1.
|
||||
*
|
||||
* DEPRECATED. This flag is not actually part of `FLAGS/EFLAGS/RFLAGS` and will be removed in the
|
||||
* next major release. Please refer to the `fpu_flags_read`/`fpu_flags_written` field instead and
|
||||
* use one of the `ZYDIS_FPUFLAG_XXX` masks to check for specific a flag.
|
||||
*/
|
||||
#define ZYDIS_CPUFLAG_C1 23
|
||||
/**
|
||||
* FPU condition-code flag 2.
|
||||
*
|
||||
* DEPRECATED. This flag is not actually part of `FLAGS/EFLAGS/RFLAGS` and will be removed in the
|
||||
* next major release. Please refer to the `fpu_flags_read`/`fpu_flags_written` field instead and
|
||||
* use one of the `ZYDIS_FPUFLAG_XXX` masks to check for specific a flag.
|
||||
*/
|
||||
#define ZYDIS_CPUFLAG_C2 24
|
||||
/**
|
||||
* FPU condition-code flag 3.
|
||||
*
|
||||
* DEPRECATED. This flag is not actually part of `FLAGS/EFLAGS/RFLAGS` and will be removed in the
|
||||
* next major release. Please refer to the `fpu_flags_read`/`fpu_flags_written` field instead and
|
||||
* use one of the `ZYDIS_FPUFLAG_XXX` masks to check for specific a flag.
|
||||
*/
|
||||
#define ZYDIS_CPUFLAG_C3 25
|
||||
|
||||
/**
|
||||
* DEPRECATED. This define will be removed in the next major release.
|
||||
*/
|
||||
#define ZYDIS_CPUFLAG_MAX_VALUE ZYDIS_CPUFLAG_C3
|
||||
|
||||
/**
|
||||
* @brief Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_CPUFLAG_MAX_VALUE = ZYDIS_CPUFLAG_C3,
|
||||
/**
|
||||
* @brief The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_CPUFLAG_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_CPUFLAG_MAX_VALUE)
|
||||
} ZydisCPUFlag;
|
||||
/**
|
||||
* @brief Defines the `ZydisMaskMode` enum.
|
||||
*/
|
||||
@@ -3793,66 +3805,79 @@ typedef enum ZydisCPUFlagAction_
|
||||
*/
|
||||
ZYDIS_CPUFLAG_ACTION_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_CPUFLAG_ACTION_MAX_VALUE)
|
||||
} ZydisCPUFlagAction;
|
||||
/**
|
||||
* Defines the `ZydisFPUFlags` data-type.
|
||||
*/
|
||||
typedef ZyanU8 ZydisFPUFlags;
|
||||
|
||||
/**
|
||||
* @brief Defines the `ZydisDecodedInstruction` struct.
|
||||
*/
|
||||
typedef struct ZydisDecodedInstruction_
|
||||
{
|
||||
/**
|
||||
* @brief The machine mode used to decode this instruction.
|
||||
* The machine mode used to decode this instruction.
|
||||
*/
|
||||
ZydisMachineMode machine_mode;
|
||||
/**
|
||||
* @brief The instruction-mnemonic.
|
||||
* The instruction-mnemonic.
|
||||
*/
|
||||
ZydisMnemonic mnemonic;
|
||||
/**
|
||||
* @brief The length of the decoded instruction.
|
||||
* The length of the decoded instruction.
|
||||
*/
|
||||
ZyanU8 length;
|
||||
/**
|
||||
* @brief The instruction-encoding (`LEGACY`, `3DNOW`, `VEX`, `EVEX`, `XOP`).
|
||||
* The instruction-encoding (`LEGACY`, `3DNOW`, `VEX`, `EVEX`, `XOP`).
|
||||
*/
|
||||
ZydisInstructionEncoding encoding;
|
||||
/**
|
||||
* @brief The opcode-map.
|
||||
* The opcode-map.
|
||||
*/
|
||||
ZydisOpcodeMap opcode_map;
|
||||
/**
|
||||
* @brief The instruction-opcode.
|
||||
* The instruction-opcode.
|
||||
*/
|
||||
ZyanU8 opcode;
|
||||
/**
|
||||
* @brief The stack width.
|
||||
* The stack width.
|
||||
*/
|
||||
ZyanU8 stack_width;
|
||||
/**
|
||||
* @brief The effective operand width.
|
||||
* The effective operand width.
|
||||
*/
|
||||
ZyanU8 operand_width;
|
||||
/**
|
||||
* @brief The effective address width.
|
||||
* The effective address width.
|
||||
*/
|
||||
ZyanU8 address_width;
|
||||
/**
|
||||
* @brief The number of instruction-operands.
|
||||
* The number of instruction-operands.
|
||||
*/
|
||||
ZyanU8 operand_count;
|
||||
/**
|
||||
* @brief Detailed info for all instruction operands.
|
||||
* Detailed info for all instruction operands.
|
||||
*
|
||||
* Explicit operands are guaranteed to be in the front and ordered as they are printed
|
||||
* by the formatter in Intel mode. No assumptions can be made about the order of hidden
|
||||
* operands, except that they always located behind the explicit operands.
|
||||
*/
|
||||
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
|
||||
/**
|
||||
* @brief Instruction attributes.
|
||||
* Instruction attributes.
|
||||
*/
|
||||
ZydisInstructionAttributes attributes;
|
||||
/**
|
||||
* @brief Information about accessed CPU flags.
|
||||
* Information about accessed CPU flags.
|
||||
*
|
||||
* DEPRECATED. This field will be removed in the next major release. Please use the
|
||||
* `cpu_flags_read`/`cpu_flags_written` or `fpu_flags_read`/`fpu_flags_written` fields
|
||||
* instead.
|
||||
*/
|
||||
struct
|
||||
struct ZydisDecodedInstructionAccessedFlags_
|
||||
{
|
||||
/**
|
||||
* @brief The CPU-flag action.
|
||||
* The CPU-flag action.
|
||||
*
|
||||
* Use `ZydisGetAccessedFlagsByAction` to get a mask with all flags matching a specific
|
||||
* action.
|
||||
@@ -3860,160 +3885,186 @@ typedef struct ZydisDecodedInstruction_
|
||||
ZydisCPUFlagAction action;
|
||||
} accessed_flags[ZYDIS_CPUFLAG_MAX_VALUE + 1];
|
||||
/**
|
||||
* @brief Extended info for `AVX` instructions.
|
||||
* A mask containing the CPU flags read by the instruction.
|
||||
*
|
||||
* The bits in this mask correspond to the actual bits in the `FLAGS/EFLAGS/RFLAGS`
|
||||
* register.
|
||||
*
|
||||
* This mask includes the actions `TESTED` and `TESTED_MODIFIED`.
|
||||
*/
|
||||
struct
|
||||
ZydisCPUFlags cpu_flags_read;
|
||||
/**
|
||||
* A mask containing the CPU flags written by the instruction.
|
||||
*
|
||||
* The bits in this mask correspond to the actual bits in the `FLAGS/EFLAGS/RFLAGS`
|
||||
* register.
|
||||
*
|
||||
* This mask includes the actions `TESTED_MODIFIED`, `SET_0`, `SET_1` and `UNDEFINED`.
|
||||
*/
|
||||
ZydisCPUFlags cpu_flags_written;
|
||||
/**
|
||||
* A mask containing the FPU flags read by the instruction.
|
||||
*/
|
||||
ZydisFPUFlags fpu_flags_read;
|
||||
/**
|
||||
* A mask containing the FPU flags written by the instruction.
|
||||
*/
|
||||
ZydisFPUFlags fpu_flags_written;
|
||||
/**
|
||||
* Extended info for `AVX` instructions.
|
||||
*/
|
||||
struct ZydisDecodedInstructionAvx_
|
||||
{
|
||||
/**
|
||||
* @brief The `AVX` vector-length.
|
||||
* The `AVX` vector-length.
|
||||
*/
|
||||
ZyanU16 vector_length;
|
||||
/**
|
||||
* @brief Info about the embedded writemask-register (`AVX-512` and `KNC` only).
|
||||
* Info about the embedded writemask-register (`AVX-512` and `KNC` only).
|
||||
*/
|
||||
struct
|
||||
struct ZydisDecodedInstructionAvxMask_
|
||||
{
|
||||
/**
|
||||
* @brief The masking mode.
|
||||
* The masking mode.
|
||||
*/
|
||||
ZydisMaskMode mode;
|
||||
/**
|
||||
* @brief The mask register.
|
||||
* The mask register.
|
||||
*/
|
||||
ZydisRegister reg;
|
||||
} mask;
|
||||
/**
|
||||
* @brief Contains info about the `AVX` broadcast.
|
||||
* Contains info about the `AVX` broadcast.
|
||||
*/
|
||||
struct
|
||||
struct ZydisDecodedInstructionAvxBroadcast_
|
||||
{
|
||||
/**
|
||||
* @brief Signals, if the broadcast is a static broadcast.
|
||||
* Signals, if the broadcast is a static broadcast.
|
||||
*
|
||||
* This is the case for instructions with inbuild broadcast functionality, which is
|
||||
* This is the case for instructions with inbuilt broadcast functionality, which is
|
||||
* always active and not controlled by the `EVEX/MVEX.RC` bits.
|
||||
*/
|
||||
ZyanBool is_static;
|
||||
/**
|
||||
* @brief The `AVX` broadcast-mode.
|
||||
* The `AVX` broadcast-mode.
|
||||
*/
|
||||
ZydisBroadcastMode mode;
|
||||
} broadcast;
|
||||
/**
|
||||
* @brief Contains info about the `AVX` rounding.
|
||||
* Contains info about the `AVX` rounding.
|
||||
*/
|
||||
struct
|
||||
struct ZydisDecodedInstructionAvxRounding_
|
||||
{
|
||||
/**
|
||||
* @brief The `AVX` rounding-mode.
|
||||
* The `AVX` rounding-mode.
|
||||
*/
|
||||
ZydisRoundingMode mode;
|
||||
} rounding;
|
||||
/**
|
||||
* @brief Contains info about the `AVX` register-swizzle (`KNC` only).
|
||||
* Contains info about the `AVX` register-swizzle (`KNC` only).
|
||||
*/
|
||||
struct
|
||||
struct ZydisDecodedInstructionAvxSwizzle_
|
||||
{
|
||||
/**
|
||||
* @brief The `AVX` register-swizzle mode.
|
||||
* The `AVX` register-swizzle mode.
|
||||
*/
|
||||
ZydisSwizzleMode mode;
|
||||
} swizzle;
|
||||
/**
|
||||
* @brief Contains info about the `AVX` data-conversion (`KNC` only).
|
||||
* Contains info about the `AVX` data-conversion (`KNC` only).
|
||||
*/
|
||||
struct
|
||||
struct ZydisDecodedInstructionAvxConversion_
|
||||
{
|
||||
/**
|
||||
* @brief The `AVX` data-conversion mode.
|
||||
* The `AVX` data-conversion mode.
|
||||
*/
|
||||
ZydisConversionMode mode;
|
||||
} conversion;
|
||||
/**
|
||||
* @brief Signals, if the `SAE` (suppress-all-exceptions) functionality is enabled for
|
||||
* the instruction.
|
||||
* Signals, if the `SAE` (suppress-all-exceptions) functionality is
|
||||
* enabled for the instruction.
|
||||
*/
|
||||
ZyanBool has_sae;
|
||||
/**
|
||||
* @brief Signals, if the instruction has a memory-eviction-hint (`KNC` only).
|
||||
* Signals, if the instruction has a memory-eviction-hint (`KNC` only).
|
||||
*/
|
||||
ZyanBool has_eviction_hint;
|
||||
// TODO: publish EVEX tuple-type and MVEX functionality
|
||||
} avx;
|
||||
/**
|
||||
* @brief Meta info.
|
||||
* Meta info.
|
||||
*/
|
||||
struct
|
||||
struct ZydisDecodedInstructionMeta_
|
||||
{
|
||||
/**
|
||||
* @brief The instruction category.
|
||||
* The instruction category.
|
||||
*/
|
||||
ZydisInstructionCategory category;
|
||||
/**
|
||||
* @brief The ISA-set.
|
||||
* The ISA-set.
|
||||
*/
|
||||
ZydisISASet isa_set;
|
||||
/**
|
||||
* @brief The ISA-set extension.
|
||||
* The ISA-set extension.
|
||||
*/
|
||||
ZydisISAExt isa_ext;
|
||||
/**
|
||||
* @brief The branch type.
|
||||
* The branch type.
|
||||
*/
|
||||
ZydisBranchType branch_type;
|
||||
/**
|
||||
* @brief The exception class.
|
||||
* The exception class.
|
||||
*/
|
||||
ZydisExceptionClass exception_class;
|
||||
} meta;
|
||||
/**
|
||||
* @brief Detailed info about different instruction-parts like `ModRM`, `SIB` or
|
||||
* encoding-prefixes.
|
||||
* Detailed info about different instruction-parts like `ModRM`, `SIB` or
|
||||
* encoding-prefixes.
|
||||
*/
|
||||
struct
|
||||
struct ZydisDecodedInstructionRaw_
|
||||
{
|
||||
/**
|
||||
* @brief The number of legacy prefixes.
|
||||
* The number of legacy prefixes.
|
||||
*/
|
||||
ZyanU8 prefix_count;
|
||||
/**
|
||||
* @brief Detailed info about the legacy prefixes (including `REX`).
|
||||
* Detailed info about the legacy prefixes (including `REX`).
|
||||
*/
|
||||
struct
|
||||
struct ZydisDecodedInstructionRawPrefixes_
|
||||
{
|
||||
/**
|
||||
* @brief The prefix type.
|
||||
* The prefix type.
|
||||
*/
|
||||
ZydisPrefixType type;
|
||||
/**
|
||||
* @brief The prefix byte.
|
||||
* The prefix byte.
|
||||
*/
|
||||
ZyanU8 value;
|
||||
} prefixes[ZYDIS_MAX_INSTRUCTION_LENGTH];
|
||||
/**
|
||||
* @brief Detailed info about the `REX` prefix.
|
||||
* Detailed info about the `REX` prefix.
|
||||
*/
|
||||
struct
|
||||
struct ZydisDecodedInstructionRawRex_
|
||||
{
|
||||
/**
|
||||
* @brief 64-bit operand-size promotion.
|
||||
* 64-bit operand-size promotion.
|
||||
*/
|
||||
ZyanU8 W;
|
||||
/**
|
||||
* @brief Extension of the `ModRM.reg` field.
|
||||
* Extension of the `ModRM.reg` field.
|
||||
*/
|
||||
ZyanU8 R;
|
||||
/**
|
||||
* @brief Extension of the `SIB.index` field.
|
||||
* Extension of the `SIB.index` field.
|
||||
*/
|
||||
ZyanU8 X;
|
||||
/**
|
||||
* @brief Extension of the `ModRM.rm`, `SIB.base`, or `opcode.reg` field.
|
||||
* Extension of the `ModRM.rm`, `SIB.base`, or `opcode.reg` field.
|
||||
*/
|
||||
ZyanU8 B;
|
||||
/**
|
||||
* @brief The offset of the effective `REX` byte, relative to the beginning of the
|
||||
* instruction, in bytes.
|
||||
* The offset of the effective `REX` byte, relative to the beginning of the
|
||||
* instruction, in bytes.
|
||||
*
|
||||
* This offset always points to the "effective" `REX` prefix (the one closest to the
|
||||
* instruction opcode), if multiple `REX` prefixes are present.
|
||||
@@ -4025,320 +4076,320 @@ typedef struct ZydisDecodedInstruction_
|
||||
ZyanU8 offset;
|
||||
} rex;
|
||||
/**
|
||||
* @brief Detailed info about the `XOP` prefix.
|
||||
* Detailed info about the `XOP` prefix.
|
||||
*/
|
||||
struct
|
||||
struct ZydisDecodedInstructionRawXop_
|
||||
{
|
||||
/**
|
||||
* @brief Extension of the `ModRM.reg` field (inverted).
|
||||
* Extension of the `ModRM.reg` field (inverted).
|
||||
*/
|
||||
ZyanU8 R;
|
||||
/**
|
||||
* @brief Extension of the `SIB.index` field (inverted).
|
||||
* Extension of the `SIB.index` field (inverted).
|
||||
*/
|
||||
ZyanU8 X;
|
||||
/**
|
||||
* @brief Extension of the `ModRM.rm`, `SIB.base`, or `opcode.reg` field (inverted).
|
||||
* Extension of the `ModRM.rm`, `SIB.base`, or `opcode.reg` field (inverted).
|
||||
*/
|
||||
ZyanU8 B;
|
||||
/**
|
||||
* @brief Opcode-map specifier.
|
||||
* Opcode-map specifier.
|
||||
*/
|
||||
ZyanU8 m_mmmm;
|
||||
/**
|
||||
* @brief 64-bit operand-size promotion or opcode-extension.
|
||||
* 64-bit operand-size promotion or opcode-extension.
|
||||
*/
|
||||
ZyanU8 W;
|
||||
/**
|
||||
* @brief `NDS`/`NDD` (non-destructive-source/destination) register specifier
|
||||
* (inverted).
|
||||
* `NDS`/`NDD` (non-destructive-source/destination) register
|
||||
* specifier (inverted).
|
||||
*/
|
||||
ZyanU8 vvvv;
|
||||
/**
|
||||
* @brief Vector-length specifier.
|
||||
* Vector-length specifier.
|
||||
*/
|
||||
ZyanU8 L;
|
||||
/**
|
||||
* @brief Compressed legacy prefix.
|
||||
* Compressed legacy prefix.
|
||||
*/
|
||||
ZyanU8 pp;
|
||||
/**
|
||||
* @brief The offset of the first xop byte, relative to the beginning of the
|
||||
* instruction, in bytes.
|
||||
* The offset of the first xop byte, relative to the beginning of
|
||||
* the instruction, in bytes.
|
||||
*/
|
||||
ZyanU8 offset;
|
||||
} xop;
|
||||
/**
|
||||
* @brief Detailed info about the `VEX` prefix.
|
||||
* Detailed info about the `VEX` prefix.
|
||||
*/
|
||||
struct
|
||||
struct ZydisDecodedInstructionRawVex_
|
||||
{
|
||||
/**
|
||||
* @brief Extension of the `ModRM.reg` field (inverted).
|
||||
* Extension of the `ModRM.reg` field (inverted).
|
||||
*/
|
||||
ZyanU8 R;
|
||||
/**
|
||||
* @brief Extension of the `SIB.index` field (inverted).
|
||||
* Extension of the `SIB.index` field (inverted).
|
||||
*/
|
||||
ZyanU8 X;
|
||||
/**
|
||||
* @brief Extension of the `ModRM.rm`, `SIB.base`, or `opcode.reg` field (inverted).
|
||||
* Extension of the `ModRM.rm`, `SIB.base`, or `opcode.reg` field (inverted).
|
||||
*/
|
||||
ZyanU8 B;
|
||||
/**
|
||||
* @brief Opcode-map specifier.
|
||||
* Opcode-map specifier.
|
||||
*/
|
||||
ZyanU8 m_mmmm;
|
||||
/**
|
||||
* @brief 64-bit operand-size promotion or opcode-extension.
|
||||
* 64-bit operand-size promotion or opcode-extension.
|
||||
*/
|
||||
ZyanU8 W;
|
||||
/**
|
||||
* @brief `NDS`/`NDD` (non-destructive-source/destination) register specifier
|
||||
* (inverted).
|
||||
* `NDS`/`NDD` (non-destructive-source/destination) register specifier
|
||||
* (inverted).
|
||||
*/
|
||||
ZyanU8 vvvv;
|
||||
/**
|
||||
* @brief Vector-length specifier.
|
||||
* Vector-length specifier.
|
||||
*/
|
||||
ZyanU8 L;
|
||||
/**
|
||||
* @brief Compressed legacy prefix.
|
||||
* Compressed legacy prefix.
|
||||
*/
|
||||
ZyanU8 pp;
|
||||
/**
|
||||
* @brief The offset of the first `VEX` byte, relative to the beginning of the
|
||||
* instruction, in bytes.
|
||||
* The offset of the first `VEX` byte, relative to the beginning of the instruction, in
|
||||
* bytes.
|
||||
*/
|
||||
ZyanU8 offset;
|
||||
/**
|
||||
* @brief The size of the `VEX` prefix, in bytes.
|
||||
* The size of the `VEX` prefix, in bytes.
|
||||
*/
|
||||
ZyanU8 size;
|
||||
} vex;
|
||||
/**
|
||||
* @brief Detailed info about the `EVEX` prefix.
|
||||
* Detailed info about the `EVEX` prefix.
|
||||
*/
|
||||
struct
|
||||
struct ZydisDecodedInstructionRawEvex_
|
||||
{
|
||||
/**
|
||||
* @brief Extension of the `ModRM.reg` field (inverted).
|
||||
* Extension of the `ModRM.reg` field (inverted).
|
||||
*/
|
||||
ZyanU8 R;
|
||||
/**
|
||||
* @brief Extension of the `SIB.index/vidx` field (inverted).
|
||||
* Extension of the `SIB.index/vidx` field (inverted).
|
||||
*/
|
||||
ZyanU8 X;
|
||||
/**
|
||||
* @brief Extension of the `ModRM.rm` or `SIB.base` field (inverted).
|
||||
* Extension of the `ModRM.rm` or `SIB.base` field (inverted).
|
||||
*/
|
||||
ZyanU8 B;
|
||||
/**
|
||||
* @brief High-16 register specifier modifier (inverted).
|
||||
* High-16 register specifier modifier (inverted).
|
||||
*/
|
||||
ZyanU8 R2;
|
||||
/**
|
||||
* @brief Opcode-map specifier.
|
||||
* Opcode-map specifier.
|
||||
*/
|
||||
ZyanU8 mm;
|
||||
/**
|
||||
* @brief 64-bit operand-size promotion or opcode-extension.
|
||||
* 64-bit operand-size promotion or opcode-extension.
|
||||
*/
|
||||
ZyanU8 W;
|
||||
/**
|
||||
* @brief `NDS`/`NDD` (non-destructive-source/destination) register specifier
|
||||
* (inverted).
|
||||
* `NDS`/`NDD` (non-destructive-source/destination) register specifier
|
||||
* (inverted).
|
||||
*/
|
||||
ZyanU8 vvvv;
|
||||
/**
|
||||
* @brief Compressed legacy prefix.
|
||||
* Compressed legacy prefix.
|
||||
*/
|
||||
ZyanU8 pp;
|
||||
/**
|
||||
* @brief Zeroing/Merging.
|
||||
* Zeroing/Merging.
|
||||
*/
|
||||
ZyanU8 z;
|
||||
/**
|
||||
* @brief Vector-length specifier or rounding-control (most significant bit).
|
||||
* Vector-length specifier or rounding-control (most significant bit).
|
||||
*/
|
||||
ZyanU8 L2;
|
||||
/**
|
||||
* @brief Vector-length specifier or rounding-control (least significant bit).
|
||||
* Vector-length specifier or rounding-control (least significant bit).
|
||||
*/
|
||||
ZyanU8 L;
|
||||
/**
|
||||
* @brief Broadcast/RC/SAE context.
|
||||
* Broadcast/RC/SAE context.
|
||||
*/
|
||||
ZyanU8 b;
|
||||
/**
|
||||
* @brief High-16 `NDS`/`VIDX` register specifier.
|
||||
* High-16 `NDS`/`VIDX` register specifier.
|
||||
*/
|
||||
ZyanU8 V2;
|
||||
/**
|
||||
* @brief Embedded opmask register specifier.
|
||||
* Embedded opmask register specifier.
|
||||
*/
|
||||
ZyanU8 aaa;
|
||||
/**
|
||||
* @brief The offset of the first evex byte, relative to the beginning of the
|
||||
* instruction, in bytes.
|
||||
* The offset of the first evex byte, relative to the beginning of the
|
||||
* instruction, in bytes.
|
||||
*/
|
||||
ZyanU8 offset;
|
||||
} evex;
|
||||
/**
|
||||
* @brief Detailed info about the `MVEX` prefix.
|
||||
* Detailed info about the `MVEX` prefix.
|
||||
*/
|
||||
struct
|
||||
struct ZydisDecodedInstructionRawMvex_
|
||||
{
|
||||
/**
|
||||
* @brief Extension of the `ModRM.reg` field (inverted).
|
||||
* Extension of the `ModRM.reg` field (inverted).
|
||||
*/
|
||||
ZyanU8 R;
|
||||
/**
|
||||
* @brief Extension of the `SIB.index/vidx` field (inverted).
|
||||
* Extension of the `SIB.index/vidx` field (inverted).
|
||||
*/
|
||||
ZyanU8 X;
|
||||
/**
|
||||
* @brief Extension of the `ModRM.rm` or `SIB.base` field (inverted).
|
||||
* Extension of the `ModRM.rm` or `SIB.base` field (inverted).
|
||||
*/
|
||||
ZyanU8 B;
|
||||
/**
|
||||
* @brief High-16 register specifier modifier (inverted).
|
||||
* High-16 register specifier modifier (inverted).
|
||||
*/
|
||||
ZyanU8 R2;
|
||||
/**
|
||||
* @brief Opcode-map specifier.
|
||||
* Opcode-map specifier.
|
||||
*/
|
||||
ZyanU8 mmmm;
|
||||
/**
|
||||
* @brief 64-bit operand-size promotion or opcode-extension.
|
||||
* 64-bit operand-size promotion or opcode-extension.
|
||||
*/
|
||||
ZyanU8 W;
|
||||
/**
|
||||
* @brief `NDS`/`NDD` (non-destructive-source/destination) register specifier
|
||||
* (inverted).
|
||||
* `NDS`/`NDD` (non-destructive-source/destination) register specifier
|
||||
* (inverted).
|
||||
*/
|
||||
ZyanU8 vvvv;
|
||||
/**
|
||||
* @brief Compressed legacy prefix.
|
||||
* Compressed legacy prefix.
|
||||
*/
|
||||
ZyanU8 pp;
|
||||
/**
|
||||
* @brief Non-temporal/eviction hint.
|
||||
* Non-temporal/eviction hint.
|
||||
*/
|
||||
ZyanU8 E;
|
||||
/**
|
||||
* @brief Swizzle/broadcast/up-convert/down-convert/static-rounding controls.
|
||||
* Swizzle/broadcast/up-convert/down-convert/static-rounding controls.
|
||||
*/
|
||||
ZyanU8 SSS;
|
||||
/**
|
||||
* @brief High-16 `NDS`/`VIDX` register specifier.
|
||||
* High-16 `NDS`/`VIDX` register specifier.
|
||||
*/
|
||||
ZyanU8 V2;
|
||||
/**
|
||||
* @brief Embedded opmask register specifier.
|
||||
* Embedded opmask register specifier.
|
||||
*/
|
||||
ZyanU8 kkk;
|
||||
/**
|
||||
* @brief The offset of the first mvex byte, relative to the beginning of the
|
||||
* instruction, in bytes.
|
||||
* The offset of the first mvex byte, relative to the beginning of the
|
||||
* instruction, in bytes.
|
||||
*/
|
||||
ZyanU8 offset;
|
||||
} mvex;
|
||||
/**
|
||||
* @brief Detailed info about the `ModRM` byte.
|
||||
* Detailed info about the `ModRM` byte.
|
||||
*/
|
||||
struct
|
||||
struct ZydisDecodedInstructionModRm_
|
||||
{
|
||||
/**
|
||||
* @brief The addressing mode.
|
||||
* The addressing mode.
|
||||
*/
|
||||
ZyanU8 mod;
|
||||
/**
|
||||
* @brief Register specifier or opcode-extension.
|
||||
* Register specifier or opcode-extension.
|
||||
*/
|
||||
ZyanU8 reg;
|
||||
/**
|
||||
* @brief Register specifier or opcode-extension.
|
||||
* Register specifier or opcode-extension.
|
||||
*/
|
||||
ZyanU8 rm;
|
||||
/**
|
||||
* @brief The offset of the `ModRM` byte, relative to the beginning of the
|
||||
* instruction, in bytes.
|
||||
* The offset of the `ModRM` byte, relative to the beginning of the
|
||||
* instruction, in bytes.
|
||||
*/
|
||||
ZyanU8 offset;
|
||||
} modrm;
|
||||
/**
|
||||
* @brief Detailed info about the `SIB` byte.
|
||||
* Detailed info about the `SIB` byte.
|
||||
*/
|
||||
struct
|
||||
struct ZydisDecodedInstructionRawSib_
|
||||
{
|
||||
/**
|
||||
* @brief The scale factor.
|
||||
* The scale factor.
|
||||
*/
|
||||
ZyanU8 scale;
|
||||
/**
|
||||
* @brief The index-register specifier.
|
||||
* The index-register specifier.
|
||||
*/
|
||||
ZyanU8 index;
|
||||
/**
|
||||
* @brief The base-register specifier.
|
||||
* The base-register specifier.
|
||||
*/
|
||||
ZyanU8 base;
|
||||
/**
|
||||
* @brief The offset of the `SIB` byte, relative to the beginning of the instruction,
|
||||
* in bytes.
|
||||
* The offset of the `SIB` byte, relative to the beginning of the
|
||||
* instruction, in bytes.
|
||||
*/
|
||||
ZyanU8 offset;
|
||||
} sib;
|
||||
/**
|
||||
* @brief Detailed info about displacement-bytes.
|
||||
* Detailed info about displacement-bytes.
|
||||
*/
|
||||
struct
|
||||
struct ZydisDecodedInstructionRawDisp_
|
||||
{
|
||||
/**
|
||||
* @brief The displacement value
|
||||
* The displacement value
|
||||
*/
|
||||
ZyanI64 value;
|
||||
/**
|
||||
* @brief The physical displacement size, in bits.
|
||||
* The physical displacement size, in bits.
|
||||
*/
|
||||
ZyanU8 size;
|
||||
// TODO: publish cd8 scale
|
||||
/**
|
||||
* @brief The offset of the displacement data, relative to the beginning of the
|
||||
* instruction, in bytes.
|
||||
* The offset of the displacement data, relative to the beginning of the
|
||||
* instruction, in bytes.
|
||||
*/
|
||||
ZyanU8 offset;
|
||||
} disp;
|
||||
/**
|
||||
* @brief Detailed info about immediate-bytes.
|
||||
* Detailed info about immediate-bytes.
|
||||
*/
|
||||
struct
|
||||
struct ZydisDecodedInstructionRawImm_
|
||||
{
|
||||
/**
|
||||
* @brief Signals, if the immediate value is signed.
|
||||
* Signals, if the immediate value is signed.
|
||||
*/
|
||||
ZyanBool is_signed;
|
||||
/**
|
||||
* @brief Signals, if the immediate value contains a relative offset. You can use
|
||||
* `ZydisCalcAbsoluteAddress` to determine the absolute address value.
|
||||
* Signals, if the immediate value contains a relative offset. You can use
|
||||
* `ZydisCalcAbsoluteAddress` to determine the absolute address value.
|
||||
*/
|
||||
ZyanBool is_relative;
|
||||
/**
|
||||
* @brief The immediate value.
|
||||
* The immediate value.
|
||||
*/
|
||||
union
|
||||
union ZydisDecodedInstructionRawImmValue_
|
||||
{
|
||||
ZyanU64 u;
|
||||
ZyanI64 s;
|
||||
} value;
|
||||
/**
|
||||
* @brief The physical immediate size, in bits.
|
||||
* The physical immediate size, in bits.
|
||||
*/
|
||||
ZyanU8 size;
|
||||
/**
|
||||
* @brief The offset of the immediate data, relative to the beginning of the
|
||||
* instruction, in bytes.
|
||||
* The offset of the immediate data, relative to the beginning of the
|
||||
* instruction, in bytes.
|
||||
*/
|
||||
ZyanU8 offset;
|
||||
} imm[2];
|
||||
|
||||
Loaded 100 of 343 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user