mirror of
https://github.com/ptitSeb/box64.git
synced 2026-11-08 17:39:19 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
59ab48b99e | ||
|
|
a7a58b920f | ||
|
|
1c26df2a90 | ||
|
|
c60e4839eb | ||
|
|
b626fc5095 | ||
|
|
bcd504eb05 | ||
|
|
7057b7f929 | ||
|
|
6af070e25f | ||
|
|
af1a7bd6f4 | ||
|
|
dfd3d0ec93 | ||
|
|
1791c0937a | ||
|
|
c2dd6a0c6a | ||
|
|
f300e76c9b | ||
|
|
8f6f880b6a | ||
|
|
3dcef655c3 | ||
|
|
4c476de74b | ||
|
|
c9e277aee5 | ||
|
|
689d6906ef | ||
|
|
1712afdae9 | ||
|
|
8428fafd3a | ||
|
|
3074846477 | ||
|
|
6c1825ba65 | ||
|
|
bef0a5f793 | ||
|
|
8e694eac57 | ||
|
|
8622f9fdc3 | ||
|
|
6e6a8f47af | ||
|
|
7a57c70d81 | ||
|
|
b2a1af1029 | ||
|
|
c44961c063 | ||
|
|
aceb234c2e | ||
|
|
dd6b60818c | ||
|
|
1978b16581 | ||
|
|
0d079b8c0b | ||
|
|
913029f4c5 | ||
|
|
c667c71a99 | ||
|
|
3cd8b9a44e | ||
|
|
126119b1fb | ||
|
|
701bf913e8 | ||
|
|
00b5944271 | ||
|
|
196076f952 | ||
|
|
e350224157 | ||
|
|
730e129a80 | ||
|
|
883fc1681d | ||
|
|
6b2b672c5e | ||
|
|
1d31bf699f | ||
|
|
c62728f44f | ||
|
|
90efb1ff31 | ||
|
|
7625cc7ceb | ||
|
|
a074115bf5 | ||
|
|
c3aa068179 | ||
|
|
e07be95646 | ||
|
|
0777a568d7 | ||
|
|
f6ce622841 | ||
|
|
508545aa87 | ||
|
|
52d86177c5 | ||
|
|
979d1cfba9 | ||
|
|
31a01aceab | ||
|
|
3b39d1270d | ||
|
|
d5b286c050 | ||
|
|
1f23848e25 | ||
|
|
db1c033c7c | ||
|
|
489afcfb41 | ||
|
|
5519ddad0b | ||
|
|
e788589944 | ||
|
|
7a894540b9 | ||
|
|
30f0f3a5a1 | ||
|
|
debc7284b3 | ||
|
|
60f5dfabd8 | ||
|
|
dd2f209096 | ||
|
|
3b181576c8 | ||
|
|
409334ea56 | ||
|
|
71218a6f70 | ||
|
|
a5be3727e9 | ||
|
|
836b646e24 | ||
|
|
15e4830dff | ||
|
|
ac1156d165 | ||
|
|
370ec24987 | ||
|
|
3bdcae10c8 | ||
|
|
681df1604d | ||
|
|
05abd88ea5 | ||
|
|
42670c0130 | ||
|
|
f4c15979db | ||
|
|
8d97f13677 | ||
|
|
75c4c3d6b9 | ||
|
|
a71e81c842 | ||
|
|
add55f3cec | ||
|
|
c6f6a9ef72 | ||
|
|
1c1e39ef64 | ||
|
|
f5655d85a3 | ||
|
|
c31262d339 | ||
|
|
570798358c | ||
|
|
05c9644ea6 | ||
|
|
051bd2b10b | ||
|
|
b1b9d10656 | ||
|
|
506f78eb32 | ||
|
|
1336ddfad7 | ||
|
|
f3617f720b | ||
|
|
844a1f43ed | ||
|
|
8e42412490 | ||
|
|
2737180a20 | ||
|
|
57e9e55705 | ||
|
|
3f3f8b41e9 | ||
|
|
d3ea390983 | ||
|
|
2f1cc844fd | ||
|
|
543af50ff8 | ||
|
|
f6444c8d45 | ||
|
|
df96dd0060 | ||
|
|
956e2aace3 | ||
|
|
1951d525d1 | ||
|
|
3d4d678bdc | ||
|
|
b78d92d288 | ||
|
|
e5dc4d7e78 | ||
|
|
cd247ef6c1 | ||
|
|
104cf8a58b | ||
|
|
976f175aa9 | ||
|
|
81a06c47a1 | ||
|
|
46b8c6bc83 | ||
|
|
5f83a3f98a | ||
|
|
2f6129bfd5 | ||
|
|
26698b6449 | ||
|
|
61839151c0 | ||
|
|
b38c9ea253 | ||
|
|
25754a47e0 | ||
|
|
278888c912 | ||
|
|
7faa4704e6 | ||
|
|
ba48b6c793 | ||
|
|
f8a969d43e | ||
|
|
55720342ad | ||
|
|
085239ef4a | ||
|
|
df61d561f6 | ||
|
|
3cd8b5f48b | ||
|
|
2e21e46e86 | ||
|
|
cb73a9a6bc | ||
|
|
5199df9b61 | ||
|
|
537ca9f724 | ||
|
|
fc5f5dab29 | ||
|
|
4be307820b | ||
|
|
15227bbc06 | ||
|
|
d0da2c24fb | ||
|
|
152a8a4666 | ||
|
|
86669beb7a | ||
|
|
ba2a70a484 | ||
|
|
88ffcf6396 | ||
|
|
4d347f9ff0 | ||
|
|
252258d138 | ||
|
|
e35b25015b | ||
|
|
422844f842 | ||
|
|
61725c8b49 | ||
|
|
727178df57 | ||
|
|
66b3303f22 | ||
|
|
47c3fad83b | ||
|
|
3928222395 | ||
|
|
414d33a46c | ||
|
|
40a2c8393e | ||
|
|
48fe298a36 | ||
|
|
2865f0eab2 | ||
|
|
a5780632ca | ||
|
|
bd5d29a825 | ||
|
|
5255935a31 | ||
|
|
a31ee062b6 | ||
|
|
c56c991bf7 | ||
|
|
5ea4b796a5 | ||
|
|
8fe7378f86 | ||
|
|
1224ffa7cd | ||
|
|
56766df719 | ||
|
|
e505e5e466 | ||
|
|
4cdc3c62b2 | ||
|
|
4402f08245 | ||
|
|
954830032b | ||
|
|
6f3fad8a16 | ||
|
|
2bb956bb06 | ||
|
|
7fa2a273d0 | ||
|
|
52e125e35a | ||
|
|
57bea35004 | ||
|
|
890842286b | ||
|
|
aec0ad9128 | ||
|
|
4f5b5a995b | ||
|
|
bcd07ff6c7 | ||
|
|
68d7188f3e | ||
|
|
a924a74d82 | ||
|
|
a20b830379 | ||
|
|
12fe96b114 | ||
|
|
3432721379 | ||
|
|
b39b7fd374 | ||
|
|
406ddff9a1 | ||
|
|
d16d985a48 | ||
|
|
0a2ea72d72 | ||
|
|
3b4de7152c | ||
|
|
5520dae2e7 | ||
|
|
7a7f26c80e | ||
|
|
35f4944afb | ||
|
|
0a107d10eb | ||
|
|
2c56ccfabe | ||
|
|
d1497e98db | ||
|
|
7925a8e1b3 | ||
|
|
d529bf3c0c | ||
|
|
802c5a9d5b | ||
|
|
3a22c36d04 | ||
|
|
512ee40dbc | ||
|
|
d84e1f49ce | ||
|
|
c4abaf8c8d | ||
|
|
59fe5f3572 | ||
|
|
18320e19bc | ||
|
|
248cd2e749 | ||
|
|
3b550eeed3 | ||
|
|
097c0ac0b7 | ||
|
|
7a95dcd6b6 | ||
|
|
47d0c04b30 | ||
|
|
16be2bd305 | ||
|
|
7cf6ee06a1 | ||
|
|
dd4c413e41 | ||
|
|
08d2ac41f6 | ||
|
|
fd939c6fce | ||
|
|
82755b5ef2 | ||
|
|
7b4cbee8e7 | ||
|
|
5346f594d4 | ||
|
|
6f217d78da | ||
|
|
cdf71c4cbc | ||
|
|
e93a280d2c | ||
|
|
51fa96c44b | ||
|
|
48d6135106 | ||
|
|
0d38b1cd91 | ||
|
|
f5c4deb42b | ||
|
|
069193e8b7 | ||
|
|
a424e996b3 | ||
|
|
3c81248335 | ||
|
|
1e3f277a71 | ||
|
|
3adeabb06d | ||
|
|
4593111871 | ||
|
|
7440be495e | ||
|
|
fded1a0718 | ||
|
|
ebbb2821d0 | ||
|
|
643b950eef | ||
|
|
63a20f537a | ||
|
|
ae94148bee | ||
|
|
9301eb9ee0 | ||
|
|
19448e242c | ||
|
|
f26c2f0812 | ||
|
|
6573476ea2 | ||
|
|
f73430a3f8 | ||
|
|
3bf90844b1 | ||
|
|
6546ae8e67 | ||
|
|
d01bdf9186 | ||
|
|
88b6cc1907 | ||
|
|
8922b63769 | ||
|
|
30d4713b28 | ||
|
|
498a52439c | ||
|
|
88798b78fc | ||
|
|
0ce7390ac1 | ||
|
|
00f5eb5338 | ||
|
|
d9967d7ea5 | ||
|
|
d42031293d | ||
|
|
76903904d0 | ||
|
|
a42f232b1e | ||
|
|
72a505a3e8 | ||
|
|
ae221ed5bd | ||
|
|
76115b30b8 | ||
|
|
7401d46bcd | ||
|
|
ee61d9c95a | ||
|
|
6db666c565 | ||
|
|
050acaa8c6 | ||
|
|
e83232fcf6 | ||
|
|
ece7ea36d9 | ||
|
|
73d27a625f | ||
|
|
a8d4f17add | ||
|
|
af6fb49e48 | ||
|
|
c593988bc1 | ||
|
|
2d590bb1f5 | ||
|
|
aef3677970 | ||
|
|
7d11254a52 | ||
|
|
3b9feeed12 | ||
|
|
6d3ca2df80 | ||
|
|
5d69ed5f4a | ||
|
|
81d13a8e0b | ||
|
|
544a2ac034 | ||
|
|
9a2bf37ac1 | ||
|
|
550d252386 | ||
|
|
2b3bdd7e60 | ||
|
|
4f38801ba6 | ||
|
|
31b41f5b94 | ||
|
|
03ce3c6592 | ||
|
|
2a4649f6ef | ||
|
|
96c3615ea5 | ||
|
|
adfcfafdc2 | ||
|
|
0a37f1cc30 | ||
|
|
70018a774b | ||
|
|
009bb94f17 | ||
|
|
0e0f1e2037 | ||
|
|
a0a0bc8270 | ||
|
|
25c532610b | ||
|
|
fcfd90b86f | ||
|
|
738d22a68a | ||
|
|
8c63b76343 | ||
|
|
ba7a04851f | ||
|
|
e3d15db6c5 | ||
|
|
ca46df09d8 | ||
|
|
f053e02868 | ||
|
|
42cbe1b397 | ||
|
|
42fe124a0e | ||
|
|
d809b59daa | ||
|
|
e14d4042d9 | ||
|
|
371b346bf7 | ||
|
|
b038dd5c9d | ||
|
|
2681a6db0d | ||
|
|
5ff1ea1435 | ||
|
|
759f165549 | ||
|
|
cb27ac8d93 | ||
|
|
035c77ad91 | ||
|
|
b45c249ed9 | ||
|
|
b90991f039 | ||
|
|
8d49ae5c68 | ||
|
|
49047cf972 | ||
|
|
aa5485ae27 | ||
|
|
fc0d9c5f92 | ||
|
|
8309c5feeb | ||
|
|
4693cac13b | ||
|
|
79f2b8448a | ||
|
|
7e09961ee7 | ||
|
|
21aded91f0 | ||
|
|
6b4bb5e7cb | ||
|
|
c1eef81fdb | ||
|
|
b1e6fa4f2b | ||
|
|
e672641878 | ||
|
|
fef0140098 | ||
|
|
4084eade0c | ||
|
|
748552d792 | ||
|
|
ff50b0c391 | ||
|
|
23e7d5c370 | ||
|
|
676b7523b3 | ||
|
|
880616397f | ||
|
|
ace8536987 | ||
|
|
3370ae4dcf | ||
|
|
8a6a1312f2 | ||
|
|
a9d633ab2d | ||
|
|
765a9d8325 | ||
|
|
67c6a661e5 | ||
|
|
b897d55873 | ||
|
|
7b099f9c64 | ||
|
|
c172fbd883 | ||
|
|
5fb581a51f | ||
|
|
f3a08a51ef | ||
|
|
a7b9590f6f | ||
|
|
998a114172 | ||
|
|
29f65bb6be | ||
|
|
cce9293413 | ||
|
|
b91a95ee49 | ||
|
|
0eb682a95b | ||
|
|
424312c2d8 | ||
|
|
969ee91506 | ||
|
|
f56ee97676 | ||
|
|
f667ec631d | ||
|
|
7bcf1cc0ae | ||
|
|
dba4ff3cff | ||
|
|
0ff030a44c | ||
|
|
7babbcf62b | ||
|
|
fd303c6e94 | ||
|
|
a8495b00f2 | ||
|
|
ae70f168a8 | ||
|
|
b239bec2c5 | ||
|
|
d0f05fed3b | ||
|
|
717c0e1299 | ||
|
|
8760064ddb | ||
|
|
ab0059eeee | ||
|
|
19a7d2139a | ||
|
|
5319117636 | ||
|
|
c5b32180d2 | ||
|
|
62baaf99b1 | ||
|
|
c03dd5951a | ||
|
|
555f4e132f | ||
|
|
c3209a2736 | ||
|
|
0b29d724db | ||
|
|
931a8063b4 | ||
|
|
c74406c89e | ||
|
|
c44b8b1936 | ||
|
|
b1671dd98d | ||
|
|
0baf0ff24a | ||
|
|
2929d7256b | ||
|
|
8d769dd3c2 | ||
|
|
e8d6f083a3 | ||
|
|
817c3d7058 | ||
|
|
e2a7dd0f17 | ||
|
|
f781537adb | ||
|
|
c2c65f46cb | ||
|
|
0f65adfaab | ||
|
|
efafe96b08 | ||
|
|
858957f6f7 | ||
|
|
128724d147 | ||
|
|
c6c6bfcf2c | ||
|
|
4f451ff653 | ||
|
|
7822f29140 | ||
|
|
98d434a0a9 | ||
|
|
61c1f7157c | ||
|
|
5ab4028257 | ||
|
|
717769f1cc | ||
|
|
7278bc9cde | ||
|
|
7bc67cd168 | ||
|
|
bc23a90ef7 | ||
|
|
2070b53967 | ||
|
|
37a8ac3b32 | ||
|
|
3b2e75055f | ||
|
|
9f5e12992a | ||
|
|
eede8e1e8d | ||
|
|
b40c4ebcd7 | ||
|
|
53e449a96f | ||
|
|
d35217d39d | ||
|
|
883463f2d5 | ||
|
|
9abfdb3431 | ||
|
|
e942a8433b | ||
|
|
0163746709 | ||
|
|
dfbdd81d41 | ||
|
|
b474a9061b | ||
|
|
eaeef7e9e9 | ||
|
|
30091b2af6 | ||
|
|
73b51adfb3 | ||
|
|
34a82f7bfc | ||
|
|
159bbcf4a4 | ||
|
|
398a8b12c2 | ||
|
|
d45558782f | ||
|
|
1c3f4c078f | ||
|
|
48588a2556 | ||
|
|
4ae5391637 | ||
|
|
28e11dec31 | ||
|
|
b343ab69a5 | ||
|
|
697dc5fa3f | ||
|
|
fa12161c47 | ||
|
|
9f0f1efafe | ||
|
|
aa4c56e466 | ||
|
|
09e1464bc8 | ||
|
|
b689c745a0 | ||
|
|
28c2c56271 | ||
|
|
2d666965cf | ||
|
|
444d5c7580 | ||
|
|
5d694fe2f2 | ||
|
|
ccd9692875 | ||
|
|
8c553cad5d | ||
|
|
a99a68b03a | ||
|
|
acb01382df | ||
|
|
23d63686e6 | ||
|
|
c0083beec0 | ||
|
|
1d680c2039 | ||
|
|
bb273b55e2 | ||
|
|
d119ae5ed4 | ||
|
|
d78dbbe4c7 | ||
|
|
663ac80fd0 | ||
|
|
2d34788607 | ||
|
|
cbf4e37bba | ||
|
|
74b70253b2 | ||
|
|
0343ee119c | ||
|
|
f9c9868349 | ||
|
|
1395090241 | ||
|
|
dc938e8a60 | ||
|
|
7dd4f1ab72 | ||
|
|
d53c9c1e87 | ||
|
|
424a08607c | ||
|
|
0d2a060e66 | ||
|
|
9748c55dd0 | ||
|
|
130d96b31e | ||
|
|
e6e420d9a3 | ||
|
|
bde4adcdef | ||
|
|
3746ae9cf3 | ||
|
|
0c4eed79da | ||
|
|
8bbd9abd27 | ||
|
|
dfa15ad9fc | ||
|
|
00ac1fdcd1 | ||
|
|
af7bfc7de7 | ||
|
|
e3759a5cd0 | ||
|
|
c5f4820b4e | ||
|
|
a3d9da2fd4 | ||
|
|
e592d2eb6d | ||
|
|
e57aaadb1d | ||
|
|
0d2492bfde | ||
|
|
1a3483e086 | ||
|
|
171c213b32 | ||
|
|
c4dcb316ca | ||
|
|
725f612eb5 | ||
|
|
3539ed5bfe | ||
|
|
a8bd94e34f | ||
|
|
0d59028eb2 | ||
|
|
7ae39b38a0 | ||
|
|
b69f9b9536 | ||
|
|
6dbc4d44a8 | ||
|
|
397eff9712 | ||
|
|
51c23856f3 | ||
|
|
6cb6605a63 | ||
|
|
6ad164d522 | ||
|
|
19915ad238 | ||
|
|
5e8fb55955 | ||
|
|
d535bf35a8 | ||
|
|
17d73a93f1 | ||
|
|
ac2f2516a2 | ||
|
|
8994f9580c | ||
|
|
6013325637 | ||
|
|
ba19837104 | ||
|
|
509a1bf56e | ||
|
|
5b07a475e1 | ||
|
|
bb97366338 | ||
|
|
a527fdcc28 | ||
|
|
5c3a4deed8 | ||
|
|
70b9bed510 | ||
|
|
37795375b6 | ||
|
|
903f9ddb41 | ||
|
|
4b6ade050f | ||
|
|
02cfa0be7f | ||
|
|
da7a7a4d0e | ||
|
|
84a1b6976f | ||
|
|
4d1641b321 | ||
|
|
ee561da549 | ||
|
|
ba1493857f | ||
|
|
fb7a0318a0 | ||
|
|
479ade9cb7 | ||
|
|
dfe62ceac8 | ||
|
|
a36c9bfe73 | ||
|
|
a7119cae76 | ||
|
|
c33368bfb4 | ||
|
|
886999bc5b | ||
|
|
1a750182d6 | ||
|
|
03a69053a6 | ||
|
|
5788d4af1e | ||
|
|
517fe28806 | ||
|
|
b272bdb198 | ||
|
|
910d22a532 | ||
|
|
2a85ea9c61 | ||
|
|
3ee5c792d1 | ||
|
|
8e377ca074 | ||
|
|
451cfa521b | ||
|
|
6d02f7f897 | ||
|
|
3e811f869e | ||
|
|
1f17a57528 | ||
|
|
8c2ea218a5 | ||
|
|
9f01b2ec0d | ||
|
|
86c5dfd664 | ||
|
|
c31aa8a78d | ||
|
|
648d99c9e6 | ||
|
|
cfe541e3ca | ||
|
|
b6faad0354 | ||
|
|
8aee3f4185 | ||
|
|
fe44725804 | ||
|
|
870e0872c0 | ||
|
|
2874e30991 | ||
|
|
d92b46426c | ||
|
|
1c34edb857 | ||
|
|
aba3bcc81a | ||
|
|
085529217e | ||
|
|
50d8016e86 | ||
|
|
4a033b8e76 | ||
|
|
4f5ad4b3ac | ||
|
|
104d51df8c | ||
|
|
5c9ab0a27d | ||
|
|
065d91cf9b | ||
|
|
acceb3155a | ||
|
|
4130e0847c | ||
|
|
37a451a38e | ||
|
|
dd26d06e1c | ||
|
|
235784b46f | ||
|
|
66af0f810c | ||
|
|
72b60a2ab3 | ||
|
|
40e6f46013 | ||
|
|
a701ff87ec | ||
|
|
6e78bc1726 | ||
|
|
3b4181c616 | ||
|
|
2bd3fa6aa7 | ||
|
|
4d0d971212 | ||
|
|
1e451e3353 | ||
|
|
207f829066 | ||
|
|
f1fba8eb42 | ||
|
|
146287331a | ||
|
|
490dcac380 | ||
|
|
e8264eb0db | ||
|
|
3c07dd58eb | ||
|
|
fcdd8fc383 | ||
|
|
0b56f5aebd | ||
|
|
178537116b | ||
|
|
11cfae2a98 | ||
|
|
348bd64449 | ||
|
|
b36eca9792 | ||
|
|
683b77c9bd | ||
|
|
7809f23d4b | ||
|
|
37a9549298 | ||
|
|
8fa2368a63 | ||
|
|
72ca99051b | ||
|
|
905e3ae583 | ||
|
|
29be84ba47 | ||
|
|
636c350461 | ||
|
|
89e305878b | ||
|
|
45873cc2b1 | ||
|
|
a32955ffec | ||
|
|
5b45f871df | ||
|
|
17bc603077 | ||
|
|
7af9158baa | ||
|
|
571a041c25 | ||
|
|
0a02340e35 | ||
|
|
12ee624358 | ||
|
|
571de7f07f | ||
|
|
b055c2be65 | ||
|
|
78750b96e5 | ||
|
|
ce51207e44 | ||
|
|
a3dcaf4284 | ||
|
|
181274636e | ||
|
|
c4198554ad | ||
|
|
ed45a8d666 | ||
|
|
5a8b5c8af4 | ||
|
|
1e3c599b4e | ||
|
|
41ca58a403 | ||
|
|
e09b18d3fb | ||
|
|
4b7958f447 | ||
|
|
b0b11572d7 | ||
|
|
c1684db78a | ||
|
|
fdbdc615da | ||
|
|
5354a134fc | ||
|
|
800d3fd109 | ||
|
|
b7f8a1eb8b | ||
|
|
dbeea3b8a1 | ||
|
|
888705c7dc | ||
|
|
d9e649c023 | ||
|
|
14da2a9a67 | ||
|
|
d7e712f48b | ||
|
|
0f9b48d446 | ||
|
|
6e90c47e74 | ||
|
|
365d2b0eb2 | ||
|
|
3642119665 | ||
|
|
705cb79819 | ||
|
|
d8e5c5372a | ||
|
|
714ccbc321 | ||
|
|
0917fbe0c4 | ||
|
|
1517177668 | ||
|
|
2487fb4d98 | ||
|
|
de0718811e | ||
|
|
12b9b1a6e9 | ||
|
|
1f819c4924 | ||
|
|
1d209596a3 | ||
|
|
b1d5e27564 | ||
|
|
732f2f106b | ||
|
|
db6319b90f | ||
|
|
601eb63c9a | ||
|
|
d237d5e807 | ||
|
|
da47d34705 | ||
|
|
ce5a5bf356 | ||
|
|
c754cb75b6 | ||
|
|
f084966fd3 | ||
|
|
79dd8c29ae | ||
|
|
a260dff197 | ||
|
|
f83179c665 | ||
|
|
31508f673c | ||
|
|
a1f87da9f5 | ||
|
|
eb102f8a82 | ||
|
|
e1a2439fbf | ||
|
|
9fb2cb86ed | ||
|
|
f6b646ef67 | ||
|
|
068025d919 | ||
|
|
f88f59926e | ||
|
|
c9d593fa17 | ||
|
|
ed452e81ae | ||
|
|
604da55f08 | ||
|
|
57a5d517c8 | ||
|
|
2b6fa580df | ||
|
|
7f750e7ac1 | ||
|
|
b9779c2184 | ||
|
|
e52c207c75 | ||
|
|
bfdcb023b3 | ||
|
|
dce3292fc7 | ||
|
|
98a567e102 | ||
|
|
d6123a87c5 | ||
|
|
f94ceccc8a | ||
|
|
cc97914ed8 | ||
|
|
829be9e506 | ||
|
|
bea68ddbfa | ||
|
|
fa039a1320 | ||
|
|
cdaf19899e | ||
|
|
b5847d83cb | ||
|
|
685cc7b0ba | ||
|
|
b14be7f614 | ||
|
|
35f8500acd | ||
|
|
cb0cceb9ae | ||
|
|
1405d83a56 | ||
|
|
0878acf04c | ||
|
|
735d9c107d | ||
|
|
daf148c4d6 | ||
|
|
922fa046bb | ||
|
|
b247fd04df | ||
|
|
0b53a98648 | ||
|
|
f76fa67303 | ||
|
|
e6d3812d6c | ||
|
|
c02946a913 | ||
|
|
8ec2851439 | ||
|
|
f2c68385ab | ||
|
|
f428001f42 | ||
|
|
83104b32b8 | ||
|
|
1a12bd7269 | ||
|
|
04aa1af72e | ||
|
|
466a8cb107 | ||
|
|
23c9d574d9 | ||
|
|
5cc73fdf40 | ||
|
|
3cfd4c8ec2 | ||
|
|
9eb6d49616 | ||
|
|
8bd81dffcf | ||
|
|
79ca411d6a | ||
|
|
9cdf1f9711 | ||
|
|
c8b6834a5e | ||
|
|
e15eb5a7f6 | ||
|
|
3d4acc3aef | ||
|
|
1349601269 | ||
|
|
0751aed1f0 | ||
|
|
4f2ed9ba62 | ||
|
|
707f41af39 | ||
|
|
3d400cf91b | ||
|
|
a77093e154 | ||
|
|
6676fe3b3b | ||
|
|
1d85580fbc | ||
|
|
f01e987d31 | ||
|
|
eb96a1c03a | ||
|
|
e99387aa83 | ||
|
|
f8341bf934 | ||
|
|
20ccf221a8 | ||
|
|
b98fe181e8 | ||
|
|
34eea95426 | ||
|
|
5f470be79e | ||
|
|
1c8683343b | ||
|
|
56f37e8745 | ||
|
|
910a466fad | ||
|
|
d3a15b7ab6 | ||
|
|
cd8ee4c4b4 | ||
|
|
c253e4a48e | ||
|
|
90bd5b0cb1 | ||
|
|
fd729da8f1 | ||
|
|
9bfc027b15 | ||
|
|
cedd8e3670 | ||
|
|
3c31ecb115 | ||
|
|
cc25976743 | ||
|
|
6fea5e5854 | ||
|
|
bf6ac0d608 | ||
|
|
cb7c7ad913 | ||
|
|
bd9cddf211 | ||
|
|
3d33454564 | ||
|
|
a70109be83 | ||
|
|
5ec0a88949 | ||
|
|
12de380799 | ||
|
|
89a3c359a6 | ||
|
|
848390d9eb | ||
|
|
2f89043b35 | ||
|
|
fcfd0d794b | ||
|
|
dbd83a8b28 | ||
|
|
36d62235b3 | ||
|
|
79c4c8bdd3 | ||
|
|
6be2c376e2 | ||
|
|
db22d8b1c9 | ||
|
|
e4fa7bc969 | ||
|
|
98b0ac713d | ||
|
|
74eea34c6e | ||
|
|
bbe817e3be | ||
|
|
f53775ac39 | ||
|
|
dfb1cd4876 | ||
|
|
c2c34ccba3 | ||
|
|
c8d005af84 | ||
|
|
7c651088b5 | ||
|
|
9a9d51440a | ||
|
|
4b3e632d14 | ||
|
|
b52b321969 | ||
|
|
e5b36d2997 | ||
|
|
cc2016bbc9 | ||
|
|
a68be9117b | ||
|
|
f4fceb53bc | ||
|
|
495d566401 | ||
|
|
7a056851d9 | ||
|
|
44eb9cf678 | ||
|
|
597a56d0ff | ||
|
|
967132b04e | ||
|
|
423795b49e | ||
|
|
27b7382be5 | ||
|
|
25d342f829 | ||
|
|
f683404db9 | ||
|
|
d8c3c38d69 | ||
|
|
0400bea3bd | ||
|
|
10088c6566 | ||
|
|
a2abb4e8b1 | ||
|
|
f1625c0d92 | ||
|
|
5c4b0baf8b | ||
|
|
af1b5a9a51 | ||
|
|
f5a7e63936 | ||
|
|
13da8f0d75 | ||
|
|
adea4ceef2 | ||
|
|
cc85f79322 | ||
|
|
c22782d2ab | ||
|
|
994a575d32 | ||
|
|
39faa1538d | ||
|
|
153343fa9e | ||
|
|
0d3e9f21ee | ||
|
|
8c01412156 | ||
|
|
bd46fd7d4f | ||
|
|
cb25e077f9 | ||
|
|
0551f13f0e | ||
|
|
0965273711 | ||
|
|
dd9e8ae8ff | ||
|
|
f08bc7846a | ||
|
|
bac90cfe57 | ||
|
|
6547166c2d | ||
|
|
5a07587437 | ||
|
|
6a14d26c1d | ||
|
|
477617240a | ||
|
|
e8d2b6d25d | ||
|
|
d1a037b38b | ||
|
|
a552e5a48f | ||
|
|
b553c3f3ac | ||
|
|
551542f99a | ||
|
|
1e5bfcdbcd | ||
|
|
c1b6cb7302 | ||
|
|
70f5003784 | ||
|
|
c2a0d7bc32 | ||
|
|
34c1fec8f7 | ||
|
|
14ec226747 | ||
|
|
aebad0cf18 | ||
|
|
ecac60f4c9 | ||
|
|
21f8b852f2 | ||
|
|
4919f161cc | ||
|
|
3dda84e58b | ||
|
|
0823bfaed2 | ||
|
|
3bcb72a083 |
No files matched your search
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 180 KiB |
@@ -1,3 +1,28 @@
|
||||
v0.1.0
|
||||
======
|
||||
* Improvement to ElfLoader
|
||||
* More opcode added to the Dynarec
|
||||
* More lib wrapping
|
||||
* Some fixes to a few function signature
|
||||
* Improvement to Signal handling, and internal mutex handling
|
||||
* A few fixes to some dynarec opcodes
|
||||
* A few fixes to some interpretor opcodes
|
||||
|
||||
v0.0.8
|
||||
======
|
||||
* Improvement to SSE/x87 handling
|
||||
* More opcode added to the Dynarec
|
||||
* More lib wrapping
|
||||
|
||||
v0.0.6
|
||||
======
|
||||
* Added Dynarec for ARM64
|
||||
* Many general CPU opcode added to the Dynarec
|
||||
* Many SSEx opcodes added to the Dynarec
|
||||
* Added a few more symbols in libc
|
||||
* A few changes to the "thread once" handling
|
||||
* New Logo and Icon from @grayduck
|
||||
|
||||
v0.0.4
|
||||
======
|
||||
* Added a lot of opcodes
|
||||
|
||||
+190
-21
@@ -1,12 +1,22 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.4)
|
||||
|
||||
cmake_policy(SET CMP0065 NEW)
|
||||
|
||||
option(RPI4ARM64 "Set to ON if targeting an RaspberryPI4 device with multiarch arm64 and armhf" ${RPI4ARM64})
|
||||
option(RK3326 "Set to ON if targeting an Rockchip RK3326 based device" ${RK3326})
|
||||
option(RK3399 "Set to ON if targeting an Rockchip RK3399 based device" ${RK3399})
|
||||
option(USE_CCACHE "Set to ON to use ccache if present in the system" ${USE_CCACHE})
|
||||
option(HAVE_TRACE "Set to ON to have Trace ability (needs ZydisInfo library)" ${HAVE_TRACE})
|
||||
option(NOLOADADDR "Set to ON to avoid fixing the load address of Box64" ${NO_LOADAADR})
|
||||
option(NOGIT "Set to ON if not building from a git clone repo (like when building from a zip download from github)" ${NOGIT})
|
||||
if(RK3399 OR RPI4ARM64 OR RK3326)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
set(ARM_DYNAREC ON CACHE BOOL "")
|
||||
endif()
|
||||
option(LD80BITS "Set to ON if host device have 80bits long double (i.e. i386)" ${LD80BITS})
|
||||
option(NOALIGN "Set to ON if host device doesn't need re-align (i.e. i386)" ${NOALIGN})
|
||||
option(ARM_DYNAREC "Set to ON to use ARM Dynamic Recompilation" ${ARM_DYNAREC})
|
||||
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.12.2")
|
||||
find_package(PythonInterp 3)
|
||||
@@ -28,7 +38,7 @@ project(box64 C ASM)
|
||||
|
||||
enable_testing()
|
||||
|
||||
set(default_build_type "RelwithDebInfo")
|
||||
set(default_build_type "RelWithDebInfo")
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
message(STATUS "Setting build type to '${default_build_type}' as none was specified.")
|
||||
set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE)
|
||||
@@ -38,9 +48,16 @@ endif()
|
||||
if(RPI4ARM64)
|
||||
add_definitions(-DRPI)
|
||||
add_definitions(-DRPI4ARM64)
|
||||
add_definitions(-pipe -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8")
|
||||
add_definitions(-pipe -march=armv8-a+crc -mtune=cortex-a72)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc -mtune=cortex-a72")
|
||||
endif()
|
||||
|
||||
if(RK3326)
|
||||
add_definitions(-DRK3326)
|
||||
add_definitions(-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a35+crypto)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a35+crypto")
|
||||
endif()
|
||||
|
||||
if(RK3399)
|
||||
add_definitions(-DRK3399)
|
||||
add_definitions(-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a72+crypto)
|
||||
@@ -57,7 +74,7 @@ else()
|
||||
set(BOX64 box64)
|
||||
endif()
|
||||
|
||||
set(BOX64_ELF_ADDRESS "0x50062800000") #random load address...
|
||||
set(BOX64_ELF_ADDRESS "0x500062800000") #random load address...
|
||||
|
||||
if(LD80BITS)
|
||||
add_definitions(-DHAVE_LD80BITS)
|
||||
@@ -71,6 +88,12 @@ if(HAVE_TRACE)
|
||||
add_definitions(-DHAVE_TRACE)
|
||||
endif()
|
||||
|
||||
if(ARM_DYNAREC)
|
||||
add_definitions(-DDYNAREC)
|
||||
add_definitions(-DARM64)
|
||||
enable_language(ASM)
|
||||
endif()
|
||||
|
||||
set(BOX64_ROOT ${CMAKE_SOURCE_DIR})
|
||||
|
||||
add_definitions(-std=gnu11 -funwind-tables -fvisibility=hidden)
|
||||
@@ -80,6 +103,8 @@ if(USE_CCACHE)
|
||||
if(CCACHE_FOUND)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
|
||||
else()
|
||||
message(SEND_ERROR "ccache not found!")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -116,12 +141,18 @@ set(ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/emu/x64run6664.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run66d9.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run66dd.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run66f0.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run67.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run670f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run6766.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run67660f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64rund8.c"
|
||||
"${BOX64_ROOT}/src/emu/x64rund9.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runda.c"
|
||||
"${BOX64_ROOT}/src/emu/x64rundb.c"
|
||||
"${BOX64_ROOT}/src/emu/x64rundc.c"
|
||||
"${BOX64_ROOT}/src/emu/x64rundd.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runde.c"
|
||||
"${BOX64_ROOT}/src/emu/x64rundf.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runf0.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runf20f.c"
|
||||
@@ -132,6 +163,9 @@ set(ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/emu/x64trace.c"
|
||||
"${BOX64_ROOT}/src/librarian/librarian.c"
|
||||
"${BOX64_ROOT}/src/librarian/library.c"
|
||||
"${BOX64_ROOT}/src/librarian/dictionnary.c"
|
||||
"${BOX64_ROOT}/src/librarian/globalsymbols.c"
|
||||
"${BOX64_ROOT}/src/librarian/symbols.c"
|
||||
"${BOX64_ROOT}/src/libtools/auxval.c"
|
||||
"${BOX64_ROOT}/src/libtools/myalign.c"
|
||||
"${BOX64_ROOT}/src/libtools/sdl1rwops.c"
|
||||
@@ -151,39 +185,95 @@ set(ELFLOADER_SRC
|
||||
set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedalure.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedalut.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedatk.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedatkbridge.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedatspi.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedbz2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcairo.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcrashhandler.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcrypto.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcurl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappeddbus.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedexpat.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedflac.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedfontconfig.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedfreetype.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgnutls.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedldlinux.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibasound.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibc.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibcrypt.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibcups.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibdl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibform.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibformw.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibgl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibglu.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibice.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibm.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibncurses.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibncurses6.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibncursesw.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibogg.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibpanel.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibpthread.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibresolv.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibrt.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibsm.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibssl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibtinfo.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibtinfo6.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibuuid.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibvorbis.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibx11.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibx11xcb.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxau.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcb.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcomposite.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcursor.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxdamage.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxdmcp.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxext.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxfixes.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxft.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxi.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxmu.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxpm.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxrandr.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxrender.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxss.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxt.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxtst.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxxf86vm.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibz.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlzma.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedopenal.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpango.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpangocairo.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpangoft2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpng16.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpulse.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpulsesimple.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl1.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl1image.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl1mixer.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl1net.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl1sound.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl1ttf.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsmpeg.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl2image.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl2mixer.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl2net.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl2ttf.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsmpeg2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedtcmallocminimal.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedudev0.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedudev1.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedutil.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedvorbisfile.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedxinerama.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedxml2.c"
|
||||
)
|
||||
|
||||
#set(WRAPPEDS_HEAD "${BOX64_ROOT}/src/wrapped/wrappedd3dadapter9_gen.h")
|
||||
@@ -197,9 +287,9 @@ set(WRAPPER "${BOX64_ROOT}/src/wrapped/generated/wrapper.c" "${BOX64_ROOT}/src/w
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT "${BOX64_ROOT}/src/wrapped/generated/functions_list.txt"
|
||||
COMMAND "${PYTHON_EXECUTABLE}" "${BOX64_ROOT}/rebuild_wrappers.py"
|
||||
"${BOX64_ROOT}"
|
||||
"PANDORA" "HAVE_LD80BITS" "NOALIGN" "HAVE_TRACE" "--"
|
||||
COMMAND "${PYTHON_EXECUTABLE}" "${BOX64_ROOT}/rebuild_wrappers.py"
|
||||
"${BOX64_ROOT}"
|
||||
"PANDORA" "HAVE_LD80BITS" "NOALIGN" "HAVE_TRACE" "--"
|
||||
${WRAPPEDS_HEAD}
|
||||
MAIN_DEPENDENCY "${BOX64_ROOT}/rebuild_wrappers.py"
|
||||
DEPENDS ${WRAPPEDS} ${WRAPPEDS_HEAD}
|
||||
@@ -210,29 +300,99 @@ add_custom_command(
|
||||
# OUTPUT "${BOX64_ROOT}/src/dynarec/last_run.txt"
|
||||
# COMMAND "${PYTHON_EXECUTABLE}" "${BOX64_ROOT}/rebuild_printer.py" "${BOX64_ROOT}"
|
||||
# MAIN_DEPENDENCY "${BOX64_ROOT}/rebuild_printer.py"
|
||||
# DEPENDS "${BOX64_ROOT}/src/dynarec/arm_instructions.txt"
|
||||
# BYPRODUCTS "${BOX64_ROOT}/src/dynarec/arm_printer.c"
|
||||
# DEPENDS "${BOX64_ROOT}/src/dynarec/arm64_instructions.txt"
|
||||
# BYPRODUCTS "${BOX64_ROOT}/src/dynarec/arm64_printer.c"
|
||||
#)
|
||||
|
||||
add_custom_target(WRAPPERS DEPENDS "${BOX64_ROOT}/src/wrapped/generated/functions_list.txt")
|
||||
#add_custom_target(PRINTER DEPENDS "${BOX64_ROOT}/src/dynarec/last_run.txt")
|
||||
|
||||
if(ARM_DYNAREC)
|
||||
set(DYNAREC_SRC
|
||||
"${BOX64_ROOT}/src/dynarec/dynablock.c"
|
||||
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_functions.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64_printer.c"
|
||||
|
||||
"${BOX64_ROOT}/src/dynarec/arm64_prolog.S"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64_epilog.S"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64_next.S"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64_lock.S"
|
||||
)
|
||||
|
||||
set(DYNAREC_PASS
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_helper.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_emit_tests.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_emit_math.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_emit_logic.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_emit_shift.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_pass.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_00.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_0f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_64.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/dynarec_arm64_65.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_66.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_67.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_d8.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_d9.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/dynarec_arm64_da.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_db.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/dynarec_arm64_dc.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_dd.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/dynarec_arm64_de.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_df.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_f0.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_660f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_6664.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_f20f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_f30f.c"
|
||||
)
|
||||
|
||||
set(DYNAREC_PASS "${BOX64_ROOT}/src/wrapped/generated/wrapper.h" ${DYNAREC_PASS})
|
||||
|
||||
add_library(dynarec_arm OBJECT ${DYNAREC_SRC})
|
||||
|
||||
add_library(arm64_pass0 OBJECT ${DYNAREC_PASS})
|
||||
set_target_properties(arm64_pass0 PROPERTIES COMPILE_FLAGS "-DSTEP=0")
|
||||
add_library(arm64_pass1 OBJECT ${DYNAREC_PASS})
|
||||
set_target_properties(arm64_pass1 PROPERTIES COMPILE_FLAGS "-DSTEP=1")
|
||||
add_library(arm64_pass2 OBJECT ${DYNAREC_PASS})
|
||||
set_target_properties(arm64_pass2 PROPERTIES COMPILE_FLAGS "-DSTEP=2")
|
||||
add_library(arm64_pass3 OBJECT ${DYNAREC_PASS})
|
||||
set_target_properties(arm64_pass3 PROPERTIES COMPILE_FLAGS "-DSTEP=3")
|
||||
add_dependencies(arm64_pass0 WRAPPERS)
|
||||
add_dependencies(arm64_pass1 WRAPPERS)
|
||||
add_dependencies(arm64_pass2 WRAPPERS)
|
||||
add_dependencies(arm64_pass3 WRAPPERS)
|
||||
|
||||
add_library(dynarec STATIC
|
||||
$<TARGET_OBJECTS:dynarec_arm>
|
||||
$<TARGET_OBJECTS:arm64_pass0>
|
||||
$<TARGET_OBJECTS:arm64_pass1>
|
||||
$<TARGET_OBJECTS:arm64_pass2>
|
||||
$<TARGET_OBJECTS:arm64_pass3>
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
# creates git_head.h
|
||||
#if(ARM_DYNAREC)
|
||||
# add_custom_command(
|
||||
# OUTPUT "${BOX64_ROOT}/src/git_head.h"
|
||||
# COMMAND bash -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\">\"${BOX64_ROOT}/src/git_head.h\""
|
||||
# DEPENDS dynarec ${ELFLOADER_SRC} ${WRAPPEDS}
|
||||
# VERBATIM)
|
||||
#else()
|
||||
if(ARM_DYNAREC)
|
||||
add_custom_command(
|
||||
OUTPUT "${BOX64_ROOT}/src/git_head.h"
|
||||
COMMAND bash -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\">\"${BOX64_ROOT}/src/git_head.h\""
|
||||
DEPENDS dynarec ${ELFLOADER_SRC} ${WRAPPEDS}
|
||||
VERBATIM)
|
||||
else()
|
||||
add_custom_command(
|
||||
OUTPUT "${BOX64_ROOT}/src/git_head.h"
|
||||
COMMAND bash -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\">\"${BOX64_ROOT}/src/git_head.h\""
|
||||
DEPENDS ${ELFLOADER_SRC} ${WRAPPEDS}
|
||||
VERBATIM)
|
||||
#endif()
|
||||
endif()
|
||||
|
||||
add_executable(${BOX64} ${ELFLOADER_SRC} ${WRAPPEDS} "${BOX64_ROOT}/src/git_head.h")
|
||||
set_target_properties(${BOX64} PROPERTIES ENABLE_EXPORTS ON)
|
||||
add_dependencies(${BOX64} WRAPPERS)
|
||||
#add_dependencies(${BOX64} PRINTER)
|
||||
target_link_libraries(${BOX64} m dl rt pthread)
|
||||
@@ -241,10 +401,14 @@ if(ARM_DYNAREC)
|
||||
endif()
|
||||
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.13")
|
||||
set_target_properties(${BOX64} PROPERTIES LINK_FLAGS "-rdynamic -Wl,-Ttext-segment,${BOX64_ELF_ADDRESS}")
|
||||
if(NOT NOLOADADDR)
|
||||
set_target_properties(${BOX64} PROPERTIES LINK_FLAGS "-Wl,-Ttext-segment,${BOX64_ELF_ADDRESS}")
|
||||
endif()
|
||||
else()
|
||||
target_link_options(${BOX64} PUBLIC -rdynamic)
|
||||
target_link_options(${BOX64} PUBLIC -Wl,-Ttext-segment,${BOX64_ELF_ADDRESS})
|
||||
# If symbols are missing, try this: target_link_options(${BOX64} PUBLIC -rdynamic)
|
||||
if(NOT NOLOADADDR)
|
||||
target_link_options(${BOX64} PUBLIC LINKER:-Ttext-segment,${BOX64_ELF_ADDRESS})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "i686" _x86)
|
||||
@@ -344,6 +508,11 @@ add_test(test15 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref15.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test16 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test16 -D TEST_OUTPUT=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)
|
||||
|
||||
Executable
+76
@@ -0,0 +1,76 @@
|
||||
Compiling
|
||||
----
|
||||
#### for RK3399
|
||||
|
||||
Using a 64bits OS:
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make -j4
|
||||
sudo make install
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
|
||||
#### for PI4
|
||||
|
||||
Warning, you need a 64bits OS:
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DRPI4ARM64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make -j4
|
||||
sudo make install
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
|
||||
#### for Other ARM64 Linux platforms
|
||||
|
||||
`mkdir build; cd build; cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j$(nproc)`
|
||||
|
||||
#### for x86_64 Linux
|
||||
|
||||
`mkdir build; cd build; cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j$(nproc)`
|
||||
|
||||
If you encounter some linking errors, try activating `NOLOADADDR` (`cmake -DNOLOADADDR=ON; make -j$(nproc)`).
|
||||
|
||||
### use ccmake
|
||||
|
||||
Alternatively, you can **use the curses-bases ccmake (or any other gui frontend for cmake)** to select wich platform to use interactively.
|
||||
|
||||
### Customize your build
|
||||
|
||||
*Use ccache if you have it*
|
||||
|
||||
Add `-DUSE_CCACHE=1` if you have ccache (it's better if you plan to touch the sources)
|
||||
|
||||
*To have some debug info*
|
||||
|
||||
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 ( ***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 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 source zipped from github), you need to activate `-DNOGIT=1` from cmake to be able to build (normal process include git sha1 of HEAD in the version that box64 print).
|
||||
|
||||
----
|
||||
|
||||
Testing
|
||||
----
|
||||
A few tests are included.
|
||||
They can be launched with `ctest`
|
||||
They are very basic and don't test much for now.
|
||||
@@ -1,7 +1,49 @@
|
||||
# box64
|
||||
|
||||

|
||||
Linux Userspace x86_64 Emulator with a twist
|
||||
|
||||
----
|
||||
|
||||
Box64 lets you run x86_64 Linux programs (such as games) on non-x86_64 Linux systems, like ARM (host system needs to be 64bit little-endian).
|
||||
Box64 lets you run x86_64 Linux programs (such as games) on non-x86_64 Linux systems, like ARM (host system needs to be 64bit little-endian).
|
||||
|
||||
Because Box64 uses the native versions of some "system" libraries, like libc, libm, SDL, and OpenGL, it's easy to integrate and use with most applications, and performance can be surprisingly high in some cases.
|
||||
|
||||
Box64 integrates a DynaRec (dynamic recompiler) for the ARM64 platform, providing a speed boost between 5 to 10 times faster than only using the interpreter.
|
||||
|
||||
Some x86 internal opcodes use parts of "Realmode X86 Emulator Library", see [x86primop.c](src/emu/x86primop.c) for copyright details
|
||||
|
||||
<img src="Box64Icon.png" width="96" height="96">
|
||||
|
||||
Logo and Icon made by @grayduck, thanks!
|
||||
|
||||
----
|
||||
|
||||
Usage
|
||||
----
|
||||
|
||||
There are a few environment variables to control the behaviour of Box64.
|
||||
|
||||
See [here](USAGE.md) for all environment variables and what they do.
|
||||
|
||||
Note: Box64's Dynarec uses a mechanism with Memory Protection and a SegFault signal handler to handle JIT code. In simpler terms, if you want to use GDB to debug a running program that use JIT'd code (like mono/Unity3D), you will still have many "normal" segfaults triggering. It is suggested to use something like `handle SIGSEGV nostop` in GDB to not stop at each segfault, and maybe put a breakpoint inside `my_memprotectionhandler` in `signals.c` if you want to trap SegFaults.
|
||||
|
||||
----
|
||||
|
||||
Compiling/Installation
|
||||
----
|
||||
> Compilation instructions can be found [here](COMPILE.md)
|
||||
|
||||
----
|
||||
|
||||
Version history
|
||||
----
|
||||
|
||||
The change log is available [here](CHANGELOG.md)
|
||||
|
||||
----
|
||||
|
||||
Final words
|
||||
----
|
||||
|
||||
(If you use Box64 in your project, please don't forget to mention Box64!)
|
||||
@@ -0,0 +1,147 @@
|
||||
|
||||
Usage
|
||||
----
|
||||
|
||||
There are many environment variables to control Box64 behaviour.
|
||||
|
||||
#### BOX64_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.
|
||||
|
||||
#### BOX64_NOBANNER
|
||||
Disables Box64 printing its version and build
|
||||
* 0 : Enable printing its banner. (Default.)
|
||||
* 1 : Disable printing its banner.
|
||||
|
||||
#### BOX64_LD_LIBRARY_PATH
|
||||
Path to look for x86_64 libraries. Default is current folder and `lib` in current folder.
|
||||
Also, `/usr/lib/x86_64-linux-gnu` and `/lib/x86_64-linux-gnu` are added if they exist.
|
||||
|
||||
#### BOX64_PATH
|
||||
Path to look for x86_64 executable. Default is current folder and `bin` in current folder.
|
||||
|
||||
#### BOX64_DLSYM_ERROR
|
||||
Enables/Disables the logging of `dlsym` errors.
|
||||
* 0 : Don't log `dlsym` errors. (Default.)
|
||||
* 1 : Log dlsym errors.
|
||||
|
||||
#### BOX64_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 box64 instance
|
||||
Use `stderr` to use this instead of default `stdout`
|
||||
|
||||
#### BOX64_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.
|
||||
|
||||
#### BOX64_TRACE_INIT
|
||||
Use BOX64_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.
|
||||
|
||||
#### BOX64_TRACE_START
|
||||
Only on builds with trace enabled.
|
||||
* NNNNNNN : Start trace only after NNNNNNNN opcode execute (number is an `uint64_t`).
|
||||
|
||||
#### BOX64_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.
|
||||
|
||||
#### BOX64_TRACE_EMM
|
||||
Only on builds with trace enabled.
|
||||
* 0 : The EMM (i.e. XMM/x87) register will not be logged with the general and x86 registers. (Default.)
|
||||
* 1 : Dump the EMM registers.
|
||||
|
||||
#### BOX64_TRACE_COLOR
|
||||
Only on builds with trace enabled.
|
||||
* 0 : The general registers will always be the default white color. (Default.)
|
||||
* 1 : The general registers will change color in the dumps when they changed value.
|
||||
|
||||
#### BOX64_LOAD_ADDR
|
||||
Try to load at 0xXXXXXX main binary (if binary is a PIE)
|
||||
* 0xXXXXXXXX : The load address . (Only active on PIE programs.)
|
||||
|
||||
#### BOX64_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.
|
||||
|
||||
#### BOX64_NOSIGILL
|
||||
Disable handling of SigILL (to ease debugging mainly).
|
||||
* 0 : Let x86 program set sighandler for Illegal Instruction
|
||||
* 1 : Disables the handling of SigILL
|
||||
|
||||
#### BOX64_X11THREADS
|
||||
Call XInitThreads when loading X11. (This is mostly for old Loki games with the Loki_Compat library.)
|
||||
* 0 : Don't force call XInitThreads. (Default.)
|
||||
* 1 : Call XInitThreads as soon as libX11 is loaded.
|
||||
|
||||
#### BOX64_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.)
|
||||
|
||||
#### BOX64_DYNAREC_DUMP
|
||||
Enables/disables Box64'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.
|
||||
|
||||
#### BOX64_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.
|
||||
|
||||
#### BOX64_DYNAREC
|
||||
Enables/Disables Box64's Dynarec.
|
||||
* 0 : Disables Dynarec.
|
||||
* 1 : Enable Dynarec. (Default.)
|
||||
|
||||
#### BOX64_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).
|
||||
|
||||
#### BOX64_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)
|
||||
|
||||
#### BOX64_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
|
||||
|
||||
#### BOX64_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
|
||||
|
||||
#### BOX64_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
|
||||
|
||||
#### BOX64_ALLOWMISSINGLIBS
|
||||
Allow Box64 to continue even if a library is missing.
|
||||
* 0 : Box64 will stop if a library cannot be loaded. (Default.)
|
||||
* 1 : Continue even if a needed library cannot be loaded. Unadvised, this will, in most cases, crash later on.
|
||||
|
||||
#### BOX64_JITGDB
|
||||
|
||||
* 0 : Just print the Segfault message on segfault (default)
|
||||
* 1 : Launch `gdb` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process and go in an endless loop, waiting.
|
||||
When in gdb, you need to find the correct thread yourself (the one with `my_box64signalhandler` in is stack)
|
||||
then probably need to `finish` 1 or 2 functions (inside `usleep(..)`) and then you'll be in `my_box64signalhandler`,
|
||||
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/box64` 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 ` BOX64_JITGDB=1`.
|
||||
This mode can be usefullwhen programs redirect all console output to a file (like Unity3D Games)
|
||||
+770
-366
File diff suppressed because it is too large.
Load diff
+109
-18
@@ -68,6 +68,76 @@ void free_tlsdatasize(void* p)
|
||||
|
||||
void x64Syscall(x64emu_t *emu);
|
||||
|
||||
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(box64context_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
|
||||
box64context_t *NewBox64Context(int argc)
|
||||
{
|
||||
@@ -87,6 +157,7 @@ box64context_t *NewBox64Context(int argc)
|
||||
|
||||
context->maplib = NewLibrarian(context, 1);
|
||||
context->local_maplib = NewLibrarian(context, 1);
|
||||
context->versym = NewDictionnary();
|
||||
context->system = NewBridge();
|
||||
// create vsyscall
|
||||
context->vsyscall = AddBridge(context->system, vFv, x64Syscall, 0, NULL);
|
||||
@@ -96,22 +167,15 @@ box64context_t *NewBox64Context(int argc)
|
||||
context->argc = argc;
|
||||
context->argv = (char**)calloc(context->argc+1, sizeof(char*));
|
||||
|
||||
pthread_mutex_init(&context->mutex_once, NULL);
|
||||
pthread_mutex_init(&context->mutex_once2, NULL);
|
||||
pthread_mutex_init(&context->mutex_trace, NULL);
|
||||
#ifndef DYNAREC
|
||||
pthread_mutex_init(&context->mutex_lock, NULL);
|
||||
#else
|
||||
pthread_mutex_init(&context->mutex_dyndump, NULL);
|
||||
#endif
|
||||
pthread_mutex_init(&context->mutex_tls, NULL);
|
||||
pthread_mutex_init(&context->mutex_thread, NULL);
|
||||
init_mutexes(context);
|
||||
pthread_atfork(NULL, NULL, atfork_child_box64context);
|
||||
|
||||
pthread_key_create(&context->tlskey, free_tlsdatasize);
|
||||
|
||||
|
||||
for (int i=0; i<8; ++i) context->canary[i] = 1 + getrand(255);
|
||||
context->canary[getrand(4)] = 0;
|
||||
printf_log(LOG_DEBUG, "Setting up canary (for Stack protector) at FS:0x14, value:%08X\n", *(uint32_t*)context->canary);
|
||||
printf_log(LOG_DEBUG, "Setting up canary (for Stack protector) at FS:0x28, value:%08X\n", *(uint32_t*)context->canary);
|
||||
|
||||
initAllHelpers(context);
|
||||
|
||||
@@ -129,16 +193,17 @@ void FreeBox64Context(box64context_t** context)
|
||||
|
||||
box64context_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);
|
||||
FreeDictionnary(&ctx->versym);
|
||||
|
||||
for(int i=0; i<ctx->elfsize; ++i) {
|
||||
FreeElfHeader(&ctx->elfs[i]);
|
||||
}
|
||||
free(ctx->elfs);
|
||||
|
||||
if(ctx->maplib)
|
||||
FreeLibrarian(&ctx->maplib);
|
||||
if(ctx->local_maplib)
|
||||
FreeLibrarian(&ctx->local_maplib);
|
||||
|
||||
FreeCollection(&ctx->box64_path);
|
||||
FreeCollection(&ctx->box64_ld_lib);
|
||||
FreeCollection(&ctx->box64_emulated_libs);
|
||||
@@ -174,8 +239,6 @@ void FreeBox64Context(box64context_t** context)
|
||||
|
||||
FreeDLPrivate(&ctx->dlprivate);
|
||||
|
||||
free(ctx->stack);
|
||||
|
||||
free(ctx->fullpath);
|
||||
free(ctx->box64path);
|
||||
|
||||
@@ -249,6 +312,9 @@ void add_neededlib(needed_libs_t* needed, library_t* lib)
|
||||
{
|
||||
if(!needed)
|
||||
return;
|
||||
for(int i=0; i<needed->size; ++i)
|
||||
if(needed->libs[i] == lib)
|
||||
return;
|
||||
if(needed->size == needed->cap) {
|
||||
needed->cap += 8;
|
||||
needed->libs = (library_t**)realloc(needed->libs, needed->cap*sizeof(library_t*));
|
||||
@@ -266,3 +332,28 @@ void free_neededlib(needed_libs_t* needed)
|
||||
free(needed->libs);
|
||||
needed->libs = NULL;
|
||||
}
|
||||
|
||||
void add_dependedlib(needed_libs_t* depended, library_t* lib)
|
||||
{
|
||||
if(!depended)
|
||||
return;
|
||||
for(int i=0; i<depended->size; ++i)
|
||||
if(depended->libs[i] == lib)
|
||||
return;
|
||||
if(depended->size == depended->cap) {
|
||||
depended->cap += 8;
|
||||
depended->libs = (library_t**)realloc(depended->libs, depended->cap*sizeof(library_t*));
|
||||
}
|
||||
depended->libs[depended->size++] = lib;
|
||||
}
|
||||
|
||||
void free_dependedlib(needed_libs_t* depended)
|
||||
{
|
||||
if(!depended)
|
||||
return;
|
||||
depended->cap = 0;
|
||||
depended->size = 0;
|
||||
if(depended->libs)
|
||||
free(depended->libs);
|
||||
depended->libs = NULL;
|
||||
}
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
#define __BOX64_VERSION_H_
|
||||
|
||||
#define BOX64_MAJOR 0
|
||||
#define BOX64_MINOR 0
|
||||
#define BOX64_REVISION 4
|
||||
#define BOX64_MINOR 1
|
||||
#define BOX64_REVISION 0
|
||||
|
||||
#endif //__BOX64_VERSION_H_
|
||||
+970
-669
File diff suppressed because it is too large.
Load diff
Executable
+1701
File diff suppressed because it is too large.
Load diff
Executable
+54
@@ -0,0 +1,54 @@
|
||||
//arm epilog for dynarec
|
||||
//Save stuff, prepare stack and register
|
||||
//called with pointer to emu as 1st parameter
|
||||
//and address to jump to as 2nd parameter
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.global arm64_epilog
|
||||
arm64_epilog:
|
||||
//update register -> emu
|
||||
stp x10, x11, [x0, (8 * 0)]
|
||||
stp x12, x13, [x0, (8 * 2)]
|
||||
stp x14, x15, [x0, (8 * 4)]
|
||||
stp x16, x17, [x0, (8 * 6)]
|
||||
stp x18, x19, [x0, (8 * 8)]
|
||||
stp x20, x21, [x0, (8 * 10)]
|
||||
stp x22, x23, [x0, (8 * 12)]
|
||||
stp x24, x25, [x0, (8 * 14)]
|
||||
stp x26, x27, [x0, (8 * 16)] // put back reg value in emu, including EIP (so x27 must be EIP now)
|
||||
//restore all used register
|
||||
//vpop {d8-d15}
|
||||
ldp x19, x20, [sp, (8 * 0)]
|
||||
ldp x21, x22, [sp, (8 * 2)]
|
||||
ldp x23, x24, [sp, (8 * 4)]
|
||||
ldp x25, x26, [sp, (8 * 6)]
|
||||
ldr x27, [sp, (8 * 8)]
|
||||
ldp d8, d9, [sp, (8 *10)]
|
||||
ldp d10, d11, [sp, (8 *12)]
|
||||
ldp d12, d13, [sp, (8 *14)]
|
||||
ldp d14, d15, [sp, (8 *16)]
|
||||
add sp, sp, (8 * 18)
|
||||
ldp lr, fp, [sp], 16 // saved lr
|
||||
//end, return...
|
||||
ret
|
||||
|
||||
|
||||
.global arm64_epilog_fast
|
||||
arm64_epilog_fast:
|
||||
//restore all used register
|
||||
//vpop {d8-d15}
|
||||
ldp x19, x20, [sp, (8 * 0)]
|
||||
ldp x21, x22, [sp, (8 * 2)]
|
||||
ldp x23, x24, [sp, (8 * 4)]
|
||||
ldp x25, x26, [sp, (8 * 6)]
|
||||
ldr x27, [sp, (8 * 8)]
|
||||
ldp d8, d9, [sp, (8 *10)]
|
||||
ldp d10, d11, [sp, (8 *12)]
|
||||
ldp d12, d13, [sp, (8 *14)]
|
||||
ldp d14, d15, [sp, (8 *16)]
|
||||
add sp, sp, (8 * 18)
|
||||
ldp lr, fp, [sp], 16 // saved lr
|
||||
//end, return...
|
||||
ret
|
||||
Executable
+112
@@ -0,0 +1,112 @@
|
||||
//arm lock helper
|
||||
//there is 2 part: read and write
|
||||
// write return 0 on success, 1 on fail (value has been changed)
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.global arm64_lock_read_b
|
||||
.global arm64_lock_write_b
|
||||
.global arm64_lock_read_h
|
||||
.global arm64_lock_write_h
|
||||
.global arm64_lock_read_d
|
||||
.global arm64_lock_write_d
|
||||
.global arm64_lock_read_dd
|
||||
.global arm64_lock_write_dd
|
||||
.global arm64_lock_read_dq
|
||||
.global arm64_lock_write_dq
|
||||
.global arm64_lock_xchg
|
||||
.global arm64_lock_storeifnull
|
||||
.global arm64_lock_storeifref
|
||||
|
||||
|
||||
arm64_lock_read_b:
|
||||
// address is x0, return is x0
|
||||
ldaxrb w0, [x0]
|
||||
ret
|
||||
|
||||
arm64_lock_write_b:
|
||||
// address is x0, value is x1, return is x0
|
||||
mov x2, x0
|
||||
stlxrb w0, w1, [x2]
|
||||
ret
|
||||
|
||||
arm64_lock_read_h:
|
||||
// address is x0, return is x0
|
||||
ldaxrh w0, [x0]
|
||||
ret
|
||||
|
||||
arm64_lock_write_h:
|
||||
// address is x0, value is x1, return is x0
|
||||
mov x2, x0
|
||||
stlxrh w0, w1, [x2]
|
||||
ret
|
||||
|
||||
arm64_lock_read_d:
|
||||
// address is x0, return is x0
|
||||
ldaxr w0, [x0]
|
||||
ret
|
||||
|
||||
arm64_lock_write_d:
|
||||
// address is x0, value is w1, return is x0
|
||||
mov x2, x0
|
||||
stlxr w0, w1, [x2]
|
||||
ret
|
||||
|
||||
arm64_lock_read_dd:
|
||||
// address is x0, return is x0
|
||||
ldaxr x0, [x0]
|
||||
ret
|
||||
|
||||
arm64_lock_write_dd:
|
||||
// address is x0, value is x1, return is x0
|
||||
mov x2, x0
|
||||
stlxr w0, x1, [x2]
|
||||
ret
|
||||
|
||||
arm64_lock_read_dq:
|
||||
// address is r2, return is r0, r1
|
||||
ldaxp x4, x3, [x2]
|
||||
str x4, [x0]
|
||||
str x3, [x1]
|
||||
ret
|
||||
|
||||
arm64_lock_write_dq:
|
||||
// address is r2, value is r0, r1, return is r0
|
||||
// r0 needs to be aligned
|
||||
stlxp w3, x0, x1, [x2]
|
||||
mov w0, w3
|
||||
ret
|
||||
|
||||
|
||||
arm64_lock_xchg:
|
||||
// address is x0, value is x1, return old value in x0
|
||||
ldaxr x2, [x0]
|
||||
stlxr w3, x1, [x0]
|
||||
cbnz w3, arm64_lock_xchg
|
||||
mov x0, x2
|
||||
ret
|
||||
|
||||
arm64_lock_storeifnull:
|
||||
// address is x0, value is x1, x1 store to x0 only if [x0] is 0. return new [x0] value (so x1 or old value)
|
||||
ldaxr x2, [x0]
|
||||
cbnz x2, arm64_lock_storeifnull_exit
|
||||
mov x2, x1
|
||||
stlxr w3, x2, [x0]
|
||||
cbnz w3, arm64_lock_storeifnull
|
||||
arm64_lock_storeifnull_exit:
|
||||
mov x0, x2
|
||||
ret
|
||||
|
||||
arm64_lock_storeifref:
|
||||
// address is x0, value is x1, x1 store to x0 only if [x0] is x3. return new [x0] value (so x1 or old value)
|
||||
ldaxr x3, [x0]
|
||||
cmp x2, x3
|
||||
bne arm64_lock_storeifref_exit
|
||||
stlxr w4, x1, [x0]
|
||||
cbnz w4, arm64_lock_storeifref
|
||||
mov x0, x1
|
||||
ret
|
||||
arm64_lock_storeifref_exit:
|
||||
mov x0, x3
|
||||
ret
|
||||
Executable
+39
@@ -0,0 +1,39 @@
|
||||
#ifndef __ARM64_LOCK__H__
|
||||
#define __ARM64_LOCK__H__
|
||||
#include <stdint.h>
|
||||
|
||||
// LDAXRB of ADDR
|
||||
extern uint8_t arm64_lock_read_b(void* addr);
|
||||
// STLXRB of ADDR, return 0 if ok, 1 if not
|
||||
extern int arm64_lock_write_b(void* addr, uint8_t val);
|
||||
|
||||
// LDAXRH of ADDR
|
||||
extern uint16_t arm64_lock_read_h(void* addr);
|
||||
// STLXRH of ADDR, return 0 if ok, 1 if not
|
||||
extern int arm64_lock_write_h(void* addr, uint16_t val);
|
||||
|
||||
// LDAXR of ADDR
|
||||
extern uint32_t arm64_lock_read_d(void* addr);
|
||||
// STLXR of ADDR, return 0 if ok, 1 if not
|
||||
extern int arm64_lock_write_d(void* addr, uint32_t val);
|
||||
|
||||
// LDAXR of ADDR
|
||||
extern uint64_t arm64_lock_read_dd(void* addr);
|
||||
// STLXR of ADDR, return 0 if ok, 1 if not
|
||||
extern int arm64_lock_write_dd(void* addr, uint64_t val);
|
||||
|
||||
// LDAXRD of ADDR
|
||||
extern void arm64_lock_read_dq(uint64_t * a, uint64_t* b, void* addr);
|
||||
// STLXRD of ADDR, return 0 if ok, 1 if not
|
||||
extern int arm64_lock_write_dq(uint64_t a, uint64_t b, void* addr);
|
||||
|
||||
// Atomicaly exchange value at [p] with val, return old p
|
||||
extern uintptr_t arm64_lock_xchg(void* p, uintptr_t val);
|
||||
|
||||
// Atomicaly store value to [p] only if [p] is NULL. Return new [p] value (so val or old)
|
||||
extern void* arm64_lock_storeifnull(void*p, void* val);
|
||||
|
||||
// Atomicaly store value to [p] only if [p] is ref. Return new [p] value (so val or old)
|
||||
extern void* arm64_lock_storeifref(void*p, void* val, void* ref);
|
||||
|
||||
#endif //__ARM64_LOCK__H__
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
//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 arm64_next
|
||||
arm64_next:
|
||||
// emu is r0
|
||||
// IP address is r1
|
||||
sub sp, sp, (8 * 12)
|
||||
stp x0, x1, [sp, (8 * 0)]
|
||||
stp x10, x11, [sp, (8 * 2)]
|
||||
stp x12, x13, [sp, (8 * 4)]
|
||||
stp x14, x15, [sp, (8 * 6)]
|
||||
stp x16, x17, [sp, (8 * 8)]
|
||||
str x18, [sp, (8 * 10)]
|
||||
mov x2, lr // "from" is in lr, so put in x2
|
||||
// call the function
|
||||
bl LinkNext
|
||||
// preserve return value
|
||||
mov x3, x0
|
||||
// pop regs
|
||||
ldp x0, x1, [sp, (8 * 0)]
|
||||
ldp x10, x11, [sp, (8 * 2)]
|
||||
ldp x12, x13, [sp, (8 * 4)]
|
||||
ldp x14, x15, [sp, (8 * 6)]
|
||||
ldp x16, x17, [sp, (8 * 8)]
|
||||
ldr x18, [sp, (8 * 10)]
|
||||
add sp, sp, (8 * 12)
|
||||
// return offset is jump address
|
||||
br x3
|
||||
|
||||
Executable
+1319
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,6 @@
|
||||
#ifndef _ARM_PRINTER_H_
|
||||
#define _ARM_PRINTER_H_
|
||||
|
||||
const char* arm64_print(uint32_t opcode, uint64_t addr);
|
||||
|
||||
#endif //_ARM_PRINTER_H_
|
||||
Executable
+35
@@ -0,0 +1,35 @@
|
||||
//arm prologue for dynarec
|
||||
//Save stuff, prepare stack and register
|
||||
//called with pointer to emu as 1st parameter
|
||||
//and address to jump to as 2nd parameter
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.global arm64_prolog
|
||||
arm64_prolog:
|
||||
//save all 18 used register
|
||||
stp lr, fp, [sp, -16]! // save lr
|
||||
sub sp, sp, (8 * 18)
|
||||
stp x19, x20, [sp, (8 * 0)]
|
||||
stp x21, x22, [sp, (8 * 2)]
|
||||
stp x23, x24, [sp, (8 * 4)]
|
||||
stp x25, x26, [sp, (8 * 6)]
|
||||
str x27, [sp, (8 * 8)]
|
||||
stp d8, d9, [sp, (8 *10)]
|
||||
stp d10, d11, [sp, (8 *12)]
|
||||
stp d12, d13, [sp, (8 *14)]
|
||||
stp d14, d15, [sp, (8 *16)]
|
||||
//vpush {d8-d15} // save NEON regs?
|
||||
//setup emu -> register
|
||||
ldp x10, x11, [x0, (8 * 0)]
|
||||
ldp x12, x13, [x0, (8 * 2)]
|
||||
ldp x14, x15, [x0, (8 * 4)]
|
||||
ldp x16, x17, [x0, (8 * 6)]
|
||||
ldp x18, x19, [x0, (8 * 8)]
|
||||
ldp x20, x21, [x0, (8 * 10)]
|
||||
ldp x22, x23, [x0, (8 * 12)]
|
||||
ldp x24, x25, [x0, (8 * 14)]
|
||||
ldp x26, x27, [x0, (8 * 16)]
|
||||
//jump to function
|
||||
br x1
|
||||
Executable
+433
@@ -0,0 +1,433 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "tools/bridge_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynablock.h"
|
||||
#include "dynablock_private.h"
|
||||
#include "dynarec_private.h"
|
||||
#include "elfloader.h"
|
||||
#ifdef ARM64
|
||||
#include "dynarec_arm64.h"
|
||||
#include "arm64_lock.h"
|
||||
#else
|
||||
#error Unsupported architecture!
|
||||
#endif
|
||||
#include "custommem.h"
|
||||
#include "khash.h"
|
||||
|
||||
KHASH_MAP_INIT_INT(dynablocks, dynablock_t*)
|
||||
|
||||
uint32_t X31_hash_code(void* addr, int len)
|
||||
{
|
||||
if(!len) return 0;
|
||||
uint8_t* p = (uint8_t*)addr;
|
||||
int32_t h = *p;
|
||||
for (--len, ++p; len; --len, ++p) h = (h << 5) - h + (int32_t)*p;
|
||||
return (uint32_t)h;
|
||||
}
|
||||
|
||||
dynablocklist_t* NewDynablockList(uintptr_t 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->text = text;
|
||||
ret->textsz = textsz;
|
||||
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 x64=%p:%p parent=%p, father=%p, with %d son(s) already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size, db->parent, db->father, db->sons_size, db->gone);
|
||||
if(db->gone)
|
||||
return; // already in the process of deletion!
|
||||
db->done = 0;
|
||||
db->gone = 1;
|
||||
// remove from direct if there
|
||||
uintptr_t startdb = db->parent->text;
|
||||
uintptr_t enddb = db->parent->text + db->parent->textsz;
|
||||
if(db->parent->direct) {
|
||||
uintptr_t addr = (uintptr_t)db->x64_addr;
|
||||
if(addr>=startdb && addr<enddb)
|
||||
arm64_lock_xchg(&db->parent->direct[addr-startdb], 0); // secured write
|
||||
}
|
||||
// remove jumptable
|
||||
setJumpTableDefault64(db->x64_addr);
|
||||
// remove and free the sons
|
||||
for (int i=0; i<db->sons_size; ++i) {
|
||||
dynablock_t *son = (dynablock_t*)arm64_lock_xchg(&db->sons[i], 0);
|
||||
FreeDynablock(son);
|
||||
}
|
||||
// only the father free the DynarecMap
|
||||
if(!db->father) {
|
||||
dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->block, db->size);
|
||||
FreeDynarecMap(db, (uintptr_t)db->block, db->size);
|
||||
}
|
||||
free(db->sons);
|
||||
free(db->instsize);
|
||||
free(db);
|
||||
}
|
||||
}
|
||||
|
||||
void FreeDynablockList(dynablocklist_t** dynablocks)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
if(!*dynablocks)
|
||||
return;
|
||||
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)
|
||||
FreeDynablock((*dynablocks)->direct[i]);
|
||||
}
|
||||
free((*dynablocks)->direct);
|
||||
}
|
||||
(*dynablocks)->direct = NULL;
|
||||
|
||||
free(*dynablocks);
|
||||
*dynablocks = NULL;
|
||||
}
|
||||
|
||||
void MarkDynablock(dynablock_t* db)
|
||||
{
|
||||
if(db) {
|
||||
if(db->father)
|
||||
db = db->father; // mark only father
|
||||
if(db->need_test)
|
||||
return; // already done
|
||||
db->need_test = 1; // test only blocks that can be marked (and so deleted)
|
||||
setJumpTableDefault64(db->x64_addr);
|
||||
for(int i=0; i<db->sons_size; ++i)
|
||||
setJumpTableDefault64(db->sons[i]->x64_addr);
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t StartDynablockList(dynablocklist_t* db)
|
||||
{
|
||||
if(db)
|
||||
return db->text;
|
||||
return 0;
|
||||
}
|
||||
uintptr_t EndDynablockList(dynablocklist_t* db)
|
||||
{
|
||||
if(db)
|
||||
return db->text+db->textsz-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->direct)
|
||||
return;
|
||||
uintptr_t startdb = dynablocks->text;
|
||||
uintptr_t enddb = startdb + dynablocks->textsz -1;
|
||||
uintptr_t start = addr;
|
||||
uintptr_t end = addr+size-1;
|
||||
if(start<startdb)
|
||||
start = startdb;
|
||||
if(end>enddb)
|
||||
end = enddb;
|
||||
dynablock_t *db;
|
||||
if(end>startdb && start<enddb)
|
||||
for(uintptr_t i = start; i<end; ++i)
|
||||
if((db=dynablocks->direct[i-startdb]))
|
||||
if(IntervalIntersects((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr+db->x64_size-1, addr, addr+size+1))
|
||||
MarkDynablock(db);
|
||||
}
|
||||
|
||||
int FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return 1;
|
||||
|
||||
if(dynablocks->direct) {
|
||||
dynablock_t* db;
|
||||
int ret;
|
||||
khint_t k;
|
||||
kh_dynablocks_t *blocks = kh_init(dynablocks);
|
||||
// copy in a temporary list
|
||||
uintptr_t startdb = dynablocks->text;
|
||||
uintptr_t enddb = startdb + dynablocks->textsz;
|
||||
uintptr_t start = addr;
|
||||
uintptr_t end = addr+size;
|
||||
if(start<startdb)
|
||||
start = startdb;
|
||||
if(end>enddb)
|
||||
end = enddb;
|
||||
if(end>startdb && start<enddb)
|
||||
for(uintptr_t i = start; i<end; ++i) {
|
||||
db = (dynablock_t*)arm64_lock_xchg(&dynablocks->direct[i-startdb], 0);
|
||||
if(db) {
|
||||
if(db->father)
|
||||
db = db->father;
|
||||
if(db->parent==dynablocks) {
|
||||
k = kh_put(dynablocks, blocks, (uintptr_t)db, &ret);
|
||||
kh_value(blocks, k) = db;
|
||||
}
|
||||
}
|
||||
}
|
||||
// purge the list
|
||||
kh_foreach_value(blocks, db,
|
||||
FreeDynablock(db);
|
||||
);
|
||||
kh_destroy(dynablocks, blocks);
|
||||
// check emptyness
|
||||
for(uintptr_t i=0; i<dynablocks->textsz; ++i)
|
||||
if(dynablocks->direct[i])
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
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(unsigned 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)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return NULL;
|
||||
dynablock_t* db;
|
||||
kh_foreach_value(dynablocks, db,
|
||||
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;
|
||||
)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static dynablocklist_t* getDBFromAddress(uintptr_t addr)
|
||||
{
|
||||
const uintptr_t idx = (addr>>DYNAMAP_SHIFT);
|
||||
return getDB(idx);
|
||||
}
|
||||
|
||||
dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* created)
|
||||
{
|
||||
if(!dynablocks) {
|
||||
dynarec_log(LOG_INFO, "Warning: Ask to create a dynablock with a NULL dynablocklist (addr=%p)\n", (void*)addr);
|
||||
*created = 0;
|
||||
return NULL;
|
||||
}
|
||||
if((addr<dynablocks->text) || (addr>=(dynablocks->text+dynablocks->textsz))) {
|
||||
return AddNewDynablock(getDBFromAddress(addr), addr, created);
|
||||
}
|
||||
dynablock_t* block = NULL;
|
||||
// first, check if it exist in direct access mode
|
||||
if(dynablocks->direct) {
|
||||
block = dynablocks->direct[addr-dynablocks->text];
|
||||
if(block) {
|
||||
dynarec_log(LOG_VERBOSE, "Block already exist in Direct Map\n");
|
||||
*created = 0;
|
||||
return block;
|
||||
}
|
||||
}
|
||||
|
||||
if (!*created)
|
||||
return block;
|
||||
|
||||
if(!dynablocks->direct) {
|
||||
dynablock_t** p = (dynablock_t**)calloc(dynablocks->textsz, sizeof(dynablock_t*));
|
||||
if(arm64_lock_storeifnull(&dynablocks->direct, p)!=p)
|
||||
free(p); // someone already create the direct array, too late...
|
||||
}
|
||||
|
||||
// create and add new block
|
||||
dynarec_log(LOG_VERBOSE, "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*)arm64_lock_storeifnull(&dynablocks->direct[addr-dynablocks->text], block);
|
||||
if(tmp != block) {
|
||||
// a block appeard!
|
||||
free(block);
|
||||
*created = 0;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
*created = 1;
|
||||
return block;
|
||||
}
|
||||
|
||||
/*
|
||||
return NULL if block is not found / cannot be created.
|
||||
Don't create if create==0
|
||||
*/
|
||||
static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, dynablock_t* current)
|
||||
{
|
||||
// try the quickest way first: get parent of current and check if ok!
|
||||
dynablocklist_t *dynablocks = NULL;
|
||||
dynablock_t* block = NULL;
|
||||
if(current) {
|
||||
dynablocks = current->parent;
|
||||
if(dynablocks && !(addr>=dynablocks->text && addr<(dynablocks->text+dynablocks->textsz)))
|
||||
dynablocks = NULL;
|
||||
}
|
||||
// nope, lets do the long way
|
||||
if(!dynablocks) {
|
||||
dynablocks = getDBFromAddress(addr);
|
||||
if(!dynablocks) {
|
||||
dynablocks = GetDynablocksFromAddress(emu->context, addr);
|
||||
if(!dynablocks)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
// check direct first, without lock
|
||||
if(dynablocks->direct/* && (addr>=dynablocks->text) && (addr<(dynablocks->text+dynablocks->textsz))*/)
|
||||
if((block = dynablocks->direct[addr-dynablocks->text]))
|
||||
return block;
|
||||
|
||||
int created = create;
|
||||
block = AddNewDynablock(dynablocks, addr, &created);
|
||||
if(!created)
|
||||
return block; // existing block...
|
||||
|
||||
#if 0
|
||||
if(box64_dynarec_dump)
|
||||
pthread_mutex_lock(&my_context->mutex_dyndump);
|
||||
#endif
|
||||
// fill the block
|
||||
block->x64_addr = (void*)addr;
|
||||
pthread_mutex_lock(&my_context->mutex_dyndump);
|
||||
void* ret = FillBlock64(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*)arm64_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 be writen
|
||||
}
|
||||
free(block);
|
||||
block = NULL;
|
||||
}
|
||||
#if 0
|
||||
if(box64_dynarec_dump)
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
#endif
|
||||
// check size
|
||||
if(block && block->x64_size) {
|
||||
int blocksz = block->x64_size;
|
||||
if(dynablocks->maxsz<blocksz) {
|
||||
dynablocks->maxsz = blocksz;
|
||||
for(unsigned idx=(addr>>DYNAMAP_SHIFT)+1; idx<=((addr+blocksz)>>DYNAMAP_SHIFT); ++idx) {
|
||||
dynablocklist_t* dblist;
|
||||
if((dblist = getDB(idx)))
|
||||
if(dblist->maxsz<blocksz)
|
||||
dblist->maxsz = blocksz;
|
||||
}
|
||||
}
|
||||
lockDB();
|
||||
protectDBnolock((uintptr_t)block->x64_addr, block->x64_size);
|
||||
// fill-in jumptable
|
||||
addJumpTableIfDefault64(block->x64_addr, block->block);
|
||||
for(int i=0; i<block->sons_size; ++i) {
|
||||
addJumpTableIfDefault64(block->sons[i]->x64_addr, block->sons[i]->block);
|
||||
block->sons[i]->done = 1;
|
||||
}
|
||||
block->done = 1;
|
||||
unlockDB();
|
||||
}
|
||||
|
||||
dynarec_log(LOG_DEBUG, " --- DynaRec Block %s @%p:%p (%p, 0x%x bytes, with %d son(s))\n", created?"created":"recycled", (void*)addr, (void*)(addr+((block)?block->x64_size:0)), (block)?block->block:0, (block)?block->size:0, (block)?block->sons_size:0);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, dynablock_t** current)
|
||||
{
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, *current);
|
||||
if(db && db->done && db->block && (db->need_test || (db->father && db->father->need_test))) {
|
||||
dynablock_t *father = db->father?db->father:db;
|
||||
uint32_t hash = X31_hash_code(father->x64_addr, father->x64_size);
|
||||
if(hash!=father->hash) {
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x64_addr, father->x64_addr+father->x64_size, hash, father->hash, father->sons_size, (void*)addr);
|
||||
// no more current if it gets invalidated too
|
||||
if(*current && father->x64_addr>=(*current)->x64_addr && (father->x64_addr+father->x64_size)<(*current)->x64_addr)
|
||||
*current = NULL;
|
||||
// Free father, it's now invalid!
|
||||
FreeDynablock(father);
|
||||
// start again... (will create a new block)
|
||||
db = internalDBGetBlock(emu, addr, addr, create, *current);
|
||||
} else {
|
||||
father->need_test = 0;
|
||||
lockDB();
|
||||
protectDBnolock((uintptr_t)father->x64_addr, father->x64_size);
|
||||
// fill back jumptable
|
||||
addJumpTableIfDefault64(father->x64_addr, father->block);
|
||||
for(int i=0; i<father->sons_size; ++i)
|
||||
addJumpTableIfDefault64(father->sons[i]->x64_addr, father->sons[i]->block);
|
||||
unlockDB();
|
||||
}
|
||||
}
|
||||
return db;
|
||||
}
|
||||
|
||||
dynablock_t* DBAlternateBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "Creating AlternateBlock at %p for %p\n", (void*)addr, (void*)filladdr);
|
||||
int create = 1;
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, NULL);
|
||||
if(db && db->done && db->block && (db->need_test || (db->father && db->father->need_test))) {
|
||||
dynablock_t *father = db->father?db->father:db;
|
||||
uint32_t hash = X31_hash_code(father->x64_addr, father->x64_size);
|
||||
if(hash!=father->hash) {
|
||||
dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x64_addr, father->x64_addr+father->x64_size, hash, father->hash, father->sons_size, (void*)addr);
|
||||
// Free father, it's now invalid!
|
||||
FreeDynablock(father);
|
||||
// start again... (will create a new block)
|
||||
db = internalDBGetBlock(emu, addr, filladdr, create, NULL);
|
||||
} else {
|
||||
father->need_test = 0;
|
||||
lockDB();
|
||||
protectDBnolock((uintptr_t)father->x64_addr, father->x64_size);
|
||||
// fill back jumptable
|
||||
addJumpTableIfDefault64(father->x64_addr, father->block);
|
||||
for(int i=0; i<father->sons_size; ++i)
|
||||
addJumpTableIfDefault64(father->sons[i]->x64_addr, father->sons[i]->block);
|
||||
unlockDB();
|
||||
}
|
||||
}
|
||||
return db;
|
||||
}
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
#ifndef __DYNABLOCK_PRIVATE_H_
|
||||
#define __DYNABLOCK_PRIVATE_H_
|
||||
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
|
||||
typedef struct instsize_s {
|
||||
unsigned int x64:4;
|
||||
unsigned int nat:4;
|
||||
} instsize_t;
|
||||
|
||||
typedef struct dynablock_s {
|
||||
dynablocklist_t* parent;
|
||||
void* block;
|
||||
int size;
|
||||
void* x64_addr;
|
||||
uintptr_t x64_size;
|
||||
uint32_t hash;
|
||||
uint8_t need_test;
|
||||
uint8_t done;
|
||||
uint8_t gone;
|
||||
uint8_t dummy;
|
||||
int isize;
|
||||
dynablock_t** sons; // sons (kind-of dummy dynablock...)
|
||||
int sons_size;
|
||||
dynablock_t* father; // set only in the case of a son
|
||||
instsize_t* instsize;
|
||||
} dynablock_t;
|
||||
|
||||
typedef struct dynablocklist_s {
|
||||
uintptr_t text;
|
||||
int textsz;
|
||||
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_
|
||||
+36
-28
@@ -22,24 +22,22 @@
|
||||
#endif
|
||||
|
||||
#ifdef DYNAREC
|
||||
#ifdef ARM
|
||||
void arm_prolog(x64emu_t* emu, void* addr) EXPORTDYN;
|
||||
void arm_epilog() EXPORTDYN;
|
||||
void arm_epilog_fast() EXPORTDYN;
|
||||
#ifdef ARM64
|
||||
void arm64_prolog(x64emu_t* emu, void* addr) EXPORTDYN;
|
||||
void arm64_epilog() EXPORTDYN;
|
||||
void arm64_epilog_fast() EXPORTDYN;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef DYNAREC
|
||||
#ifdef HAVE_TRACE
|
||||
uintptr_t getX64Address(dynablock_t* db, uintptr_t arm_addr);
|
||||
#endif
|
||||
|
||||
void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2)
|
||||
{
|
||||
#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);
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
|
||||
printf_log(LOG_NONE, "Warning, jumping to NULL address from %p (db=%p, x64addr=%p)\n", x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL);
|
||||
}
|
||||
#endif
|
||||
dynablock_t* current = NULL;
|
||||
@@ -47,23 +45,30 @@ void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2)
|
||||
dynablock_t* block = DBGetBlock(emu, addr, 1, ¤t);
|
||||
if(!block) {
|
||||
// no block, let link table as is...
|
||||
//tableupdate(arm_epilog, addr, table);
|
||||
return arm_epilog;
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
|
||||
printf_log(LOG_NONE, "Warning, jumping to a no-block address %p from %p (db=%p, x64addr=%p)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL);
|
||||
//tableupdate(arm64_epilog, addr, table);
|
||||
return arm64_epilog;
|
||||
}
|
||||
if(!block->done) {
|
||||
// not finished yet... leave linker
|
||||
//tableupdate(arm_linker, addr, table);
|
||||
return arm_epilog;
|
||||
return arm64_epilog;
|
||||
}
|
||||
if(!(jblock=block->block)) {
|
||||
// null block, but done: go to epilog, no linker here
|
||||
return arm_epilog;
|
||||
return arm64_epilog;
|
||||
}
|
||||
//dynablock_t *father = block->father?block->father:block;
|
||||
return jblock;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
// Disable "clobbered" warnings
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wclobbered"
|
||||
#endif
|
||||
void DynaCall(x64emu_t* emu, uintptr_t addr)
|
||||
{
|
||||
// prepare setjump for signal handling
|
||||
@@ -75,14 +80,14 @@ void DynaCall(x64emu_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 DynaCall, fs=0x%x\n", ejb->emu->segs[_FS]);
|
||||
addr = R_RIP; // not sure if it should still be inside DynaCall!
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef DYNAREC
|
||||
if(!box86_dynarec)
|
||||
if(!box64_dynarec)
|
||||
#endif
|
||||
EmuCall(emu, addr);
|
||||
#ifdef DYNAREC
|
||||
@@ -107,24 +112,24 @@ void DynaCall(x64emu_t* emu, uintptr_t addr)
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling Interpretor @%p, emu=%p\n", GetTID(), (void*)R_RIP, emu);
|
||||
Run(emu, 1);
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling DynaRec Block @%p (%p) of %d x86 instructions (father=%p) emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize ,block->father, emu);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling DynaRec Block @%p (%p) of %d x64 instructions (father=%p) emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize ,block->father, emu);
|
||||
CHECK_FLAGS(emu);
|
||||
// block is here, let's run it!
|
||||
#ifdef ARM
|
||||
arm_prolog(emu, block->block);
|
||||
#ifdef ARM64
|
||||
arm64_prolog(emu, block->block);
|
||||
#endif
|
||||
}
|
||||
if(emu->fork) {
|
||||
int forktype = emu->fork;
|
||||
emu->quit = 0;
|
||||
emu->fork = 0;
|
||||
emu = x86emu_fork(emu, forktype);
|
||||
emu = x64emu_fork(emu, forktype);
|
||||
if(emu->type == EMUTYPE_MAIN) {
|
||||
ejb = GetJmpBuf();
|
||||
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_RIP;
|
||||
}
|
||||
@@ -165,12 +170,12 @@ int DynaRun(x64emu_t* emu)
|
||||
#ifdef DYNAREC
|
||||
jmpbuf_reset = 1;
|
||||
#endif
|
||||
if(setjmp((struct __jmp_buf_tag*)ejb->jmpbuf))
|
||||
if(sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))
|
||||
printf_log(LOG_DEBUG, "Setjmp DynaRun, fs=0x%x\n", ejb->emu->segs[_FS]);
|
||||
}
|
||||
}
|
||||
#ifdef DYNAREC
|
||||
if(!box86_dynarec)
|
||||
if(!box64_dynarec)
|
||||
#endif
|
||||
return Run(emu, 0);
|
||||
#ifdef DYNAREC
|
||||
@@ -186,23 +191,23 @@ int DynaRun(x64emu_t* emu)
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running Interpretor @%p, emu=%p\n", GetTID(), (void*)R_RIP, emu);
|
||||
Run(emu, 1);
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x86 insts (father=%p) emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize, block->father, emu);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x64 insts (father=%p) emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize, block->father, emu);
|
||||
// block is here, let's run it!
|
||||
#ifdef ARM
|
||||
arm_prolog(emu, block->block);
|
||||
#ifdef ARM64
|
||||
arm64_prolog(emu, block->block);
|
||||
#endif
|
||||
}
|
||||
if(emu->fork) {
|
||||
int forktype = emu->fork;
|
||||
emu->quit = 0;
|
||||
emu->fork = 0;
|
||||
emu = x86emu_fork(emu, forktype);
|
||||
emu = x64emu_fork(emu, forktype);
|
||||
if(emu->type == EMUTYPE_MAIN) {
|
||||
ejb = GetJmpBuf();
|
||||
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]);
|
||||
}
|
||||
}
|
||||
@@ -213,4 +218,7 @@ int DynaRun(x64emu_t* emu)
|
||||
ejb->jmpbuf_ok = 0;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
Executable
+494
@@ -0,0 +1,494 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "custommem.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "tools/bridge_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynablock.h"
|
||||
#include "dynablock_private.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "elfloader.h"
|
||||
|
||||
void printf_x64_instruction(zydis_dec_t* dec, instruction_x64_t* inst, const char* name) {
|
||||
uint8_t *ip = (uint8_t*)inst->addr;
|
||||
if(ip[0]==0xcc && ip[1]=='S' && ip[2]=='C') {
|
||||
uintptr_t a = *(uintptr_t*)(ip+3);
|
||||
if(a==0) {
|
||||
dynarec_log(LOG_NONE, "%s%p: Exit x64emu%s\n", (box64_dynarec_dump>1)?"\e[1m":"", (void*)ip, (box64_dynarec_dump>1)?"\e[m":"");
|
||||
} else {
|
||||
dynarec_log(LOG_NONE, "%s%p: Native call to %p%s\n", (box64_dynarec_dump>1)?"\e[1m":"", (void*)ip, (void*)a, (box64_dynarec_dump>1)?"\e[m":"");
|
||||
}
|
||||
} else {
|
||||
if(dec) {
|
||||
dynarec_log(LOG_NONE, "%s%p: %s", (box64_dynarec_dump>1)?"\e[1m":"", ip, DecodeX64Trace(dec, inst->addr));
|
||||
} else {
|
||||
dynarec_log(LOG_NONE, "%s%p: ", (box64_dynarec_dump>1)?"\e[1m":"", ip);
|
||||
for(int i=0; i<inst->size; ++i) {
|
||||
dynarec_log(LOG_NONE, "%02X ", ip[i]);
|
||||
}
|
||||
dynarec_log(LOG_NONE, " %s", name);
|
||||
}
|
||||
// print Call function name if possible
|
||||
if(ip[0]==0xE8 || ip[0]==0xE9) { // Call / Jmp
|
||||
uintptr_t nextaddr = (uintptr_t)ip + 5 + *((int32_t*)(ip+1));
|
||||
printFunctionAddr(nextaddr, "=> ");
|
||||
} else if(ip[0]==0xFF) {
|
||||
if(ip[1]==0x25) {
|
||||
uintptr_t nextaddr = (uintptr_t)ip + 6 + *((int32_t*)(ip+2));
|
||||
printFunctionAddr(nextaddr, "=> ");
|
||||
}
|
||||
}
|
||||
// end of line and colors
|
||||
dynarec_log(LOG_NONE, "%s\n", (box64_dynarec_dump>1)?"\e[m":"");
|
||||
}
|
||||
}
|
||||
|
||||
void add_next(dynarec_arm_t *dyn, uintptr_t addr) {
|
||||
if(dyn->next_sz == dyn->next_cap) {
|
||||
dyn->next_cap += 16;
|
||||
dyn->next = (uintptr_t*)realloc(dyn->next, dyn->next_cap*sizeof(uintptr_t));
|
||||
}
|
||||
for(int i=0; i<dyn->next_sz; ++i)
|
||||
if(dyn->next[i]==addr)
|
||||
return;
|
||||
dyn->next[dyn->next_sz++] = addr;
|
||||
}
|
||||
uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr) {
|
||||
// get closest, but no addresses befores
|
||||
uintptr_t best = 0;
|
||||
int i = 0;
|
||||
while((i<dyn->next_sz) && (best!=addr)) {
|
||||
if(dyn->next[i]<addr) { // remove the address, it's before current address
|
||||
memmove(dyn->next+i, dyn->next+i+1, (dyn->next_sz-i-1)*sizeof(uintptr_t));
|
||||
--dyn->next_sz;
|
||||
} else {
|
||||
if((dyn->next[i]<best) || !best)
|
||||
best = dyn->next[i];
|
||||
++i;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
#define PK(A) (*((uint8_t*)(addr+(A))))
|
||||
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n)
|
||||
{
|
||||
if(!n)
|
||||
return 1;
|
||||
if(PK(0)==0x90)
|
||||
return is_nops(dyn, addr+1, n-1);
|
||||
if(n>1 && PK(0)==0x66) // if opcode start with 0x66, and there is more after, than is *can* be a NOP
|
||||
return is_nops(dyn, addr+1, n-1);
|
||||
if(n>2 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x00)
|
||||
return is_nops(dyn, addr+3, n-3);
|
||||
if(n>2 && PK(0)==0x8d && PK(1)==0x76 && PK(2)==0x00) // lea esi, [esi]
|
||||
return is_nops(dyn, addr+3, n-3);
|
||||
if(n>3 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x40 && PK(3)==0x00)
|
||||
return is_nops(dyn, addr+4, n-4);
|
||||
if(n>3 && PK(0)==0x8d && PK(1)==0x74 && PK(2)==0x26 && PK(3)==0x00)
|
||||
return is_nops(dyn, addr+4, n-4);
|
||||
if(n>4 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x44 && PK(3)==0x00 && PK(4)==0x00)
|
||||
return is_nops(dyn, addr+5, n-5);
|
||||
if(n>5 && PK(0)==0x8d && PK(1)==0xb6 && PK(2)==0x00 && PK(3)==0x00 && PK(4)==0x00 && PK(5)==0x00)
|
||||
return is_nops(dyn, addr+6, n-6);
|
||||
if(n>6 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x80 && PK(3)==0x00 && PK(4)==0x00 && PK(5)==0x00 && PK(6)==0x00)
|
||||
return is_nops(dyn, addr+7, n-7);
|
||||
if(n>6 && PK(0)==0x8d && PK(1)==0xb4 && PK(2)==0x26 && PK(3)==0x00 && PK(4)==0x00 && PK(5)==0x00 && PK(6)==0x00) // lea esi, [esi+0]
|
||||
return is_nops(dyn, addr+7, n-7);
|
||||
if(n>7 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x84 && PK(3)==0x00 && PK(4)==0x00 && PK(5)==0x00 && PK(6)==0x00 && PK(7)==0x00)
|
||||
return is_nops(dyn, addr+8, n-8);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
if(recurse == 10)
|
||||
return X_PEND;
|
||||
if(ninst == dyn->size)
|
||||
return X_PEND; // no more instructions, or too many jmp loop, stop
|
||||
|
||||
uint32_t needed = dyn->insts[ninst].x64.use_flags;
|
||||
if(needed) {
|
||||
setf &= ~needed;
|
||||
if(!setf) // all flags already used, no need to continue
|
||||
return needed;
|
||||
}
|
||||
|
||||
if(!needed && !dyn->insts[ninst].x64.set_flags && !dyn->insts[ninst].x64.jmp_insts) {
|
||||
int start = ninst;
|
||||
int end = ninst;
|
||||
while(end<dyn->size && !dyn->insts[end].x64.use_flags && !dyn->insts[end].x64.set_flags && !dyn->insts[end].x64.jmp_insts)
|
||||
++end;
|
||||
needed = needed_flags(dyn, end, setf, recurse);
|
||||
for(int i=start; i<end; ++i)
|
||||
dyn->insts[i].x64.need_flags = needed;
|
||||
return needed;
|
||||
}
|
||||
|
||||
if(dyn->insts[ninst].x64.set_flags && (dyn->insts[ninst].x64.state_flags!=SF_MAYSET)) {
|
||||
if((setf & ~dyn->insts[ninst].x64.set_flags) == 0)
|
||||
return needed; // all done, gives all the flags needed
|
||||
setf |= dyn->insts[ninst].x64.set_flags; // add new flags to continue
|
||||
}
|
||||
|
||||
int jinst = dyn->insts[ninst].x64.jmp_insts;
|
||||
if(dyn->insts[ninst].x64.jmp) {
|
||||
dyn->insts[ninst].x64.need_flags = (jinst==-1)?X_PEND:needed_flags(dyn, jinst, setf, recurse+1);
|
||||
if(dyn->insts[ninst].x64.use_flags) // conditionnal jump
|
||||
dyn->insts[ninst].x64.need_flags |= needed_flags(dyn, ninst+1, setf, recurse);
|
||||
} else
|
||||
dyn->insts[ninst].x64.need_flags = needed_flags(dyn, ninst+1, setf, recurse);
|
||||
if(dyn->insts[ninst].x64.state_flags==SF_MAYSET)
|
||||
needed |= dyn->insts[ninst].x64.need_flags;
|
||||
else
|
||||
needed |= (dyn->insts[ninst].x64.need_flags & ~dyn->insts[ninst].x64.set_flags);
|
||||
if(needed == (X_PEND|X_ALL))
|
||||
needed = X_ALL;
|
||||
return needed;
|
||||
}
|
||||
|
||||
instsize_t* addInst(instsize_t* insts, size_t* size, size_t* cap, int x64_size, int arm_size)
|
||||
{
|
||||
// x64 instruction is <16 bytes
|
||||
int toadd;
|
||||
if(x64_size>arm_size)
|
||||
toadd = 1 + x64_size/15;
|
||||
else
|
||||
toadd = 1 + arm_size/15;
|
||||
if((*size)+toadd>(*cap)) {
|
||||
*cap = (*size)+toadd;
|
||||
insts = (instsize_t*)realloc(insts, (*cap)*sizeof(instsize_t));
|
||||
}
|
||||
while(toadd) {
|
||||
if(x64_size>15)
|
||||
insts[*size].x64 = 15;
|
||||
else
|
||||
insts[*size].x64 = x64_size;
|
||||
x64_size -= insts[*size].x64;
|
||||
if(arm_size>15)
|
||||
insts[*size].nat = 15;
|
||||
else
|
||||
insts[*size].nat = arm_size;
|
||||
arm_size -= insts[*size].nat;
|
||||
++(*size);
|
||||
--toadd;
|
||||
}
|
||||
return insts;
|
||||
}
|
||||
|
||||
// add a value to table64 (if needed) and gives back the imm19 to use in LDR_literal
|
||||
int Table64(dynarec_arm_t *dyn, uint64_t val)
|
||||
{
|
||||
// find the value if already present
|
||||
int idx = -1;
|
||||
for(int i=0; i<dyn->table64size && (idx==-1); ++i)
|
||||
if(dyn->table64[i] == val)
|
||||
idx = i;
|
||||
// not found, add it
|
||||
if(idx==-1) {
|
||||
if(dyn->table64size == dyn->table64cap) {
|
||||
dyn->table64cap+=4;
|
||||
dyn->table64 = (uint64_t*)realloc(dyn->table64, dyn->table64cap * sizeof(uint64_t));
|
||||
}
|
||||
idx = dyn->table64size++;
|
||||
dyn->table64[idx] = val;
|
||||
}
|
||||
// calculate offset
|
||||
int delta = dyn->tablestart + idx*sizeof(uint64_t) - (uintptr_t)dyn->block;
|
||||
return delta;
|
||||
}
|
||||
|
||||
|
||||
uintptr_t arm_pass0(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
uintptr_t arm_pass1(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
uintptr_t arm_pass2(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
uintptr_t arm_pass3(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
|
||||
void* FillBlock64(dynablock_t* block, uintptr_t addr) {
|
||||
if(addr>=box64_nodynarec_start && addr<box64_nodynarec_end) {
|
||||
block->done = 1;
|
||||
return (void*)block;
|
||||
}
|
||||
// init the helper
|
||||
dynarec_arm_t helper = {0};
|
||||
helper.start = 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;
|
||||
return (void*)block;
|
||||
}
|
||||
helper.cap = helper.size+3; // needs epilog handling
|
||||
helper.insts = (instruction_arm64_t*)calloc(helper.cap, sizeof(instruction_arm64_t));
|
||||
// already protect the block and compute hash signature
|
||||
protectDB(addr, end-addr); //end is 1byte after actual end
|
||||
uint32_t hash = X31_hash_code((void*)addr, end-addr);
|
||||
// pass 1, addresses, x64 jump addresses, flags
|
||||
arm_pass1(&helper, addr);
|
||||
// calculate barriers
|
||||
for(int i=0; i<helper.size; ++i)
|
||||
if(helper.insts[i].x64.jmp) {
|
||||
uintptr_t j = helper.insts[i].x64.jmp;
|
||||
if(j<start || j>=end)
|
||||
helper.insts[i].x64.jmp_insts = -1;
|
||||
else {
|
||||
// find jump address instruction
|
||||
int k=-1;
|
||||
for(int i2=0; i2<helper.size && k==-1; ++i2) {
|
||||
if(helper.insts[i2].x64.addr==j)
|
||||
k=i2;
|
||||
}
|
||||
if(k!=-1) // -1 if not found, mmm, probably wrong, exit anyway
|
||||
helper.insts[k].x64.barrier = 1;
|
||||
helper.insts[i].x64.jmp_insts = k;
|
||||
}
|
||||
}
|
||||
for(int i=0; i<helper.size; ++i)
|
||||
if(helper.insts[i].x64.set_flags && !helper.insts[i].x64.need_flags) {
|
||||
helper.insts[i].x64.need_flags = needed_flags(&helper, i+1, helper.insts[i].x64.set_flags, 0);
|
||||
if((helper.insts[i].x64.need_flags&X_PEND) && (helper.insts[i].x64.state_flags==SF_MAYSET))
|
||||
helper.insts[i].x64.need_flags = X_ALL;
|
||||
}
|
||||
|
||||
// pass 2, instruction size
|
||||
arm_pass2(&helper, addr);
|
||||
// ok, now allocate mapped memory, with executable flag on
|
||||
size_t sz = helper.arm_size + helper.table64size*sizeof(uint64_t);
|
||||
void* p = (void*)AllocDynarecMap(block, sz);
|
||||
if(p==NULL) {
|
||||
dynarec_log(LOG_DEBUG, "AllocDynarecMap(%p, %zu) failed, cancelling block\n", block, sz);
|
||||
free(helper.insts);
|
||||
free(helper.next);
|
||||
free(helper.table64);
|
||||
return NULL;
|
||||
}
|
||||
helper.block = p;
|
||||
helper.arm_start = (uintptr_t)p;
|
||||
helper.tablestart = helper.arm_start + helper.arm_size;
|
||||
if(helper.sons_size) {
|
||||
helper.sons_x64 = (uintptr_t*)calloc(helper.sons_size, sizeof(uintptr_t));
|
||||
helper.sons_arm = (void**)calloc(helper.sons_size, sizeof(void*));
|
||||
}
|
||||
// pass 3, emit (log emit arm opcode)
|
||||
if(box64_dynarec_dump) {
|
||||
dynarec_log(LOG_NONE, "%s%04d|Emitting %zu bytes for %u x64 bytes", (box64_dynarec_dump>1)?"\e[01;36m":"", GetTID(), helper.arm_size, helper.isize);
|
||||
printFunctionAddr(helper.start, " => ");
|
||||
dynarec_log(LOG_NONE, "%s\n", (box64_dynarec_dump>1)?"\e[m":"");
|
||||
}
|
||||
int oldtable64size = helper.table64size;
|
||||
size_t oldarmsize = helper.arm_size;
|
||||
helper.arm_size = 0;
|
||||
helper.table64size = 0; // reset table64 (but not the cap)
|
||||
arm_pass3(&helper, addr);
|
||||
if((oldarmsize!=helper.arm_size) || (oldtable64size<helper.table64size)) {
|
||||
printf_log(LOG_NONE, "BOX64: Warning, size difference in block between pass2 (%zu) & pass3 (%zu)!\n", sz, helper.arm_size+helper.table64size*8);
|
||||
uint8_t *dump = (uint8_t*)helper.start;
|
||||
printf_log(LOG_NONE, "Dump of %d x64 opcodes:\n", helper.size);
|
||||
for(int i=0; i<helper.size; ++i) {
|
||||
printf_log(LOG_NONE, "%p:", dump);
|
||||
for(; dump<(uint8_t*)helper.insts[i+1].x64.addr; ++dump)
|
||||
printf_log(LOG_NONE, " %02X", *dump);
|
||||
printf_log(LOG_NONE, "\t%d -> %d\n", helper.insts[i].size2, helper.insts[i].size);
|
||||
}
|
||||
printf_log(LOG_NONE, "Table64 \t%d -> %d\n", oldtable64size*8, helper.table64size*8);
|
||||
printf_log(LOG_NONE, " ------------\n");
|
||||
//TODO: Cancel block and return empty one
|
||||
}
|
||||
// add table64 if needed
|
||||
if(helper.table64size) {
|
||||
memcpy((void*)helper.tablestart, helper.table64, helper.table64size*8);
|
||||
}
|
||||
// all done...
|
||||
__clear_cache(p, p+sz); // need to clear the cache before execution...
|
||||
// keep size of instructions for signal handling
|
||||
{
|
||||
size_t cap = 1;
|
||||
for(int i=0; i<helper.size; ++i)
|
||||
cap += 1 + ((helper.insts[i].x64.size>helper.insts[i].size)?helper.insts[i].x64.size:helper.insts[i].size)/15;
|
||||
size_t size = 0;
|
||||
block->instsize = (instsize_t*)calloc(cap, sizeof(instsize_t));
|
||||
for(int i=0; i<helper.size; ++i)
|
||||
block->instsize = addInst(block->instsize, &size, &cap, helper.insts[i].x64.size, helper.insts[i].size/4);
|
||||
block->instsize = addInst(block->instsize, &size, &cap, 0, 0); // add a "end of block" mark, just in case
|
||||
}
|
||||
// ok, free the helper now
|
||||
free(helper.insts);
|
||||
free(helper.next);
|
||||
free(helper.table64);
|
||||
block->size = sz;
|
||||
block->isize = helper.size;
|
||||
block->block = p;
|
||||
block->need_test = 0;
|
||||
//block->x64_addr = (void*)start;
|
||||
block->x64_size = end-start;
|
||||
block->hash = X31_hash_code(block->x64_addr, block->x64_size);
|
||||
// Check if something changed, to abbort if it as
|
||||
if(block->hash != hash) {
|
||||
dynarec_log(LOG_INFO, "Warning, a block changed while beeing processed hash(%p:%ld)=%x/%x\n", block->x64_addr, block->x64_size, block->hash, hash);
|
||||
free(helper.sons_x64);
|
||||
free(helper.sons_arm);
|
||||
FreeDynarecMap(block, (uintptr_t)p, sz);
|
||||
return NULL;
|
||||
} // fill sons if any
|
||||
dynablock_t** sons = NULL;
|
||||
int sons_size = 0;
|
||||
if(helper.sons_size) {
|
||||
sons = (dynablock_t**)calloc(helper.sons_size, sizeof(dynablock_t*));
|
||||
for (int i=0; i<helper.sons_size; ++i) {
|
||||
int created = 1;
|
||||
dynablock_t *son = AddNewDynablock(block->parent, helper.sons_x64[i], &created);
|
||||
if(created) { // avoid breaking a working block!
|
||||
son->block = helper.sons_arm[i];
|
||||
son->x64_addr = (void*)helper.sons_x64[i];
|
||||
son->x64_size = end-helper.sons_x64[i];
|
||||
if(!son->x64_size) {printf_log(LOG_NONE, "Warning, son with null x64 size! (@%p / ARM=%p)", son->x64_addr, son->block);}
|
||||
son->father = block;
|
||||
son->size = sz + son->block - block->block; // update size count, for debugging
|
||||
//son->done = 1;
|
||||
if(!son->parent)
|
||||
son->parent = block->parent;
|
||||
sons[sons_size] = son;
|
||||
++sons_size;
|
||||
}
|
||||
}
|
||||
if(sons_size) {
|
||||
block->sons = sons;
|
||||
block->sons_size = sons_size;
|
||||
} else
|
||||
free(sons);
|
||||
}
|
||||
free(helper.sons_x64);
|
||||
free(helper.sons_arm);
|
||||
//block->done = 1;
|
||||
return (void*)block;
|
||||
}
|
||||
Executable
+2360
File diff suppressed because it is too large.
Load diff
Executable
+1818
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,395 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
#define GETG gd = ((nextop&0x38)>>3)+(rex.r<<3)
|
||||
|
||||
uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int seg, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)rep; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
uint8_t u8;
|
||||
uint8_t gd, ed, eb1, eb2;
|
||||
uint8_t wback, wb1, wb2;
|
||||
int64_t i64, j64;
|
||||
int v0;
|
||||
int q0;
|
||||
int d0;
|
||||
int64_t fixedaddress;
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(v0);
|
||||
|
||||
while((opcode==0xF2) || (opcode==0xF3)) {
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
// REX prefix before the F0 are ignored
|
||||
rex.rex = 0;
|
||||
while(opcode>=0x40 && opcode<=0x4f) {
|
||||
rex.rex = opcode;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x03:
|
||||
INST_NAME("ADD Gd, Seg:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x4, 0);
|
||||
emit_add32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
break;
|
||||
|
||||
case 0x0F:
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
|
||||
case 0x10:
|
||||
switch(rep) {
|
||||
case 1:
|
||||
INST_NAME("MOVSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+ (rex.b<<3);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
d0 = sse_get_reg(dyn, ninst, x1, ed);
|
||||
VMOVeD(v0, 0, d0, 0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
ADDx_REG(x4, x4, ed);
|
||||
VLDR64_U12(v0, x4, fixedaddress); // upper part reseted
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("MOVSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
VMOVeS(v0, 0, q0, 0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
ADDx_REG(x4, x4, ed);
|
||||
VLDR32_U12(v0, x4, fixedaddress);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
switch(rep) {
|
||||
case 1:
|
||||
INST_NAME("MOVSD Ex, Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+ (rex.b<<3);
|
||||
d0 = sse_get_reg(dyn, ninst, x1, ed);
|
||||
VMOVeD(d0, 0, v0, 0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
ADDx_REG(x4, x4, ed);
|
||||
VSTR64_U12(v0, x4, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("MOVSS Ex, Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
if(MODREG) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
VMOVeS(q0, 0, v0, 0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
ADDx_REG(x4, x4, ed);
|
||||
VSTR32_U12(v0, x4, fixedaddress);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x33:
|
||||
INST_NAME("XOR Gd, Seg:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x4, 0);
|
||||
emit_xor32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
break;
|
||||
|
||||
case 0x80:
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: //ADD
|
||||
INST_NAME("ADD Eb, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_add8c(dyn, ninst, x1, u8, x2, x4);
|
||||
EBBACK;
|
||||
break;
|
||||
case 1: //OR
|
||||
INST_NAME("OR Eb, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_or8c(dyn, ninst, x1, u8, x2, x4);
|
||||
EBBACK;
|
||||
break;
|
||||
case 2: //ADC
|
||||
INST_NAME("ADC Eb, Ib");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_adc8c(dyn, ninst, x1, u8, x2, x4, x5);
|
||||
EBBACK;
|
||||
break;
|
||||
case 3: //SBB
|
||||
INST_NAME("SBB Eb, Ib");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_sbb8c(dyn, ninst, x1, u8, x2, x4, x5);
|
||||
EBBACK;
|
||||
break;
|
||||
case 4: //AND
|
||||
INST_NAME("AND Eb, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_and8c(dyn, ninst, x1, u8, x2, x4);
|
||||
EBBACK;
|
||||
break;
|
||||
case 5: //SUB
|
||||
INST_NAME("SUB Eb, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_sub8c(dyn, ninst, x1, u8, x2, x4, x5);
|
||||
EBBACK;
|
||||
break;
|
||||
case 6: //XOR
|
||||
INST_NAME("XOR Eb, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_xor8c(dyn, ninst, x1, u8, x2, x4);
|
||||
EBBACK;
|
||||
break;
|
||||
case 7: //CMP
|
||||
INST_NAME("CMP Eb, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
if(u8) {
|
||||
MOV32w(x2, u8);
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
} else {
|
||||
emit_cmp8_0(dyn, ninst, x1, x3, x4);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x6, seg);
|
||||
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_PENDING);
|
||||
GETEDO(x6, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_add32c(dyn, ninst, rex, ed, i64, x3, x4, x5);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 1: //OR
|
||||
if(opcode==0x81) {INST_NAME("OR Ed, Id");} else {INST_NAME("OR Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEDO(x6, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_or32c(dyn, ninst, rex, ed, i64, x3, x4);
|
||||
WBACKO(x6);
|
||||
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_PENDING);
|
||||
GETEDO(x6, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
emit_adc32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
WBACKO(x6);
|
||||
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_PENDING);
|
||||
GETEDO(x6, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
emit_sbb32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 4: //AND
|
||||
if(opcode==0x81) {INST_NAME("AND Ed, Id");} else {INST_NAME("AND Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEDO(x6, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_and32c(dyn, ninst, rex, ed, i64, x3, x4);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 5: //SUB
|
||||
if(opcode==0x81) {INST_NAME("SUB Ed, Id");} else {INST_NAME("SUB Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEDO(x6, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_sub32c(dyn, ninst, rex, ed, i64, x3, x4, x5);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 6: //XOR
|
||||
if(opcode==0x81) {INST_NAME("XOR Ed, Id");} else {INST_NAME("XOR Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEDO(x6, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_xor32c(dyn, ninst, rex, ed, i64, x3, x4);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 7: //CMP
|
||||
if(opcode==0x81) {INST_NAME("CMP Ed, Id");} else {INST_NAME("CMP Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEDO(x6, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
if(i64) {
|
||||
MOV64xw(x2, i64);
|
||||
emit_cmp32(dyn, ninst, rex, ed, x2, x3, x4, x5);
|
||||
} else
|
||||
emit_cmp32_0(dyn, ninst, rex, ed, x3, x4);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x89:
|
||||
INST_NAME("MOV Seg:Ed, Gd");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg
|
||||
MOVxw_REG(xRAX+(nextop&7)+(rex.b<<3), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
STRxw_REG(gd, ed, x4);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, Seg:Ed");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg
|
||||
MOVxw_REG(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
LDRxw_REG(gd, ed, x4);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC6:
|
||||
INST_NAME("MOV Seg:Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop=F8;
|
||||
if(MODREG) { // reg <= u8
|
||||
u8 = F8;
|
||||
if(!rex.rex) {
|
||||
ed = (nextop&7);
|
||||
eb1 = xRAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
} else {
|
||||
eb1 = xRAX+(nextop&7)+(rex.b<<3);
|
||||
eb2 = 0;
|
||||
}
|
||||
MOV32w(x3, u8);
|
||||
BFIx(eb1, x3, eb2*8, 8);
|
||||
} else { // mem <= u8
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x3, u8);
|
||||
STRB_REG(x3, ed, x4);
|
||||
}
|
||||
break;
|
||||
case 0xC7:
|
||||
INST_NAME("MOV Seg:Ed, Id");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop=F8;
|
||||
if(MODREG) { // reg <= i32
|
||||
i64 = F32S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV64xw(ed, i64);
|
||||
} else { // mem <= i32
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 4);
|
||||
i64 = F32S;
|
||||
MOV64xw(x3, i64);
|
||||
STRxw_REG(x3, ed, x4);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
Executable
+850
@@ -0,0 +1,850 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
int16_t i16;
|
||||
uint16_t u16;
|
||||
uint64_t u64;
|
||||
int32_t i32;
|
||||
int64_t j64;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1;
|
||||
int64_t fixedaddress;
|
||||
MAYUSE(u8);
|
||||
MAYUSE(u16);
|
||||
MAYUSE(u64);
|
||||
MAYUSE(j64);
|
||||
|
||||
while((opcode==0x2E) || (opcode==0x66)) // ignoring CS: or multiple 0x66
|
||||
opcode = F8;
|
||||
|
||||
while((opcode==0xF2) || (opcode==0xF3)) {
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
// REX prefix before the F0 are ignored
|
||||
rex.rex = 0;
|
||||
while(opcode>=0x40 && opcode<=0x4f) {
|
||||
rex.rex = opcode;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
if(rex.w && opcode!=0x0f) // rex.w cancels "66", but not for 66 0f type of prefix
|
||||
return dynarec64_00(dyn, addr-2, ip, ninst, rex, rep, ok, need_epilog);
|
||||
|
||||
switch(opcode) {
|
||||
case 0x01:
|
||||
INST_NAME("ADD Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_add16(dyn, ninst, x1, x2, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x03:
|
||||
INST_NAME("ADD Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_add16(dyn, ninst, x1, x2, x3, x4);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x05:
|
||||
INST_NAME("ADD AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_add16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x09:
|
||||
INST_NAME("OR Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_or16(dyn, ninst, x1, x2, x4, x2);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x0B:
|
||||
INST_NAME("OR Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_or16(dyn, ninst, x1, x2, x4, x3);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x0D:
|
||||
INST_NAME("OR AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_or16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x0F:
|
||||
addr = dynarec64_660F(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("ADC Ew, Gw");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_adc16(dyn, ninst, x1, x2, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x13:
|
||||
INST_NAME("ADC Gw, Ew");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_adc16(dyn, ninst, x1, x2, x4, x3);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x15:
|
||||
INST_NAME("ADC AX, Iw");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_adc16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x19:
|
||||
INST_NAME("SBB Ew, Gw");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_sbb16(dyn, ninst, x1, x2, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x1B:
|
||||
INST_NAME("SBB Gw, Ew");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_sbb16(dyn, ninst, x1, x2, x4, x3);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x1D:
|
||||
INST_NAME("SBB AX, Iw");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i16 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i16);
|
||||
emit_sbb16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x21:
|
||||
INST_NAME("AND Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_and16(dyn, ninst, x1, x2, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x23:
|
||||
INST_NAME("AND Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_and16(dyn, ninst, x1, x2, x3, x4);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x25:
|
||||
INST_NAME("AND AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_and16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x29:
|
||||
INST_NAME("SUB Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_sub16(dyn, ninst, x1, x2, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x2B:
|
||||
INST_NAME("SUB Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_sub16(dyn, ninst, x1, x2, x3, x4);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("SUB AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_sub16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x31:
|
||||
INST_NAME("XOR Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_xor16(dyn, ninst, x1, x2, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x33:
|
||||
INST_NAME("XOR Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_xor16(dyn, ninst, x1, x2, x3, x4);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x35:
|
||||
INST_NAME("XOR AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_xor16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x39:
|
||||
INST_NAME("CMP Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
case 0x3B:
|
||||
INST_NAME("CMP Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
case 0x3D:
|
||||
INST_NAME("CMP AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
if(i32) {
|
||||
MOV32w(x2, i32);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
} else {
|
||||
emit_cmp16_0(dyn, ninst, x1, x3, x4);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x64:
|
||||
addr = dynarec64_6664(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
break;
|
||||
|
||||
case 0x66:
|
||||
addr = dynarec64_66(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
break;
|
||||
|
||||
case 0x69:
|
||||
INST_NAME("IMUL Gw,Ew,Iw");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
nextop = F8;
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
GETSEW(x1, 2);
|
||||
i32 = F16S;
|
||||
MOV32w(x2, i32);
|
||||
MULw(x2, x2, x1);
|
||||
UFLAG_RES(x2);
|
||||
gd=x2;
|
||||
GWBACK;
|
||||
break;
|
||||
|
||||
case 0x6B:
|
||||
INST_NAME("IMUL Gw,Ew,Ib");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
nextop = F8;
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
GETSEW(x1, 1);
|
||||
i32 = F8S;
|
||||
MOV32w(x2, i32);
|
||||
MULw(x2, x2, x1);
|
||||
UFLAG_RES(x2);
|
||||
gd=x2;
|
||||
GWBACK;
|
||||
break;
|
||||
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: //ADD
|
||||
if(opcode==0x81) {
|
||||
INST_NAME("ADD Ew, Iw");
|
||||
} else {
|
||||
INST_NAME("ADD Ew, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
emit_add16(dyn, ninst, ed, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1: //OR
|
||||
if(opcode==0x81) {INST_NAME("OR Ew, Iw");} else {INST_NAME("OR Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
emit_or16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 2: //ADC
|
||||
if(opcode==0x81) {INST_NAME("ADC Ew, Iw");} else {INST_NAME("ADC Ew, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
emit_adc16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 3: //SBB
|
||||
if(opcode==0x81) {INST_NAME("SBB Ew, Iw");} else {INST_NAME("SBB Ew, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
emit_sbb16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 4: //AND
|
||||
if(opcode==0x81) {INST_NAME("AND Ew, Iw");} else {INST_NAME("AND Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
emit_and16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 5: //SUB
|
||||
if(opcode==0x81) {INST_NAME("SUB Ew, Iw");} else {INST_NAME("SUB Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
emit_sub16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 6: //XOR
|
||||
if(opcode==0x81) {INST_NAME("XOR Ew, Iw");} else {INST_NAME("XOR Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
emit_xor16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 7: //CMP
|
||||
if(opcode==0x81) {INST_NAME("CMP Ew, Iw");} else {INST_NAME("CMP Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
if(i16) {
|
||||
MOV32w(x2, i16);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
} else
|
||||
emit_cmp16_0(dyn, ninst, x1, x3, x4);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x85:
|
||||
INST_NAME("TEST Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEW(x1, 0);
|
||||
GETGW(x2);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
|
||||
case 0x89:
|
||||
INST_NAME("MOV Ew, Gw");
|
||||
nextop = F8;
|
||||
GETGD; // don't need GETGW here
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
if(ed!=gd) {
|
||||
BFIx(ed, gd, 0, 16);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
STRH_U12(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gw, Ew");
|
||||
nextop = F8;
|
||||
GETGD; // don't need GETGW neither
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
if(ed!=gd) {
|
||||
BFIx(gd, ed, 0, 16);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
LDRH_U12(x1, ed, fixedaddress);
|
||||
BFIx(gd, x1, 0, 16);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x90:
|
||||
INST_NAME("NOP");
|
||||
break;
|
||||
|
||||
case 0xA1:
|
||||
INST_NAME("MOV EAX,Od");
|
||||
u64 = F64;
|
||||
MOV64x(x1, u64);
|
||||
LDRH_U12(x2, x1, 0);
|
||||
BFIx(xRAX, x2, 0, 16);
|
||||
break;
|
||||
|
||||
case 0xA3:
|
||||
INST_NAME("MOV Od,EAX");
|
||||
u64 = F64;
|
||||
MOV64x(x1, u64);
|
||||
STRH_U12(xRAX, x1, 0);
|
||||
break;
|
||||
|
||||
case 0xA5:
|
||||
if(rep) {
|
||||
INST_NAME("REP MOVSW");
|
||||
CBZx_NEXT(xRCX);
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
LDRH_S9_postindex(x1, xRSI, 2);
|
||||
STRH_S9_postindex(x1, xRDI, 2);
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CBNZx_MARK(xRCX);
|
||||
B_NEXT_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
LDRH_S9_postindex(x1, xRSI, -2);
|
||||
STRH_S9_postindex(x1, xRDI, -2);
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CBNZx_MARK2(xRCX);
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("MOVSW");
|
||||
GETDIR(x3, 2);
|
||||
LDRH_U12(x1, xRSI, 0);
|
||||
STRH_U12(x1, xRDI, 0);
|
||||
ADDx_REG(xRSI, xRSI, x3);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA9:
|
||||
INST_NAME("TEST AX,Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u16 = F16;
|
||||
MOV32w(x2, u16);
|
||||
UBFXx(x1, xRAX, 0, 16);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
|
||||
case 0xAB:
|
||||
if(rep) {
|
||||
INST_NAME("REP STOSW");
|
||||
CBZx_NEXT(xRCX);
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
STRH_S9_postindex(xRAX, xRDI, 2);
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CBNZx_MARK(xRCX);
|
||||
B_NEXT_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
STRH_S9_postindex(xRAX, xRDI, -2);
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CBNZx_MARK2(xRCX);
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("STOSW");
|
||||
GETDIR(x3, 2);
|
||||
STRH_U12(xRAX, xRDI, 0);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xB8:
|
||||
case 0xB9:
|
||||
case 0xBA:
|
||||
case 0xBB:
|
||||
case 0xBC:
|
||||
case 0xBD:
|
||||
case 0xBE:
|
||||
case 0xBF:
|
||||
INST_NAME("MOV Reg16, Iw");
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
gd = xRAX+(opcode&7)+(rex.b<<3);
|
||||
BFIx(gd, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0xC1:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ew, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(rol16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ew, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(ror16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Ew, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(rcl16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Ew, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(rcr16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
INST_NAME("SHL Ew, Ib");
|
||||
UFLAG_IF {MESSAGE(LOG_DUMP, "Need Optimization for flags\n");}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, (u8&0x1f));
|
||||
UFLAG_OP12(ed, x2)
|
||||
LSLw_IMM(ed, ed, u8&0x1f);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shl16);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("SHR Ed, Ib");
|
||||
UFLAG_IF {MESSAGE(LOG_DUMP, "Need Optimization for flags\n");}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, (u8&0x1f));
|
||||
UFLAG_OP12(ed, x2)
|
||||
LSRw_IMM(ed, ed, u8&0x1f);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shr16);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("SAR Ed, Ib");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
UFLAG_IF {MESSAGE(LOG_DUMP, "Need Optimization for flags\n");}
|
||||
GETSEW(x1, 0);
|
||||
u8 = F8;
|
||||
MOV32w(x2, (u8&0x1f));
|
||||
UFLAG_OP12(ed, x2)
|
||||
ASRw_REG(ed, ed, x2);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_sar16);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC7:
|
||||
INST_NAME("MOV Ew, Iw");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
BFIx(ed, x1, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<1, 1, rex, 0, 2);
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
STRH_U12(x1, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xD1:
|
||||
case 0xD3:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("ROL Ew, 1");
|
||||
MOV32w(x2, 1);
|
||||
} else {
|
||||
INST_NAME("ROL Ew, CL");
|
||||
ANDSw_mask(x2, xRCX, 0, 0b00100);
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEW(x1, 0);
|
||||
CALL_(rol16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("ROR Ew, 1");
|
||||
MOV32w(x2, 1);
|
||||
} else {
|
||||
INST_NAME("ROR Ew, CL");
|
||||
ANDSw_mask(x2, xRCX, 0, 0b00100);
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEW(x1, 0);
|
||||
CALL_(ror16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 2:
|
||||
if(opcode==0xD1) {INST_NAME("RCL Ew, 1"); } else { INST_NAME("RCL Ew, CL");}
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
if(opcode==0xD1) {MOV32w(x2, 1);} else {ANDSw_mask(x2, xRCX, 0, 0b00100);}
|
||||
GETEW(x1, 0);
|
||||
CALL_(rcl16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 3:
|
||||
if(opcode==0xD1) {INST_NAME("RCR Ew, 1");} else {INST_NAME("RCR Ew, CL");}
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
if(opcode==0xD1) {MOV32w(x2, 1);} else {ANDSw_mask(x2, xRCX, 0, 0b00100);}
|
||||
GETEW(x1, 0);
|
||||
CALL_(rcr16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("SHL Ew, 1");
|
||||
MOV32w(x4, 1);
|
||||
} else {
|
||||
INST_NAME("SHL Ew, CL");
|
||||
ANDSw_mask(x4, xRCX, 0, 0b00100);
|
||||
}
|
||||
UFLAG_IF {MESSAGE(LOG_DUMP, "Need Optimization for flags\n");}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1, 0);
|
||||
UFLAG_OP12(ed, x4)
|
||||
LSLw_REG(ed, ed, x4);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shl16);
|
||||
break;
|
||||
case 5:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("SHR Ew, 1");
|
||||
MOV32w(x4, 1);
|
||||
} else {
|
||||
INST_NAME("SHR Ew, CL");
|
||||
ANDSw_mask(x4, xRCX, 0, 0b00100);
|
||||
}
|
||||
UFLAG_IF {MESSAGE(LOG_DUMP, "Need Optimization for flags\n");}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1, 0);
|
||||
UFLAG_OP12(ed, x4)
|
||||
LSRw_REG(ed, ed, x4);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shr16);
|
||||
break;
|
||||
case 7:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("SAR Ew, 1");
|
||||
MOV32w(x4, 1);
|
||||
} else {
|
||||
INST_NAME("SAR Ew, CL");
|
||||
ANDSw_mask(x4, xRCX, 0, 0b00100);
|
||||
}
|
||||
UFLAG_IF {MESSAGE(LOG_DUMP, "Need Optimization for flags\n");}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETSEW(x1, 0);
|
||||
UFLAG_OP12(ed, x4)
|
||||
ASRw_REG(ed, ed, x4);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_sar16);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF7:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
case 1:
|
||||
INST_NAME("TEST Ew, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, 2);
|
||||
u16 = F16;
|
||||
MOV32w(x2, u16);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("NOT Ew");
|
||||
GETEW(x1, 0);
|
||||
MVNw_REG(ed, ed);
|
||||
EWBACK;
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("NEG Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, 0);
|
||||
emit_neg16(dyn, ninst, ed, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("MUL AX, Ew");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
UFLAG_DF(x1, d_mul16);
|
||||
GETEW(x1, 0);
|
||||
UXTHw(x2, xRAX);
|
||||
MULw(x1, x2, x1);
|
||||
UFLAG_RES(x1);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
BFXILx(xRDX, x1, 16, 16);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("IMUL AX, Ew");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
GETSEW(x1, 0);
|
||||
SXTHw(x2, xRAX);
|
||||
MULw(x1, x2, x1);
|
||||
UFLAG_RES(x1);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
BFXILx(xRDX, x1, 16, 16);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("DIV Ew");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEW(x1, 0);
|
||||
CALL(div16, -1);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("IDIV Ew");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEW(x1, 0);
|
||||
CALL(idiv16, -1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("INC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
GETEW(x1, 0);
|
||||
emit_inc16(dyn, ninst, x1, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("DEC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
GETEW(x1, 0);
|
||||
emit_dec16(dyn, ninst, x1, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
Executable
+1596
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,80 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)rep; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
uint8_t gd, ed;
|
||||
int64_t fixedaddress;
|
||||
|
||||
// REX prefix before the 66 are ignored
|
||||
rex.rex = 0;
|
||||
while(opcode>=0x40 && opcode<=0x4f) {
|
||||
rex.rex = opcode;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
/*if(rex.w && opcode!=0x0f) { // rex.w cancels "66", but not for 66 0f type of prefix
|
||||
MESSAGE(LOG_DUMP, "Here!\n");
|
||||
return dynarec64_64(dyn, addr-2, ip, ninst, rex, rep, ok, need_epilog);
|
||||
}*/
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, FS:Ed");
|
||||
grab_segdata(dyn, addr, ninst, x4, _FS);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
if(rex.w) {
|
||||
MOVx_REG(gd, ed);
|
||||
} else {
|
||||
if(ed!=gd) {
|
||||
BFIx(gd, ed, 0, 16);
|
||||
}
|
||||
}
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
if(rex.w) {
|
||||
LDRx_REG(gd, ed, x4);
|
||||
} else {
|
||||
LDRH_REG(x1, ed, x4);
|
||||
BFIx(gd, x1, 0, 16);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
Executable
+164
@@ -0,0 +1,164 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
#define GETGX(a) \
|
||||
gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg(dyn, ninst, x1, gd)
|
||||
|
||||
uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
uint8_t gd, ed;
|
||||
int64_t fixedaddress;
|
||||
int8_t i8;
|
||||
int32_t i32;
|
||||
int64_t j64;
|
||||
int v0, s0;
|
||||
MAYUSE(i32);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(v0);
|
||||
MAYUSE(s0);
|
||||
|
||||
// REX prefix before the 67 are ignored
|
||||
rex.rex = 0;
|
||||
while(opcode>=0x40 && opcode<=0x4f) {
|
||||
rex.rex = opcode;
|
||||
opcode = F8;
|
||||
}
|
||||
rep = 0;
|
||||
while((opcode==0xF2) || (opcode==0xF3)) {
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x0F:
|
||||
opcode=F8;
|
||||
switch(opcode) {
|
||||
|
||||
case 0x2E:
|
||||
// no special check...
|
||||
case 0x2F:
|
||||
if(rep) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
if(opcode==0x2F) {INST_NAME("COMISS Gx, Ex");} else {INST_NAME("UCOMISS Gx, Ex");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
if(MODREG) {
|
||||
s0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
} else {
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
}
|
||||
FCMPS(v0, s0);
|
||||
FCOMI(x1, x2);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8D:
|
||||
INST_NAME("LEA Gd, Ed");
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg? that's an invalid operation
|
||||
DEFAULT;
|
||||
} else { // mem <= reg
|
||||
// should a geted32 be created, to use 32bits regs instead of 64bits?
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, gd, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
if(ed!=gd) {
|
||||
MOVw_REG(gd, ed);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
#define GO(NO, YES) \
|
||||
BARRIER(2); \
|
||||
JUMP(addr+i8);\
|
||||
if(dyn->insts) { \
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst+1].address-(dyn->arm_size); \
|
||||
Bcond(NO, i32); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst); \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->arm_size); \
|
||||
Bcond(YES, i32); \
|
||||
} \
|
||||
}
|
||||
case 0xE0:
|
||||
INST_NAME("LOOPNZ (32bits)");
|
||||
READFLAGS(X_ZF);
|
||||
i8 = F8S;
|
||||
MOVw_REG(x1, xRCX);
|
||||
SUBSw_U12(x1, x1, 1);
|
||||
BFIx(xRCX, x1, 0, 32);
|
||||
B_NEXT(cEQ); // ECX is 0, no LOOP
|
||||
TSTw_mask(xFlags, 0b011010, 0); //mask=0x40
|
||||
GO(cNE, cEQ);
|
||||
break;
|
||||
case 0xE1:
|
||||
INST_NAME("LOOPZ (32bits)");
|
||||
READFLAGS(X_ZF);
|
||||
i8 = F8S;
|
||||
MOVw_REG(x1, xRCX);
|
||||
SUBSw_U12(x1, x1, 1);
|
||||
BFIx(xRCX, x1, 0, 32);
|
||||
B_NEXT(cEQ); // ECX is 0, no LOOP
|
||||
TSTw_mask(xFlags, 0b011010, 0); //mask=0x40
|
||||
GO(cEQ, cNE);
|
||||
break;
|
||||
case 0xE2:
|
||||
INST_NAME("LOOP (32bits)");
|
||||
i8 = F8S;
|
||||
MOVw_REG(x1, xRCX);
|
||||
SUBSw_U12(x1, x1, 1);
|
||||
BFIx(xRCX, x1, 0, 32);
|
||||
GO(cEQ, cNE);
|
||||
break;
|
||||
case 0xE3:
|
||||
INST_NAME("JECXZ");
|
||||
i8 = F8S;
|
||||
MOVw_REG(x1, xRCX);
|
||||
TSTw_REG(x1, x1);
|
||||
GO(cNE, cEQ);
|
||||
break;
|
||||
#undef GO
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)rep; (void)need_epilog;
|
||||
|
||||
uint8_t nextop = F8;
|
||||
uint8_t ed;
|
||||
int64_t fixedaddress;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FADD ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
FADDD(v1, v1, v2);
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
INST_NAME("FMUL ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
FMULD(v1, v1, v2);
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
INST_NAME("FCOM ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
INST_NAME("FCOMP ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
INST_NAME("FSUB ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
FSUBD(v1, v1, v2);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FSUBR ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
FSUBD(v1, v2, v1);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
INST_NAME("FDIV ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
FDIVD(v1, v1, v2);
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFA:
|
||||
case 0xFB:
|
||||
case 0xFC:
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
INST_NAME("FDIVR ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
FDIVD(v1, v2, v1);
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FADD ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
FCVT_D_S(s0, s0);
|
||||
FADDD(v1, v1, s0);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FMUL ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
FCVT_D_S(s0, s0);
|
||||
FMULD(v1, v1, s0);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FCOM ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
FCVT_D_S(s0, s0);
|
||||
FCMPD(v1, s0);
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FCOMP ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
FCVT_D_S(s0, s0);
|
||||
FCMPD(v1, s0);
|
||||
FCOM(x1, x2, x3);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FSUB ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
FCVT_D_S(s0, s0);
|
||||
FSUBD(v1, v1, s0);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FSUBR ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
FCVT_D_S(s0, s0);
|
||||
FSUBD(v1, s0, v1);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FDIV ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
FCVT_D_S(s0, s0);
|
||||
FDIVD(v1, v1, s0);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FDIVR ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
FCVT_D_S(s0, s0);
|
||||
FDIVD(v1, s0, v1);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,356 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)rep; (void)need_epilog;
|
||||
|
||||
uint8_t nextop = F8;
|
||||
uint8_t ed;
|
||||
uint8_t wback, wb1;
|
||||
int64_t fixedaddress;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
int i1, i2, i3;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FLD STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
v2 = x87_do_push(dyn, ninst);
|
||||
FMOVD(v2, v1);
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
INST_NAME("FXCH STx");
|
||||
// swap the cache value, not the double value itself :p
|
||||
i1 = x87_get_cache(dyn, ninst, x1, x2, nextop&7);
|
||||
i2 = x87_get_cache(dyn, ninst, x1, x2, 0);
|
||||
i3 = dyn->x87cache[i1];
|
||||
dyn->x87cache[i1] = dyn->x87cache[i2];
|
||||
dyn->x87cache[i2] = i3;
|
||||
break;
|
||||
|
||||
case 0xD0:
|
||||
INST_NAME("FNOP");
|
||||
break;
|
||||
|
||||
case 0xE0:
|
||||
INST_NAME("FCHS");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
FNEGD(v1, v1);
|
||||
break;
|
||||
case 0xE1:
|
||||
INST_NAME("FABS");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
FABSD(v1, v1);
|
||||
break;
|
||||
|
||||
case 0xE4:
|
||||
INST_NAME("FTST");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
FCMPD_0(v1);
|
||||
FCOM(x1, x2, x3); // same flags...
|
||||
break;
|
||||
case 0xE5:
|
||||
INST_NAME("FXAM");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_refresh(dyn, ninst, x1, x2, 0);
|
||||
CALL(fpu_fxam, -1); // should be possible inline, but is it worth it?
|
||||
break;
|
||||
|
||||
case 0xE8:
|
||||
INST_NAME("FLD1");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
FTABLE64(v1, 1.0);
|
||||
break;
|
||||
case 0xE9:
|
||||
INST_NAME("FLDL2T");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
FTABLE64(v1, L2T);
|
||||
break;
|
||||
case 0xEA:
|
||||
INST_NAME("FLDL2E");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
FTABLE64(v1, L2E);
|
||||
break;
|
||||
case 0xEB:
|
||||
INST_NAME("FLDPI");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
FTABLE64(v1, PI);
|
||||
break;
|
||||
case 0xEC:
|
||||
INST_NAME("FLDLG2");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
FTABLE64(v1, LG2);
|
||||
break;
|
||||
case 0xED:
|
||||
INST_NAME("FLDLN2");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
FTABLE64(v1, LN2);
|
||||
break;
|
||||
case 0xEE:
|
||||
INST_NAME("FLDZ");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
FTABLE64(v1, 0.0);
|
||||
break;
|
||||
|
||||
case 0xFA:
|
||||
INST_NAME("FSQRT");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
FSQRTD(v1, v1);
|
||||
break;
|
||||
|
||||
case 0xFC:
|
||||
INST_NAME("FRNDINT");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
// use C helper for now, nothing staightforward is available
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_frndint, -1);
|
||||
/*
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
VCMP_F64_0(v1);
|
||||
VMRS_APSR();
|
||||
B_NEXT(cVS); // Unordered, skip
|
||||
B_NEXT(cEQ); // Zero, skip
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x3);
|
||||
VCVT_S32_F64(x1, v1); // limit to 32bits....
|
||||
VCVT_F64_S32(v1, x1);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
*/
|
||||
break;
|
||||
case 0xF0:
|
||||
INST_NAME("F2XM1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_f2xm1, -1);
|
||||
break;
|
||||
case 0xF1:
|
||||
INST_NAME("FYL2X");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fyl2x, -1);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 0xF2:
|
||||
INST_NAME("FTAN");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_ftan, -1);
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
FTABLE64(v1, 1.0);
|
||||
break;
|
||||
case 0xF3:
|
||||
INST_NAME("FPATAN");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fpatan, -1);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 0xF4:
|
||||
INST_NAME("FXTRACT");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_do_push_empty(dyn, ninst, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fxtract, -1);
|
||||
break;
|
||||
case 0xF5:
|
||||
INST_NAME("FPREM1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fprem1, -1);
|
||||
break;
|
||||
case 0xF6:
|
||||
INST_NAME("FDECSTP");
|
||||
fpu_purgecache(dyn, ninst, x1, x2, x3);
|
||||
LDRw_U12(x2, xEmu, offsetof(x64emu_t, top));
|
||||
SUBw_U12(x2, x2, 1);
|
||||
ANDw_mask(x2, x2, 0, 2); //mask=7
|
||||
STRw_U12(x2, xEmu, offsetof(x64emu_t, top));
|
||||
break;
|
||||
case 0xF7:
|
||||
INST_NAME("FINCSTP");
|
||||
fpu_purgecache(dyn, ninst, x1, x2, x3);
|
||||
LDRw_U12(x2, xEmu, offsetof(x64emu_t, top));
|
||||
ADDw_U12(x2, x2, 1);
|
||||
ANDw_mask(x2, x2, 0, 2); //mask=7
|
||||
STRw_U12(x2, xEmu, offsetof(x64emu_t, top));
|
||||
break;
|
||||
case 0xF8:
|
||||
INST_NAME("FPREM");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fprem, -1);
|
||||
break;
|
||||
case 0xF9:
|
||||
INST_NAME("FYL2XP1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fyl2xp1, -1);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 0xFB:
|
||||
INST_NAME("FSINCOS");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_do_push_empty(dyn, ninst, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fsincos, -1);
|
||||
break;
|
||||
case 0xFD:
|
||||
INST_NAME("FSCALE");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fscale, -1);
|
||||
break;
|
||||
case 0xFE:
|
||||
INST_NAME("FSIN");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_fsin, -1);
|
||||
break;
|
||||
case 0xFF:
|
||||
INST_NAME("FCOS");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_fcos, -1);
|
||||
break;
|
||||
|
||||
|
||||
case 0xD1:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
case 0xEF:
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FLD ST0, float[ED]");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
FCVT_D_S(v1, s0);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FST float[ED], ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
FCVT_S_D(s0, v1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VSTR32_U12(s0, ed, fixedaddress);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FSTP float[ED], ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
FCVT_S_D(s0, v1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VSTR32_U12(s0, ed, fixedaddress);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FLDENV Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, x1, x2, x3); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
MOV32w(x2, 0);
|
||||
CALL(fpu_loadenv, -1);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FLDCW Ew");
|
||||
GETEW(x1, 0);
|
||||
STRH_U12(x1, xEmu, offsetof(x64emu_t, cw)); // hopefully cw is not too far for an imm8
|
||||
UBFXw(x1, x1, 10, 2); // extract round
|
||||
STRw_U12(x1, xEmu, offsetof(x64emu_t, round));
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FNSTENV Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, x1, x2, x3); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
MOV32w(x2, 0);
|
||||
CALL(fpu_savenv, -1);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FNSTCW Ew");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
ed = x1;
|
||||
wb1 = 1;
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, cw));
|
||||
EWBACK;
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,306 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)rep; (void)need_epilog;
|
||||
|
||||
uint8_t nextop = F8;
|
||||
uint8_t ed;
|
||||
uint8_t wback;
|
||||
uint8_t u8;
|
||||
int64_t fixedaddress;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
int64_t j64;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(j64);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FCMOVNB ST0, STx");
|
||||
READFLAGS(X_CF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
TSTw_mask(xFlags, 0, 0); //mask=1<<F_CF
|
||||
FCSELD(v1, v2, v1, cEQ); // F_CF==0
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
INST_NAME("FCMOVNE ST0, STx");
|
||||
READFLAGS(X_ZF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
TSTw_mask(xFlags, 0b011010, 0); //mask=1<<F_ZF
|
||||
FCSELD(v1, v2, v1, cEQ); // F_ZF==0
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
INST_NAME("FCMOVNBE ST0, STx");
|
||||
READFLAGS(X_CF|X_ZF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
MOV32w(x1, (1<<F_CF)|(1<<F_ZF));
|
||||
TSTw_REG(xFlags, x1);
|
||||
FCSELD(v1, v2, v1, cEQ); // F_CF==0 & F_ZF==0
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
INST_NAME("FCMOVNU ST0, STx");
|
||||
READFLAGS(X_PF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
TSTw_mask(xFlags, 0b011110, 0); //mask=1<<F_PF
|
||||
FCSELD(v1, v2, v1, cEQ); // F_PF==0
|
||||
break;
|
||||
case 0xE1:
|
||||
INST_NAME("FDISI8087_NOP"); // so.. NOP?
|
||||
break;
|
||||
case 0xE2:
|
||||
INST_NAME("FNCLEX");
|
||||
LDRH_U12(x2, xEmu, offsetof(x64emu_t, sw));
|
||||
MOV32w(x1, 0);
|
||||
BFIw(x2, x1, 0, 8); // IE .. PE, SF, ES
|
||||
BFIw(x2, x1, 15, 1); // B
|
||||
STRH_U12(x2, xEmu, offsetof(x64emu_t, sw));
|
||||
break;
|
||||
case 0xE3:
|
||||
INST_NAME("FNINIT");
|
||||
x87_purgecache(dyn, ninst, x1, x2, x3);
|
||||
CALL(reset_fpu, -1);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FUCOMI ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
FCMPD(v1, v2);
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
INST_NAME("FCOMI ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
FCMPD(v1, v2);
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
|
||||
case 0xE0:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ed");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
SXTL_32(v1, s0);
|
||||
SCVTFDD(v1, v1);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FISTTP Ed, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
ed = x1;
|
||||
}
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
FRINT32ZD(s0, v1);
|
||||
FCVTZSwD(ed, s0);
|
||||
WBACK;
|
||||
#else
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
FRINTZD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
VSTR32_U12(s0, wback, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
MOV32w(x5, 0x80000000);
|
||||
STRw_U12(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FIST Ed, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4); // x1 have the modified RPSCR reg
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
ed = x1;
|
||||
}
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
FRINT32XD(s0, v1);
|
||||
FCVTZSwD(ed, s0);
|
||||
WBACK;
|
||||
#else
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
FRINTXD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
VSTR32_U12(s0, wback, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
MOV32w(x5, 0x80000000);
|
||||
STRw_U12(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FISTP Ed, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4); // x1 have the modified RPSCR reg
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
ed = x1;
|
||||
}
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
FRINT32XD(s0, v1);
|
||||
FCVTZSwD(ed, s0);
|
||||
WBACK;
|
||||
#else
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
FRINTXD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
VSTR32_U12(s0, wback, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
MOV32w(x5, 0x80000000);
|
||||
STRw_U12(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FLD tbyte");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
if(PK(0)==0xDB && ((PK(1)>>3)&7)==7) {
|
||||
// the FLD is immediatly followed by an FSTP
|
||||
LDRx_U12(x5, ed, 0);
|
||||
LDRH_U12(x6, 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, rex, 0, 0);
|
||||
STRx_U12(x5, ed, 0);
|
||||
STRH_U12(x6, ed, 8);
|
||||
} else {
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
x87_do_push_empty(dyn, ninst, x3);
|
||||
CALL(arm_fld, -1);
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FSTP tbyte");
|
||||
x87_forget(dyn, ninst, x1, x3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
CALL(arm_fstp, -1);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)rep; (void)need_epilog;
|
||||
|
||||
uint8_t nextop = F8;
|
||||
uint8_t ed;
|
||||
int64_t fixedaddress;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FFREE STx");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_purgecache(dyn, ninst, x1, x2, x3);
|
||||
MOV32w(x1, nextop-0xC0);
|
||||
CALL(fpu_do_free, -1);
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
INST_NAME("FST ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
FMOVD(v2, v1);
|
||||
break;
|
||||
case 0xD8:
|
||||
INST_NAME("FSTP ST0, ST0");
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
INST_NAME("FSTP ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
FMOVD(v2, v1);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
INST_NAME("FUCOM ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FUCOMP ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFA:
|
||||
case 0xFB:
|
||||
case 0xFC:
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FLD double");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VLDR64_U12(v1, ed, fixedaddress);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FISTTP i64, ST0");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
FRINT64ZD(s0, v1);
|
||||
FCVTZSxD(x2, s0);
|
||||
STRx_U12(x2, ed, fixedaddress);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FST double");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VSTR64_U12(v1, ed, fixedaddress);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FSTP double");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VSTR64_U12(v1, ed, fixedaddress);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FRSTOR m108byte");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(arm_frstor, -1);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FSAVE m108byte");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(arm_fsave, -1);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FNSTSW m2byte");
|
||||
fpu_purgecache(dyn, ninst, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x4, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
LDRw_U12(x1, xEmu, offsetof(x64emu_t, top));
|
||||
LDRH_U12(x3, xEmu, offsetof(x64emu_t, sw));
|
||||
BFIw(x3, x1, 11, 3); // inject TOP at bit 11 (3 bits)
|
||||
STRH_U12(x3, ed, fixedaddress); // store whole sw flags
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)rep; (void)need_epilog;
|
||||
|
||||
uint8_t nextop = F8;
|
||||
uint8_t ed, wback, u8;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(j64);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FFREEP STx");
|
||||
// not handling Tag...
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
|
||||
case 0xE0:
|
||||
INST_NAME("FNSTSW AX");
|
||||
LDRw_U12(x2, xEmu, offsetof(x64emu_t, top));
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
BFIw(x1, x2, 11, 3); // inject top
|
||||
BFIw(xRAX, x1, 0, 16);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FUCOMIP ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
FCMPD(v1, v2);
|
||||
FCOMI(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
INST_NAME("FCOMIP ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
FCMPD(v1, v2);
|
||||
FCOMI(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
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:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
case 0xE1:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFA:
|
||||
case 0xFB:
|
||||
case 0xFC:
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ew");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
LDRSHw_U12(x1, wback, fixedaddress);
|
||||
SCVTFDw(v1, x1);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FISTTP Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
// this version needs ARM v8.5, //TODO: add detection of this extensio to use it
|
||||
FRINT32ZD(s0, v1);
|
||||
// no saturation instruction on Arm, so using NEON
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
SQXTN_H_S(s0, s0);
|
||||
VSTR16_U12(s0, wback, fixedaddress);
|
||||
#else
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
VFCVTZSd(s0, v1);
|
||||
SQXTN_S_D(s0, s0);
|
||||
SQXTN_H_S(s0, s0);
|
||||
VSTR16_U12(s0, wback, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
MOV32w(x5, 0x8000);
|
||||
STRH_U12(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FIST Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
FRINT32XD(s0, v1);
|
||||
// no saturation instruction on Arm, so using NEON
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
SQXTN_H_S(s0, s0);
|
||||
VSTR16_U12(s0, wback, fixedaddress);
|
||||
#else
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
FRINTXD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
SQXTN_H_S(s0, s0);
|
||||
VSTR16_U12(s0, wback, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
MOV32w(x5, 0x8000);
|
||||
STRH_U12(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FISTP Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
FRINT32XD(s0, v1);
|
||||
// no saturation instruction on Arm, so using NEON
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
SQXTN_H_S(s0, s0);
|
||||
VSTR16_U12(s0, wback, fixedaddress);
|
||||
#else
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
FRINTXD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
SQXTN_H_S(s0, s0);
|
||||
VSTR16_U12(s0, wback, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
MOV32w(x5, 0x8000);
|
||||
STRH_U12(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FBLD ST0, tbytes");
|
||||
x87_do_push_empty(dyn, ninst, x1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(fpu_fbld, -1);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FILD ST0, i64");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
LDRx_U12(x1, wback, fixedaddress);
|
||||
SCVTFDx(v1, x1);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FBSTP tbytes, ST0");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(fpu_fbst, -1);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FISTP i64, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
FRINT64XD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
VSTR64_U12(s0, wback, fixedaddress);
|
||||
#else
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
FRINTXD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
VSTR64_U12(s0, wback, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
MOV64x(x5, 0x8000000000000000LL);
|
||||
STRx_U12(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
Executable
+679
@@ -0,0 +1,679 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
#include "../tools/bridge_private.h"
|
||||
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
// emit OR32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_or32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_or64:d_or32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
ORRxw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit OR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_or32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV64xw(s3, c);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_or64:d_or32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_PEND) {} else {MOV64xw(s3, c);}
|
||||
ORRxw_REG(s1, s1, s3);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit XOR32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_xor32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_xor64:d_xor32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
EORxw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit XOR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_xor32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV64xw(s3, c);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_xor64:d_xor32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_PEND) {} else {MOV64xw(s3, c);}
|
||||
EORxw_REG(s1, s1, s3);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit AND32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_and32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_and64:d_and32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSxw_REG(s1, s1, s2);
|
||||
} else {
|
||||
ANDxw_REG(s1, s1, s2);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit AND32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_and32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV64xw(s3, c);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_and64:d_and32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_PEND) {} else {MOV64xw(s3, c);}
|
||||
IFX(X_ALL) {
|
||||
ANDSxw_REG(s1, s1, s3);
|
||||
} else {
|
||||
ANDxw_REG(s1, s1, s3);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit OR8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_or8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
ORRw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit OR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_or8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
MOV32w(s3, c&0xff);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_or8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
ORRw_REG(s1, s1, s3);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit XOR8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_xor8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
EORx_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit XOR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_xor8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
MOV32w(s3, c&0xff);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_xor8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
EORw_REG(s1, s1, s3);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit AND8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_and8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_REG(s1, s1, s2);
|
||||
} else {
|
||||
ANDw_REG(s1, s1, s2);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw_REG(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit AND8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_and8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
MOV32w(s3, c&0xff);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_and8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_REG(s1, s1, s3);
|
||||
} else {
|
||||
ANDw_REG(s1, s1, s3);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// emit OR16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_or16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
ORRw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 15); //mask=0xffff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 15);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit OR16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
//void emit_or16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
//{
|
||||
// IFX(X_PEND) {
|
||||
// MOVW(s3, c);
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
// STR_IMM9(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
// SET_DF(s4, d_or16);
|
||||
// } else IFX(X_ALL) {
|
||||
// SET_DFNONE(s4);
|
||||
// }
|
||||
// if(c>=0 && c<256) {
|
||||
// IFX(X_ALL) {
|
||||
// ORRS_IMM8(s1, s1, c, 0);
|
||||
// } else {
|
||||
// ORR_IMM8(s1, s1, c, 0);
|
||||
// }
|
||||
// } else {
|
||||
// IFX(X_PEND) {} else {MOVW(s3, c);}
|
||||
// IFX(X_ALL) {
|
||||
// ORRS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
// } else {
|
||||
// ORR_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
// }
|
||||
// }
|
||||
// IFX(X_PEND) {
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, res));
|
||||
// }
|
||||
// IFX(X_CF | X_AF | X_ZF) {
|
||||
// BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
// }
|
||||
// IFX(X_OF) {
|
||||
// BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
// }
|
||||
// IFX(X_ZF) {
|
||||
// ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
// }
|
||||
// IFX(X_SF) {
|
||||
// MOV_REG_LSR_IMM5(s3, s1, 15);
|
||||
// BFI(xFlags, s3, F_SF, 1);
|
||||
// }
|
||||
// IFX(X_PF) {
|
||||
// emit_pf(dyn, ninst, s1, s3, s4);
|
||||
// }
|
||||
//}
|
||||
|
||||
// emit XOR16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_xor16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
EORw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 15); //mask=0xffff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 15);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit XOR16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
//void emit_xor16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
//{
|
||||
// IFX(X_PEND) {
|
||||
// MOVW(s3, c);
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
// STR_IMM9(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
// SET_DF(s4, d_xor16);
|
||||
// } else IFX(X_ALL) {
|
||||
// SET_DFNONE(s4);
|
||||
// }
|
||||
// if(c>=0 && c<256) {
|
||||
// IFX(X_ALL) {
|
||||
// XORS_IMM8(s1, s1, c);
|
||||
// } else {
|
||||
// XOR_IMM8(s1, s1, c);
|
||||
// }
|
||||
// } else {
|
||||
// IFX(X_PEND) {} else {MOVW(s3, c);}
|
||||
// IFX(X_ALL) {
|
||||
// XORS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
// } else {
|
||||
// XOR_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
// }
|
||||
// }
|
||||
// IFX(X_PEND) {
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, res));
|
||||
// }
|
||||
// IFX(X_CF | X_AF | X_ZF) {
|
||||
// BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
// }
|
||||
// IFX(X_OF) {
|
||||
// BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
// }
|
||||
// IFX(X_ZF) {
|
||||
// ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
// }
|
||||
// IFX(X_SF) {
|
||||
// MOV_REG_LSR_IMM5(s3, s1, 15);
|
||||
// BFI(xFlags, s3, F_SF, 1);
|
||||
// }
|
||||
// IFX(X_PF) {
|
||||
// emit_pf(dyn, ninst, s1, s3, s4);
|
||||
// }
|
||||
//}
|
||||
|
||||
// emit AND16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_and16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
IFX(X_ALL) {
|
||||
ANDSw_REG(s1, s1, s2);
|
||||
} else {
|
||||
ANDw_REG(s1, s1, s2);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw_REG(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 15);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit AND16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
//void emit_and16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
//{
|
||||
// IFX(X_PEND) {
|
||||
// MOVW(s3, c);
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
// STR_IMM9(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
// SET_DF(s4, d_and16);
|
||||
// } else IFX(X_ALL) {
|
||||
// SET_DFNONE(s4);
|
||||
// }
|
||||
// if(c>=0 && c<256) {
|
||||
// IFX(X_ALL) {
|
||||
// ANDS_IMM8(s1, s1, c);
|
||||
// } else {
|
||||
// AND_IMM8(s1, s1, c);
|
||||
// }
|
||||
// } else {
|
||||
// IFX(X_PEND) {} else {MOVW(s3, c);}
|
||||
// IFX(X_ALL) {
|
||||
// ANDS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
// } else {
|
||||
// AND_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
// }
|
||||
// }
|
||||
// IFX(X_PEND) {
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, res));
|
||||
// }
|
||||
// IFX(X_CF | X_AF | X_ZF) {
|
||||
// BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
// }
|
||||
// IFX(X_OF) {
|
||||
// BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
// }
|
||||
// IFX(X_ZF) {
|
||||
// ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
// }
|
||||
// IFX(X_SF) {
|
||||
// MOV_REG_LSR_IMM5(s3, s1, 15);
|
||||
// BFI(xFlags, s3, F_SF, 1);
|
||||
// }
|
||||
// IFX(X_PF) {
|
||||
// emit_pf(dyn, ninst, s1, s3, s4);
|
||||
// }
|
||||
//}
|
||||
Executable
+1849
File diff suppressed because it is too large.
Load diff
Executable
+443
@@ -0,0 +1,443 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
#include "../tools/bridge_private.h"
|
||||
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_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, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
int64_t j64;
|
||||
MAYUSE(j64);
|
||||
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_shl64:d_shl32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(F_OF) {
|
||||
CMPSxw_U12(s2, 0);
|
||||
IFX(F_OF) {
|
||||
Bcond(cNE, +8);
|
||||
BFCx(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
Bcond(cNE, +8);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
}
|
||||
IFX(X_CF | X_OF) {
|
||||
MOV32w(s4, rex.w?64:32);
|
||||
SUBxw_REG(s4, s4, s2);
|
||||
LSRxw_REG(s4, s1, s4);
|
||||
BFIw(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
LSLxw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPSxw_U12(s2, 1); // if s2==1
|
||||
IFX(X_SF) {} else {LSRxw(s4, s1, (rex.w)?63:31);}
|
||||
EORxw_REG(s4, s4, xFlags); // CF is set if OF is asked
|
||||
CSELw(s4, s4, wZR, cEQ);
|
||||
BFIw(xFlags, s4, 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, rex_t rex, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_shl64:d_shl32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(c==0) {
|
||||
IFX(F_OF) {
|
||||
BFCx(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_CF|X_OF) {
|
||||
LSRxw(s3, s1, (rex.w?64:32)-c);
|
||||
BFIxw(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
LSLxw(s1, s1, c);
|
||||
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
IFX(X_SF) {} else {LSRxw(s4, s1, (rex.w)?63:31);}
|
||||
EORxw_REG(s4, s4, xFlags); // CF is set if OF is asked
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
} else {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_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, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
int64_t j64;
|
||||
MAYUSE(j64);
|
||||
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_shr64:d_shr32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_ALL) {
|
||||
CMPSxw_U12(s2, 0); //if(!c)
|
||||
IFX(X_PEND) {
|
||||
Bcond(cNE, +12);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
SUBxw_U12(s3, s2, 1);
|
||||
LSRxw_REG(s3, s1, s3);
|
||||
BFIw(xFlags, s3, 0, 1);
|
||||
}
|
||||
LSRxw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPSxw_U12(s2, 1); // if s2==1
|
||||
Bcond(cNE, 4+3*4);
|
||||
if(rex.w) {
|
||||
LSRx(s4, s1, 62);
|
||||
} else {
|
||||
LSRw(s4, s1, 30);
|
||||
}
|
||||
EORw_REG_LSR(s4, s4, s4, 1);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_shr64:d_shr32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
LSRxw_REG(s3, s1, c-1);
|
||||
BFIw(xFlags, s3, 0, 1);
|
||||
}
|
||||
LSRxw(s1, s1, c);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
LSRxw(s4, s1, rex.w?62:30);
|
||||
EORw_REG_LSR(s4, s4, s4, 1);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SAR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_sar32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_sar64:d_sar32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
ASRxw(s3, s1, c-1);
|
||||
BFIw(xFlags, s3, 0, 1);
|
||||
}
|
||||
ASRxw(s1, s1, c);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTw_REG(s1, s1);
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit ROL32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rol32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
MAYUSE(rex); MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_rol32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
RORxw(s1, s1, (rex.w?64:32)-c);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, s1, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
ADDxw_REG_LSR(s3, s1, s1, rex.w?63:31);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit ROR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_ror32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_ror64:d_ror32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
RORxw(s1, s1, c);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
LSRxw(s3, s1, rex.w?63:31);
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
LSRxw(s3, s1, rex.w?62:30);
|
||||
EORxw_REG_LSR(s3, s3, s3, 1);
|
||||
BFIw(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, rex_t rex, int s1, int s2, int32_t c, int s3, int s4)
|
||||
{
|
||||
c&=(rex.w?0x3f:0x1f);
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
// same flags computation as with shl64/shl32
|
||||
SET_DF(s4, rex.w?d_shl64:d_shl32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
LSRxw_REG(s3, s1, c-1);
|
||||
BFIw(xFlags, s3, 0, 1);
|
||||
}
|
||||
LSRxw(s1, s1, c);
|
||||
ORRxw_REG_LSL(s1, s1, s2, (rex.w?64:32)-c);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
LSRxw(s4, s1, rex.w?62:30);
|
||||
EORw_REG_LSR(s4, s4, s4, 1);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
void emit_shld32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int32_t c, int s3, int s4)
|
||||
{
|
||||
c&=(rex.w?0x3f:0x1f);
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
// same flags computation as with shl64/shl32
|
||||
SET_DF(s4, rex.w?d_shl64:d_shl32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(c==0) {
|
||||
IFX(F_OF) {
|
||||
BFCx(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_CF|X_OF) {
|
||||
LSRxw(s3, s1, (rex.w?64:32)-c);
|
||||
BFIxw(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
LSLxw(s1, s1, c);
|
||||
ORRxw_REG_LSR(s1, s1, s2, (rex.w?64:32)-c);
|
||||
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
UBFXxw(s3, s1, rex.w?63:31, 1);
|
||||
EORxw_REG(s3, s3, xFlags); // CF is set if OF is asked
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
} else {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
Executable
+374
@@ -0,0 +1,374 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
#include "../tools/bridge_private.h"
|
||||
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
// emit CMP32 instruction, from cmp s1, s2, using s3 and s4 as scratch
|
||||
void emit_cmp32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s2);
|
||||
IFX_PENDOR0 {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_cmp64:d_cmp32);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_AF) {
|
||||
ORNxw_REG(s3, s2, s1); // s3 = ~op1 | op2
|
||||
BICxw(s4, s2, s1); // s4 = ~op1 & op2
|
||||
}
|
||||
SUBSxw_REG(s5, s1, s2); // res = s1 - s2
|
||||
IFX_PENDOR0 {
|
||||
STRxw_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_AF) {
|
||||
ANDxw_REG(s3, s3, s5); // s3 = (~op1 | op2) & res
|
||||
ORRxw_REG(s3, s3, s4); // s3 = (~op1 & op2) | ((~op1 | op2) & res)
|
||||
LSRxw(s4, s3, 3);
|
||||
BFIx(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
// inverted carry
|
||||
CSETw(s4, cCC);
|
||||
BFIw(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CSETw(s4, cVS);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s5, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP32 instruction, from cmp s1 , 0, using s3 and s4 as scratch
|
||||
void emit_cmp32_0(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
MOV64xw(s4, 0);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s4, xEmu, offsetof(x64emu_t, op2));
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
SET_DF(s4, rex.w?d_cmp64:d_cmp32);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
SUBSxw_U12(s3, s1, 0); // res = s1 - 0
|
||||
// and now the tricky ones (and mostly unused), PF and AF
|
||||
// bc = (res & (~d | s)) | (~d & s) => is 0 here...
|
||||
IFX(X_OF|X_AF) {
|
||||
MOV32w(s4, (1<<F_OF)|(1<<F_AF));
|
||||
BICw(xFlags, xFlags, s4);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
// inverted carry
|
||||
CSETw(s4, cCC);
|
||||
BFIw(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_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, int s5)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s2);
|
||||
IFX_PENDOR0 {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_cmp16);
|
||||
} else {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
SUBw_REG(s5, s1, s2); // res = s1 - s2
|
||||
IFX_PENDOR0 {
|
||||
STRH_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTw_mask(s5, 0, 15); //mask=0xffff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s4, s5, 15);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s)
|
||||
IFX(X_CF|X_AF|X_OF) {
|
||||
MVNw_REG(s4, s1); // s4 = ~d
|
||||
ORRw_REG(s4, s4, s2); // s4 = ~d | s
|
||||
ANDw_REG(s4, s4, s5); // s4 = res & (~d | s)
|
||||
BICw_REG(s3, s2, s1); // s3 = s & ~d
|
||||
ORRw_REG(s3, s4, s3); // s3 = (res & (~d | s)) | (s & ~d)
|
||||
IFX(X_CF) {
|
||||
LSRw(s4, s3, 15);
|
||||
BFIw(xFlags, s4, F_CF, 1); // CF : bc & 0x8000
|
||||
}
|
||||
IFX(X_AF) {
|
||||
LSRw(s4, s3, 3);
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_OF) {
|
||||
LSRw(s4, s3, 14);
|
||||
EORw_REG_LSR(s4, s4, s4, 1);
|
||||
BFIw(xFlags, s4, F_OF, 1); // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP16 instruction, from cmp s1 , #0, using s3 and s4 as scratch
|
||||
void emit_cmp16_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
MOV32w(s3, 0);
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
SET_DF(s3, d_cmp16);
|
||||
} else {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s) = 0
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 15); //mask=0xffff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s4, s1, 15);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_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, int s5)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s2);
|
||||
IFX_PENDOR0 {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_cmp8);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
SUBSw_REG(s5, s1, s2); // res = s1 - s2
|
||||
} else {
|
||||
SUBw_REG(s5, s1, s2); // res = s1 - s2
|
||||
}
|
||||
IFX_PENDOR0 {
|
||||
STRB_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s5, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s)
|
||||
IFX(X_CF|X_AF|X_OF) {
|
||||
ORNw_REG(s4, s2, s1); // s4 = ~d | s
|
||||
ANDw_REG(s4, s4, s5); // s4 = res & (~d | s)
|
||||
BICw_REG(s3, s2, s1); // s3 = s & ~d
|
||||
ORRw_REG(s3, s4, s3); // s3 = (res & (~d | s)) | (s & ~d)
|
||||
IFX(X_CF) {
|
||||
LSRw(s4, s3, 7);
|
||||
BFIw(xFlags, s4, F_CF, 1); // CF : bc & 0x80
|
||||
}
|
||||
IFX(X_AF) {
|
||||
LSRw(s4, s3, 3);
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_OF) {
|
||||
LSRw(s4, s3, 6);
|
||||
EORw_REG_LSR(s4, s4, s4, 1);
|
||||
BFIw(xFlags, s4, F_OF, 1); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s3, s4);
|
||||
}
|
||||
}
|
||||
// emit CMP8 instruction, from cmp s1 , 0, using s3 and s4 as scratch
|
||||
void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
MOV32w(s4, 0);
|
||||
STRB_U12(s4, xEmu, offsetof(x64emu_t, op2));
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
SET_DF(s3, d_cmp8);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s) = 0
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 0b000111); //mask=000000ff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_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, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s2); MAYUSE(s3); MAYUSE(s4);
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, rex.w?d_tst64:d_tst32);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
ANDSxw_REG(s3, s1, s2); // res = s1 & s2
|
||||
IFX_PENDOR0 {
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s3, rex.w?63:31);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// PF: (((emu->x64emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
ANDw_mask(s3, s3, 0b011011, 000010); // 0xE0
|
||||
LSRw(s3, s3, 5);
|
||||
MOV64x(s4, (uintptr_t)GetParityTab());
|
||||
LDRw_REG_LSL2(s4, s4, s3);
|
||||
ANDw_mask(s3, s1, 0, 0b000100); // 0x1f
|
||||
LSRw_REG(s4, s4, s3);
|
||||
MVNx_REG(s4, s4);
|
||||
BFIw(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, int s5)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s2);
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, d_tst16);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFCw(xFlags, F_CF, 1);
|
||||
}
|
||||
ANDSw_REG(s5, s1, s2); // res = s1 & s2
|
||||
IFX_PENDOR0 {
|
||||
STRH_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s4, s5, 15);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// PF: (((emu->x64emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST8 instruction, from test s1, s2, using s3 and s4 as scratch
|
||||
void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s2);
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, d_tst8);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFCw(xFlags, F_CF, 1);
|
||||
}
|
||||
ANDSw_REG(s5, s1, s2); // res = s1 & s2
|
||||
IFX_PENDOR0 {
|
||||
STRB_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s4, s5, 7);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// PF: (((emu->x64emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s3, s4);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,712 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)rep; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2, gb1, gb2;
|
||||
int32_t i32;
|
||||
int64_t i64, j64;
|
||||
int64_t fixedaddress;
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(j64);
|
||||
|
||||
while((opcode==0xF2) || (opcode==0xF3)) {
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
// REX prefix before the F0 are ignored
|
||||
rex.rex = 0;
|
||||
while(opcode>=0x40 && opcode<=0x4f) {
|
||||
rex.rex = opcode;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
switch(opcode) {
|
||||
case 0x00:
|
||||
INST_NAME("LOCK ADD Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGB(x2);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(rex.rex) {
|
||||
wback = xRAX + (nextop&7) + (rex.b<<3);
|
||||
wb2 = 0;
|
||||
} else {
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2);
|
||||
wback = xRAX+(wback&3);
|
||||
}
|
||||
UBFXw(x1, wback, wb2*8, 8);
|
||||
emit_add8(dyn, ninst, x1, x2, x4, x3);
|
||||
BFIx(wback, x1, wb2*8, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
MARKLOCK;
|
||||
LDAXRB(x1, wback);
|
||||
emit_add8(dyn, ninst, x1, x2, x4, x3);
|
||||
STLXRB(x4, x1, wback);
|
||||
CBNZx_MARKLOCK(x4);
|
||||
}
|
||||
break;
|
||||
case 0x01:
|
||||
INST_NAME("LOCK ADD Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
emit_add32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_add32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0F:
|
||||
nextop = F8;
|
||||
switch(nextop) {
|
||||
|
||||
case 0xB1:
|
||||
INST_NAME("LOCK CMPXCHG Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = 0;
|
||||
UFLAG_IF {emit_cmp32(dyn, ninst, rex, xRAX, ed, x3, x4, x5);}
|
||||
MOVxw_REG(x1, ed); // save value
|
||||
CMPSxw_REG(xRAX, x1);
|
||||
B_MARK2(cNE);
|
||||
MOVxw_REG(ed, gd);
|
||||
MARK2;
|
||||
MOVxw_REG(xRAX, x1);
|
||||
B_NEXT_nocond;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK3(cNE);
|
||||
// Aligned version
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
CMPSxw_REG(xRAX, x1);
|
||||
B_MARK(cNE);
|
||||
// EAX == Ed
|
||||
STLXRxw(x4, gd, wback);
|
||||
CBNZx_MARKLOCK(x4);
|
||||
// done
|
||||
B_MARK_nocond;
|
||||
// Unaligned version
|
||||
MARK3;
|
||||
LDRxw_U12(x1, wback, 0);
|
||||
LDAXRB(x3, wback); // dummy read, to arm the write...
|
||||
CMPSxw_REG(xRAX, x1);
|
||||
B_MARK(cNE);
|
||||
// EAX == Ed
|
||||
STLXRB(x4, gd, wback);
|
||||
CBNZx_MARK3(x4);
|
||||
STRxw_U12(gd, wback, 0);
|
||||
MARK;
|
||||
// Common part (and fallback for EAX != Ed)
|
||||
UFLAG_IF {emit_cmp32(dyn, ninst, rex, xRAX, x1, x3, x4, x5);}
|
||||
MOVxw_REG(xRAX, x1); // upper par of RAX will be erase on 32bits, no mater what
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC1:
|
||||
INST_NAME("LOCK XADD Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOVxw_REG(x1, ed);
|
||||
MOVxw_REG(ed, gd);
|
||||
MOVxw_REG(gd, x1);
|
||||
emit_add32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE); // unaligned
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
ADDxw_REG(x4, x1, gd);
|
||||
STLXRxw(x3, x4, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
B_MARK2_nocond;
|
||||
MARK;
|
||||
LDRxw_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIxw(x1, x4, 0, 8);
|
||||
ADDxw_REG(x4, x1, gd);
|
||||
STLXRB(x3, x4, wback);
|
||||
CBNZx_MARK(x3);
|
||||
STRxw_U12(x4, wback, 0);
|
||||
MARK2;
|
||||
IFX(X_ALL|X_PEND) {
|
||||
MOVxw_REG(x2, x1);
|
||||
emit_add32(dyn, ninst, rex, x2, gd, x3, x4);
|
||||
}
|
||||
MOVxw_REG(gd, x1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC7:
|
||||
INST_NAME("LOCK CMPXCHG8B Gq, Eq");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
nextop = F8;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
MARKLOCK;
|
||||
LDAXPxw(x2, x3, wback);
|
||||
CMPSxw_REG(xRAX, x2);
|
||||
B_MARK(cNE); // EAX != Ed[0]
|
||||
CMPSxw_REG(xRDX, x3);
|
||||
B_MARK(cNE); // EDX != Ed[1]
|
||||
STLXPxw(x4, xRBX, xRCX, wback);
|
||||
CBNZx_MARKLOCK(x4);
|
||||
MOV32w(x1, 1);
|
||||
B_MARK3_nocond;
|
||||
MARK;
|
||||
MOVxw_REG(xRAX, x2);
|
||||
MOVxw_REG(xRDX, x3);
|
||||
MOV32w(x1, 0);
|
||||
MARK3;
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x29:
|
||||
INST_NAME("LOCK SUB Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
emit_sub32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_sub32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x66:
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: //ADD
|
||||
if(opcode==0x81) {
|
||||
INST_NAME("LOCK ADD Ew, Iw");
|
||||
} else {
|
||||
INST_NAME("LOCK ADD Ew, Iw");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV32w(x5, i32);
|
||||
UXTHw(x6, ed);
|
||||
emit_add16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
MOV32w(x5, i32);
|
||||
TSTx_mask(wback, 1, 0, 0); // mask=1
|
||||
B_MARK(cNE);
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_add16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
B_NEXT_nocond;
|
||||
MARK; // unaligned! also, not enough
|
||||
LDRH_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIw(x1, x4, 0, 8); // re-inject
|
||||
emit_add16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRB(x3, x1, wback);
|
||||
CBNZx_MARK(x3);
|
||||
STRH_U12(x1, wback, 0); // put the whole value
|
||||
}
|
||||
break;
|
||||
case 1: //OR
|
||||
if(opcode==0x81) {INST_NAME("LOCK OR Ew, Iw");} else {INST_NAME("LOCK OR Ew, Iw");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV32w(x5, i32);
|
||||
UXTHw(x6, ed);
|
||||
emit_or16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
MOV32w(x5, i32);
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_or16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
break;
|
||||
case 2: //ADC
|
||||
if(opcode==0x81) {INST_NAME("LOCK ADC Ew, Iw");} else {INST_NAME("LOCK ADC Ew, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV32w(x5, i32);
|
||||
UXTHw(x6, ed);
|
||||
emit_adc16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
MOV32w(x5, i32);
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_adc16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
break;
|
||||
case 3: //SBB
|
||||
if(opcode==0x81) {INST_NAME("LOCK SBB Ew, Iw");} else {INST_NAME("LOCK SBB Ew, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV32w(x5, i32);
|
||||
UXTHw(x6, ed);
|
||||
emit_sbb16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
MOV32w(x5, i32);
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_sbb16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
break;
|
||||
case 4: //AND
|
||||
if(opcode==0x81) {INST_NAME("LOCK AND Ew, Iw");} else {INST_NAME("LOCK AND Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV32w(x5, i32);
|
||||
UXTHw(x6, ed);
|
||||
emit_and16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
MOV32w(x5, i32);
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_and16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
break;
|
||||
case 5: //SUB
|
||||
if(opcode==0x81) {INST_NAME("LOCK SUB Ew, Iw");} else {INST_NAME("LOCK SUB Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV32w(x5, i32);
|
||||
UXTHw(x6, ed);
|
||||
emit_sub16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
MOV32w(x5, i32);
|
||||
TSTx_mask(wback, 1, 0, 0); // mask=1
|
||||
B_MARK(cNE);
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_sub16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
B_NEXT_nocond;
|
||||
MARK; // unaligned! also, not enough
|
||||
LDRH_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIw(x1, x4, 0, 8); // re-inject
|
||||
emit_sub16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRB(x3, x1, wback);
|
||||
CBNZx_MARK(x3);
|
||||
STRH_U12(x1, wback, 0); // put the whole value
|
||||
}
|
||||
break;
|
||||
case 6: //XOR
|
||||
if(opcode==0x81) {INST_NAME("LOCK XOR Ew, Iw");} else {INST_NAME("LOCK XOR Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV32w(x5, i32);
|
||||
UXTHw(x6, ed);
|
||||
emit_xor16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
MOV32w(x5, i32);
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_xor16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
break;
|
||||
case 7: //CMP
|
||||
if(opcode==0x81) {INST_NAME("(LOCK) CMP Ew, Iw");} else {INST_NAME("(LOCK) CMP Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x6, (opcode==0x81)?2:1);
|
||||
(void)wb1;
|
||||
// No need to LOCK, this is readonly
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
if(i32) {
|
||||
MOV32w(x5, i32);
|
||||
UXTHw(x6, ed);
|
||||
emit_cmp16(dyn, ninst, x6, x5, x3, x4, x6);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
emit_cmp16_0(dyn, ninst, ed, x3, x4);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: //ADD
|
||||
if(opcode==0x81) {
|
||||
INST_NAME("LOCK ADD Ed, Id");
|
||||
} else {
|
||||
INST_NAME("LOCK ADD Ed, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV64xw(x5, i64);
|
||||
emit_add32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
TSTx_mask(wback, 1, 0, 0); // mask=1
|
||||
B_MARK(cNE);
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_add32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
B_NEXT_nocond;
|
||||
MARK; // unaligned! also, not enough
|
||||
LDRxw_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIxw(x1, x4, 0, 8); // re-inject
|
||||
emit_add32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
STLXRB(x3, x1, wback);
|
||||
CBNZx_MARK(x3);
|
||||
STRxw_U12(x1, wback, 0); // put the whole value
|
||||
}
|
||||
break;
|
||||
case 1: //OR
|
||||
if(opcode==0x81) {INST_NAME("LOCK OR Ed, Id");} else {INST_NAME("LOCK OR Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV64xw(x5, i64);
|
||||
emit_or32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_or32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
break;
|
||||
case 2: //ADC
|
||||
if(opcode==0x81) {INST_NAME("LOCK ADC Ed, Id");} else {INST_NAME("LOCK ADC Ed, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV64xw(x5, i64);
|
||||
emit_adc32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_adc32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
break;
|
||||
case 3: //SBB
|
||||
if(opcode==0x81) {INST_NAME("LOCK SBB Ed, Id");} else {INST_NAME("LOCK SBB Ed, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV64xw(x5, i64);
|
||||
emit_sbb32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_sbb32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
break;
|
||||
case 4: //AND
|
||||
if(opcode==0x81) {INST_NAME("LOCK AND Ed, Id");} else {INST_NAME("LOCK AND Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV64xw(x5, i64);
|
||||
emit_and32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_and32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
break;
|
||||
case 5: //SUB
|
||||
if(opcode==0x81) {INST_NAME("LOCK SUB Ed, Id");} else {INST_NAME("LOCK SUB Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV64xw(x5, i64);
|
||||
emit_sub32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
TSTx_mask(wback, 1, 0, 0); // mask=1
|
||||
B_MARK(cNE);
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_sub32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
B_NEXT_nocond;
|
||||
MARK; // unaligned! also, not enough
|
||||
LDRxw_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIxw(x1, x4, 0, 8); // re-inject
|
||||
emit_sub32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
STLXRB(x3, x1, wback);
|
||||
CBNZx_MARK(x3);
|
||||
STRxw_U12(x1, wback, 0); // put the whole value
|
||||
}
|
||||
break;
|
||||
case 6: //XOR
|
||||
if(opcode==0x81) {INST_NAME("LOCK XOR Ed, Id");} else {INST_NAME("LOCK XOR Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV64xw(x5, i64);
|
||||
emit_xor32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_xor32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
break;
|
||||
case 7: //CMP
|
||||
if(opcode==0x81) {INST_NAME("(LOCK) CMP Ed, Id");} else {INST_NAME("(LOCK) CMP Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED((opcode==0x81)?4:1);
|
||||
// No need to LOCK, this is readonly
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
if(i64) {
|
||||
MOV64xw(x5, i64);
|
||||
emit_cmp32(dyn, ninst, rex, ed, x5, x3, x4, x6);
|
||||
} else {
|
||||
emit_cmp32_0(dyn, ninst, rex, ed, x3, x4);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x87:
|
||||
INST_NAME("LOCK XCHG Ed, Gd");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
GETGD;
|
||||
GETED(0);
|
||||
MOVxw_REG(x1, gd);
|
||||
MOVxw_REG(gd, ed);
|
||||
MOVxw_REG(ed, x1);
|
||||
} else {
|
||||
GETGD;
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
TSTx_mask(ed, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE);
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, ed);
|
||||
STLXRxw(x3, gd, ed);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
B_MARK2_nocond;
|
||||
MARK;
|
||||
LDRxw_U12(x1, ed, 0);
|
||||
STRxw_U12(gd, ed, 0);
|
||||
MARK2;
|
||||
MOVxw_REG(gd, x1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7)
|
||||
{
|
||||
case 0: // INC Ed
|
||||
INST_NAME("LOCK INC Ed");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
emit_inc32(dyn, ninst, rex, ed, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE); // unaligned
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_inc32(dyn, ninst, rex, x1, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
LDRxw_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIxw(x1, x4, 0, 8); // re-inject
|
||||
emit_inc32(dyn, ninst, rex, x1, x3, x4);
|
||||
STLXRB(x3, x1, wback);
|
||||
CBNZw_MARK(x3);
|
||||
STRxw_U12(x1, wback, 0);
|
||||
}
|
||||
break;
|
||||
case 1: //DEC Ed
|
||||
INST_NAME("LOCK DEC Ed");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
emit_dec32(dyn, ninst, rex, ed, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE); // unaligned
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_dec32(dyn, ninst, rex, x1, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
LDRxw_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIxw(x1, x4, 0, 8); // re-inject
|
||||
emit_dec32(dyn, ninst, rex, x1, x3, x4);
|
||||
STLXRB(x3, x1, wback);
|
||||
CBNZw_MARK(x3);
|
||||
STRxw_U12(x1, wback, 0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
Executable
+323
@@ -0,0 +1,323 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
// Get Ex as a double, not a quad (warning, x2 get used)
|
||||
#define GETEX(a, D) \
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3)); \
|
||||
} else { \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, D); \
|
||||
VLDR64_U12(a, ed, fixedaddress); \
|
||||
}
|
||||
|
||||
#define GETG gd = ((nextop&0x38)>>3)+(rex.r<<3)
|
||||
|
||||
#define GETGX(a) gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg(dyn, ninst, x1, gd)
|
||||
|
||||
#define GETGX_empty(a) gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg_empty(dyn, ninst, x1, gd)
|
||||
|
||||
uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback;
|
||||
uint8_t u8;
|
||||
uint64_t u64;
|
||||
int v0, v1;
|
||||
int q0;
|
||||
int d0, d1;
|
||||
int64_t fixedaddress;
|
||||
|
||||
#ifdef PRECISE_CVT
|
||||
int j32;
|
||||
MAYUSE(j32);
|
||||
#endif
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(v0);
|
||||
MAYUSE(v1);
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x10:
|
||||
INST_NAME("MOVSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+ (rex.b<<3);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
d0 = sse_get_reg(dyn, ninst, x1, ed);
|
||||
VMOVeD(v0, 0, d0, 0);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VLDR64_U12(v0, ed, fixedaddress); // upper part reseted
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("MOVSD Ex, Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+ (rex.b<<3);
|
||||
d0 = sse_get_reg(dyn, ninst, x1, ed);
|
||||
VMOVeD(d0, 0, v0, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VSTR64_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
INST_NAME("MOVDDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
d0 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVeD(v0, 0, d0, 0);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VLDR64_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
VMOVeD(v0, 1, v0, 0);
|
||||
break;
|
||||
|
||||
case 0x2A:
|
||||
INST_NAME("CVTSI2SD Gx, Ed");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETED(0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if(rex.w) {
|
||||
SCVTFDx(d1, ed);
|
||||
} else {
|
||||
SCVTFDw(d1, ed);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
break;
|
||||
|
||||
case 0x2C:
|
||||
INST_NAME("CVTTSD2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEX(q0, 0);
|
||||
FCVTZSxwD(gd, q0);
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("CVTSD2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEX(q0, 0);
|
||||
#ifdef PRECISE_CVT
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
UBFXx(x1, x1, 13, 2); // extract round requested
|
||||
LSLx_REG(x1, x1, 3);
|
||||
ADDx_U12(x1, x1, 8); // add the actual add+jump opcodes
|
||||
// Construct a "switch case", with each case 2 instructions, so 8 bytes
|
||||
BL(+4); // Branch with Link to next, so LR gets next PC address
|
||||
ADDx_REG(xLR, xLR, x1);
|
||||
B(xLR); // could use RET, but it's not really one
|
||||
FCVTNSxwD(gd, q0); // 0: Nearest (even)
|
||||
B_NEXT_nocond;
|
||||
FCVTMSxwD(gd, q0); // 1: Toward -inf
|
||||
B_NEXT_nocond;
|
||||
FCVTPSxwD(gd, q0); // 2: Toward +inf
|
||||
B_NEXT_nocond;
|
||||
FCVTZSxwD(gd, q0); // 3: Toward 0
|
||||
#else
|
||||
FCVTNSxwD(gd, q0);
|
||||
#endif
|
||||
break;
|
||||
|
||||
|
||||
case 0x51:
|
||||
INST_NAME("SQRTSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0);
|
||||
FSQRTD(d1, d0);
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
break;
|
||||
|
||||
case 0x58:
|
||||
INST_NAME("ADDSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0);
|
||||
FADDD(d1, v0, d0); // the high part of the vector is erased...
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("MULSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0);
|
||||
FMULD(d1, v0, d0);
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTSD2SS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(d0, 0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FCVT_S_D(d1, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
|
||||
case 0x5C:
|
||||
INST_NAME("SUBSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0);
|
||||
FSUBD(d1, v0, d0);
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("MINSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(v1, 0);
|
||||
// MINSD: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FMINNMD(d0, v0, v1); // NaN handling may be slightly different, is that a problem?
|
||||
VMOVeD(v0, 0, d0, 0); // to not erase uper part
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0);
|
||||
FDIVD(d1, v0, d0);
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("MAXSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(v1, 0);
|
||||
// MAXSD: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FMAXNMD(d0, v0, v1); // NaN handling may be slightly different, is that a problem?
|
||||
VMOVeD(v0, 0, d0, 0); // to not erase uper part
|
||||
break;
|
||||
|
||||
case 0x70:
|
||||
INST_NAME("PSHUFLW Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETEX(v1, 1);
|
||||
GETGX(v0);
|
||||
|
||||
u8 = F8;
|
||||
// only low part need to be suffled. VTBL only handle 8bits value, so the 16bits suffles need to be changed in 8bits
|
||||
u64 = 0;
|
||||
for (int i=0; i<4; ++i) {
|
||||
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+0)<<(i*16+0);
|
||||
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+1)<<(i*16+8);
|
||||
}
|
||||
MOV64x(x2, u64);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VMOVQDfrom(d0, 0, x2);
|
||||
VTBL1_8(d0, v1, d0);
|
||||
VMOVeD(v0, 0, d0, 0);
|
||||
if(v0!=v1) {
|
||||
VMOVeD(v0, 1, v1, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7C:
|
||||
INST_NAME("HADDPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VLDR128_U12(v1, ed, fixedaddress);
|
||||
}
|
||||
VFADDPQS(v0, v0, v1);
|
||||
break;
|
||||
|
||||
case 0xC2:
|
||||
INST_NAME("CMPSD Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(v1, 1);
|
||||
u8 = F8;
|
||||
if((u8&7)==6){
|
||||
FCMPD(v1, v0);
|
||||
} else {
|
||||
FCMPD(v0, v1);
|
||||
}
|
||||
switch(u8&7) {
|
||||
case 0: CSETMx(x2, cEQ); break; // Equal
|
||||
case 1: CSETMx(x2, cMI); break; // Less than
|
||||
case 2: //CSETMx(x2, cLE); break; // Less or equal (or unordered on ARM64, not on x86...)
|
||||
CSETMx(x2, cPL); CSINVx(x2, xZR, x2, cEQ); break; // so use a 2 step here, but 1st test inverted because 2nd step invert again
|
||||
case 3: CSETMx(x2, cVS); break; // NaN
|
||||
case 4: CSETMx(x2, cNE); break; // Not Equal (or unordered on ARM, not on X86...)
|
||||
case 5: CSETMx(x2, cCS); break; // Greater or equal or unordered
|
||||
case 6: CSETMx(x2, cLT); break; // Greater or unordered, test inverted, N!=V so unordereded or less than (inverted)
|
||||
case 7: CSETMx(x2, cVC); break; // not NaN
|
||||
}
|
||||
VMOVQDfrom(v0, 0, x2);
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
INST_NAME("LDDQU Gx,Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 7, rex, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
Executable
+409
@@ -0,0 +1,409 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
// Get Ex as a single, not a quad (warning, x2 get used)
|
||||
#define GETEX(a, D) \
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3)); \
|
||||
} else { \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, 0, D); \
|
||||
VLDR32_U12(a, ed, fixedaddress); \
|
||||
}
|
||||
|
||||
#define GETG gd = ((nextop&0x38)>>3)+(rex.r<<3)
|
||||
|
||||
#define GETGX(a) gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg(dyn, ninst, x1, gd)
|
||||
|
||||
#define GETGX_empty(a) gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg_empty(dyn, ninst, x1, gd)
|
||||
|
||||
uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback;
|
||||
uint64_t u64;
|
||||
int v0, v1;
|
||||
int q0, q1;
|
||||
int d0, d1;
|
||||
int64_t fixedaddress;
|
||||
int64_t j64;
|
||||
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(v0);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(j64);
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x10:
|
||||
INST_NAME("MOVSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
VMOVeS(v0, 0, q0, 0);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VLDR32_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("MOVSS Ex, Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
if(MODREG) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
VMOVeS(q0, 0, v0, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VSTR32_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
INST_NAME("MOVSLDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VLDR128_U12(q1, ed, fixedaddress);
|
||||
}
|
||||
GETGX_empty(q0);
|
||||
VTRNQ1_32(q0, q1, q1);
|
||||
break;
|
||||
|
||||
case 0x16:
|
||||
INST_NAME("MOVSHDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VLDR128_U12(q1, ed, fixedaddress);
|
||||
}
|
||||
GETGX_empty(q0);
|
||||
VTRNQ2_32(q0, q1, q1);
|
||||
break;
|
||||
|
||||
case 0x1E:
|
||||
INST_NAME("NOP / ENDBR32 / ENDBR64");
|
||||
nextop = F8;
|
||||
FAKEED;
|
||||
break;
|
||||
|
||||
case 0x2A:
|
||||
INST_NAME("CVTSI2SS Gx, Ed");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETED(0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if(rex.w) {
|
||||
SCVTFSx(d1, ed);
|
||||
} else {
|
||||
SCVTFSw(d1, ed);
|
||||
}
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
|
||||
case 0x2C:
|
||||
INST_NAME("CVTTSS2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEX(d0, 0);
|
||||
FCVTZSxwS(gd, d0);
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("CVTSS2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEX(q0, 0);
|
||||
#ifdef PRECISE_CVT
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
UBFXx(x1, x1, 13, 2); // extract round requested
|
||||
LSLx_REG(x1, x1, 3);
|
||||
ADDx_U12(x1, x1, 8); // add the actual add+jump opcodes
|
||||
// Construct a "switch case", with each case 2 instructions, so 8 bytes
|
||||
BL(+4); // Branch with Link to next, so LR gets next PC address
|
||||
ADDx_REG(xLR, xLR, x1);
|
||||
B(xLR); // could use RET, but it's not really one
|
||||
FCVTNSxwS(gd, q0); // 0: Nearest (even)
|
||||
B_NEXT_nocond;
|
||||
FCVTMSxwS(gd, q0); // 1: Toward -inf
|
||||
B_NEXT_nocond;
|
||||
FCVTPSxwS(gd, q0); // 2: Toward +inf
|
||||
B_NEXT_nocond;
|
||||
FCVTZSxwS(gd, q0); // 3: Toward 0
|
||||
#else
|
||||
FCVTNSxwS(gd, q0);
|
||||
#endif
|
||||
break;
|
||||
case 0x51:
|
||||
INST_NAME("SQRTSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0);
|
||||
FSQRTS(d1, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
case 0x52:
|
||||
INST_NAME("RSQRTSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(v1, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
// so here: F32: Imm8 = abcd efgh that gives => aBbbbbbc defgh000 00000000 00000000
|
||||
// and want 1.0f = 0x3f800000
|
||||
// so 00111111 10000000 00000000 00000000
|
||||
// a = 0, b = 1, c = 1, d = 1, efgh=0
|
||||
// 0b01110000
|
||||
FMOVS_8(d0, 0b01110000);
|
||||
FSQRTS(v0, v1);
|
||||
FDIVS(d0, d0, v0);
|
||||
VMOVeS(v0, 0, d0, 0);
|
||||
break;
|
||||
|
||||
case 0x58:
|
||||
INST_NAME("ADDSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0);
|
||||
FADDS(d1, v0, d0); // the high part of the vector is erased...
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("MULSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0);
|
||||
FMULS(d1, v0, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTSS2SD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(v1, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FCVT_D_S(d0, v1);
|
||||
VMOVeD(v0, 0, d0, 0);
|
||||
break;
|
||||
case 0x5B:
|
||||
INST_NAME("CVTPS2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(d0, 0);
|
||||
GETGX_empty(v0);
|
||||
VFCVTZSQS(v0, d0);
|
||||
break;
|
||||
|
||||
case 0x5C:
|
||||
INST_NAME("SUBSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0);
|
||||
FSUBS(d1, v0, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("MINSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(v1, 0);
|
||||
// MINSS: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FMINNMS(d0, v0, v1); // NaN handling may be slightly different, is that a problem?
|
||||
VMOVeS(v0, 0, d0, 0); // to not erase uper part
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0);
|
||||
FDIVS(d1, v0, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("MAXSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(v1, 0);
|
||||
// MAXSS: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FMAXNMS(d0, v0, v1); // NaN handling may be slightly different, is that a problem?
|
||||
VMOVeS(v0, 0, d0, 0); // to not erase uper part
|
||||
break;
|
||||
|
||||
case 0x6F:
|
||||
INST_NAME("MOVDQU Gx,Ex");// no alignment constraint on NEON here, so same as MOVDQA
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x70:
|
||||
INST_NAME("PSHUFHW Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETEX(v1, 1);
|
||||
GETGX(v0);
|
||||
|
||||
u8 = F8;
|
||||
// only high part need to be suffled. VTBL only handle 8bits value, so the 16bits suffles need to be changed in 8bits
|
||||
u64 = 0;
|
||||
for (int i=0; i<4; ++i) {
|
||||
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+8)<<(i*16+0);
|
||||
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+9)<<(i*16+8);
|
||||
}
|
||||
MOV64x(x2, u64);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VMOVQDfrom(d0, 0, x2);
|
||||
VTBL1_8(d0, v1, d0);
|
||||
VMOVeD(v0, 1, d0, 0);
|
||||
if(v0!=v1) {
|
||||
VMOVeD(v0, 0, v1, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7E:
|
||||
INST_NAME("MOVQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
FMOVD(v0, v1);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VLDR64_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x7F:
|
||||
INST_NAME("MOVDQU Ex,Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xBC:
|
||||
INST_NAME("TZCNT Gd, Ed");
|
||||
SETFLAGS(X_CF|X_ZF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
TSTxw_REG(ed, ed);
|
||||
BFIw(xFlags, x1, F_CF, 1); // CF = is source 0?
|
||||
RBITxw(x1, ed); // reverse
|
||||
CLZxw(gd, x1); // x2 gets leading 0 == TZCNT
|
||||
TSTxw_REG(gd, gd);
|
||||
CSETw(x1, cEQ);
|
||||
BFIw(xFlags, x1, F_ZF, 1); // ZF = is dest 0?
|
||||
break;
|
||||
|
||||
case 0xC2:
|
||||
INST_NAME("CMPSS Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(v1, 1);
|
||||
u8 = F8;
|
||||
if((u8&7)==6){
|
||||
FCMPS(v1, v0);
|
||||
} else {
|
||||
FCMPS(v0, v1);
|
||||
}
|
||||
switch(u8&7) {
|
||||
case 0: CSETMw(x2, cEQ); break; // Equal
|
||||
case 1: CSETMw(x2, cMI); break; // Less than
|
||||
case 2: //CSETMw(x2, cLE); break; // Less or equal (or unordered on ARM64, not on x86...)
|
||||
CSETMw(x2, cPL); CSINVw(x2, xZR, x2, cEQ); break; // so use a 2 step here, but 1st test inverted because 2nd step invert again
|
||||
case 3: CSETMw(x2, cVS); break; // NaN
|
||||
case 4: CSETMw(x2, cNE); break; // Not Equal (or unordered on ARM, not on X86...)
|
||||
case 5: CSETMw(x2, cCS); break; // Greater or equal or unordered
|
||||
case 6: CSETMw(x2, cLT); break; // Greater or unordered, test inverted, N!=V so unordereded or less than (inverted)
|
||||
case 7: CSETMw(x2, cVC); break; // not NaN
|
||||
}
|
||||
VMOVQSfrom(v0, 0, x2);
|
||||
break;
|
||||
|
||||
case 0xD6:
|
||||
INST_NAME("MOVQ2DQ Gx, Em");
|
||||
nextop = F8;
|
||||
GETGX_empty(v0);
|
||||
if(MODREG) {
|
||||
v1 = mmx_get_reg(dyn, ninst, x1, (nextop&7));
|
||||
VEORQ(v0, v0, v0); // usefull?
|
||||
VMOV(v0, v1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VLDR64_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xE6:
|
||||
INST_NAME("CVTDQ2PD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(v1, 0);
|
||||
GETGX_empty(v0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
SXTL_32(v0, v1);
|
||||
SCVTQFD(v0, v0); // there is only I64 -> Double vector conversion, not from i32
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
Executable
+341
@@ -0,0 +1,341 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "tools/bridge_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "signals.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
void arm_fstp(x64emu_t* emu, void* p)
|
||||
{
|
||||
if(ST0.q!=STld(0).ref)
|
||||
D2LD(&ST0.d, p);
|
||||
else
|
||||
memcpy(p, &STld(0).ld, 10);
|
||||
}
|
||||
|
||||
void arm_print_armreg(x64emu_t* emu, uintptr_t reg, uintptr_t n)
|
||||
{
|
||||
(void)emu;
|
||||
dynarec_log(LOG_DEBUG, "R%lu=0x%lx (%lu)\n", n, reg, reg);
|
||||
}
|
||||
|
||||
void arm_f2xm1(x64emu_t* emu)
|
||||
{
|
||||
ST0.d = exp2(ST0.d) - 1.0;
|
||||
}
|
||||
void arm_fyl2x(x64emu_t* emu)
|
||||
{
|
||||
ST(1).d = log2(ST0.d)*ST(1).d;
|
||||
}
|
||||
void arm_ftan(x64emu_t* emu)
|
||||
{
|
||||
ST0.d = tan(ST0.d);
|
||||
}
|
||||
void arm_fpatan(x64emu_t* emu)
|
||||
{
|
||||
ST1.d = atan2(ST1.d, ST0.d);
|
||||
}
|
||||
void arm_fxtract(x64emu_t* emu)
|
||||
{
|
||||
int32_t tmp32s = (ST1.q&0x7ff0000000000000LL)>>52;
|
||||
tmp32s -= 1023;
|
||||
ST1.d /= exp2(tmp32s);
|
||||
ST0.d = tmp32s;
|
||||
}
|
||||
void arm_fprem(x64emu_t* emu)
|
||||
{
|
||||
int32_t tmp32s = ST0.d / ST1.d;
|
||||
ST0.d -= ST1.d * tmp32s;
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C0 = (tmp32s&1);
|
||||
emu->sw.f.F87_C3 = ((tmp32s>>1)&1);
|
||||
emu->sw.f.F87_C1 = ((tmp32s>>2)&1);
|
||||
}
|
||||
void arm_fyl2xp1(x64emu_t* emu)
|
||||
{
|
||||
ST(1).d = log2(ST0.d + 1.0)*ST(1).d;
|
||||
}
|
||||
void arm_fsincos(x64emu_t* emu)
|
||||
{
|
||||
sincos(ST1.d, &ST1.d, &ST0.d);
|
||||
}
|
||||
void arm_frndint(x64emu_t* emu)
|
||||
{
|
||||
ST0.d = fpu_round(emu, ST0.d);
|
||||
}
|
||||
void arm_fscale(x64emu_t* emu)
|
||||
{
|
||||
if(ST0.d!=0.0)
|
||||
ST0.d *= exp2(trunc(ST1.d));
|
||||
}
|
||||
void arm_fsin(x64emu_t* emu)
|
||||
{
|
||||
ST0.d = sin(ST0.d);
|
||||
}
|
||||
void arm_fcos(x64emu_t* emu)
|
||||
{
|
||||
ST0.d = cos(ST0.d);
|
||||
}
|
||||
|
||||
void arm_fbld(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_fbld(emu, ed);
|
||||
}
|
||||
|
||||
void arm_fild64(x64emu_t* emu, int64_t* ed)
|
||||
{
|
||||
int64_t tmp;
|
||||
memcpy(&tmp, ed, sizeof(tmp));
|
||||
ST0.d = tmp;
|
||||
STll(0).ll = tmp;
|
||||
STll(0).ref = ST0.q;
|
||||
}
|
||||
|
||||
void arm_fbstp(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_fbst(emu, ed);
|
||||
}
|
||||
|
||||
void arm_fistp64(x64emu_t* emu, int64_t* ed)
|
||||
{
|
||||
// used of memcpy to avoid aligments issues
|
||||
if((uint64_t)STll(0).ref==ST(0).q) {
|
||||
memcpy(ed, &STll(0).ll, sizeof(int64_t));
|
||||
} else {
|
||||
int64_t tmp;
|
||||
if(isgreater(ST0.d, (double)(int64_t)0x7fffffffffffffffLL) || isless(ST0.d, (double)(int64_t)0x8000000000000000LL) || !isfinite(ST0.d))
|
||||
tmp = 0x8000000000000000LL;
|
||||
else
|
||||
tmp = fpu_round(emu, ST0.d);
|
||||
memcpy(ed, &tmp, sizeof(tmp));
|
||||
}
|
||||
}
|
||||
|
||||
void arm_fistt64(x64emu_t* emu, int64_t* ed)
|
||||
{
|
||||
// used of memcpy to avoid aligments issues
|
||||
int64_t tmp = ST0.d;
|
||||
memcpy(ed, &tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
void arm_fld(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
memcpy(&STld(0).ld, ed, 10);
|
||||
LD2D(&STld(0), &ST(0).d);
|
||||
STld(0).ref = ST0.q;
|
||||
}
|
||||
|
||||
void arm_ud(x64emu_t* emu)
|
||||
{
|
||||
emit_signal(emu, SIGILL, (void*)R_RIP, 0);
|
||||
}
|
||||
|
||||
void arm_fsave(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_savenv(emu, (char*)ed, 0);
|
||||
|
||||
uint8_t* p = ed;
|
||||
p += 28;
|
||||
for (int i=0; i<8; ++i) {
|
||||
LD2D(p, &ST(i).d);
|
||||
p+=10;
|
||||
}
|
||||
}
|
||||
void arm_frstor(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_loadenv(emu, (char*)ed, 0);
|
||||
|
||||
uint8_t* p = ed;
|
||||
p += 28;
|
||||
for (int i=0; i<8; ++i) {
|
||||
D2LD(&ST(i).d, p);
|
||||
p+=10;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void arm_fprem1(x64emu_t* emu)
|
||||
{
|
||||
// simplified version
|
||||
int32_t tmp32s = round(ST0.d / ST1.d);
|
||||
ST0.d -= ST1.d*tmp32s;
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C0 = (tmp32s&1);
|
||||
emu->sw.f.F87_C3 = ((tmp32s>>1)&1);
|
||||
emu->sw.f.F87_C1 = ((tmp32s>>2)&1);
|
||||
}
|
||||
#define XMM0 0
|
||||
#define XMM8 16
|
||||
#define X870 8
|
||||
#define EMM0 8
|
||||
#define SCRATCH0 24
|
||||
|
||||
// Get a FPU scratch reg
|
||||
int fpu_get_scratch(dynarec_arm_t* dyn)
|
||||
{
|
||||
return SCRATCH0 + dyn->fpu_scratch++; // return an Sx
|
||||
}
|
||||
// Reset scratch regs counter
|
||||
void fpu_reset_scratch(dynarec_arm_t* dyn)
|
||||
{
|
||||
dyn->fpu_scratch = 0;
|
||||
}
|
||||
// Get a x87 double reg
|
||||
int fpu_get_reg_x87(dynarec_arm_t* dyn)
|
||||
{
|
||||
int i=X870;
|
||||
while (dyn->fpuused[i]) ++i;
|
||||
dyn->fpuused[i] = 1;
|
||||
return i; // return a Dx
|
||||
}
|
||||
// Free a FPU double reg
|
||||
void fpu_free_reg(dynarec_arm_t* dyn, int reg)
|
||||
{
|
||||
// TODO: check upper limit?
|
||||
dyn->fpuused[reg] = 0;
|
||||
}
|
||||
// Get an MMX double reg
|
||||
int fpu_get_reg_emm(dynarec_arm_t* dyn, int emm)
|
||||
{
|
||||
dyn->fpuused[EMM0 + emm] = 1;
|
||||
return EMM0 + emm;
|
||||
}
|
||||
// Get an XMM quad reg
|
||||
int fpu_get_reg_xmm(dynarec_arm_t* dyn, int xmm)
|
||||
{
|
||||
if(xmm>7) {
|
||||
dyn->fpuused[XMM8 + xmm - 8] = 1;
|
||||
return XMM8 + xmm - 8;
|
||||
} else {
|
||||
dyn->fpuused[XMM0 + xmm] = 1;
|
||||
return XMM0 + xmm;
|
||||
}
|
||||
}
|
||||
// Reset fpu regs counter
|
||||
void fpu_reset_reg(dynarec_arm_t* dyn)
|
||||
{
|
||||
dyn->fpu_reg = 0;
|
||||
for (int i=0; i<32; ++i)
|
||||
dyn->fpuused[i]=0;
|
||||
}
|
||||
|
||||
#define F8 *(uint8_t*)(addr++)
|
||||
#define F32 *(uint32_t*)(addr+=4, addr-4)
|
||||
#define F32S64 (uint64_t)(int64_t)*(int32_t*)(addr+=4, addr-4)
|
||||
// Get if ED will have the correct parity. Not emiting anything. Parity is 2 for DWORD or 3 for QWORD
|
||||
int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity, int delta)
|
||||
{
|
||||
(void)dyn; (void)ninst;
|
||||
|
||||
uint32_t tested = (1<<parity)-1;
|
||||
if((nextop&0xC0)==0xC0)
|
||||
return 0; // direct register, no parity...
|
||||
if(!(nextop&0xC0)) {
|
||||
if((nextop&7)==4) {
|
||||
uint8_t sib = F8;
|
||||
int sib_reg = (sib>>3)&7;
|
||||
if((sib&0x7)==5) {
|
||||
uint64_t tmp = F32S64;
|
||||
if (sib_reg!=4) {
|
||||
// if XXXXXX+reg<<N then check parity of XXXXX and N should be enough
|
||||
return ((tmp&tested)==0 && (sib>>6)>=parity)?1:0;
|
||||
} else {
|
||||
// just a constant...
|
||||
return (tmp&tested)?0:1;
|
||||
}
|
||||
} else {
|
||||
if(sib_reg==4 && parity<3)
|
||||
return 0; // simple [reg]
|
||||
// don't try [reg1 + reg2<<N], unless reg1 is ESP
|
||||
return ((sib&0x7)==4 && (sib>>6)>=parity)?1:0;
|
||||
}
|
||||
} else if((nextop&7)==5) {
|
||||
uint64_t tmp = F32S64;
|
||||
tmp+=addr+delta;
|
||||
return (tmp&tested)?0:1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0; //Form [reg1 + reg2<<N + XXXXXX]
|
||||
}
|
||||
}
|
||||
|
||||
// Do the GETED, but don't emit anything...
|
||||
uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop)
|
||||
{
|
||||
(void)dyn; (void)addr; (void)ninst;
|
||||
|
||||
if((nextop&0xC0)==0xC0)
|
||||
return addr;
|
||||
if(!(nextop&0xC0)) {
|
||||
if((nextop&7)==4) {
|
||||
uint8_t sib = F8;
|
||||
if((sib&0x7)==5) {
|
||||
addr+=4;
|
||||
}
|
||||
} else if((nextop&7)==5) {
|
||||
addr+=4;
|
||||
}
|
||||
} else {
|
||||
if((nextop&7)==4) {
|
||||
++addr;
|
||||
}
|
||||
if(nextop&0x80) {
|
||||
addr+=4;
|
||||
} else {
|
||||
++addr;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
#undef F8
|
||||
#undef F32
|
||||
|
||||
int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn)
|
||||
{
|
||||
(void)dyn;
|
||||
|
||||
#define PK(a) *(uint8_t*)(addr+a)
|
||||
#define PK32(a) *(int32_t*)(addr+a)
|
||||
|
||||
if(!addr)
|
||||
return 0;
|
||||
if(PK(0)==0xff && PK(1)==0x25) { // "absolute" jump, maybe the GOT (well, RIP relative in fact)
|
||||
uintptr_t a1 = addr + 6 + (PK32(2)); // need to add a check to see if the address is from the GOT !
|
||||
addr = *(uintptr_t*)a1;
|
||||
}
|
||||
if(addr<0x10000) // too low, that is suspicious
|
||||
return 0;
|
||||
onebridge_t *b = (onebridge_t*)(addr);
|
||||
if(b->CC==0xCC && b->S=='S' && b->C=='C' && b->w!=(wrapper_t)0 && b->f!=(uintptr_t)PltResolver) {
|
||||
// found !
|
||||
if(retn) *retn = (b->C3==0xC2)?b->N:0;
|
||||
if(calladdress) *calladdress = addr+1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
#undef PK32
|
||||
#undef PK
|
||||
}
|
||||
Executable
+57
@@ -0,0 +1,57 @@
|
||||
#ifndef __DYNAREC_ARM_FUNCTIONS_H__
|
||||
#define __DYNAREC_ARM_FUNCTIONS_H__
|
||||
|
||||
typedef struct x64emu_s x64emu_t;
|
||||
|
||||
void arm_fstp(x64emu_t* emu, void* p);
|
||||
|
||||
void arm_print_armreg(x64emu_t* emu, uintptr_t reg, uintptr_t n);
|
||||
|
||||
void arm_f2xm1(x64emu_t* emu);
|
||||
void arm_fyl2x(x64emu_t* emu);
|
||||
void arm_ftan(x64emu_t* emu);
|
||||
void arm_fpatan(x64emu_t* emu);
|
||||
void arm_fxtract(x64emu_t* emu);
|
||||
void arm_fprem(x64emu_t* emu);
|
||||
void arm_fyl2xp1(x64emu_t* emu);
|
||||
void arm_fsincos(x64emu_t* emu);
|
||||
void arm_frndint(x64emu_t* emu);
|
||||
void arm_fscale(x64emu_t* emu);
|
||||
void arm_fsin(x64emu_t* emu);
|
||||
void arm_fcos(x64emu_t* emu);
|
||||
void arm_fbld(x64emu_t* emu, uint8_t* ed);
|
||||
void arm_fild64(x64emu_t* emu, int64_t* ed);
|
||||
void arm_fbstp(x64emu_t* emu, uint8_t* ed);
|
||||
void arm_fistp64(x64emu_t* emu, int64_t* ed);
|
||||
void arm_fistt64(x64emu_t* emu, int64_t* ed);
|
||||
void arm_fld(x64emu_t* emu, uint8_t* ed);
|
||||
void arm_fsave(x64emu_t* emu, uint8_t* ed);
|
||||
void arm_frstor(x64emu_t* emu, uint8_t* ed);
|
||||
void arm_fprem1(x64emu_t* emu);
|
||||
|
||||
void arm_ud(x64emu_t* emu);
|
||||
|
||||
// Get an FPU scratch reg
|
||||
int fpu_get_scratch(dynarec_arm_t* dyn);
|
||||
// Reset scratch regs counter
|
||||
void fpu_reset_scratch(dynarec_arm_t* dyn);
|
||||
// Get an x87 double reg
|
||||
int fpu_get_reg_x87(dynarec_arm_t* dyn);
|
||||
// Get an MMX double reg
|
||||
int fpu_get_reg_emm(dynarec_arm_t* dyn, int emm);
|
||||
// Get an XMM quad reg
|
||||
int fpu_get_reg_xmm(dynarec_arm_t* dyn, int xmm);
|
||||
// Free a FPU/MMX/XMM reg
|
||||
void fpu_free_reg(dynarec_arm_t* dyn, int reg);
|
||||
// Reset fpu regs counter
|
||||
void fpu_reset_reg(dynarec_arm_t* dyn);
|
||||
|
||||
// Get if ED will have the correct parity. Not emiting anything. Parity is 2 for DWORD or 3 for QWORD
|
||||
int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity, int delta);
|
||||
// Do the GETED, but don't emit anything...
|
||||
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);
|
||||
|
||||
#endif //__DYNAREC_ARM_FUNCTIONS_H__
|
||||
Executable
+1208
File diff suppressed because it is too large.
Load diff
Executable
+1012
File diff suppressed because it is too large.
Load diff
Executable
+140
@@ -0,0 +1,140 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "custommem.h"
|
||||
|
||||
#ifndef STEP
|
||||
#error No STEP defined
|
||||
#endif
|
||||
|
||||
uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
{
|
||||
int ok = 1;
|
||||
int ninst = 0;
|
||||
uintptr_t ip = addr;
|
||||
uintptr_t init_addr = addr;
|
||||
rex_t rex;
|
||||
int rep; // 0 none, 1=F2 prefix, 2=F3 prefix
|
||||
int need_epilog = 1;
|
||||
dyn->sons_size = 0;
|
||||
// Clean up (because there are multiple passes)
|
||||
dyn->state_flags = 0;
|
||||
dyn->dfnone = 0;
|
||||
dyn->last_ip = ip; // RIP is always set at start of block!
|
||||
MAYUSE(init_addr);
|
||||
fpu_reset(dyn, ninst);
|
||||
// ok, go now
|
||||
INIT;
|
||||
while(ok) {
|
||||
ip = addr;
|
||||
if(dyn->insts && (dyn->insts[ninst].x64.barrier==1)) {
|
||||
dyn->last_ip = 0;
|
||||
NEW_BARRIER_INST;
|
||||
}
|
||||
NEW_INST;
|
||||
fpu_reset_scratch(dyn);
|
||||
#ifdef HAVE_TRACE
|
||||
if(my_context->dec && box64_dynarec_trace) {
|
||||
if((trace_end == 0)
|
||||
|| ((ip >= trace_start) && (ip < trace_end))) {
|
||||
MESSAGE(LOG_DUMP, "TRACE ----\n");
|
||||
fpu_reflectcache(dyn, ninst, x1, x2, x3);
|
||||
GETIP(ip);
|
||||
MOVx_REG(x1, xRIP);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
MOV32w(x2, 1);
|
||||
CALL(PrintTrace, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
MESSAGE(LOG_DUMP, "----------\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
rep = 0;
|
||||
uint8_t pk = PK(0);
|
||||
while((pk==0xF2) || (pk==0xF3)) {
|
||||
rep = pk-0xF1;
|
||||
++addr;
|
||||
pk = PK(0);
|
||||
}
|
||||
while(pk==0x3E) { //Branch Taken Hint ignored
|
||||
++addr;
|
||||
pk = PK(0);
|
||||
}
|
||||
rex.rex = 0;
|
||||
while(pk>=0x40 && pk<=0x4f) {
|
||||
rex.rex = pk;
|
||||
++addr;
|
||||
pk = PK(0);
|
||||
}
|
||||
|
||||
addr = dynarec64_00(dyn, addr, ip, ninst, rex, rep, &ok, &need_epilog);
|
||||
|
||||
INST_EPILOG;
|
||||
|
||||
if(dyn->insts && dyn->insts[ninst+1].x64.barrier) {
|
||||
fpu_purgecache(dyn, ninst, x1, x2, x3);
|
||||
if(dyn->insts[ninst+1].x64.barrier!=2) {
|
||||
dyn->state_flags = 0;
|
||||
dyn->dfnone = 0;
|
||||
}
|
||||
}
|
||||
if(!ok && !need_epilog && dyn->insts && (addr < (dyn->start+dyn->isize))) {
|
||||
ok = 1;
|
||||
}
|
||||
if(!ok && !need_epilog && !dyn->insts && getProtection(addr+3))
|
||||
if(*(uint32_t*)addr!=0) { // check if need to continue (but is next 4 bytes are 0, stop)
|
||||
uintptr_t next = get_closest_next(dyn, addr);
|
||||
if(next && (
|
||||
(((next-addr)<15) && is_nops(dyn, addr, next-addr))
|
||||
||(((next-addr)<30) && is_instructions(dyn, addr, next-addr)) ))
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "Extend block %p, %p -> %p (ninst=%d)\n", dyn, (void*)addr, (void*)next, ninst);
|
||||
ok = 1;
|
||||
} else if(next && (next-addr)<30) {
|
||||
dynarec_log(LOG_DEBUG, "Cannot extend block %p -> %p (%02X %02X %02X %02X %02X %02X %02X %02x)\n", (void*)addr, (void*)next, PK(0), PK(1), PK(2), PK(3), PK(4), PK(5), PK(6), PK(7));
|
||||
}
|
||||
}
|
||||
if(ok<0) {ok = 0; need_epilog=1;}
|
||||
++ninst;
|
||||
#if STEP == 0
|
||||
if(ok && !isJumpTableDefault64((void*)addr))
|
||||
#else
|
||||
if(ok && dyn->insts && (ninst==dyn->size))
|
||||
#endif
|
||||
{
|
||||
#if STEP == 3
|
||||
dynarec_log(LOG_DEBUG, "Stopping block %p (%d / %d)\n",(void*)init_addr, ninst, dyn->size);
|
||||
#endif
|
||||
BARRIER(2);
|
||||
fpu_purgecache(dyn, ninst, x1, x2, x3);
|
||||
jump_to_next(dyn, addr, 0, ninst);
|
||||
ok=0; need_epilog=0;
|
||||
}
|
||||
}
|
||||
if(need_epilog) {
|
||||
fpu_purgecache(dyn, ninst, x1, x2, x3);
|
||||
jump_to_epilog(dyn, ip, 0, ninst); // no linker here, it's an unknow instruction
|
||||
}
|
||||
FINI;
|
||||
MESSAGE(LOG_DUMP, "---- END OF BLOCK ---- (%d, %d sons)\n", dyn->size, dyn->sons_size);
|
||||
return addr;
|
||||
}
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
|
||||
#define INIT uintptr_t sav_addr=addr
|
||||
#define FINI dyn->isize = addr-sav_addr
|
||||
#define MESSAGE(A, ...)
|
||||
#define SETFLAGS(A, B)
|
||||
#define READFLAGS(A)
|
||||
#define EMIT(A)
|
||||
#define JUMP(A) add_next(dyn, (uintptr_t)A)
|
||||
#define NEW_INST ++dyn->size
|
||||
#define INST_EPILOG
|
||||
#define INST_NAME(name)
|
||||
#define DEFAULT \
|
||||
--dyn->size; \
|
||||
*ok = -1; \
|
||||
if(box64_dynarec_log>=LOG_INFO) {\
|
||||
dynarec_log(LOG_NONE, "%p: Dynarec stopped because of Opcode %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", \
|
||||
(void*)ip, PKip(0), \
|
||||
PKip(1), PKip(2), PKip(3), \
|
||||
PKip(4), PKip(5), PKip(6), \
|
||||
PKip(7), PKip(8), PKip(9), \
|
||||
PKip(10),PKip(11),PKip(12), \
|
||||
PKip(13),PKip(14)); \
|
||||
printFunctionAddr(ip, " => "); \
|
||||
dynarec_log(LOG_NONE, "\n"); \
|
||||
}
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
#define INIT
|
||||
#define FINI \
|
||||
dyn->insts[ninst].x64.addr = addr; \
|
||||
if(ninst) dyn->insts[ninst-1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst-1].x64.addr;
|
||||
#define MESSAGE(A, ...)
|
||||
#define EMIT(A)
|
||||
#define READFLAGS(A) dyn->insts[ninst].x64.use_flags = A
|
||||
#define SETFLAGS(A,B) {dyn->insts[ninst].x64.set_flags = A; dyn->insts[ninst].x64.state_flags = B;}
|
||||
#define JUMP(A) dyn->insts[ninst].x64.jmp = A
|
||||
#define BARRIER(A) dyn->insts[ninst].x64.barrier = A
|
||||
#define BARRIER_NEXT(A) if(ninst<dyn->size) dyn->insts[ninst+1].x64.barrier = A
|
||||
|
||||
#define NEW_INST \
|
||||
dyn->insts[ninst].x64.addr = ip; \
|
||||
if(ninst) dyn->insts[ninst-1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst-1].x64.addr;
|
||||
#define INST_EPILOG
|
||||
#define INST_NAME(name)
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#define INIT dyn->arm_size = 0
|
||||
#define FINI if(ninst) {dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size);}
|
||||
|
||||
#define MESSAGE(A, ...)
|
||||
#define EMIT(A) dyn->insts[ninst].size+=4; dyn->arm_size+=4
|
||||
#define NEW_INST if(ninst) {dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size);}
|
||||
#define INST_EPILOG dyn->insts[ninst].epilog = dyn->arm_size;
|
||||
#define INST_NAME(name)
|
||||
#define NEW_BARRIER_INST if(ninst) ++dyn->sons_size
|
||||
#define TABLE64(A, V) {Table64(dyn, (V)); EMIT(0);}
|
||||
#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; Table64(dyn, v.q); EMIT(0);}
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
#define INIT
|
||||
#define FINI
|
||||
#define EMIT(A) \
|
||||
if(box64_dynarec_dump) {dynarec_log(LOG_NONE, "\t%08x\t%s\n", (uint32_t)(A), arm64_print(A, (uintptr_t)dyn->block));} \
|
||||
*(uint32_t*)(dyn->block) = (uint32_t)(A); \
|
||||
dyn->block += 4; dyn->arm_size += 4;\
|
||||
dyn->insts[ninst].size2 += 4
|
||||
|
||||
#define MESSAGE(A, ...) if(box64_dynarec_dump) dynarec_log(LOG_NONE, __VA_ARGS__)
|
||||
#define NEW_INST
|
||||
#define INST_EPILOG
|
||||
#define INST_NAME(name) \
|
||||
if(box64_dynarec_dump) {\
|
||||
printf_x64_instruction(my_context->dec, &dyn->insts[ninst].x64, name); \
|
||||
dynarec_log(LOG_NONE, "%s%p: %d emited opcodes, state=%d/%d, set=%X, use=%X, need=%X%s\n", \
|
||||
(box64_dynarec_dump>1)?"\e[32m":"", \
|
||||
(void*)(dyn->arm_start+dyn->insts[ninst].address), \
|
||||
dyn->insts[ninst].size/4, \
|
||||
dyn->insts[ninst].x64.state_flags, \
|
||||
dyn->state_flags, \
|
||||
dyn->insts[ninst].x64.set_flags, \
|
||||
dyn->insts[ninst].x64.use_flags, \
|
||||
dyn->insts[ninst].x64.need_flags, \
|
||||
(box64_dynarec_dump>1)?"\e[m":""); \
|
||||
}
|
||||
|
||||
#define NEW_BARRIER_INST \
|
||||
if(ninst) { \
|
||||
dyn->sons_x64[dyn->sons_size] = (uintptr_t)ip; \
|
||||
dyn->sons_arm[dyn->sons_size] = dyn->block; \
|
||||
MESSAGE(LOG_DUMP, "----> potential Son here\n");\
|
||||
++dyn->sons_size; \
|
||||
}
|
||||
|
||||
#define TABLE64(A, V) {int val64offset = Table64(dyn, (V)); MESSAGE(LOG_DUMP, " Table64: 0x%lx\n", (V)); LDRx_literal(A, val64offset);}
|
||||
#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; int val64offset = Table64(dyn, v.q); MESSAGE(LOG_DUMP, " FTable64: %g\n", v.d); VLDR64_literal(A, val64offset);}
|
||||
Executable
+62
@@ -0,0 +1,62 @@
|
||||
#ifndef __DYNAREC_ARM_PRIVATE_H_
|
||||
#define __DYNAREC_ARM_PRIVATE_H_
|
||||
|
||||
#include "dynarec_private.h"
|
||||
|
||||
typedef struct x64emu_s x64emu_t;
|
||||
|
||||
typedef struct instruction_arm_s {
|
||||
instruction_x64_t x64;
|
||||
uintptr_t address; // (start) address of the arm emited instruction
|
||||
uintptr_t epilog; // epilog of current instruction (can be start of next, of barrier stuff)
|
||||
int size; // size of the arm emited instruction
|
||||
int size2; // size of the arm emited instrucion after pass2
|
||||
uintptr_t mark, mark2, mark3;
|
||||
uintptr_t markf;
|
||||
uintptr_t markseg;
|
||||
uintptr_t marklock;
|
||||
int pass2choice;// value for choices that are fixed on pass2 for pass3
|
||||
uintptr_t natcall;
|
||||
int retn;
|
||||
} instruction_arm64_t;
|
||||
|
||||
typedef struct dynarec_arm_s {
|
||||
instruction_arm64_t *insts;
|
||||
int32_t size;
|
||||
int32_t cap;
|
||||
uintptr_t start; // start of the block
|
||||
uint32_t isize; // size in byte of x64 instructions included
|
||||
void* block; // memory pointer where next instruction is emited
|
||||
uintptr_t arm_start; // start of the arm code
|
||||
size_t arm_size; // size of emitted arm code
|
||||
int state_flags;// actual state for on-demand flags
|
||||
uintptr_t last_ip; // last set IP in RIP (or NULL if unclean state)
|
||||
int8_t x87cache[8];// cache status for the 8 x87 register behind the fpu stack
|
||||
int8_t x87reg[8]; // reg used for x87cache entry
|
||||
int8_t mmxcache[8];// cache status for the 8 MMX registers
|
||||
int8_t ssecache[16];// cache status for the 16 SSE(2) registers
|
||||
int8_t fpuused[32];// all 8..31 Q reg from fpu, used by x87, sse and mmx
|
||||
int x87stack; // cache stack counter
|
||||
int fpu_scratch;// scratch counter
|
||||
int fpu_reg; // x87/sse/mmx reg counter
|
||||
int dfnone; // if defered flags is already set to df_none
|
||||
uint64_t *table64; // table of 64bits value
|
||||
int table64size;// size of table (will be appended at end of executable code)
|
||||
int table64cap;
|
||||
uintptr_t tablestart;
|
||||
uintptr_t* next; // variable array of "next" jump address
|
||||
int next_sz;
|
||||
int next_cap;
|
||||
uintptr_t* sons_x64; // the x64 address of potential dynablock sons
|
||||
void** sons_arm; // the arm address of potential dynablock sons
|
||||
int sons_size; // number of potential dynablock sons
|
||||
} dynarec_arm_t;
|
||||
|
||||
void add_next(dynarec_arm_t *dyn, uintptr_t addr);
|
||||
uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr);
|
||||
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n);
|
||||
int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n);
|
||||
|
||||
int Table64(dynarec_arm_t *dyn, uint64_t val); // add a value to etable64 (if needed) and gives back the imm19 to use in LDR_literal
|
||||
|
||||
#endif //__DYNAREC_ARM_PRIVATE_H_
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
#ifndef __DYNAREC_PRIVATE_H_
|
||||
#define __DYNAREC_PRIVATE_H_
|
||||
|
||||
// all flags for the use_flags field
|
||||
#define X_CF (1<<0)
|
||||
#define X_PF (1<<1)
|
||||
#define X_AF (1<<2)
|
||||
#define X_ZF (1<<3)
|
||||
#define X_SF (1<<4)
|
||||
#define X_OF (1<<5)
|
||||
#define X_ALL ((1<<6)-1)
|
||||
#define X_PEND (0x1000)
|
||||
|
||||
// all state flags
|
||||
#define SF_UNKNOWN 0
|
||||
#define SF_SET 1
|
||||
#define SF_PENDING 2
|
||||
#define SF_SET_PENDING 3
|
||||
#define SF_MAYSET 4
|
||||
#define SF_SUBSET 5
|
||||
|
||||
typedef struct instruction_x64_s {
|
||||
uintptr_t addr; //address of the instruction
|
||||
int32_t size; // size of the instruction
|
||||
int barrier; // next instruction is a jump point, so no optim allowed
|
||||
uintptr_t jmp; // offset to jump to, even if conditionnal (0 if not), no relative offset here
|
||||
int jmp_insts; // instuction to jump to (-1 if out of the block)
|
||||
uint32_t use_flags; // 0 or combination of X_?F
|
||||
uint32_t set_flags; // 0 or combination of X_?F
|
||||
uint32_t need_flags; // calculated
|
||||
int state_flags; // One of SF_XXX state
|
||||
} instruction_x64_t;
|
||||
|
||||
void printf_x64_instruction(zydis_dec_t* dec, instruction_x64_t* inst, const char* name);
|
||||
|
||||
#endif //__DYNAREC_PRIVATE_H_
|
||||
+68
-65
@@ -225,13 +225,14 @@ const char* DumpRelType(int t)
|
||||
return buff;
|
||||
}
|
||||
|
||||
const char* DumpSym(elfheader_t *h, Elf64_Sym* sym)
|
||||
const char* DumpSym(elfheader_t *h, Elf64_Sym* sym, int version)
|
||||
{
|
||||
static char buff[4096];
|
||||
const char* vername = (version==-1)?"(none)":((version==0)?"*local*":((version==1)?"*global*":GetSymbolVersion(h, version)));
|
||||
memset(buff, 0, sizeof(buff));
|
||||
sprintf(buff, "\"%s\", value=%p, size=%ld, info/other=%d/%d index=%d",
|
||||
sprintf(buff, "\"%s\", value=%p, size=%ld, info/other=%d/%d index=%d (ver=%d/%s)",
|
||||
h->DynStr+sym->st_name, (void*)sym->st_value, sym->st_size,
|
||||
sym->st_info, sym->st_other, sym->st_shndx);
|
||||
sym->st_info, sym->st_other, sym->st_shndx, version, vername);
|
||||
return buff;
|
||||
}
|
||||
|
||||
@@ -246,116 +247,118 @@ const char* IdxSymName(elfheader_t *h, int sym)
|
||||
|
||||
void DumpMainHeader(Elf64_Ehdr *header, elfheader_t *h)
|
||||
{
|
||||
if(box64_log>=LOG_DUMP) {
|
||||
printf_log(LOG_DUMP, "ELF Dump main header\n");
|
||||
printf_log(LOG_DUMP, " Entry point = %p\n", (void*)header->e_entry);
|
||||
printf_log(LOG_DUMP, " Program Header table offset = %p\n", (void*)header->e_phoff);
|
||||
printf_log(LOG_DUMP, " Section Header table offset = %p\n", (void*)header->e_shoff);
|
||||
printf_log(LOG_DUMP, " Flags = 0x%X\n", header->e_flags);
|
||||
printf_log(LOG_DUMP, " ELF Header size = %d\n", header->e_ehsize);
|
||||
printf_log(LOG_DUMP, " Program Header Entry num/size = %d(%d)/%d\n", h->numPHEntries, header->e_phnum, header->e_phentsize);
|
||||
printf_log(LOG_DUMP, " Section Header Entry num/size = %d(%d)/%d\n", h->numSHEntries, header->e_shnum, header->e_shentsize);
|
||||
printf_log(LOG_DUMP, " Section Header index num = %d(%d)\n", h->SHIdx, header->e_shstrndx);
|
||||
printf_log(LOG_DUMP, "ELF Dump ==========\n");
|
||||
if(box64_dump) {
|
||||
printf_dump(LOG_NEVER, "ELF Dump main header\n");
|
||||
printf_dump(LOG_NEVER, " Entry point = %p\n", (void*)header->e_entry);
|
||||
printf_dump(LOG_NEVER, " Program Header table offset = %p\n", (void*)header->e_phoff);
|
||||
printf_dump(LOG_NEVER, " Section Header table offset = %p\n", (void*)header->e_shoff);
|
||||
printf_dump(LOG_NEVER, " Flags = 0x%X\n", header->e_flags);
|
||||
printf_dump(LOG_NEVER, " ELF Header size = %d\n", header->e_ehsize);
|
||||
printf_dump(LOG_NEVER, " Program Header Entry num/size = %zu(%d)/%d\n", h->numPHEntries, header->e_phnum, header->e_phentsize);
|
||||
printf_dump(LOG_NEVER, " Section Header Entry num/size = %zu(%d)/%d\n", h->numSHEntries, header->e_shnum, header->e_shentsize);
|
||||
printf_dump(LOG_NEVER, " Section Header index num = %zu(%d)\n", h->SHIdx, header->e_shstrndx);
|
||||
printf_dump(LOG_NEVER, "ELF Dump ==========\n");
|
||||
|
||||
printf_log(LOG_DUMP, "ELF Dump PEntries (%d)\n", h->numSHEntries);
|
||||
for (int i=0; i<h->numPHEntries; ++i)
|
||||
printf_log(LOG_DUMP, " PHEntry %04d : %s\n", i, DumpPHEntry(h->PHEntries+i));
|
||||
printf_log(LOG_DUMP, "ELF Dump PEntries ====\n");
|
||||
printf_dump(LOG_NEVER, "ELF Dump PEntries (%zu)\n", h->numPHEntries);
|
||||
for (size_t i=0; i<h->numPHEntries; ++i)
|
||||
printf_dump(LOG_NEVER, " PHEntry %04zu : %s\n", i, DumpPHEntry(h->PHEntries+i));
|
||||
printf_dump(LOG_NEVER, "ELF Dump PEntries ====\n");
|
||||
|
||||
printf_log(LOG_DUMP, "ELF Dump Sections (%d)\n", h->numSHEntries);
|
||||
for (int i=0; i<h->numSHEntries; ++i)
|
||||
printf_log(LOG_DUMP, " Section %04d : %s\n", i, DumpSection(h->SHEntries+i, h->SHStrTab));
|
||||
printf_log(LOG_DUMP, "ELF Dump Sections ====\n");
|
||||
printf_dump(LOG_NEVER, "ELF Dump Sections (%zu)\n", h->numSHEntries);
|
||||
for (size_t i=0; i<h->numSHEntries; ++i)
|
||||
printf_dump(LOG_NEVER, " Section %04zu : %s\n", i, DumpSection(h->SHEntries+i, h->SHStrTab));
|
||||
printf_dump(LOG_NEVER, "ELF Dump Sections ====\n");
|
||||
}
|
||||
}
|
||||
|
||||
void DumpSymTab(elfheader_t *h)
|
||||
{
|
||||
if(box64_log>=LOG_DUMP && h->SymTab) {
|
||||
if(box64_dump && h->SymTab) {
|
||||
const char* name = ElfName(h);
|
||||
printf_log(LOG_DUMP, "ELF Dump SymTab(%d)=\n", h->numSymTab);
|
||||
for (int i=0; i<h->numSymTab; ++i)
|
||||
printf_log(LOG_DUMP, " %s:SymTab[%d] = \"%s\", value=%p, size=%ld, info/other=%d/%d index=%d\n", name,
|
||||
printf_dump(LOG_NEVER, "ELF Dump SymTab(%zu)=\n", h->numSymTab);
|
||||
for (size_t i=0; i<h->numSymTab; ++i)
|
||||
printf_dump(LOG_NEVER, " %s:SymTab[%zu] = \"%s\", value=%p, size=%ld, info/other=%d/%d index=%d\n", name,
|
||||
i, h->StrTab+h->SymTab[i].st_name, (void*)h->SymTab[i].st_value, h->SymTab[i].st_size,
|
||||
h->SymTab[i].st_info, h->SymTab[i].st_other, h->SymTab[i].st_shndx);
|
||||
printf_log(LOG_DUMP, "ELF Dump SymTab=====\n");
|
||||
printf_dump(LOG_NEVER, "ELF Dump SymTab=====\n");
|
||||
}
|
||||
}
|
||||
|
||||
void DumpDynamicSections(elfheader_t *h)
|
||||
{
|
||||
if(box64_log>=LOG_DUMP && h->Dynamic) {
|
||||
printf_log(LOG_DUMP, "ELF Dump Dynamic(%d)=\n", h->numDynamic);
|
||||
for (int i=0; i<h->numDynamic; ++i)
|
||||
printf_log(LOG_DUMP, " Dynamic %04d : %s\n", i, DumpDynamic(h->Dynamic+i));
|
||||
printf_log(LOG_DUMP, "ELF Dump Dynamic=====\n");
|
||||
if(box64_dump && h->Dynamic) {
|
||||
printf_dump(LOG_NEVER, "ELF Dump Dynamic(%zu)=\n", h->numDynamic);
|
||||
for (size_t i=0; i<h->numDynamic; ++i)
|
||||
printf_dump(LOG_NEVER, " Dynamic %04zu : %s\n", i, DumpDynamic(h->Dynamic+i));
|
||||
printf_dump(LOG_NEVER, "ELF Dump Dynamic=====\n");
|
||||
}
|
||||
}
|
||||
|
||||
void DumpDynSym(elfheader_t *h)
|
||||
{
|
||||
if(box64_log>=LOG_DUMP && h->DynSym) {
|
||||
if(box64_dump && h->DynSym) {
|
||||
const char* name = ElfName(h);
|
||||
printf_log(LOG_DUMP, "ELF Dump DynSym(%d)=\n", h->numDynSym);
|
||||
for (int i=0; i<h->numDynSym; ++i)
|
||||
printf_log(LOG_DUMP, " %s:DynSym[%d] = %s\n", name, i, DumpSym(h, h->DynSym+i));
|
||||
printf_log(LOG_DUMP, "ELF Dump DynSym=====\n");
|
||||
printf_dump(LOG_NEVER, "ELF Dump DynSym(%zu)=\n", h->numDynSym);
|
||||
for (size_t i=0; i<h->numDynSym; ++i) {
|
||||
int version = h->VerSym?((Elf64_Half*)((uintptr_t)h->VerSym+h->delta))[i]:-1;
|
||||
printf_dump(LOG_NEVER, " %s:DynSym[%zu] = %s\n", name, i, DumpSym(h, h->DynSym+i, version));
|
||||
}
|
||||
printf_dump(LOG_NEVER, "ELF Dump DynSym=====\n");
|
||||
}
|
||||
}
|
||||
|
||||
void DumpDynamicNeeded(elfheader_t *h)
|
||||
{
|
||||
if(box64_log>=LOG_DUMP && h->DynStrTab) {
|
||||
printf_log(LOG_DUMP, "ELF Dump DT_NEEDED=====\n");
|
||||
for (int i=0; i<h->numDynamic; ++i)
|
||||
if(box64_dump && h->DynStrTab) {
|
||||
printf_dump(LOG_NEVER, "ELF Dump DT_NEEDED=====\n");
|
||||
for (size_t i=0; i<h->numDynamic; ++i)
|
||||
if(h->Dynamic[i].d_tag==DT_NEEDED) {
|
||||
printf_log(LOG_DUMP, " Needed : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
|
||||
printf_dump(LOG_NEVER, " Needed : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
|
||||
}
|
||||
printf_log(LOG_DUMP, "ELF Dump DT_NEEDED=====\n");
|
||||
printf_dump(LOG_NEVER, "ELF Dump DT_NEEDED=====\n");
|
||||
}
|
||||
}
|
||||
|
||||
void DumpDynamicRPath(elfheader_t *h)
|
||||
{
|
||||
if(box64_log>=LOG_DUMP && h->DynStrTab) {
|
||||
printf_log(LOG_DUMP, "ELF Dump DT_RPATH/DT_RUNPATH=====\n");
|
||||
for (int i=0; i<h->numDynamic; ++i) {
|
||||
if(box64_dump && h->DynStrTab) {
|
||||
printf_dump(LOG_NEVER, "ELF Dump DT_RPATH/DT_RUNPATH=====\n");
|
||||
for (size_t i=0; i<h->numDynamic; ++i) {
|
||||
if(h->Dynamic[i].d_tag==DT_RPATH) {
|
||||
printf_log(LOG_DUMP, " RPATH : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
|
||||
printf_dump(LOG_NEVER, " RPATH : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
|
||||
}
|
||||
if(h->Dynamic[i].d_tag==DT_RUNPATH) {
|
||||
printf_log(LOG_DUMP, " RUNPATH : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
|
||||
printf_dump(LOG_NEVER, " RUNPATH : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
|
||||
}
|
||||
}
|
||||
printf_log(LOG_DUMP, "=====ELF Dump DT_RPATH/DT_RUNPATH\n");
|
||||
printf_dump(LOG_NEVER, "=====ELF Dump DT_RPATH/DT_RUNPATH\n");
|
||||
}
|
||||
}
|
||||
|
||||
void DumpRelTable(elfheader_t *h, int cnt, Elf64_Rel *rel, const char* name)
|
||||
{
|
||||
if(box64_log>=LOG_DUMP) {
|
||||
if(box64_dump) {
|
||||
const char* elfname = ElfName(h);
|
||||
printf_log(LOG_DUMP, "ELF Dump %s Table(%d) @%p\n", name, cnt, rel);
|
||||
printf_dump(LOG_NEVER, "ELF Dump %s Table(%d) @%p\n", name, cnt, rel);
|
||||
for (int i = 0; i<cnt; ++i)
|
||||
printf_log(LOG_DUMP, " %s:Rel[%d] = %p (0x%lX: %s, sym=0x%0lX/%s)\n", elfname,
|
||||
printf_dump(LOG_NEVER, " %s:Rel[%d] = %p (0x%lX: %s, sym=0x%0lX/%s)\n", elfname,
|
||||
i, (void*)rel[i].r_offset, rel[i].r_info, DumpRelType(ELF64_R_TYPE(rel[i].r_info)),
|
||||
ELF64_R_SYM(rel[i].r_info), IdxSymName(h, ELF64_R_SYM(rel[i].r_info)));
|
||||
printf_log(LOG_DUMP, "ELF Dump Rel Table=====\n");
|
||||
printf_dump(LOG_NEVER, "ELF Dump Rel Table=====\n");
|
||||
}
|
||||
}
|
||||
|
||||
void DumpRelATable(elfheader_t *h, int cnt, Elf64_Rela *rela, const char* name)
|
||||
{
|
||||
if(box64_log>=LOG_DUMP && h->rela) {
|
||||
if(box64_dump && h->rela) {
|
||||
const char* elfname = ElfName(h);
|
||||
printf_log(LOG_DUMP, "ELF Dump %s Table(%d) @%p\n", name, cnt, rela);
|
||||
printf_dump(LOG_NEVER, "ELF Dump %s Table(%d) @%p\n", name, cnt, rela);
|
||||
for (int i = 0; i<cnt; ++i)
|
||||
printf_log(LOG_DUMP, " %s:RelA[%d] = %p (0x%lX: %s, sym=0x%lX/%s) Addend=%ld\n", elfname,
|
||||
printf_dump(LOG_NEVER, " %s:%s[%d] = %p (0x%lX: %s, sym=0x%lX/%s) Addend=0x%lx\n", elfname, name,
|
||||
i, (void*)rela[i].r_offset, rela[i].r_info, DumpRelType(ELF64_R_TYPE(rela[i].r_info)),
|
||||
ELF64_R_SYM(rela[i].r_info), IdxSymName(h, ELF64_R_SYM(rela[i].r_info)),
|
||||
rela[i].r_addend);
|
||||
printf_log(LOG_DUMP, "ELF Dump RelA Table=====\n");
|
||||
printf_dump(LOG_NEVER, "ELF Dump %s Table=====\n", name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,24 +369,24 @@ void DumpBinary(char* p, int sz)
|
||||
unsigned char* d = (unsigned char*)p;
|
||||
int delta = ((uintptr_t)p)&0xf;
|
||||
for (int i = 0; sz; ++i) {
|
||||
printf_log(LOG_DUMP, "%p ", (void*)(((uintptr_t)d)&~0xf));
|
||||
printf_dump(LOG_NEVER, "%p ", (void*)(((uintptr_t)d)&~0xf));
|
||||
int n = 16 - delta;
|
||||
if (n>sz) n = sz;
|
||||
int fill = 16-sz;
|
||||
for (int j = 0; j<delta; ++j)
|
||||
printf_log(LOG_DUMP, " ");
|
||||
printf_dump(LOG_NEVER, " ");
|
||||
for (int j = 0; j<n; ++j)
|
||||
printf_log(LOG_DUMP, "%02X ", d[j]);
|
||||
printf_dump(LOG_NEVER, "%02X ", d[j]);
|
||||
for (int j = 0; j<fill; ++j)
|
||||
printf_log(LOG_DUMP, " ");
|
||||
printf_log(LOG_DUMP, " | ");
|
||||
printf_dump(LOG_NEVER, " ");
|
||||
printf_dump(LOG_NEVER, " | ");
|
||||
for (int j = 0; j<delta; ++j)
|
||||
printf_log(LOG_DUMP, " ");
|
||||
printf_dump(LOG_NEVER, " ");
|
||||
for (int j = 0; j<n; ++j)
|
||||
printf_log(LOG_DUMP, "%c", (d[j]<32 || d[j]>127)?'.':d[j]);
|
||||
printf_dump(LOG_NEVER, "%c", (d[j]<32 || d[j]>127)?'.':d[j]);
|
||||
for (int j = 0; j<fill; ++j)
|
||||
printf_log(LOG_DUMP, " ");
|
||||
printf_log(LOG_DUMP, "\n");
|
||||
printf_dump(LOG_NEVER, " ");
|
||||
printf_dump(LOG_NEVER, "\n");
|
||||
d+=n;
|
||||
sz-=n;
|
||||
delta=0;
|
||||
|
||||
+407
-215
File diff suppressed because it is too large.
Load diff
@@ -13,23 +13,28 @@ typedef struct needed_libs_s needed_libs_t;
|
||||
struct elfheader_s {
|
||||
char* name;
|
||||
char* path; // Resolved path to file
|
||||
int numPHEntries;
|
||||
size_t numPHEntries;
|
||||
Elf64_Phdr *PHEntries;
|
||||
int numSHEntries;
|
||||
size_t numSHEntries;
|
||||
Elf64_Shdr *SHEntries;
|
||||
int SHIdx;
|
||||
int numSST;
|
||||
size_t SHIdx;
|
||||
size_t numSST;
|
||||
char* SHStrTab;
|
||||
char* StrTab;
|
||||
Elf64_Sym* SymTab;
|
||||
int numSymTab;
|
||||
size_t numSymTab;
|
||||
char* DynStr;
|
||||
Elf64_Sym* DynSym;
|
||||
int numDynSym;
|
||||
size_t numDynSym;
|
||||
Elf64_Dyn* Dynamic;
|
||||
int numDynamic;
|
||||
size_t numDynamic;
|
||||
char* DynStrTab;
|
||||
int szDynStrTab;
|
||||
size_t szDynStrTab;
|
||||
Elf64_Half* VerSym;
|
||||
Elf64_Verneed* VerNeed;
|
||||
int szVerNeed;
|
||||
Elf64_Verdef* VerDef;
|
||||
int szVerDef;
|
||||
int e_type;
|
||||
|
||||
intptr_t delta; // should be 0
|
||||
@@ -37,19 +42,19 @@ struct elfheader_s {
|
||||
uintptr_t entrypoint;
|
||||
uintptr_t initentry;
|
||||
uintptr_t initarray;
|
||||
int initarray_sz;
|
||||
size_t initarray_sz;
|
||||
uintptr_t finientry;
|
||||
uintptr_t finiarray;
|
||||
int finiarray_sz;
|
||||
size_t finiarray_sz;
|
||||
|
||||
uintptr_t rel;
|
||||
int relsz;
|
||||
size_t relsz;
|
||||
int relent;
|
||||
uintptr_t rela;
|
||||
int relasz;
|
||||
size_t relasz;
|
||||
int relaent;
|
||||
uintptr_t jmprel;
|
||||
int pltsz;
|
||||
size_t pltsz;
|
||||
int pltent;
|
||||
uint64_t pltrel;
|
||||
uintptr_t gotplt;
|
||||
@@ -60,18 +65,18 @@ struct elfheader_s {
|
||||
uintptr_t plt;
|
||||
uintptr_t plt_end;
|
||||
uintptr_t text;
|
||||
int textsz;
|
||||
size_t textsz;
|
||||
|
||||
uintptr_t paddr;
|
||||
uintptr_t vaddr;
|
||||
int align;
|
||||
size_t align;
|
||||
uint64_t memsz;
|
||||
uint64_t stacksz;
|
||||
int stackalign;
|
||||
uint32_t tlssize;
|
||||
int tlsalign;
|
||||
size_t stackalign;
|
||||
uint64_t tlssize;
|
||||
size_t tlsalign;
|
||||
|
||||
int32_t tlsbase; // the base of the tlsdata in the global tlsdata (always negative)
|
||||
int64_t tlsbase; // the base of the tlsdata in the global tlsdata (always negative)
|
||||
|
||||
int init_done;
|
||||
int fini_done;
|
||||
@@ -133,4 +138,4 @@ struct elfheader_s {
|
||||
|
||||
elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec);
|
||||
|
||||
#endif //__ELFLOADER_PRIVATE_H_
|
||||
#endif //__ELFLOADER_PRIVATE_H_
|
||||
+146
-67
@@ -43,7 +43,7 @@ int FindSection(Elf64_Shdr *s, int n, char* SHStrTab, const char* name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LoadNamedSection(FILE *f, Elf64_Shdr *s, int size, char* SHStrTab, const char* name, const char* clearname, uint32_t type, void** what, int* num)
|
||||
void LoadNamedSection(FILE *f, Elf64_Shdr *s, int size, char* SHStrTab, const char* name, const char* clearname, uint32_t type, void** what, size_t* num)
|
||||
{
|
||||
int n = FindSection(s, size, SHStrTab, name);
|
||||
printf_log(LOG_DEBUG, "Loading %s (idx = %d)\n", clearname, n);
|
||||
@@ -71,8 +71,13 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
return NULL;
|
||||
}
|
||||
if(header.e_ident[EI_CLASS]!=ELFCLASS64) {
|
||||
if(strstr(name, ".so")) {
|
||||
// less naging on libs...
|
||||
printf_log(LOG_DEBUG, "Not a 64bits ELF (%d)\n", header.e_ident[EI_CLASS]);
|
||||
return NULL;
|
||||
}
|
||||
if(header.e_ident[EI_CLASS]==ELFCLASS32) {
|
||||
printf_log(LOG_INFO, "This is a 32bits ELF! box64 can only run 64bits ELF!\n");
|
||||
printf_log(LOG_INFO, "This is a 32bits ELF! box64 can only run 64bits ELF (%s)!\n", name);
|
||||
} else {
|
||||
printf_log(LOG_INFO, "Not a 64bits ELF (%d)\n", header.e_ident[EI_CLASS]);
|
||||
}
|
||||
@@ -136,7 +141,7 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
h->numSHEntries = section.sh_size;
|
||||
}
|
||||
// now read all section headers
|
||||
printf_log(LOG_DEBUG, "Read %d Section header\n", h->numSHEntries);
|
||||
printf_log(LOG_DEBUG, "Read %zu Section header\n", h->numSHEntries);
|
||||
h->SHEntries = (Elf64_Shdr*)calloc(h->numSHEntries, sizeof(Elf64_Shdr));
|
||||
fseeko64(f, header.e_shoff ,SEEK_SET);
|
||||
if(fread(h->SHEntries, sizeof(Elf64_Shdr), h->numSHEntries, f)!=h->numSHEntries) {
|
||||
@@ -152,7 +157,7 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
}
|
||||
}
|
||||
|
||||
printf_log(LOG_DEBUG, "Read %d Program header\n", h->numPHEntries);
|
||||
printf_log(LOG_DEBUG, "Read %zu Program header\n", h->numPHEntries);
|
||||
h->PHEntries = (Elf64_Phdr*)calloc(h->numPHEntries, sizeof(Elf64_Phdr));
|
||||
fseeko64(f, header.e_phoff ,SEEK_SET);
|
||||
if(fread(h->PHEntries, sizeof(Elf64_Phdr), h->numPHEntries, f)!=h->numPHEntries) {
|
||||
@@ -167,68 +172,125 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
h->SHIdx = h->SHEntries[0].sh_link;
|
||||
}
|
||||
if(h->SHIdx > h->numSHEntries) {
|
||||
printf_log(LOG_INFO, "Incoherent Section String Table Index : %d / %d\n", h->SHIdx, h->numSHEntries);
|
||||
printf_log(LOG_INFO, "Incoherent Section String Table Index : %zu / %zu\n", h->SHIdx, h->numSHEntries);
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
}
|
||||
// load Section table
|
||||
printf_log(LOG_DEBUG, "Loading Sections Table String (idx = %d)\n", h->SHIdx);
|
||||
printf_log(LOG_DEBUG, "Loading Sections Table String (idx = %zu)\n", h->SHIdx);
|
||||
if(LoadSH(f, h->SHEntries+h->SHIdx, (void*)&h->SHStrTab, ".shstrtab", SHT_STRTAB)) {
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
}
|
||||
if(box64_log>=LOG_DUMP) DumpMainHeader(&header, h);
|
||||
if(box64_dump) DumpMainHeader(&header, h);
|
||||
|
||||
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".strtab", "SymTab Strings", SHT_STRTAB, (void**)&h->StrTab, NULL);
|
||||
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".symtab", "SymTab", SHT_SYMTAB, (void**)&h->SymTab, &h->numSymTab);
|
||||
if(box64_log>=LOG_DUMP && h->SymTab) DumpSymTab(h);
|
||||
if(box64_dump && h->SymTab) DumpSymTab(h);
|
||||
|
||||
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynamic", "Dynamic", SHT_DYNAMIC, (void**)&h->Dynamic, &h->numDynamic);
|
||||
if(box64_log>=LOG_DUMP && h->Dynamic) DumpDynamicSections(h);
|
||||
if(box64_dump && h->Dynamic) DumpDynamicSections(h);
|
||||
// grab DT_REL & DT_RELA stuffs
|
||||
// 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;
|
||||
for (size_t i=0; i<h->numDynamic; ++i) {
|
||||
Elf64_Dyn d = h->Dynamic[i];
|
||||
Elf64_Word val = d.d_un.d_val;
|
||||
Elf64_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 = ptr;
|
||||
break;
|
||||
case DT_PLTREL:
|
||||
h->pltrel = val;
|
||||
break;
|
||||
case DT_PLTRELSZ:
|
||||
h->pltsz = val;
|
||||
break;
|
||||
case DT_JMPREL:
|
||||
h->jmprel = ptr;
|
||||
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(Elf64_Addr);
|
||||
printf_log(LOG_DEBUG, "The DT_INIT_ARRAYSZ is %zu\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(Elf64_Addr);
|
||||
printf_log(LOG_DEBUG, "The DT_FINI_ARRAYSZ is %zu\n", h->finiarray_sz);
|
||||
break;
|
||||
case DT_VERNEEDNUM:
|
||||
h->szVerNeed = val;
|
||||
printf_log(LOG_DEBUG, "The DT_VERNEEDNUM is %d\n", h->szVerNeed);
|
||||
break;
|
||||
case DT_VERNEED:
|
||||
h->VerNeed = (Elf64_Verneed*)ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_VERNEED is at address %p\n", h->VerNeed);
|
||||
break;
|
||||
case DT_VERDEFNUM:
|
||||
h->szVerDef = val;
|
||||
printf_log(LOG_DEBUG, "The DT_VERDEFNUM is %d\n", h->szVerDef);
|
||||
break;
|
||||
case DT_VERDEF:
|
||||
h->VerDef = (Elf64_Verdef*)ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_VERDEF is at address %p\n", h->VerDef);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(h->rel) {
|
||||
if(h->relent != sizeof(Elf64_Rel)) {
|
||||
printf_log(LOG_NONE, "Rel Table Entry size invalid (0x%x should be 0x%lx)\n", h->relent, sizeof(Elf64_Rel));
|
||||
printf_log(LOG_NONE, "Rel Table Entry size invalid (0x%x should be 0x%zx)\n", h->relent, sizeof(Elf64_Rel));
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
}
|
||||
printf_log(LOG_DEBUG, "Rel Table @%p (0x%x/0x%x)\n", (void*)h->rel, h->relsz, h->relent);
|
||||
printf_log(LOG_DEBUG, "Rel Table @%p (0x%zx/0x%x)\n", (void*)h->rel, h->relsz, h->relent);
|
||||
}
|
||||
if(h->rela) {
|
||||
if(h->relaent != sizeof(Elf64_Rela)) {
|
||||
printf_log(LOG_NONE, "RelA Table Entry size invalid (0x%x should be 0x%lx)\n", h->relaent, sizeof(Elf64_Rela));
|
||||
printf_log(LOG_NONE, "RelA Table Entry size invalid (0x%x should be 0x%zx)\n", h->relaent, sizeof(Elf64_Rela));
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
}
|
||||
printf_log(LOG_DEBUG, "RelA Table @%p (0x%x/0x%x)\n", (void*)h->rela, h->relasz, h->relaent);
|
||||
printf_log(LOG_DEBUG, "RelA Table @%p (0x%zx/0x%x)\n", (void*)h->rela, h->relasz, h->relaent);
|
||||
}
|
||||
if(h->jmprel) {
|
||||
if(h->pltrel == DT_REL) {
|
||||
@@ -236,16 +298,16 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
} else if(h->pltrel == DT_RELA) {
|
||||
h->pltent = sizeof(Elf64_Rela);
|
||||
} else {
|
||||
printf_log(LOG_NONE, "PLT Table type is unknown (size = 0x%x, type=%ld)\n", h->pltsz, h->pltrel);
|
||||
printf_log(LOG_NONE, "PLT Table type is unknown (size = 0x%zx, type=%ld)\n", h->pltsz, h->pltrel);
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
}
|
||||
if((h->pltsz / h->pltent)*h->pltent != h->pltsz) {
|
||||
printf_log(LOG_NONE, "PLT Table Entry size invalid (0x%x, ent=0x%x, type=%ld)\n", h->pltsz, h->pltent, h->pltrel);
|
||||
printf_log(LOG_NONE, "PLT Table Entry size invalid (0x%zx, ent=0x%x, type=%ld)\n", h->pltsz, h->pltent, h->pltrel);
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
}
|
||||
printf_log(LOG_DEBUG, "PLT Table @%p (type=%ld 0x%x/0x%0x)\n", (void*)h->jmprel, h->pltrel, h->pltsz, h->pltent);
|
||||
printf_log(LOG_DEBUG, "PLT Table @%p (type=%ld 0x%zx/0x%0x)\n", (void*)h->jmprel, h->pltrel, h->pltsz, h->pltent);
|
||||
}
|
||||
if(h->DynStrTab && h->szDynStrTab) {
|
||||
//DumpDynamicNeeded(h); cannot dump now, it's not loaded yet
|
||||
@@ -270,44 +332,61 @@ 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(Elf64_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(Elf64_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 = (Elf64_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");
|
||||
if(ii) {
|
||||
h->text = (uintptr_t)(h->SHEntries[ii].sh_addr);
|
||||
h->textsz = h->SHEntries[ii].sh_size;
|
||||
printf_log(LOG_DEBUG, "The .text is at address %p, and is %d big\n", (void*)h->text, h->textsz);
|
||||
printf_log(LOG_DEBUG, "The .text is at address %p, and is %zu big\n", (void*)h->text, h->textsz);
|
||||
}
|
||||
|
||||
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynstr", "DynSym Strings", SHT_STRTAB, (void**)&h->DynStr, NULL);
|
||||
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynsym", "DynSym", SHT_DYNSYM, (void**)&h->DynSym, &h->numDynSym);
|
||||
if(box64_log>=LOG_DUMP && h->DynSym) DumpDynSym(h);
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
const char* GetSymbolVersion(elfheader_t* h, int version)
|
||||
{
|
||||
if(!h->VerNeed || (version<2))
|
||||
return NULL;
|
||||
/*if(version==1)
|
||||
return "*";*/
|
||||
Elf64_Verneed *ver = (Elf64_Verneed*)((uintptr_t)h->VerNeed + h->delta);
|
||||
while(ver) {
|
||||
Elf64_Vernaux *aux = (Elf64_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 = (Elf64_Vernaux*)((uintptr_t)aux + aux->vna_next);
|
||||
}
|
||||
ver = ver->vn_next?((Elf64_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL;
|
||||
}
|
||||
return GetParentSymbolVersion(h, version); // if symbol is "internal", use Def table instead
|
||||
}
|
||||
|
||||
const char* GetParentSymbolVersion(elfheader_t* h, int index)
|
||||
{
|
||||
if(!h->VerDef || (index<1))
|
||||
return NULL;
|
||||
Elf64_Verdef *def = (Elf64_Verdef*)((uintptr_t)h->VerDef + h->delta);
|
||||
while(def) {
|
||||
if(def->vd_ndx==index) {
|
||||
if(def->vd_cnt<1)
|
||||
return NULL;
|
||||
/*if(def->vd_flags&VER_FLG_BASE)
|
||||
return NULL;*/
|
||||
Elf64_Verdaux *aux = (Elf64_Verdaux*)((uintptr_t)def + def->vd_aux);
|
||||
return h->DynStr+aux->vda_name; // return Parent, so 1st aux
|
||||
}
|
||||
def = def->vd_next?((Elf64_Verdef*)((uintptr_t)def + def->vd_next)):NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#define F8 *(uint8_t*)(R_RIP++)
|
||||
#define F8S *(int8_t*)(R_RIP++)
|
||||
#define F16 *(uint16_t*)(R_RIP+=2, R_RIP-2)
|
||||
#define F16S *(int16_t*)(R_RIP+=2, R_RIP-2)
|
||||
#define F32 *(uint32_t*)(R_RIP+=4, R_RIP-4)
|
||||
#define F32S *(int32_t*)(R_RIP+=4, R_RIP-4)
|
||||
#define F32S64 (uint64_t)(int64_t)F32S
|
||||
@@ -18,12 +19,16 @@
|
||||
#define GETED_OFFS(D, O) oped=GetEdO(emu, rex, nextop, D, O)
|
||||
#define GETGD opgd=GetGd(emu, rex, nextop)
|
||||
#define GETEB(D) oped=GetEb(emu, rex, nextop, D)
|
||||
#define GETEB32(D) oped=GetEb32O(emu, rex, nextop, D, 0)
|
||||
#define GETEB_OFFS(D, O) oped=GetEbO(emu, rex, nextop, D, O)
|
||||
#define GETGB opgd=GetGb(emu, rex, nextop)
|
||||
#define GETEW(D) oped=GetEw(emu, rex, nextop, D)
|
||||
#define GETEW32(D) oped=GetEw32O(emu, rex, nextop, D, 0)
|
||||
#define GETEW_OFFS(D, O) oped=GetEdO(emu, rex, nextop, D, O)
|
||||
#define GETGW opgd=GetGw(emu, rex, nextop)
|
||||
#define GETEX(D) opex=GetEx(emu, rex, nextop, D)
|
||||
#define GETEX32(D) opex=GetEx32O(emu, rex, nextop, D, 0)
|
||||
#define GETEX_OFFS(D, O) opex=GetExO(emu, rex, nextop, D, O)
|
||||
#define GETGX opgx=GetGx(emu, rex, nextop)
|
||||
#define GETEM(D) opem=GetEm(emu, rex, nextop, D)
|
||||
#define GETGM opgm=GetGm(emu, rex, nextop)
|
||||
|
||||
+62
-19
@@ -5,6 +5,7 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64stack.h"
|
||||
@@ -16,6 +17,9 @@
|
||||
#include "x64run_private.h"
|
||||
#include "callback.h"
|
||||
#include "bridge.h"
|
||||
#ifdef HAVE_TRACE
|
||||
#include "x64trace.h"
|
||||
#endif
|
||||
#ifdef DYNAREC
|
||||
#include "custommem.h"
|
||||
#endif
|
||||
@@ -62,7 +66,7 @@ static void internalX64Setup(x64emu_t* emu, box64context_t *context, uintptr_t s
|
||||
emu->sbiidx[i] = &emu->regs[i];
|
||||
emu->sbiidx[4] = &emu->zero;
|
||||
emu->x64emu_parity_tab = x86emu_parity_tab;
|
||||
emu->eflags.x32 = 0x202; // default flags?
|
||||
emu->eflags.x64 = 0x202; // default flags?
|
||||
// own stack?
|
||||
emu->stack2free = (ownstack)?(void*)stack:NULL;
|
||||
emu->init_stack = (void*)stack;
|
||||
@@ -105,8 +109,10 @@ EXPORTDYN
|
||||
void SetupX64Emu(x64emu_t *emu)
|
||||
{
|
||||
printf_log(LOG_DEBUG, "Setup X86_64 Emu\n");
|
||||
(void)emu; // Not doing much here...
|
||||
}
|
||||
|
||||
#ifdef HAVE_TRACE
|
||||
void SetTraceEmu(uintptr_t start, uintptr_t end)
|
||||
{
|
||||
if(my_context->zydis) {
|
||||
@@ -121,9 +127,12 @@ void SetTraceEmu(uintptr_t start, uintptr_t end)
|
||||
trace_start = start;
|
||||
trace_end = end;
|
||||
}
|
||||
#endif
|
||||
|
||||
void AddCleanup(x64emu_t *emu, void *p)
|
||||
{
|
||||
(void)emu;
|
||||
|
||||
if(my_context->clean_sz == my_context->clean_cap) {
|
||||
my_context->clean_cap += 4;
|
||||
my_context->cleanups = (cleanup_t*)realloc(my_context->cleanups, sizeof(cleanup_t)*my_context->clean_cap);
|
||||
@@ -135,6 +144,8 @@ void AddCleanup(x64emu_t *emu, void *p)
|
||||
|
||||
void AddCleanup1Arg(x64emu_t *emu, void *p, void* a)
|
||||
{
|
||||
(void)emu;
|
||||
|
||||
if(my_context->clean_sz == my_context->clean_cap) {
|
||||
my_context->clean_cap += 4;
|
||||
my_context->cleanups = (cleanup_t*)realloc(my_context->cleanups, sizeof(cleanup_t)*my_context->clean_cap);
|
||||
@@ -173,7 +184,8 @@ void CallAllCleanup(x64emu_t *emu)
|
||||
|
||||
static void internalFreeX64(x64emu_t* emu)
|
||||
{
|
||||
free(emu->stack2free);
|
||||
if(emu && emu->stack2free)
|
||||
munmap(emu->stack2free, emu->size_stack);
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
@@ -311,6 +323,10 @@ uint64_t GetRSP(x64emu_t *emu)
|
||||
{
|
||||
return R_RSP;
|
||||
}
|
||||
uint64_t GetRBP(x64emu_t *emu)
|
||||
{
|
||||
return R_RBP;
|
||||
}
|
||||
void SetFS(x64emu_t *emu, uint16_t v)
|
||||
{
|
||||
emu->segs[_FS] = v;
|
||||
@@ -329,12 +345,13 @@ void ResetFlags(x64emu_t *emu)
|
||||
const char* DumpCPURegs(x64emu_t* emu, uintptr_t ip)
|
||||
{
|
||||
static char buff[1000];
|
||||
char* regname[] = {"RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI",
|
||||
char* regname[] = {"RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI",
|
||||
" R8", " R9", "R10", "R11", "R12", "R13", "R14", "R15"};
|
||||
char tmp[160];
|
||||
buff[0] = '\0';
|
||||
#ifdef HAVE_TRACE
|
||||
if(trace_emm) {
|
||||
// do emm reg is needed
|
||||
// do emm reg if needed
|
||||
for(int i=0; i<8; ++i) {
|
||||
sprintf(tmp, "mm%d:%016lx", i, emu->mmx87[i].q);
|
||||
strcat(buff, tmp);
|
||||
@@ -342,13 +359,14 @@ const char* DumpCPURegs(x64emu_t* emu, uintptr_t ip)
|
||||
}
|
||||
}
|
||||
if(trace_xmm) {
|
||||
// do xmm reg is needed
|
||||
// do xmm reg if needed
|
||||
for(int i=0; i<8; ++i) {
|
||||
sprintf(tmp, "%d:%016lx%016lx", i, emu->xmm[i].q[1], emu->xmm[i].q[0]);
|
||||
strcat(buff, tmp);
|
||||
if ((i&3)==3) strcat(buff, "\n"); else strcat(buff, " ");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// start with FPU regs...
|
||||
if(emu->fpu_stack) {
|
||||
for (int i=0; i<emu->fpu_stack; i++) {
|
||||
@@ -362,16 +380,28 @@ const char* DumpCPURegs(x64emu_t* emu, uintptr_t ip)
|
||||
strcat(buff, "\n");
|
||||
}
|
||||
for (int i=_AX; i<=_R15; ++i) {
|
||||
#ifdef HAVE_TRACE
|
||||
if (trace_regsdiff && (emu->regs[i].q[0] != emu->oldregs[i].q[0])) {
|
||||
sprintf(tmp, "\e[1;35m%s=%016lx\e[m ", regname[i], emu->regs[i].q[0]);
|
||||
emu->oldregs[i].q[0] = emu->regs[i].q[0];
|
||||
} else {
|
||||
sprintf(tmp, "%s=%016lx ", regname[i], emu->regs[i].q[0]);
|
||||
}
|
||||
#else
|
||||
sprintf(tmp, "%s=%016lx ", regname[i], emu->regs[i].q[0]);
|
||||
#endif
|
||||
strcat(buff, tmp);
|
||||
|
||||
if (i%5==4) {
|
||||
if(i==4) {
|
||||
if(emu->df) {
|
||||
strcat(buff, "FLAGS=??????\n");
|
||||
#define FLAG_CHAR(f) (ACCESS_FLAG(F_##f##F)) ? #f : "?"
|
||||
sprintf(tmp, "flags=%s%s%s%s%s%s%s\n", FLAG_CHAR(O), FLAG_CHAR(D), FLAG_CHAR(S), FLAG_CHAR(Z), FLAG_CHAR(A), FLAG_CHAR(P), FLAG_CHAR(C));
|
||||
strcat(buff, tmp);
|
||||
#undef FLAG_CHAR
|
||||
} else {
|
||||
#define FLAG_CHAR(f) (ACCESS_FLAG(F_##f##F)) ? #f : "-"
|
||||
sprintf(tmp, "FLAGS=%s%s%s%s%s%s\n", FLAG_CHAR(O), FLAG_CHAR(C), FLAG_CHAR(P), FLAG_CHAR(A), FLAG_CHAR(Z), FLAG_CHAR(S));
|
||||
sprintf(tmp, "FLAGS=%s%s%s%s%s%s%s\n", FLAG_CHAR(O), FLAG_CHAR(D), FLAG_CHAR(S), FLAG_CHAR(Z), FLAG_CHAR(A), FLAG_CHAR(P), FLAG_CHAR(C));
|
||||
strcat(buff, tmp);
|
||||
#undef FLAG_CHAR
|
||||
}
|
||||
@@ -390,8 +420,19 @@ void StopEmu(x64emu_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_RIP));
|
||||
// TODO: stack, memory/instruction around EIP, etc..
|
||||
printf_log(LOG_NONE, "==== CPU Registers ====\n%s\n", DumpCPURegs(emu, R_RIP));
|
||||
printf_log(LOG_NONE, "======== Stack ========\nStack is from %lX to %lX\n", R_RBP, R_RSP);
|
||||
if (R_RBP == R_RSP) {
|
||||
printf_log(LOG_NONE, "RBP = RSP: 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 (uint64_t *sp = R_RBP; sp >= R_RSP; --sp) {
|
||||
} */
|
||||
}
|
||||
printf_log(LOG_NONE, "Old IP: %tX\n", emu->old_ip);
|
||||
#ifdef HAVE_TRACE
|
||||
printf_log(LOG_NONE, "%s\n", DecodeX64Trace(my_context->dec, emu->old_ip));
|
||||
#endif
|
||||
}
|
||||
|
||||
void UnimpOpcode(x64emu_t* emu)
|
||||
@@ -437,18 +478,20 @@ void EmuCall(x64emu_t* emu, uintptr_t addr)
|
||||
|
||||
uint64_t ReadTSC(x64emu_t* emu)
|
||||
{
|
||||
//TODO: implement hardware counter read?
|
||||
(void)emu;
|
||||
|
||||
//TODO: implement hardware counter read? (only available in kernel space?)
|
||||
// Read the TimeStamp Counter as 64bits.
|
||||
// this is supposed to be the number of instrunctions executed since last reset
|
||||
// fall back to gettime...
|
||||
// this is supposed to be the number of instructions executed since last reset
|
||||
// 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
|
||||
}
|
||||
|
||||
@@ -457,4 +500,4 @@ void ResetSegmentsCache(x64emu_t *emu)
|
||||
if(!emu)
|
||||
return;
|
||||
memset(emu->segs_serial, 0, sizeof(emu->segs_serial));
|
||||
}
|
||||
}
|
||||
+20
-16
@@ -10,11 +10,6 @@ typedef struct x64_ucontext_s x64_ucontext_t;
|
||||
#define ERR_DIVBY0 2
|
||||
#define ERR_ILLEGAL 4
|
||||
|
||||
#ifdef DYNAREC
|
||||
#define CSTACK 32
|
||||
#define CSTACKMASK 31
|
||||
#endif
|
||||
|
||||
typedef struct forkpty_s {
|
||||
void* amaster;
|
||||
void* name;
|
||||
@@ -23,6 +18,13 @@ typedef struct forkpty_s {
|
||||
void* f; // forkpty function
|
||||
} forkpty_t;
|
||||
|
||||
typedef union multiuint_s {
|
||||
uint8_t u8;
|
||||
uint16_t u16;
|
||||
uint32_t u32;
|
||||
uint64_t u64;
|
||||
} multiuint_t;
|
||||
|
||||
typedef struct x64emu_s {
|
||||
// cpu
|
||||
reg64_t regs[16];
|
||||
@@ -35,26 +37,33 @@ typedef struct x64emu_s {
|
||||
x87flags_t sw;
|
||||
uint32_t top; // top is part of sw, but it's faster to have it separatly
|
||||
int fpu_stack;
|
||||
uint32_t mxcsr;
|
||||
fpu_round_t round;
|
||||
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[16];
|
||||
uint32_t mxcsr;
|
||||
// defered flags
|
||||
int dummy1; // to align on 64bits with df
|
||||
defered_flags_t df;
|
||||
uint64_t op1;
|
||||
uint64_t op2;
|
||||
uint64_t res;
|
||||
multiuint_t op1;
|
||||
multiuint_t op2;
|
||||
multiuint_t res;
|
||||
uint32_t *x64emu_parity_tab; // helper
|
||||
#ifdef HAVE_TRACE
|
||||
reg64_t oldregs[16];
|
||||
uintptr_t prev2_ip;
|
||||
#endif
|
||||
// segments
|
||||
uint32_t segs[6]; // only 32bits value?
|
||||
uintptr_t segs_offs[6]; // computed offset associate with segment
|
||||
uint64_t segs_serial[6]; // are seg offset clean (not 0) or does they need to be re-computed (0)? For GS, serial need to be the same as context->sel_serial
|
||||
uint32_t segs_serial[6]; // are seg offset clean (not 0) or does they need to be re-computed (0)? For GS, serial need to be the same as context->sel_serial
|
||||
// parent context
|
||||
box64context_t *context;
|
||||
// cpu helpers
|
||||
reg64_t zero;
|
||||
reg64_t *sbiidx[16];
|
||||
// emu control
|
||||
int quit;
|
||||
int error;
|
||||
@@ -63,11 +72,6 @@ typedef struct x64emu_s {
|
||||
int exit;
|
||||
int quitonlongjmp; // quit if longjmp is called
|
||||
int longjmp; // if quit because of longjmp
|
||||
// parent context
|
||||
box64context_t *context;
|
||||
// cpu helpers
|
||||
reg64_t zero;
|
||||
reg64_t *sbiidx[16];
|
||||
// scratch stack, used for alignement of double and 64bits ints on arm. 200 elements should be enough
|
||||
uint64_t scratch[200];
|
||||
// local stack, do be deleted when emu is freed
|
||||
@@ -88,4 +92,4 @@ typedef struct x64emu_s {
|
||||
//#define INTR_RAISE_DIV0(emu) {emu->error |= ERR_DIVBY0; emu->quit=1;}
|
||||
#define INTR_RAISE_DIV0(emu) {emu->error |= ERR_DIVBY0;} // should rise a SIGFPE and not quit
|
||||
|
||||
#endif //__X86EMU_PRIVATE_H_
|
||||
#endif //__X86EMU_PRIVATE_H_
|
||||
+109
-13
@@ -10,6 +10,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64stack.h"
|
||||
@@ -91,21 +92,116 @@ void x64Int3(x64emu_t* emu)
|
||||
char *tmp;
|
||||
int post = 0;
|
||||
int perr = 0;
|
||||
uint32_t *pu32 = NULL;
|
||||
uint64_t *pu64 = NULL;
|
||||
const char *s = NULL;
|
||||
s = GetNativeName((void*)addr);
|
||||
if(addr==(uintptr_t)PltResolver) {
|
||||
snprintf(buff, 256, "%s", " ... ");
|
||||
} else if(strstr(s, "__open")==s || !strcmp(s, "open") || !strcmp(s, "open ")) {
|
||||
} else if (!strcmp(s, "__open") || !strcmp(s, "open") || !strcmp(s, "open ")) {
|
||||
tmp = (char*)(R_RDI);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %d (,%d))", tid, *(void**)(R_RSP), s, (tmp)?tmp:"(nil)", (int)(R_ESI), (int)(R_EDX));
|
||||
perr = 1;
|
||||
} else if(strstr(s, "my___printf_chk")) {
|
||||
} else if (!strcmp(s, "fopen") || !strcmp(s, "fopen64")) {
|
||||
tmp = (char*)(R_RDI);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %d)", tid, *(void**)(R_RSP), s, (tmp)?tmp:"(nil)", (int)(R_ESI));
|
||||
perr = 2;
|
||||
} else if (!strcmp(s, "__openat64") || !strcmp(s, "openat64") || !strcmp(s, "__openat64_2")) {
|
||||
tmp = (char*)(R_RSI);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, \"%s\", %d (,%d))", tid, *(void**)(R_RSP), s, (int)R_EDI, (tmp)?tmp:"(nil)", (int)(R_EDX), (int)(R_ECX));
|
||||
perr = 1;
|
||||
} else if (strstr(s, "mkdir")==s) {
|
||||
tmp = (char*)(R_RDI);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %d)", tid, *(void**)(R_RSP), s, (tmp)?tmp:"(nil)", (int)(R_ESI));
|
||||
perr = 1;
|
||||
} else if (strstr(s, "opendir")==s) {
|
||||
tmp = (char*)(R_RDI);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)(R_RSP), s, (tmp)?tmp:"(nil)");
|
||||
perr = 2;
|
||||
} else if (!strcmp(s, "read")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p, %zu)", tid, *(void**)(R_RSP), s, R_EDI, (void*)R_RSI, R_RDX);
|
||||
perr = 1;
|
||||
} else if (!strcmp(s, "write")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p, %zu)", tid, *(void**)(R_RSP), s, R_EDI, (void*)R_RSI, R_RDX);
|
||||
perr = 1;
|
||||
} else if (strstr(s, "access")==s) {
|
||||
tmp = (char*)(R_RDI);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", 0x%x)", tid, *(void**)(R_RSP), s, (tmp)?tmp:"(nil)", R_ESI);
|
||||
perr = 1;
|
||||
} else if (!strcmp(s, "lseek64") || !strcmp(s, "my_lseek64")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %ld, %d)", tid, *(void**)(R_RSP), s, (int)R_EDI, (int64_t)R_RSI, (int)R_EDX);
|
||||
perr = 1;
|
||||
} else if (!strcmp(s, "lseek") || !strcmp(s, "my_lseek")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %ld, %d)", tid, *(void**)(R_RSP), s, (int)R_EDI, (int64_t)R_RSI, (int)R_EDX);
|
||||
perr = 1;
|
||||
} else if (strstr(s, "puts")==s) {
|
||||
tmp = (char*)(R_RDI);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)(R_RSP), s, (tmp)?tmp:"(nil)");
|
||||
} else if (strstr(s, "strlen")==s) {
|
||||
tmp = (char*)(R_RDI);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)(R_RSP), s, (tmp)?tmp:"(nil)");
|
||||
} else if (strstr(s, "strcmp")==s) {
|
||||
tmp = (char*)(R_RDI);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\")", tid, *(void**)(R_RSP), s, (tmp)?tmp:"(nil)", (char*)R_RSI);
|
||||
} else if (strstr(s, "getenv")==s) {
|
||||
tmp = (char*)(R_RDI);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)(R_RSP), s, (tmp)?tmp:"(nil)");
|
||||
} else if (!strcmp(s, "poll")) {
|
||||
struct pollfd* pfd = (struct pollfd*)(R_RDI);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p[%d/%d/%d, ...], %d, %d)", tid, *(void**)(R_RSP), s, pfd, pfd->fd, pfd->events, pfd->revents, R_ESI, R_EDX);
|
||||
} else if (strstr(s, "my___printf_chk") || !strcmp(s, "__printf_chk")) {
|
||||
tmp = (char*)(R_RSI);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, \"%s\" (,%p))", tid, *(void**)(R_RSP), s, R_EDI, (tmp)?tmp:"(nil)", (void*)(R_RDX));
|
||||
} else if(!strcmp(s, "sscanf")) {
|
||||
} else if (strstr(s, "my___snprintf_chk") || !strcmp(s, "__snprintf_chk")) {
|
||||
tmp = (char*)(R_R8);
|
||||
pu64 = (uint64_t*)R_RDI;
|
||||
post = 3;
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, %zu, %d, %zu, \"%s\" (,%p))", tid, *(void**)(R_RSP), s, (void*)R_RDI, R_RSI, R_EDX, R_RCX, (tmp)?tmp:"(nil)", (void*)(R_R9));
|
||||
} else if (strstr(s, "my_snprintf") || !strcmp(s, "snprintf")) {
|
||||
tmp = (char*)(R_RDX);
|
||||
pu64 = (uint64_t*)R_RDI;
|
||||
post = 3;
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, %zu, \"%s\" (,%p))", tid, *(void**)(R_RSP), s, (void*)R_RDI, R_RSI, (tmp)?tmp:"(nil)", (void*)(R_RCX));
|
||||
} else if (!strcmp(s, "getcwd")) {
|
||||
post = 2;
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, %zu)", tid, *(void**)(R_RSP), s, (void*)R_RDI, R_RSI);
|
||||
} else if (!strcmp(s, "ftok")) {
|
||||
tmp = (char*)(R_RDI);
|
||||
perr = 1;
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %d)", tid, *(void**)(R_RSP), s, tmp?tmp:"nil", R_ESI);
|
||||
} else if (!strcmp(s, "glXGetProcAddress") || !strcmp(s, "SDL_GL_GetProcAddress") || !strcmp(s, "glXGetProcAddressARB")) {
|
||||
tmp = (char*)(R_RDI);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)(R_RSP), s, (tmp)?tmp:"(nil)");
|
||||
} else if (!strcmp(s, "glLabelObjectEXT")) {
|
||||
tmp = (char*)(R_RCX);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(0x%x, %d, %d, \"%s\")", tid, *(void**)(R_RSP), s, R_EDI, R_ESI, R_ECX, (tmp)?tmp:"(nil)");
|
||||
} else if (!strcmp(s, "glGetStringi")) {
|
||||
post = 2;
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(0x%x, %d)", tid, *(void**)(R_RSP), s, R_EDI, R_ESI);
|
||||
} else if (!strcmp(s, "glFramebufferTexture2D")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(0x%x, 0x%x, 0x%x, %u, %d)", tid, *(void**)(R_RSP), s, R_EDI, R_ESI, R_EDX, R_ECX, R_R8d);
|
||||
} else if (!strcmp(s, "glTexSubImage2D")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(0x%x, %d, %d, %d, %d, %d, 0x%x, 0x%x, %p)", tid, *(void**)(R_RSP), s, R_EDI, R_ESI, R_EDX, R_ECX, R_R8d, R_R9d, *(uint32_t*)(R_RSP+8), *(uint32_t*)(R_RSP+16), *(void**)(R_RSP+24));
|
||||
} else if (!strcmp(s, "glCompressedTexSubImage2D")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(0x%x, %d, %d, %d, %d, %d, 0x%x, %d, %p)", tid, *(void**)(R_RSP), s, R_EDI, R_ESI, R_EDX, R_ECX, R_R8d, R_R9d, *(uint32_t*)(R_RSP+8), *(uint32_t*)(R_RSP+16), *(void**)(R_RSP+24));
|
||||
} else if (!strcmp(s, "glVertexAttribPointer")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%u, %d, 0x%x, %d, %d, %p)", tid, *(void**)(R_RSP), s, R_EDI, R_ESI, R_EDX, R_ECX, R_R8d, (void*)R_R9);
|
||||
} else if (!strcmp(s, "glDrawElements")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(0x%x, %d, 0x%x, %p)", tid, *(void**)(R_RSP), s, R_EDI, R_ESI, R_EDX, (void*)R_RCX);
|
||||
} else if (!strcmp(s, "glUniform4fv")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %d, %p[%g/%g/%g/%g...])", tid, *(void**)(R_RSP), s, R_EDI, R_ESI, (void*)R_RDX, ((float*)(R_RDX))[0], ((float*)(R_RDX))[1], ((float*)(R_RDX))[2], ((float*)(R_RDX))[3]);
|
||||
} else if (!strcmp(s, "mmap64") || !strcmp(s, "mmap")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, %lu, 0x%x, 0x%x, %d, %ld)", tid, *(void**)(R_RSP), s,
|
||||
(void*)R_RDI, R_RSI, (int)(R_RDX), (int)R_RCX, (int)R_R8, R_R9);
|
||||
} else if (!strcmp(s, "sscanf")) {
|
||||
tmp = (char*)(R_RSI);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\" (,%p))", tid, *(void**)(R_RSP), s, (void*)R_RDI, (tmp)?tmp:"(nil)", (void*)(R_RDX));
|
||||
} else if (!strcmp(s, "XCreateWindow")) {
|
||||
tmp = (char*)(R_RSI);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, %p, %d, %d, %u, %u, %u, %d, %u, %p, 0x%lx, %p)", tid, *(void**)(R_RSP), s,
|
||||
(void*)R_RDI, (void*)R_RSI, (int)R_EDX, (int)R_ECX, R_R8d, R_R9d,
|
||||
(uint32_t)*(uint64_t*)(R_RSP+8), (int)*(uint64_t*)(R_RSP+16),
|
||||
(uint32_t)*(uint64_t*)(R_RSP+24), (void*)*(uint64_t*)(R_RSP+32),
|
||||
(unsigned long)*(uint64_t*)(R_RSP+40), (void*)*(uint64_t*)(R_RSP+48));
|
||||
} else {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(0x%lX, 0x%lX, 0x%lX, ...)", tid, *(void**)(R_RSP), s, R_RDI, R_RSI, R_RDX);
|
||||
}
|
||||
@@ -114,23 +210,23 @@ void x64Int3(x64emu_t* emu)
|
||||
w(emu, addr); // some function never come back, so unlock the mutex first!
|
||||
pthread_mutex_lock(&emu->context->mutex_trace);
|
||||
if(post)
|
||||
switch(post) {
|
||||
case 1: snprintf(buff2, 63, " [%d sec %d nsec]", pu32?pu32[0]:-1, pu32?pu32[1]:-1);
|
||||
switch(post) { // Only ever 2 for now...
|
||||
case 1: snprintf(buff2, 63, " [%llu sec %llu nsec]", pu64?pu64[0]:~0ull, pu64?pu64[1]:~0ull);
|
||||
break;
|
||||
case 2: snprintf(buff2, 63, "(%s)", R_RAX?((char*)R_RAX):"nil");
|
||||
break;
|
||||
case 3: snprintf(buff2, 63, "(%s)", pu32?((char*)pu32):"nil");
|
||||
case 3: snprintf(buff2, 63, "(%s)", pu64?((char*)pu64):"nil");
|
||||
break;
|
||||
case 4: snprintf(buff2, 63, " (%f)", ST0.d);
|
||||
break;
|
||||
case 5: {
|
||||
uint32_t* p = (uint32_t*)R_RAX;
|
||||
uint32_t* p = (uint32_t*)R_RAX; // uint64_t? (case never used)
|
||||
if(p)
|
||||
snprintf(buff2, 63, " size=%dx%d, pitch=%d, pixels=%p", p[2], p[3], p[4], p+5);
|
||||
snprintf(buff2, 63, " size=%ux%u, pitch=%u, pixels=%p", p[2], p[3], p[4], p+5);
|
||||
else
|
||||
snprintf(buff2, 63, "NULL Surface");
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(perr==1 && ((int)R_EAX)<0)
|
||||
snprintf(buff3, 63, " (errno=%d:\"%s\")", errno, strerror(errno));
|
||||
@@ -143,7 +239,7 @@ void x64Int3(x64emu_t* emu)
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(my_context->signals[SIGTRAP])
|
||||
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_RIP);
|
||||
@@ -153,4 +249,4 @@ void x64Int3(x64emu_t* emu)
|
||||
int GetTID()
|
||||
{
|
||||
return syscall(SYS_gettid);
|
||||
}
|
||||
}
|
||||
+14
-14
@@ -96,7 +96,7 @@
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
// This has been heavily modified to fit box86 purpose...
|
||||
// This has been heavily modified to fit box64 purpose...
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -785,7 +785,7 @@ uint8_t rol8(x64emu_t *emu, uint8_t d, uint8_t s)
|
||||
if((cnt = s % 8) != 0) {
|
||||
d = (d << cnt) + ((d >> (8 - cnt)) & ((1 << cnt) - 1));
|
||||
}
|
||||
RESET_FLAGS(emu);
|
||||
CHECK_FLAGS(emu);
|
||||
|
||||
/* OF flag is set if s == 1; OF = CF _XOR_ MSB of result */
|
||||
if(s == 1) {
|
||||
@@ -808,7 +808,7 @@ uint16_t rol16(x64emu_t *emu, uint16_t d, uint8_t s)
|
||||
if((cnt = s % 16) != 0) {
|
||||
d = (d << cnt) + ((d >> (16 - cnt)) & ((1 << cnt) - 1));
|
||||
}
|
||||
RESET_FLAGS(emu);
|
||||
CHECK_FLAGS(emu);
|
||||
|
||||
/* OF flag is set if s == 1; OF = CF _XOR_ MSB of result */
|
||||
if(s == 1) {
|
||||
@@ -831,7 +831,7 @@ uint32_t rol32(x64emu_t *emu, uint32_t d, uint8_t s)
|
||||
if((cnt = s % 32) != 0) {
|
||||
d = (d << cnt) + ((d >> (32 - cnt)) & ((1 << cnt) - 1));
|
||||
}
|
||||
RESET_FLAGS(emu);
|
||||
CHECK_FLAGS(emu);
|
||||
|
||||
/* OF flag is set if s == 1; OF = CF _XOR_ MSB of result */
|
||||
if(s == 1) {
|
||||
@@ -854,7 +854,7 @@ uint64_t rol64(x64emu_t *emu, uint64_t d, uint8_t s)
|
||||
if((cnt = s % 64) != 0) {
|
||||
d = (d << cnt) + ((d >> (64 - cnt)) & ((1L << cnt) - 1));
|
||||
}
|
||||
RESET_FLAGS(emu);
|
||||
CHECK_FLAGS(emu);
|
||||
|
||||
/* OF flag is set if s == 1; OF = CF _XOR_ MSB of result */
|
||||
if(s == 1) {
|
||||
@@ -881,7 +881,7 @@ uint8_t ror8(x64emu_t *emu, uint8_t d, uint8_t s)
|
||||
if((cnt = s % 8) != 0) {
|
||||
d = (d << (8 - cnt)) + ((d >> (cnt)) & ((1 << (8 - cnt)) - 1));
|
||||
}
|
||||
RESET_FLAGS(emu);
|
||||
CHECK_FLAGS(emu);
|
||||
|
||||
/* OF flag is set if s == 1; OF = MSB _XOR_ (M-1)SB of result */
|
||||
if(s == 1) {
|
||||
@@ -904,7 +904,7 @@ uint16_t ror16(x64emu_t *emu, uint16_t d, uint8_t s)
|
||||
if((cnt = s % 16) != 0) {
|
||||
d = (d << (16 - cnt)) + ((d >> (cnt)) & ((1 << (16 - cnt)) - 1));
|
||||
}
|
||||
RESET_FLAGS(emu);
|
||||
CHECK_FLAGS(emu);
|
||||
|
||||
/* OF flag is set if s == 1; OF = MSB _XOR_ (M-1)SB of result */
|
||||
if(s == 1) {
|
||||
@@ -927,7 +927,7 @@ uint32_t ror32(x64emu_t *emu, uint32_t d, uint8_t s)
|
||||
if((cnt = s % 32) != 0) {
|
||||
d = (d << (32 - cnt)) + ((d >> (cnt)) & ((1 << (32 - cnt)) - 1));
|
||||
}
|
||||
RESET_FLAGS(emu);
|
||||
CHECK_FLAGS(emu);
|
||||
|
||||
/* OF flag is set if s == 1; OF = MSB _XOR_ (M-1)SB of result */
|
||||
if(s == 1) {
|
||||
@@ -950,7 +950,7 @@ uint64_t ror64(x64emu_t *emu, uint64_t d, uint8_t s)
|
||||
if((cnt = s % 64) != 0) {
|
||||
d = (d << (64 - cnt)) + ((d >> (cnt)) & ((1L << (64 - cnt)) - 1L));
|
||||
}
|
||||
RESET_FLAGS(emu);
|
||||
CHECK_FLAGS(emu);
|
||||
|
||||
/* OF flag is set if s == 1; OF = MSB _XOR_ (M-1)SB of result */
|
||||
if(s == 1) {
|
||||
@@ -1384,8 +1384,8 @@ void idiv32(x64emu_t *emu, uint32_t s)
|
||||
SET_FLAG(F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
|
||||
|
||||
R_EAX = (uint32_t)quot;
|
||||
R_EDX = (uint32_t)mod;
|
||||
R_RAX = (uint32_t)quot;
|
||||
R_RDX = (uint32_t)mod;
|
||||
}
|
||||
|
||||
void idiv64(x64emu_t *emu, uint64_t s)
|
||||
@@ -1400,7 +1400,7 @@ void idiv64(x64emu_t *emu, uint64_t s)
|
||||
}
|
||||
quot = dvd/(int64_t)s;
|
||||
mod = dvd%(int64_t)s;
|
||||
if (llabs(quot) > 0x7fffffffffffffffL) {
|
||||
if ((quot > 0x7fffffffffffffffLL) || (quot < -0x7fffffffffffffffLL)) {
|
||||
INTR_RAISE_DIV0(emu);
|
||||
return;
|
||||
}
|
||||
@@ -1485,8 +1485,8 @@ void div32(x64emu_t *emu, uint32_t s)
|
||||
SET_FLAG(F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
|
||||
|
||||
R_EAX = (uint32_t)div;
|
||||
R_EDX = (uint32_t)mod;
|
||||
R_RAX = (uint32_t)div;
|
||||
R_RDX = (uint32_t)mod;
|
||||
}
|
||||
|
||||
void div64(x64emu_t *emu, uint64_t s)
|
||||
|
||||
+172
-172
@@ -16,70 +16,70 @@ uint64_t adc64 (x64emu_t *emu, uint64_t d, uint64_t s);
|
||||
|
||||
static inline uint8_t add8(x64emu_t *emu, uint8_t d, uint8_t s)
|
||||
{
|
||||
emu->res = d + s;
|
||||
emu->op1 = d;
|
||||
emu->op2 = s;
|
||||
emu->res.u16 = d + s;
|
||||
emu->op1.u8 = d;
|
||||
emu->op2.u8 = s;
|
||||
emu->df = d_add8;
|
||||
return (uint8_t)emu->res;
|
||||
return emu->res.u8;
|
||||
}
|
||||
|
||||
static inline uint16_t add16(x64emu_t *emu, uint16_t d, uint16_t s)
|
||||
{
|
||||
emu->res = d + s;
|
||||
emu->op1 = d;
|
||||
emu->op2 = s;
|
||||
emu->res.u32 = d + s;
|
||||
emu->op1.u16 = d;
|
||||
emu->op2.u16 = s;
|
||||
emu->df = d_add16;
|
||||
return (uint16_t)emu->res;
|
||||
return emu->res.u16;
|
||||
}
|
||||
|
||||
static inline uint32_t add32(x64emu_t *emu, uint32_t d, uint32_t s)
|
||||
{
|
||||
emu->res = (uint64_t)d + s;
|
||||
emu->op1 = d;
|
||||
emu->op2 = s;
|
||||
emu->res.u64 = (uint64_t)d + s;
|
||||
emu->op1.u32 = d;
|
||||
emu->op2.u32 = s;
|
||||
emu->df = d_add32;
|
||||
return emu->res;
|
||||
return emu->res.u32;
|
||||
}
|
||||
|
||||
static inline uint64_t add64(x64emu_t *emu, uint64_t d, uint64_t s)
|
||||
{
|
||||
emu->res = d + s;
|
||||
emu->op1 = d;
|
||||
emu->op2 = s;
|
||||
emu->res.u64 = d + s;
|
||||
emu->op1.u64 = d;
|
||||
emu->op2.u64 = s;
|
||||
emu->df = d_add64;
|
||||
return emu->res;
|
||||
return emu->res.u64;
|
||||
}
|
||||
|
||||
static inline uint8_t and8(x64emu_t *emu, uint8_t d, uint8_t s)
|
||||
{
|
||||
emu->res = d & s;
|
||||
emu->res.u8 = d & s;
|
||||
emu->df = d_and8;
|
||||
|
||||
return emu->res;
|
||||
return emu->res.u8;
|
||||
}
|
||||
|
||||
static inline uint16_t and16(x64emu_t *emu, uint16_t d, uint16_t s)
|
||||
{
|
||||
emu->res = d & s;
|
||||
emu->res.u16 = d & s;
|
||||
emu->df = d_and16;
|
||||
|
||||
return emu->res;
|
||||
return emu->res.u16;
|
||||
}
|
||||
|
||||
static inline uint32_t and32(x64emu_t *emu, uint32_t d, uint32_t s)
|
||||
{
|
||||
emu->res = d & s;
|
||||
emu->res.u32 = d & s;
|
||||
emu->df = d_and32;
|
||||
|
||||
return emu->res;
|
||||
return emu->res.u32;
|
||||
}
|
||||
|
||||
static inline uint64_t and64(x64emu_t *emu, uint64_t d, uint64_t s)
|
||||
{
|
||||
emu->res = d & s;
|
||||
emu->res.u64 = d & s;
|
||||
emu->df = d_and64;
|
||||
|
||||
return emu->res;
|
||||
return emu->res.u64;
|
||||
}
|
||||
|
||||
uint8_t cmp8 (x64emu_t *emu, uint8_t d, uint8_t s);
|
||||
@@ -91,165 +91,169 @@ uint8_t das8 (x64emu_t *emu, uint8_t d);
|
||||
|
||||
static inline uint8_t dec8(x64emu_t *emu, uint8_t d)
|
||||
{
|
||||
emu->res = d - 1;
|
||||
emu->op1 = d;
|
||||
emu->res.u8 = d - 1;
|
||||
emu->op1.u8 = d;
|
||||
emu->df = d_dec8;
|
||||
return (uint8_t)emu->res;
|
||||
return emu->res.u8;
|
||||
}
|
||||
|
||||
static inline uint16_t dec16(x64emu_t *emu, uint16_t d)
|
||||
{
|
||||
emu->res = d - 1;
|
||||
emu->op1 = d;
|
||||
emu->res.u16 = d - 1;
|
||||
emu->op1.u16 = d;
|
||||
emu->df = d_dec16;
|
||||
return (uint16_t)emu->res;
|
||||
return emu->res.u16;
|
||||
|
||||
}
|
||||
|
||||
static inline uint32_t dec32(x64emu_t *emu, uint32_t d)
|
||||
{
|
||||
emu->res = d - 1;
|
||||
emu->op1 = d;
|
||||
emu->res.u32 = d - 1;
|
||||
emu->op1.u32 = d;
|
||||
emu->df = d_dec32;
|
||||
|
||||
return emu->res;
|
||||
return emu->res.u32;
|
||||
}
|
||||
|
||||
static inline uint64_t dec64(x64emu_t *emu, uint64_t d)
|
||||
{
|
||||
emu->res = d - 1;
|
||||
emu->op1 = d;
|
||||
emu->res.u64 = d - 1;
|
||||
emu->op1.u64 = d;
|
||||
emu->df = d_dec64;
|
||||
|
||||
return emu->res;
|
||||
return emu->res.u64;
|
||||
}
|
||||
|
||||
static inline uint8_t inc8(x64emu_t *emu, uint8_t d)
|
||||
{
|
||||
emu->res = d + 1;
|
||||
emu->op1 = d;
|
||||
emu->res.u8 = d + 1;
|
||||
emu->op1.u8 = d;
|
||||
emu->df = d_inc8;
|
||||
return (uint8_t)emu->res;
|
||||
return emu->res.u8;
|
||||
}
|
||||
|
||||
static inline uint16_t inc16(x64emu_t *emu, uint16_t d)
|
||||
{
|
||||
emu->res = d + 1;
|
||||
emu->op1 = d;
|
||||
emu->res.u16 = d + 1;
|
||||
emu->op1.u16 = d;
|
||||
emu->df = d_inc16;
|
||||
return (uint16_t)emu->res;
|
||||
return emu->res.u16;
|
||||
}
|
||||
|
||||
static inline uint32_t inc32(x64emu_t *emu, uint32_t d)
|
||||
{
|
||||
if(emu->df == d_shr32) {
|
||||
// workaround for some wine trickery
|
||||
uint32_t cnt = emu->op2;
|
||||
uint32_t cnt = emu->op2.u32;
|
||||
if (cnt > 0) {
|
||||
uint32_t cc = emu->op1 & (1 << (cnt - 1));
|
||||
uint32_t cc = emu->op1.u32 & (1 << (cnt - 1));
|
||||
CONDITIONAL_SET_FLAG(cc, F_CF);
|
||||
}
|
||||
}
|
||||
emu->res = d + 1;
|
||||
emu->op1 = d;
|
||||
emu->res.u32 = d + 1;
|
||||
emu->op1.u32 = d;
|
||||
emu->df = d_inc32;
|
||||
return emu->res;
|
||||
return emu->res.u32;
|
||||
}
|
||||
|
||||
static inline uint64_t inc64(x64emu_t *emu, uint64_t d)
|
||||
{
|
||||
if(emu->df == d_shr64) {
|
||||
// workaround for some wine trickery
|
||||
uint64_t cnt = emu->op2;
|
||||
uint64_t cnt = emu->op2.u64;
|
||||
if (cnt > 0) {
|
||||
uint64_t cc = emu->op1 & (1L << (cnt - 1));
|
||||
uint64_t cc = emu->op1.u64 & (1LL << (cnt - 1));
|
||||
CONDITIONAL_SET_FLAG(cc, F_CF);
|
||||
}
|
||||
}
|
||||
emu->res = d + 1;
|
||||
emu->op1 = d;
|
||||
emu->res.u64 = d + 1;
|
||||
emu->op1.u64 = d;
|
||||
emu->df = d_inc64;
|
||||
return emu->res;
|
||||
return emu->res.u64;
|
||||
}
|
||||
|
||||
static inline uint8_t or8(x64emu_t *emu, uint8_t d, uint8_t s)
|
||||
{
|
||||
emu->res = d | s;
|
||||
emu->res.u8 = d | s;
|
||||
emu->df = d_or8;
|
||||
return emu->res;
|
||||
return emu->res.u8;
|
||||
}
|
||||
|
||||
static inline uint16_t or16(x64emu_t *emu, uint16_t d, uint16_t s)
|
||||
{
|
||||
emu->res = d | s;
|
||||
emu->res.u16 = d | s;
|
||||
emu->df = d_or16;
|
||||
/* set the carry flag to be bit 8 */
|
||||
return emu->res;
|
||||
return emu->res.u16;
|
||||
}
|
||||
|
||||
static inline uint32_t or32(x64emu_t *emu, uint32_t d, uint32_t s)
|
||||
{
|
||||
emu->res = d | s;
|
||||
emu->res.u32 = d | s;
|
||||
emu->df = d_or32;
|
||||
return emu->res;
|
||||
return emu->res.u32;
|
||||
}
|
||||
|
||||
static inline uint64_t or64(x64emu_t *emu, uint64_t d, uint64_t s)
|
||||
{
|
||||
emu->res = d | s;
|
||||
emu->res.u64 = d | s;
|
||||
emu->df = d_or64;
|
||||
return emu->res;
|
||||
return emu->res.u64;
|
||||
}
|
||||
|
||||
static inline uint8_t neg8(x64emu_t *emu, uint8_t s)
|
||||
{
|
||||
emu->res = (uint8_t)-s;
|
||||
emu->op1 = s;
|
||||
emu->res.u8 = (uint8_t)-s;
|
||||
emu->op1.u8 = s;
|
||||
emu->df = d_neg8;
|
||||
return emu->res;
|
||||
return emu->res.u8;
|
||||
}
|
||||
|
||||
static inline uint16_t neg16(x64emu_t *emu, uint16_t s)
|
||||
{
|
||||
emu->res = (uint16_t)-s;
|
||||
emu->op1 = s;
|
||||
emu->res.u16 = (uint16_t)-s;
|
||||
emu->op1.u16 = s;
|
||||
emu->df = d_neg16;
|
||||
return emu->res;
|
||||
return emu->res.u16;
|
||||
}
|
||||
|
||||
static inline uint32_t neg32(x64emu_t *emu, uint32_t s)
|
||||
{
|
||||
emu->res = (uint32_t)-s;
|
||||
emu->op1 = s;
|
||||
emu->res.u32 = (uint32_t)-s;
|
||||
emu->op1.u32 = s;
|
||||
emu->df = d_neg32;
|
||||
return emu->res;
|
||||
return emu->res.u32;
|
||||
}
|
||||
|
||||
static inline uint64_t neg64(x64emu_t *emu, uint64_t s)
|
||||
{
|
||||
emu->res = (uint64_t)-s;
|
||||
emu->op1 = s;
|
||||
emu->res.u64 = (uint64_t)-s;
|
||||
emu->op1.u64 = s;
|
||||
emu->df = d_neg64;
|
||||
return emu->res;
|
||||
return emu->res.u64;
|
||||
}
|
||||
|
||||
static inline uint8_t not8(x64emu_t *emu, uint8_t s)
|
||||
{
|
||||
(void)emu; // No flags affected
|
||||
return ~s;
|
||||
}
|
||||
|
||||
static inline uint16_t not16(x64emu_t *emu, uint16_t s)
|
||||
{
|
||||
(void)emu; // No flags affected
|
||||
return ~s;
|
||||
}
|
||||
|
||||
static inline uint32_t not32(x64emu_t *emu, uint32_t s)
|
||||
{
|
||||
(void)emu; // No flags affected
|
||||
return ~s;
|
||||
}
|
||||
|
||||
static inline uint64_t not64(x64emu_t *emu, uint64_t s)
|
||||
{
|
||||
(void)emu; // No flags affected
|
||||
return ~s;
|
||||
}
|
||||
|
||||
@@ -283,184 +287,180 @@ uint64_t sbb64 (x64emu_t *emu, uint64_t d, uint64_t s);
|
||||
static inline uint8_t shl8(x64emu_t *emu, uint8_t d, uint8_t s)
|
||||
{
|
||||
emu->df = d_shl8;
|
||||
emu->op1 = d;
|
||||
emu->op1.u8 = d;
|
||||
|
||||
s &= 0x1f;
|
||||
emu->op2 = s;
|
||||
emu->res = d << s;
|
||||
emu->op2.u8 = s;
|
||||
emu->res.u8 = d << s;
|
||||
|
||||
return (uint8_t)emu->res;
|
||||
return emu->res.u8;
|
||||
}
|
||||
|
||||
static inline uint16_t shl16(x64emu_t *emu, uint16_t d, uint8_t s)
|
||||
{
|
||||
emu->df = d_shl16;
|
||||
emu->op1 = d;
|
||||
emu->op1.u16 = d;
|
||||
|
||||
s &= 0x1f;
|
||||
emu->op2 = s;
|
||||
emu->res = d << s;
|
||||
return (uint16_t)emu->res;
|
||||
emu->op2.u16 = s;
|
||||
emu->res.u16 = d << s;
|
||||
return emu->res.u16;
|
||||
}
|
||||
|
||||
static inline uint32_t shl32(x64emu_t *emu, uint32_t d, uint8_t s)
|
||||
{
|
||||
emu->df = d_shl32;
|
||||
emu->op1 = d;
|
||||
emu->op1.u32 = d;
|
||||
|
||||
s &= 0x1f;
|
||||
emu->op2 = s;
|
||||
emu->res = d << s;
|
||||
emu->op2.u32 = s;
|
||||
emu->res.u32 = d << s;
|
||||
|
||||
return emu->res;
|
||||
return emu->res.u32;
|
||||
}
|
||||
|
||||
static inline uint64_t shl64(x64emu_t *emu, uint64_t d, uint8_t s)
|
||||
{
|
||||
emu->df = d_shl64;
|
||||
emu->op1 = d;
|
||||
emu->op1.u64 = d;
|
||||
|
||||
s &= 0x3f;
|
||||
emu->op2 = s;
|
||||
emu->res = d << s;
|
||||
emu->op2.u64 = s;
|
||||
emu->res.u64 = d << s;
|
||||
|
||||
return emu->res;
|
||||
return emu->res.u64;
|
||||
}
|
||||
|
||||
static inline uint8_t shr8(x64emu_t *emu, uint8_t d, uint8_t s)
|
||||
{
|
||||
emu->df = d_shr8;
|
||||
emu->op1 = d;
|
||||
emu->op1.u8 = d;
|
||||
|
||||
s &= 0x1f;
|
||||
emu->op2 = s;
|
||||
emu->res = d >> s;
|
||||
emu->op2.u8 = s;
|
||||
emu->res.u8 = d >> s;
|
||||
|
||||
return (uint8_t)emu->res;
|
||||
return emu->res.u8;
|
||||
}
|
||||
|
||||
static inline uint16_t shr16(x64emu_t *emu, uint16_t d, uint8_t s)
|
||||
{
|
||||
emu->df = d_shr16;
|
||||
emu->op1 = d;
|
||||
emu->op1.u16 = d;
|
||||
|
||||
s &= 0x1f;
|
||||
emu->op2 = s;
|
||||
emu->res = d >> s;
|
||||
emu->op2.u16 = s;
|
||||
emu->res.u16 = d >> s;
|
||||
|
||||
return (uint16_t)emu->res;
|
||||
return emu->res.u16;
|
||||
}
|
||||
|
||||
static inline uint32_t shr32(x64emu_t *emu, uint32_t d, uint8_t s)
|
||||
{
|
||||
RESET_FLAGS(emu); // TODO: Defered this one?
|
||||
|
||||
emu->df = d_shr32;
|
||||
emu->op1 = d;
|
||||
emu->op1.u32 = d;
|
||||
|
||||
s &= 0x1f;
|
||||
emu->op2 = s;
|
||||
emu->res = d >> s;
|
||||
emu->op2.u32 = s;
|
||||
emu->res.u32 = d >> s;
|
||||
|
||||
return emu->res;
|
||||
return emu->res.u32;
|
||||
}
|
||||
|
||||
static inline uint64_t shr64(x64emu_t *emu, uint64_t d, uint8_t s)
|
||||
{
|
||||
RESET_FLAGS(emu); // TODO: Defered this one?
|
||||
|
||||
emu->df = d_shr64;
|
||||
emu->op1 = d;
|
||||
emu->op1.u64 = d;
|
||||
|
||||
s &= 0x3f;
|
||||
emu->op2 = s;
|
||||
emu->res = d >> s;
|
||||
emu->op2.u64 = s;
|
||||
emu->res.u64 = d >> s;
|
||||
|
||||
return emu->res;
|
||||
return emu->res.u64;
|
||||
}
|
||||
|
||||
static inline uint8_t sar8(x64emu_t *emu, uint8_t d, uint8_t s)
|
||||
{
|
||||
emu->df = d_sar8;
|
||||
emu->op1 = d;
|
||||
emu->op1.u8 = d;
|
||||
|
||||
s &= 0x1f;
|
||||
emu->op2 = s;
|
||||
emu->res = (uint8_t)(((int8_t)d)>>s);
|
||||
emu->op2.u8 = s;
|
||||
emu->res.u8 = (uint8_t)(((int8_t)d)>>s);
|
||||
|
||||
return (uint8_t)emu->res;
|
||||
return emu->res.u8;
|
||||
}
|
||||
|
||||
static inline uint16_t sar16(x64emu_t *emu, uint16_t d, uint8_t s)
|
||||
{
|
||||
emu->df = d_sar16;
|
||||
emu->op1 = d;
|
||||
emu->op1.u16 = d;
|
||||
|
||||
s &= 0x1f;
|
||||
emu->op2 = s;
|
||||
emu->res = (uint16_t)(((int16_t)d)>>s);
|
||||
emu->op2.u16 = s;
|
||||
emu->res.u16 = (uint16_t)(((int16_t)d)>>s);
|
||||
|
||||
return (uint16_t)emu->res;
|
||||
return emu->res.u16;
|
||||
}
|
||||
|
||||
static inline uint32_t sar32(x64emu_t *emu, uint32_t d, uint8_t s)
|
||||
{
|
||||
emu->df = d_sar32;
|
||||
emu->op1 = d;
|
||||
emu->op1.u32 = d;
|
||||
|
||||
s &= 0x1f;
|
||||
emu->op2 = s;
|
||||
emu->res = (uint32_t)(((int32_t)d)>>s);
|
||||
emu->op2.u32 = s;
|
||||
emu->res.u32 = (uint32_t)(((int32_t)d)>>s);
|
||||
|
||||
return emu->res;
|
||||
return emu->res.u32;
|
||||
}
|
||||
|
||||
static inline uint64_t sar64(x64emu_t *emu, uint64_t d, uint8_t s)
|
||||
{
|
||||
emu->df = d_sar64;
|
||||
emu->op1 = d;
|
||||
emu->op1.u64 = d;
|
||||
|
||||
s &= 0x3f;
|
||||
emu->op2 = s;
|
||||
emu->res = (uint64_t)(((int64_t)d)>>s);
|
||||
emu->op2.u64 = s;
|
||||
emu->res.u64 = (uint64_t)(((int64_t)d)>>s);
|
||||
|
||||
return emu->res;
|
||||
return emu->res.u64;
|
||||
}
|
||||
|
||||
static inline uint8_t sub8(x64emu_t *emu, uint8_t d, uint8_t s)
|
||||
{
|
||||
emu->res = d - s;
|
||||
emu->op1 = d;
|
||||
emu->op2 = s;
|
||||
emu->res.u8 = d - s;
|
||||
emu->op1.u8 = d;
|
||||
emu->op2.u8 = s;
|
||||
emu->df = d_sub8;
|
||||
return (uint8_t)emu->res;
|
||||
return emu->res.u8;
|
||||
}
|
||||
|
||||
static inline uint16_t sub16(x64emu_t *emu, uint16_t d, uint16_t s)
|
||||
{
|
||||
emu->res = d - s;
|
||||
emu->op1 = d;
|
||||
emu->op2 = s;
|
||||
emu->res.u16 = d - s;
|
||||
emu->op1.u16 = d;
|
||||
emu->op2.u16 = s;
|
||||
emu->df = d_sub16;
|
||||
return (uint16_t)emu->res;
|
||||
return emu->res.u16;
|
||||
}
|
||||
|
||||
static inline uint32_t sub32(x64emu_t *emu, uint32_t d, uint32_t s)
|
||||
{
|
||||
emu->res = d - s;
|
||||
emu->op1 = d;
|
||||
emu->op2 = s;
|
||||
emu->res.u32 = d - s;
|
||||
emu->op1.u32 = d;
|
||||
emu->op2.u32 = s;
|
||||
emu->df = d_sub32;
|
||||
return emu->res;
|
||||
return emu->res.u32;
|
||||
}
|
||||
|
||||
static inline uint64_t sub64(x64emu_t *emu, uint64_t d, uint64_t s)
|
||||
{
|
||||
emu->res = d - s;
|
||||
emu->op1 = d;
|
||||
emu->op2 = s;
|
||||
emu->res.u64 = d - s;
|
||||
emu->op1.u64 = d;
|
||||
emu->op2.u64 = s;
|
||||
emu->df = d_sub64;
|
||||
return emu->res;
|
||||
return emu->res.u64;
|
||||
}
|
||||
|
||||
void test8 (x64emu_t *emu, uint8_t d, uint8_t s);
|
||||
@@ -470,52 +470,52 @@ void test64 (x64emu_t *emu, uint64_t d, uint64_t s);
|
||||
|
||||
static inline uint8_t xor8(x64emu_t *emu, uint8_t d, uint8_t s)
|
||||
{
|
||||
emu->res = d ^ s;
|
||||
emu->res.u8 = d ^ s;
|
||||
emu->df = d_xor8;
|
||||
return emu->res;
|
||||
return emu->res.u8;
|
||||
}
|
||||
|
||||
|
||||
static inline uint16_t xor16(x64emu_t *emu, uint16_t d, uint16_t s)
|
||||
{
|
||||
emu->res = d ^ s;
|
||||
emu->res.u16 = d ^ s;
|
||||
emu->df = d_xor16;
|
||||
return emu->res;
|
||||
return emu->res.u16;
|
||||
}
|
||||
|
||||
static inline uint32_t xor32(x64emu_t *emu, uint32_t d, uint32_t s)
|
||||
{
|
||||
emu->res = d ^ s;
|
||||
emu->res.u32 = d ^ s;
|
||||
emu->df = d_xor32;
|
||||
return emu->res;
|
||||
return emu->res.u32;
|
||||
}
|
||||
|
||||
static inline uint64_t xor64(x64emu_t *emu, uint64_t d, uint64_t s)
|
||||
{
|
||||
emu->res = d ^ s;
|
||||
emu->res.u64 = d ^ s;
|
||||
emu->df = d_xor64;
|
||||
return emu->res;
|
||||
return emu->res.u64;
|
||||
}
|
||||
|
||||
static inline void imul8(x64emu_t *emu, uint8_t s)
|
||||
{
|
||||
emu->df = d_imul8;
|
||||
R_AX = emu->res = (int16_t)(int8_t)R_AL * (int8_t)s;
|
||||
R_AX = emu->res.u16 = (int16_t)(int8_t)R_AL * (int8_t)s;
|
||||
}
|
||||
|
||||
static inline void imul16_eax(x64emu_t *emu, uint16_t s)
|
||||
{
|
||||
emu->df = d_imul16;
|
||||
emu->res = (int32_t)(int16_t)R_AX * (int16_t)s;
|
||||
R_AX = (uint16_t)emu->res;
|
||||
R_DX = (uint16_t)(emu->res >> 16);
|
||||
emu->res.u32 = (int32_t)(int16_t)R_AX * (int16_t)s;
|
||||
R_AX = (uint16_t)emu->res.u32;
|
||||
R_DX = (uint16_t)(emu->res.u32 >> 16);
|
||||
}
|
||||
|
||||
static inline uint16_t imul16(x64emu_t *emu, uint16_t op1, uint16_t op2)
|
||||
{
|
||||
emu->df = d_imul16;
|
||||
emu->res = (int32_t)(int16_t)op1 * (int16_t)op2;
|
||||
return (uint16_t)emu->res;
|
||||
emu->res.u32 = (int32_t)(int16_t)op1 * (int16_t)op2;
|
||||
return emu->res.u16;
|
||||
}
|
||||
|
||||
static inline void imul32_direct(uint32_t *res_lo, uint32_t* res_hi,uint32_t d, uint32_t s)
|
||||
@@ -531,17 +531,17 @@ static inline uint32_t imul32(x64emu_t *emu, uint32_t op1, uint32_t op2)
|
||||
emu->df = d_imul32;
|
||||
uint32_t _res, _op1;
|
||||
imul32_direct(&_res,&_op1,op1,op2);
|
||||
emu->res = _res;
|
||||
emu->op1 = _op1;
|
||||
return emu->res;
|
||||
emu->res.u32 = _res;
|
||||
emu->op1.u32 = _op1;
|
||||
return emu->res.u32;
|
||||
}
|
||||
|
||||
static inline void imul32_eax(x64emu_t *emu, uint32_t s)
|
||||
{
|
||||
emu->df = d_imul32;
|
||||
imul32_direct(&R_EAX,&R_EDX,R_EAX,s);
|
||||
emu->res = R_EAX;
|
||||
emu->op1 = R_EDX;
|
||||
emu->res.u32 = R_EAX;
|
||||
emu->op1.u32 = R_EDX;
|
||||
}
|
||||
|
||||
static inline void imul64_direct(uint64_t *res_lo, uint64_t* res_hi,uint64_t d, uint64_t s)
|
||||
@@ -555,46 +555,46 @@ static inline void imul64_direct(uint64_t *res_lo, uint64_t* res_hi,uint64_t d,
|
||||
static inline uint64_t imul64(x64emu_t *emu, uint64_t op1, uint64_t op2)
|
||||
{
|
||||
emu->df = d_imul64;
|
||||
imul64_direct(&emu->res,&emu->op1,op1,op2);
|
||||
return emu->res;
|
||||
imul64_direct(&emu->res.u64,&emu->op1.u64,op1,op2);
|
||||
return emu->res.u64;
|
||||
}
|
||||
|
||||
static inline void imul64_rax(x64emu_t *emu, uint64_t s)
|
||||
{
|
||||
emu->df = d_imul64;
|
||||
imul64_direct(&R_RAX,&R_RDX,R_RAX,s);
|
||||
emu->res = R_RAX;
|
||||
emu->op1 = R_RDX;
|
||||
emu->res.u64 = R_RAX;
|
||||
emu->op1.u64 = R_RDX;
|
||||
}
|
||||
|
||||
static inline void mul8(x64emu_t *emu, uint8_t s)
|
||||
{
|
||||
emu->df = d_mul8;
|
||||
R_AX = emu->res = (uint16_t)(R_AL) * s;
|
||||
R_AX = emu->res.u16 = (uint16_t)(R_AL) * s;
|
||||
}
|
||||
|
||||
static inline void mul16(x64emu_t *emu, uint16_t s)
|
||||
{
|
||||
emu->df = d_mul16;
|
||||
emu->res = (uint32_t)R_AX * s;
|
||||
R_AX = (uint16_t)emu->res;
|
||||
R_DX = (uint16_t)(emu->res >> 16);
|
||||
emu->res.u32 = (uint32_t)R_AX * s;
|
||||
R_AX = (uint16_t)emu->res.u32;
|
||||
R_DX = (uint16_t)(emu->res.u32 >> 16);
|
||||
}
|
||||
|
||||
static inline void mul32_eax(x64emu_t *emu, uint32_t s)
|
||||
{
|
||||
emu->df = d_mul32;
|
||||
uint64_t res = (uint64_t)R_EAX * s;
|
||||
emu->res = R_EAX = (uint32_t)res;
|
||||
emu->op1 = R_EDX = (uint32_t)(res >> 32);
|
||||
emu->res.u32 = R_EAX = (uint32_t)res;
|
||||
emu->op1.u32 = R_EDX = (uint32_t)(res >> 32);
|
||||
}
|
||||
|
||||
static inline void mul64_rax(x64emu_t *emu, uint64_t s)
|
||||
{
|
||||
emu->df = d_mul64;
|
||||
__int128 res = (__int128)R_RAX * s;
|
||||
emu->res = R_RAX = (uint64_t)res;
|
||||
emu->op1 = R_RDX = (uint64_t)(res >> 64);
|
||||
unsigned __int128 res = (unsigned __int128)R_RAX * s;
|
||||
emu->res.u64 = R_RAX = (uint64_t)res;
|
||||
emu->op1.u64 = R_RDX = (uint64_t)(res >> 64);
|
||||
}
|
||||
|
||||
void idiv8 (x64emu_t *emu, uint8_t s);
|
||||
|
||||
+172
-49
@@ -21,7 +21,7 @@
|
||||
#include "bridge.h"
|
||||
#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#include "../dynarec/arm64_lock.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
@@ -48,7 +48,7 @@ int Run(x64emu_t *emu, int step)
|
||||
return 0;
|
||||
|
||||
//ref opcode: http://ref.x64asm.net/geek32.html#xA1
|
||||
printf_log(LOG_DEBUG, "Run X86 (%p), RIP=%p, Stack=%p\n", emu, (void*)R_RIP, emu->context->stack);
|
||||
printf_log(LOG_DEBUG, "Run X86 (%p), RIP=%p, Stack=%p\n", emu, (void*)R_RIP, (void*)R_RSP);
|
||||
|
||||
x64emurun:
|
||||
|
||||
@@ -70,6 +70,8 @@ x64emurun:
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
while((opcode==0x3E)) //Branch Taken Hint ignored
|
||||
opcode = F8;
|
||||
rex.rex = 0;
|
||||
while(opcode>=0x40 && opcode<=0x4f) {
|
||||
rex.rex = opcode;
|
||||
@@ -234,19 +236,26 @@ x64emurun:
|
||||
GD->sq[0] = ED->sdword[0];
|
||||
else
|
||||
if(MODREG)
|
||||
GD->q[0] = ED->sdword[0];
|
||||
GD->q[0] = ED->dword[0]; // not really a sign extension
|
||||
else
|
||||
GD->sdword[0] = ED->sdword[0]; // meh?
|
||||
break;
|
||||
case 0x64: /* FS: prefix */
|
||||
if(Run64(emu, rex)) {
|
||||
if(Run64(emu, rex, _FS)) {
|
||||
unimp = 1;
|
||||
goto fini;
|
||||
}
|
||||
if(emu->quit)
|
||||
goto fini;
|
||||
break;
|
||||
case 0x65: /* GS: prefix */
|
||||
if(Run64(emu, rex, _GS)) {
|
||||
unimp = 1;
|
||||
goto fini;
|
||||
}
|
||||
if(emu->quit)
|
||||
goto fini;
|
||||
break;
|
||||
|
||||
case 0x66: /* 16bits prefix */
|
||||
if(Run66(emu, rex, rep)) {
|
||||
unimp = 1;
|
||||
@@ -256,7 +265,7 @@ x64emurun:
|
||||
goto fini;
|
||||
break;
|
||||
case 0x67: /* reduce EASize prefix */
|
||||
if(Run67(emu, rex)) {
|
||||
if(Run67(emu, rex, rep)) {
|
||||
unimp = 1;
|
||||
goto fini;
|
||||
}
|
||||
@@ -274,10 +283,7 @@ x64emurun:
|
||||
if(rex.w)
|
||||
GD->q[0] = imul64(emu, ED->q[0], tmp64u);
|
||||
else
|
||||
if((nextop&0xC0)==0xC0)
|
||||
GD->q[0] = imul32(emu, ED->dword[0], tmp64u);
|
||||
else
|
||||
GD->dword[0] = imul32(emu, ED->dword[0], tmp64u);
|
||||
GD->q[0] = imul32(emu, ED->dword[0], tmp64u);
|
||||
break;
|
||||
case 0x6A: /* Push Ib */
|
||||
tmp64s = F8S;
|
||||
@@ -325,7 +331,7 @@ x64emurun:
|
||||
tmp32s = F8S;
|
||||
}
|
||||
if(rex.w) {
|
||||
tmp64u = (uint64_t)tmp32s;
|
||||
tmp64u = (uint64_t)(int64_t)tmp32s;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: ED->q[0] = add64(emu, ED->q[0], tmp64u); break;
|
||||
case 1: ED->q[0] = or64(emu, ED->q[0], tmp64u); break;
|
||||
@@ -381,48 +387,54 @@ x64emurun:
|
||||
case 0x86: /* XCHG Eb,Gb */
|
||||
nextop = F8;
|
||||
#ifdef DYNAREC
|
||||
GET_EB;
|
||||
if((nextop&0xC0)==0xC0) { // reg / reg: no lock
|
||||
GETEB(0);
|
||||
GETGB;
|
||||
if(MODREG) { // reg / reg: no lock
|
||||
tmp8u = GB;
|
||||
GB = EB->byte[0];
|
||||
EB->byte[0] = tmp8u;
|
||||
} else {
|
||||
do {
|
||||
tmp8u = arm_lock_read_b(EB);
|
||||
} while(arm_lock_write_b(EB, GB));
|
||||
tmp8u = arm64_lock_read_b(EB);
|
||||
} while(arm64_lock_write_b(EB, GB));
|
||||
GB = tmp8u;
|
||||
}
|
||||
// dynarec use need it's own mecanism
|
||||
#else
|
||||
GETEB(0);
|
||||
GETGB;
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
if(!MODREG)
|
||||
pthread_mutex_lock(&emu->context->mutex_lock); // XCHG always LOCK (but when accessing memory only)
|
||||
tmp8u = GB;
|
||||
GB = EB->byte[0];
|
||||
EB->byte[0] = tmp8u;
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
if(!MODREG)
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
case 0x87: /* XCHG Ed,Gd */
|
||||
nextop = F8;
|
||||
#ifdef DYNAREC
|
||||
GET_ED;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
tmp32u = GD.dword[0];
|
||||
GD.dword[0] = ED->dword[0];
|
||||
ED->dword[0] = tmp32u;
|
||||
} else {
|
||||
if(((uintptr_t)ED)&3)
|
||||
{
|
||||
// not aligned, dont't try to "LOCK"
|
||||
tmp32u = ED->dword[0];
|
||||
ED->dword[0] = GD.dword[0];
|
||||
GD.dword[0] = tmp32u;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
if(rex.w) {
|
||||
tmp64u = GD->q[0];
|
||||
GD->q[0] = ED->q[0];
|
||||
ED->q[0] = tmp64u;
|
||||
} else {
|
||||
// XCHG is supposed to automaticaly LOCK memory bus
|
||||
GD.dword[0] = arm_lock_xchg(ED, GD.dword[0]);
|
||||
tmp32u = GD->dword[0];
|
||||
GD->q[0] = ED->dword[0];
|
||||
ED->q[0] = tmp32u;
|
||||
}
|
||||
} else {
|
||||
if(rex.w) {
|
||||
GD->q[0] = arm64_lock_xchg(ED, GD->q[0]);
|
||||
} else {
|
||||
do {
|
||||
tmp32u = arm64_lock_read_d(ED);
|
||||
} while(arm64_lock_write_d(ED, GD->dword[0]));
|
||||
GD->q[0] = tmp32u;
|
||||
}
|
||||
}
|
||||
#else
|
||||
@@ -466,7 +478,12 @@ x64emurun:
|
||||
ED->dword[0] = GD->dword[0];
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8A: /* MOV Gb,Eb */
|
||||
nextop = F8;
|
||||
GETEB(0);
|
||||
GETGB;
|
||||
GB = EB->byte[0];
|
||||
break;
|
||||
case 0x8B: /* MOV Gd,Ed */
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
@@ -476,7 +493,11 @@ x64emurun:
|
||||
else
|
||||
GD->q[0] = ED->dword[0];
|
||||
break;
|
||||
|
||||
case 0x8C: /* MOV Ed, Seg */
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
ED->dword[0] = emu->segs[((nextop&0x38)>>3)];
|
||||
break;
|
||||
case 0x8D: /* LEA Gd,M */
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
@@ -484,7 +505,7 @@ x64emurun:
|
||||
if(rex.w)
|
||||
GD->q[0] = (uint64_t)ED;
|
||||
else
|
||||
GD->q[0] = (uint32_t)(uintptr_t)ED;
|
||||
GD->q[0] = ((uintptr_t)ED)&0xffffffff;
|
||||
break;
|
||||
|
||||
case 0x8F: /* POP Ed */
|
||||
@@ -499,7 +520,26 @@ x64emurun:
|
||||
R_ESP += sizeof(void*);
|
||||
}
|
||||
break;
|
||||
case 0x90: /* NOP */
|
||||
case 0x90: /* NOP or XCHG R8, RAX*/
|
||||
case 0x91:
|
||||
case 0x92:
|
||||
case 0x93:
|
||||
case 0x94:
|
||||
case 0x95:
|
||||
case 0x96:
|
||||
case 0x97: /* XCHG reg,EAX */
|
||||
tmp8u = _AX+(opcode&7)+(rex.b<<3);
|
||||
if(tmp8u!=_AX) {
|
||||
if(rex.w) {
|
||||
tmp64u = R_RAX;
|
||||
R_RAX = emu->regs[tmp8u].q[0];
|
||||
emu->regs[tmp8u].q[0] = tmp64u;
|
||||
} else {
|
||||
tmp64u = R_EAX;
|
||||
R_RAX = emu->regs[tmp8u].dword[0];
|
||||
emu->regs[tmp8u].q[0] = tmp64u;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x98: /* CWDE */
|
||||
@@ -527,7 +567,38 @@ x64emurun:
|
||||
emu->eflags.x64 = ((Pop(emu) & 0x3F7FD7)/* & (0xffff-40)*/ ) | 0x2; // mask off res2 and res3 and on res1
|
||||
RESET_FLAGS(emu);
|
||||
break;
|
||||
|
||||
case 0x9E: /* SAHF */
|
||||
CHECK_FLAGS(emu);
|
||||
tmp8u = emu->regs[_AX].byte[1];
|
||||
CONDITIONAL_SET_FLAG(tmp8u&0x01, F_CF);
|
||||
CONDITIONAL_SET_FLAG(tmp8u&0x04, F_PF);
|
||||
CONDITIONAL_SET_FLAG(tmp8u&0x10, F_AF);
|
||||
CONDITIONAL_SET_FLAG(tmp8u&0x40, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(tmp8u&0x80, F_SF);
|
||||
RESET_FLAGS(emu);
|
||||
break;
|
||||
case 0x9F: /* LAHF */
|
||||
CHECK_FLAGS(emu);
|
||||
R_AH = (uint8_t)emu->eflags.x64;
|
||||
break;
|
||||
case 0xA0: /* MOV AL,Ob */
|
||||
R_AL = *(uint8_t*)F64;
|
||||
break;
|
||||
case 0xA1: /* MOV EAX,Od */
|
||||
if(rex.w)
|
||||
R_RAX = *(uint64_t*)F64;
|
||||
else
|
||||
R_RAX = *(uint32_t*)F64;
|
||||
break;
|
||||
case 0xA2: /* MOV Ob,AL */
|
||||
*(uint8_t*)F64 = R_AL;
|
||||
break;
|
||||
case 0xA3: /* MOV Od,EAX */
|
||||
if(rex.w)
|
||||
*(uint64_t*)F64 = R_RAX;
|
||||
else
|
||||
*(uint32_t*)F64 = R_EAX;
|
||||
break;
|
||||
case 0xA4: /* MOVSB */
|
||||
tmp8s = ACCESS_FLAG(F_DF)?-1:+1;
|
||||
tmp64u = (rep)?R_RCX:1L;
|
||||
@@ -878,7 +949,6 @@ x64emurun:
|
||||
else
|
||||
emu->regs[(opcode&7)+(rex.b<<3)].q[0] = F32;
|
||||
break;
|
||||
|
||||
case 0xC0: /* GRP2 Eb,Ib */
|
||||
nextop = F8;
|
||||
GETEB(1);
|
||||
@@ -1074,7 +1144,14 @@ x64emurun:
|
||||
if(emu->quit)
|
||||
goto fini;
|
||||
break;
|
||||
|
||||
case 0xDC: /* x87 opcodes */
|
||||
if(RunDC(emu, rex)) {
|
||||
unimp = 1;
|
||||
goto fini;
|
||||
}
|
||||
if(emu->quit)
|
||||
goto fini;
|
||||
break;
|
||||
case 0xDD: /* x87 opcodes */
|
||||
if(RunDD(emu, rex)) {
|
||||
unimp = 1;
|
||||
@@ -1083,7 +1160,14 @@ x64emurun:
|
||||
if(emu->quit)
|
||||
goto fini;
|
||||
break;
|
||||
|
||||
case 0xDE: /* x87 opcodes */
|
||||
if(RunDE(emu, rex)) {
|
||||
unimp = 1;
|
||||
goto fini;
|
||||
}
|
||||
if(emu->quit)
|
||||
goto fini;
|
||||
break;
|
||||
case 0xDF: /* x87 opcodes */
|
||||
if(RunDF(emu, rex)) {
|
||||
unimp = 1;
|
||||
@@ -1092,6 +1176,35 @@ x64emurun:
|
||||
if(emu->quit)
|
||||
goto fini;
|
||||
break;
|
||||
case 0xE0: /* LOOPNZ */
|
||||
CHECK_FLAGS(emu);
|
||||
tmp8s = F8S;
|
||||
--R_RCX; // don't update flags
|
||||
if(R_RCX && !ACCESS_FLAG(F_ZF))
|
||||
R_RIP += tmp8s;
|
||||
STEP
|
||||
break;
|
||||
case 0xE1: /* LOOPZ */
|
||||
CHECK_FLAGS(emu);
|
||||
tmp8s = F8S;
|
||||
--R_RCX; // don't update flags
|
||||
if(R_RCX && ACCESS_FLAG(F_ZF))
|
||||
R_RIP += tmp8s;
|
||||
STEP
|
||||
break;
|
||||
case 0xE2: /* LOOP */
|
||||
tmp8s = F8S;
|
||||
--R_RCX; // don't update flags
|
||||
if(R_RCX)
|
||||
R_RIP += tmp8s;
|
||||
STEP
|
||||
break;
|
||||
case 0xE3: /* JECXZ */
|
||||
tmp8s = F8S;
|
||||
if(!R_RCX)
|
||||
R_RIP += tmp8s;
|
||||
STEP
|
||||
break;
|
||||
|
||||
case 0xE8: /* CALL Id */
|
||||
tmp32s = F32S; // call is relative
|
||||
@@ -1120,6 +1233,10 @@ x64emurun:
|
||||
goto fini;
|
||||
break;
|
||||
|
||||
case 0xF5: /* CMC */
|
||||
CHECK_FLAGS(emu);
|
||||
CONDITIONAL_SET_FLAG(!ACCESS_FLAG(F_CF), F_CF);
|
||||
break;
|
||||
case 0xF6: /* GRP3 Eb(,Ib) */
|
||||
nextop = F8;
|
||||
tmp8u = (nextop>>3)&7;
|
||||
@@ -1209,18 +1326,17 @@ x64emurun:
|
||||
break;
|
||||
case 6: /* DIV Ed */
|
||||
div32(emu, ED->dword[0]);
|
||||
emu->regs[_AX].dword[1] = 0;
|
||||
emu->regs[_DX].dword[1] = 0;
|
||||
//emu->regs[_AX].dword[1] = 0; // already put high regs to 0
|
||||
//emu->regs[_DX].dword[1] = 0;
|
||||
break;
|
||||
case 7: /* IDIV Ed */
|
||||
idiv32(emu, ED->dword[0]);
|
||||
emu->regs[_AX].dword[1] = 0;
|
||||
emu->regs[_DX].dword[1] = 0;
|
||||
//emu->regs[_AX].dword[1] = 0;
|
||||
//emu->regs[_DX].dword[1] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF8: /* CLC */
|
||||
CHECK_FLAGS(emu);
|
||||
CLEAR_FLAG(F_CF);
|
||||
@@ -1263,14 +1379,22 @@ x64emurun:
|
||||
case 0: /* INC Ed */
|
||||
if(rex.w)
|
||||
ED->q[0] = inc64(emu, ED->q[0]);
|
||||
else
|
||||
ED->q[0] = inc32(emu, ED->dword[0]);
|
||||
else {
|
||||
if(MODREG)
|
||||
ED->q[0] = inc32(emu, ED->dword[0]);
|
||||
else
|
||||
ED->dword[0] = inc32(emu, ED->dword[0]);
|
||||
}
|
||||
break;
|
||||
case 1: /* DEC Ed */
|
||||
if(rex.w)
|
||||
ED->q[0] = dec64(emu, ED->q[0]);
|
||||
else
|
||||
ED->q[0] = dec32(emu, ED->dword[0]);
|
||||
else {
|
||||
if(MODREG)
|
||||
ED->q[0] = dec32(emu, ED->dword[0]);
|
||||
else
|
||||
ED->dword[0] = dec32(emu, ED->dword[0]);
|
||||
}
|
||||
break;
|
||||
case 2: /* CALL NEAR Ed */
|
||||
tmp64u = (uintptr_t)getAlternate((void*)ED->q[0]);
|
||||
@@ -1307,7 +1431,6 @@ x64emurun:
|
||||
} else {
|
||||
R_RIP = ED->q[0];
|
||||
R_CS = (ED+1)->word[0];
|
||||
STEP
|
||||
goto fini; // exit loop to recompute CS...
|
||||
}
|
||||
break;
|
||||
|
||||
+302
-60
@@ -22,7 +22,8 @@
|
||||
#include "bridge.h"
|
||||
#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#include "custommem.h"
|
||||
#include "../dynarec/arm64_lock.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
@@ -38,7 +39,7 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
uint64_t tmp64u, tmp64u2;
|
||||
reg64_t *oped, *opgd;
|
||||
sse_regs_t *opex, *opgx, eax1;
|
||||
mmx87_regs_t *opem, *opgm;
|
||||
mmx87_regs_t *opem, *opgm, eam1;
|
||||
|
||||
opcode = F8;
|
||||
|
||||
@@ -48,6 +49,22 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
x64Syscall(emu);
|
||||
break;
|
||||
|
||||
case 0x0B: /* UD2 */
|
||||
emit_signal(emu, SIGILL, (void*)R_RIP, 0);
|
||||
break;
|
||||
|
||||
case 0x0D:
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
switch((nextop>>3)&7) {
|
||||
case 1: //PREFETCHW
|
||||
__builtin_prefetch((void*)ED, 1, 0);
|
||||
break;
|
||||
default: //???
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x10: /* MOVUPS Gx,Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
@@ -104,6 +121,22 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
GETGX;
|
||||
EX->q[0] = GX->q[1];
|
||||
break;
|
||||
case 0x18: /* PREFETCHh Ed */
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
if(MODREG) {
|
||||
} else
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: //PREFETCHnta
|
||||
case 1: //PREFETCH1
|
||||
case 2: //PREFETCH2
|
||||
case 3: //PREFETCH3
|
||||
__builtin_prefetch((void*)ED, 0, 0); // ignoring wich level of cache
|
||||
break;
|
||||
default: //NOP
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x1F: /* NOP (multi-byte) */
|
||||
nextop = F8;
|
||||
@@ -188,6 +221,75 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
CLEAR_FLAG(F_OF); CLEAR_FLAG(F_AF); CLEAR_FLAG(F_SF);
|
||||
break;
|
||||
|
||||
case 0x31: /* RDTSC */
|
||||
tmp64u = ReadTSC(emu);
|
||||
R_RDX = tmp64u>>32;
|
||||
R_RAX = tmp64u&0xFFFFFFFF;
|
||||
break;
|
||||
|
||||
case 0x38: // these are some SSE3 opcodes
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
case 0x00: /* PSHUFB */
|
||||
nextop = F8;
|
||||
GETEM(0);
|
||||
GETGM;
|
||||
eam1 = *GM;
|
||||
for (int i=0; i<8; ++i) {
|
||||
if(EM->ub[i]&128)
|
||||
GM->ub[i] = 0;
|
||||
else
|
||||
GM->ub[i] = eam1.ub[EM->ub[i]&7];
|
||||
}
|
||||
break;
|
||||
case 0x04: /* PMADDUBSW Gm,Em */
|
||||
nextop = F8;
|
||||
GETEM(0);
|
||||
GETGM;
|
||||
for (int i=0; i<4; ++i) {
|
||||
tmp32s = (int32_t)(GM->ub[i*2+0])*EM->sb[i*2+0] + (int32_t)(GM->ub[i*2+1])*EM->sb[i*2+1];
|
||||
GM->sw[i] = (tmp32s>32767)?32767:((tmp32s<-32768)?-32768:tmp32s);
|
||||
}
|
||||
break;
|
||||
case 0x0B: /* PMULHRSW Gm, Em */
|
||||
nextop = F8;
|
||||
GETEM(0);
|
||||
GETGM;
|
||||
for (int i=0; i<4; ++i) {
|
||||
tmp32s = ((((int32_t)(GM->sw[i])*(int32_t)(EM->sw[i]))>>14) + 1)>>1;
|
||||
GM->uw[i] = tmp32s&0xffff;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x1C: /* PABSB Gm, Em */
|
||||
nextop = F8;
|
||||
GETEM(0);
|
||||
GETGM;
|
||||
for (int i=0; i<8; ++i) {
|
||||
GM->sb[i] = abs(EM->sb[i]);
|
||||
}
|
||||
break;
|
||||
case 0x1D: /* PABSW Gm, Em */
|
||||
nextop = F8;
|
||||
GETEM(0);
|
||||
GETGM;
|
||||
for (int i=0; i<4; ++i) {
|
||||
GM->sw[i] = abs(EM->sw[i]);
|
||||
}
|
||||
break;
|
||||
case 0x1E: /* PABSD Gm, Em */
|
||||
nextop = F8;
|
||||
GETEM(0);
|
||||
GETGM;
|
||||
for (int i=0; i<2; ++i) {
|
||||
GM->sd[i] = abs(EM->sd[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
GOCOND(0x40
|
||||
, nextop = F8;
|
||||
@@ -202,7 +304,7 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGD;
|
||||
GD->dword[0] = 0;
|
||||
GD->q[0] = 0;
|
||||
for(int i=0; i<4; ++i)
|
||||
GD->dword[0] |= ((EX->ud[i]>>31)&1)<<i;
|
||||
break;
|
||||
@@ -443,13 +545,103 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
GM->sw[2+i] = (EM->sd[i]<-32768)?-32768:((EM->sd[i]>32767)?32767:EM->sd[i]);
|
||||
break;
|
||||
|
||||
case 0x6E: /* MOVD Gm, Ed */
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGM;
|
||||
if(rex.w)
|
||||
GM->q = ED->q[0];
|
||||
else
|
||||
GM->q = ED->dword[0]; // zero extended
|
||||
break;
|
||||
case 0x6F: /* MOVQ Gm, Em */
|
||||
nextop = F8;
|
||||
GETEM(0);
|
||||
GETGM;
|
||||
GM->q = EM->q;
|
||||
break;
|
||||
|
||||
case 0x70: /* PSHUFW Gm, Em, Ib */
|
||||
nextop = F8;
|
||||
GETEM(1);
|
||||
GETGM;
|
||||
tmp8u = F8;
|
||||
if(EM==GM) {eam1 = *GM; EM = &eam1;} // copy is needed
|
||||
for(int i=0; i<4; ++i)
|
||||
GM->uw[i] = EM->uw[(tmp8u>>(i*2))&3];
|
||||
break;
|
||||
case 0x71: /* GRP */
|
||||
nextop = F8;
|
||||
GETEM(1);
|
||||
tmp8u = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 2: /* PSRLW Em, Ib */
|
||||
if(tmp8u>15)
|
||||
{EM->q = 0;}
|
||||
else
|
||||
for (int i=0; i<4; ++i) EM->uw[i] >>= tmp8u;
|
||||
break;
|
||||
case 4: /* PSRAW Em, Ib */
|
||||
if(tmp8u>15) tmp8u = 15;
|
||||
for (int i=0; i<4; ++i) EM->sw[i] >>= tmp8u;
|
||||
break;
|
||||
case 6: /* PSLLW Em, Ib */
|
||||
if(tmp8u>15)
|
||||
{EM->q = 0;}
|
||||
else
|
||||
for (int i=0; i<4; ++i) EM->uw[i] <<= tmp8u;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 0x72: /* GRP */
|
||||
nextop = F8;
|
||||
GETEM(1);
|
||||
switch((nextop>>3)&7) {
|
||||
case 2: /* PSRLD Em, Ib */
|
||||
tmp8u = F8;
|
||||
if(tmp8u>31)
|
||||
{EM->q = 0;}
|
||||
else
|
||||
for (int i=0; i<2; ++i) EM->ud[i] >>= tmp8u;
|
||||
break;
|
||||
case 4: /* PSRAD Em, Ib */
|
||||
tmp8u = F8;
|
||||
for (int i=0; i<2; ++i) EM->sd[i] >>= tmp8u;
|
||||
break;
|
||||
case 6: /* PSLLD Em, Ib */
|
||||
tmp8u = F8;
|
||||
if(tmp8u>31)
|
||||
{EM->q = 0;}
|
||||
else
|
||||
for (int i=0; i<2; ++i) EM->ud[i] <<= tmp8u;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 0x73: /* GRP */
|
||||
nextop = F8;
|
||||
GETEM(1);
|
||||
switch((nextop>>3)&7) {
|
||||
case 2: /* PSRLQ Em, Ib */
|
||||
tmp8u = F8;
|
||||
if(tmp8u>63)
|
||||
{EM->q = 0;}
|
||||
else
|
||||
{EM->q >>= tmp8u;}
|
||||
break;
|
||||
case 6: /* PSLLQ Em, Ib */
|
||||
tmp8u = F8;
|
||||
if(tmp8u>63)
|
||||
{EM->q = 0;}
|
||||
else
|
||||
{EM->q <<= tmp8u;}
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 0x74: /* PCMPEQB Gm,Em */
|
||||
nextop = F8;
|
||||
GETEM(0);
|
||||
@@ -486,8 +678,12 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
GETGM;
|
||||
if(rex.w)
|
||||
ED->q[0] = GM->q;
|
||||
else
|
||||
ED->q[0] = GM->ud[0];
|
||||
else {
|
||||
if(MODREG)
|
||||
ED->q[0] = GM->ud[0];
|
||||
else
|
||||
ED->dword[0] = GM->ud[0];
|
||||
}
|
||||
break;
|
||||
case 0x7F: /* MOVQ Em, Gm */
|
||||
nextop = F8;
|
||||
@@ -516,19 +712,19 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
tmp8u = GD->byte[0];
|
||||
tmp32s = GD->sdword[0];
|
||||
tmp8u=tmp32s&(rex.w?63:31);
|
||||
tmp32s >>= (rex.w?6:5);
|
||||
if(!MODREG)
|
||||
{
|
||||
ED=(reg64_t*)(((uint32_t*)(ED))+(tmp8u>>5));
|
||||
ED=(reg64_t*)(((uintptr_t)(ED))+(tmp32s<<(rex.w?3:2)));
|
||||
}
|
||||
if(rex.w) {
|
||||
tmp8u&=63;
|
||||
if(ED->q[0] & (1LL<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
else
|
||||
CLEAR_FLAG(F_CF);
|
||||
} else {
|
||||
tmp8u&=31;
|
||||
if(ED->dword[0] & (1<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
else
|
||||
@@ -546,8 +742,12 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
tmp8u = R_CL;
|
||||
if(rex.w)
|
||||
ED->q[0] = shld64(emu, ED->q[0], GD->q[0], tmp8u);
|
||||
else
|
||||
ED->q[0] = shld32(emu, ED->dword[0], GD->dword[0], tmp8u);
|
||||
else {
|
||||
if(MODREG)
|
||||
ED->q[0] = shld32(emu, ED->dword[0], GD->dword[0], tmp8u);
|
||||
else
|
||||
ED->dword[0] = shld32(emu, ED->dword[0], GD->dword[0], tmp8u);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xAB: /* BTS Ed,Gd */
|
||||
@@ -555,13 +755,14 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
tmp8u = GD->byte[0];
|
||||
tmp32s = GD->sdword[0];
|
||||
tmp8u=tmp32s&(rex.w?63:31);
|
||||
tmp32s >>= (rex.w?6:5);
|
||||
if(!MODREG)
|
||||
{
|
||||
ED=(reg64_t*)(((uint32_t*)(ED))+(tmp8u>>5));
|
||||
ED=(reg64_t*)(((uintptr_t)(ED))+(tmp32s<<(rex.w?3:2)));
|
||||
}
|
||||
if(rex.w) {
|
||||
tmp8u&=63;
|
||||
if(ED->q[0] & (1LL<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
else {
|
||||
@@ -569,7 +770,6 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
CLEAR_FLAG(F_CF);
|
||||
}
|
||||
} else {
|
||||
tmp8u&=31;
|
||||
if(ED->dword[0] & (1<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
else {
|
||||
@@ -588,8 +788,12 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
tmp8u = (opcode==0xAC)?(F8):R_CL;
|
||||
if(rex.w)
|
||||
ED->q[0] = shrd64(emu, ED->q[0], GD->q[0], tmp8u);
|
||||
else
|
||||
ED->q[0] = shrd32(emu, ED->dword[0], GD->dword[0], tmp8u);
|
||||
else {
|
||||
if(MODREG)
|
||||
ED->q[0] = shrd32(emu, ED->dword[0], GD->dword[0], tmp8u);
|
||||
else
|
||||
ED->dword[0] = shrd32(emu, ED->dword[0], GD->dword[0], tmp8u);
|
||||
}
|
||||
break;
|
||||
case 0xAE: /* Grp Ed (SSE) */
|
||||
nextop = F8;
|
||||
@@ -622,6 +826,11 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
case 3: /* STMXCSR Md */
|
||||
ED->dword[0] = emu->mxcsr;
|
||||
break;
|
||||
case 7: /* CLFLUSH Ed */
|
||||
#ifdef DYNAREC
|
||||
cleanDBFromAddressRange((uintptr_t)ED, 8, 0);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
@@ -633,7 +842,7 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
if(rex.w)
|
||||
GD->q[0] = imul64(emu, GD->q[0], ED->q[0]);
|
||||
else
|
||||
GD->dword[0] = imul32(emu, GD->dword[0], ED->dword[0]);
|
||||
GD->q[0] = imul32(emu, GD->dword[0], ED->dword[0]);
|
||||
break;
|
||||
case 0xB0: /* CMPXCHG Eb,Gb */
|
||||
nextop = F8;
|
||||
@@ -659,13 +868,12 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
}
|
||||
} else {
|
||||
cmp32(emu, R_EAX, ED->dword[0]);
|
||||
R_RAX = ED->dword[0]; // to erase upper part of RAX
|
||||
if(ACCESS_FLAG(F_ZF)) {
|
||||
if(MODREG)
|
||||
ED->q[0] = GD->dword[0];
|
||||
else
|
||||
ED->dword[0] = GD->dword[0];
|
||||
} else {
|
||||
R_RAX = ED->dword[0];
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -674,20 +882,20 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
tmp8u = GD->byte[0];
|
||||
tmp32s = GD->sdword[0];
|
||||
tmp8u=tmp32s&(rex.w?63:31);
|
||||
tmp32s >>= (rex.w?6:5);
|
||||
if(!MODREG)
|
||||
{
|
||||
ED=(reg64_t*)(((uint32_t*)(ED))+(tmp8u>>5));
|
||||
ED=(reg64_t*)(((uintptr_t)(ED))+(tmp32s<<(rex.w?3:2)));
|
||||
}
|
||||
if(rex.w) {
|
||||
tmp8u&=63;
|
||||
if(ED->q[0] & (1LL<<tmp8u)) {
|
||||
SET_FLAG(F_CF);
|
||||
ED->q[0] ^= (1LL<<tmp8u);
|
||||
} else
|
||||
CLEAR_FLAG(F_CF);
|
||||
} else {
|
||||
tmp8u&=31;
|
||||
if(ED->dword[0] & (1<<tmp8u)) {
|
||||
SET_FLAG(F_CF);
|
||||
ED->dword[0] ^= (1<<tmp8u);
|
||||
@@ -718,8 +926,6 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
CHECK_FLAGS(emu);
|
||||
GETED(1);
|
||||
tmp8u = F8;
|
||||
if(!MODREG)
|
||||
ED=(reg64_t*)(((uintptr_t*)(ED))+(tmp8u>>5));
|
||||
if(rex.w) {
|
||||
tmp8u&=63;
|
||||
if(ED->q[0] & (1LL<<tmp8u))
|
||||
@@ -738,8 +944,6 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
CHECK_FLAGS(emu);
|
||||
GETED(1);
|
||||
tmp8u = F8;
|
||||
if(!MODREG)
|
||||
ED=(reg64_t*)(((uintptr_t*)(ED))+(tmp8u>>5));
|
||||
if(rex.w) {
|
||||
tmp8u&=63;
|
||||
if(ED->q[0] & (1LL<<tmp8u)) {
|
||||
@@ -762,8 +966,6 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
CHECK_FLAGS(emu);
|
||||
GETED(1);
|
||||
tmp8u = F8;
|
||||
if(!MODREG)
|
||||
ED=(reg64_t*)(((uintptr_t*)(ED))+(tmp8u>>5));
|
||||
if(rex.w) {
|
||||
tmp8u&=63;
|
||||
if(ED->q[0] & (1LL<<tmp8u)) {
|
||||
@@ -784,8 +986,6 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
CHECK_FLAGS(emu);
|
||||
GETED(1);
|
||||
tmp8u = F8;
|
||||
if(!MODREG)
|
||||
ED=(reg64_t*)(((uintptr_t*)(ED))+(tmp8u>>5));
|
||||
if(rex.w) {
|
||||
tmp8u&=63;
|
||||
if(ED->q[0] & (1LL<<tmp8u))
|
||||
@@ -812,23 +1012,20 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
tmp8u = GD->byte[0];
|
||||
tmp32s = GD->sdword[0];
|
||||
tmp8u=tmp32s&(rex.w?63:31);
|
||||
tmp32s >>= (rex.w?6:5);
|
||||
if(!MODREG)
|
||||
{
|
||||
if(rex.w)
|
||||
ED=(reg64_t*)(((uint64_t*)(ED))+(tmp8u>>6));
|
||||
else
|
||||
ED=(reg64_t*)(((uint32_t*)(ED))+(tmp8u>>5));
|
||||
ED=(reg64_t*)(((uintptr_t)(ED))+(tmp32s<<(rex.w?3:2)));
|
||||
}
|
||||
if(rex.w) {
|
||||
tmp8u&=63;
|
||||
if(ED->q[0] & (1LL<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
else
|
||||
CLEAR_FLAG(F_CF);
|
||||
ED->q[0] ^= (1LL<<tmp8u);
|
||||
} else {
|
||||
tmp8u&=31;
|
||||
if(ED->dword[0] & (1<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
else
|
||||
@@ -960,6 +1157,20 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC4: /* PINSRW Gm,Ew,Ib */
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGM;
|
||||
tmp8u = F8;
|
||||
GM->uw[tmp8u&3] = ED->word[0]; // only low 16bits
|
||||
break;
|
||||
case 0xC5: /* PEXTRW Gw,Em,Ib */
|
||||
nextop = F8;
|
||||
GETEM(0);
|
||||
GETGD;
|
||||
tmp8u = F8;
|
||||
GD->q[0] = EM->uw[tmp8u&3]; // 16bits extract, 0 extended
|
||||
break;
|
||||
case 0xC6: /* SHUFPS Gx, Ex, Ib */
|
||||
nextop = F8;
|
||||
GETEX(1);
|
||||
@@ -1078,7 +1289,13 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
GM->uw[i] = (tmp32s < 0) ? 0 : tmp32s;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xDA: /* PMINUB Gm,Em */
|
||||
nextop = F8;
|
||||
GETEM(0);
|
||||
GETGM;
|
||||
for (int i=0; i<8; ++i)
|
||||
GM->ub[i] = (GM->ub[i]<EM->ub[i])?GM->ub[i]:EM->ub[i];
|
||||
break;
|
||||
case 0xDB: /* PAND Gm,Em */
|
||||
nextop = F8;
|
||||
GETEM(0);
|
||||
@@ -1103,14 +1320,26 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
GM->uw[i] = (tmp32u>65535) ? 65535 : tmp32u;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xDE: /* PMAXUB Gm,Em */
|
||||
nextop = F8;
|
||||
GETEM(0);
|
||||
GETGM;
|
||||
for (int i=0; i<8; ++i)
|
||||
GM->ub[i] = (GM->ub[i]>EM->ub[i])?GM->ub[i]:EM->ub[i];
|
||||
break;
|
||||
case 0xDF: /* PANDN Gm,Em */
|
||||
nextop = F8;
|
||||
GETEM(0);
|
||||
GETGM;
|
||||
GM->q = (~GM->q) & EM->q;
|
||||
break;
|
||||
|
||||
case 0xE0: /* PAVGB Gm, Em */
|
||||
nextop = F8;
|
||||
GETEM(0);
|
||||
GETGM;
|
||||
for(int i=0; i<8; ++i)
|
||||
GM->ub[i] = ((uint32_t)GM->ub[i]+EM->ub[i]+1)>>1;
|
||||
break;
|
||||
case 0xE1: /* PSRAW Gm, Em */
|
||||
nextop = F8;
|
||||
GETEM(0);
|
||||
@@ -1135,22 +1364,19 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
GM->sd[i] >>= tmp8u;
|
||||
}
|
||||
break;
|
||||
case 0xE3: /* PSRAQ Gm, Em */
|
||||
case 0xE3: /* PAVGW Gm, Em */
|
||||
nextop = F8;
|
||||
GETEM(0);
|
||||
GETGM;
|
||||
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;
|
||||
break;
|
||||
case 0xE4: /* PMULHUW Gm, Em */
|
||||
nextop = F8;
|
||||
GETEM(0);
|
||||
GETGM;
|
||||
for(int i=0; i<4; ++i) {
|
||||
tmp32u = (int32_t)GM->uw[i] * EM->uw[i];
|
||||
tmp32u = (uint32_t)GM->uw[i] * (uint32_t)EM->uw[i];
|
||||
GM->uw[i] = (tmp32u>>16)&0xffff;
|
||||
}
|
||||
break;
|
||||
@@ -1159,17 +1385,24 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
GETEM(0);
|
||||
GETGM;
|
||||
for(int i=0; i<4; ++i) {
|
||||
tmp32s = (int32_t)GM->sw[i] * EM->sw[i];
|
||||
GM->uw[i] = (tmp32s>>16)&0xffff;
|
||||
tmp32s = (int32_t)GM->sw[i] * (int32_t)EM->sw[i];
|
||||
GM->sw[i] = (tmp32s>>16)&0xffff;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xE7: /* MOVNTQ Em,Gm */
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0)
|
||||
return 1;
|
||||
GETEM(0);
|
||||
GETGM;
|
||||
EM->q = GM->q;
|
||||
break;
|
||||
case 0xE8: /* PSUBSB Gm,Em */
|
||||
nextop = F8;
|
||||
GETEM(0);
|
||||
GETGM;
|
||||
for(int i=0; i<8; ++i) {
|
||||
tmp32s = (int32_t)GM->sb[i] - EM->sb[i];
|
||||
tmp32s = (int32_t)GM->sb[i] - (int32_t)EM->sb[i];
|
||||
GM->sb[i] = (tmp32s>127)?127:((tmp32s<-128)?-128:tmp32s);
|
||||
}
|
||||
break;
|
||||
@@ -1257,27 +1490,36 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
GM->sd[i] = tmp32s + tmp32s2;
|
||||
}
|
||||
break;
|
||||
case 0xF6: /* PSADBW Gm, Em */
|
||||
nextop = F8;
|
||||
GETEM(0);
|
||||
GETGM;
|
||||
tmp32u = 0;
|
||||
for (int i=0; i<8; ++i)
|
||||
tmp32u += (GM->ub[i]>EM->ub[i])?(GM->ub[i] - EM->ub[i]):(EM->ub[i] - GM->ub[i]);
|
||||
GM->q = tmp32u;
|
||||
break;
|
||||
|
||||
case 0xF8: /* PSUBB Gm,Em */
|
||||
nextop = F8;
|
||||
GETEM(0);
|
||||
GETGM;
|
||||
for(int i=0; i<8; ++i)
|
||||
GM->sb[i] -= EM->sb[i];
|
||||
GM->ub[i] -= EM->ub[i];
|
||||
break;
|
||||
case 0xF9: /* PSUBW Gm,Em */
|
||||
nextop = F8;
|
||||
GETEM(0);
|
||||
GETGM;
|
||||
for(int i=0; i<4; ++i)
|
||||
GM->sw[i] -= EM->sw[i];
|
||||
GM->uw[i] -= EM->uw[i];
|
||||
break;
|
||||
case 0xFA: /* PSUBD Gm,Em */
|
||||
nextop = F8;
|
||||
GETEM(0);
|
||||
GETGM;
|
||||
for(int i=0; i<2; ++i)
|
||||
GM->sd[i] -= EM->sd[i];
|
||||
GM->ud[i] -= EM->ud[i];
|
||||
break;
|
||||
|
||||
case 0xFC: /* PADDB Gm, Em */
|
||||
@@ -1285,21 +1527,21 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
GETEM(0);
|
||||
GETGM;
|
||||
for(int i=0; i<8; ++i)
|
||||
GM->sb[i] += EM->sb[i];
|
||||
GM->ub[i] += EM->ub[i];
|
||||
break;
|
||||
case 0xFD: /* PADDW Gm,Em */
|
||||
nextop = F8;
|
||||
GETEM(0);
|
||||
GETGM;
|
||||
for(int i=0; i<4; ++i)
|
||||
GM->sw[i] += EM->sw[i];
|
||||
GM->uw[i] += EM->uw[i];
|
||||
break;
|
||||
case 0xFE: /* PADDD Gm,Em */
|
||||
nextop = F8;
|
||||
GETEM(0);
|
||||
GETGM;
|
||||
for(int i=0; i<2; ++i)
|
||||
GM->sd[i] += EM->sd[i];
|
||||
GM->ud[i] += EM->ud[i];
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
+217
-13
@@ -19,25 +19,23 @@
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
#include "bridge.h"
|
||||
//#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
int Run64(x64emu_t *emu, rex_t rex)
|
||||
int Run64(x64emu_t *emu, rex_t rex, int seg)
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t nextop;
|
||||
uint8_t tmp8u;
|
||||
int16_t tmp16s;
|
||||
uint16_t tmp16u;
|
||||
uint8_t tmp8u; (void)tmp8u;
|
||||
int16_t tmp16s; (void)tmp16s;
|
||||
uint16_t tmp16u; (void)tmp16u;
|
||||
int32_t tmp32s;
|
||||
uint32_t tmp32u;
|
||||
uint64_t tmp64u;
|
||||
reg64_t *oped, *opgd;
|
||||
uintptr_t tlsdata = GetFSBaseEmu(emu);
|
||||
sse_regs_t *opex, *opgx;
|
||||
int rep;
|
||||
uintptr_t tlsdata = GetSegmentBaseEmu(emu, seg);
|
||||
|
||||
opcode = F8;
|
||||
// REX prefix before the F0 are ignored
|
||||
@@ -46,19 +44,220 @@ int Run64(x64emu_t *emu, rex_t rex)
|
||||
rex.rex = opcode;
|
||||
opcode = F8;
|
||||
}
|
||||
rep = 0;
|
||||
while((opcode==0xF2) || (opcode==0xF3)) {
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
switch(opcode) {
|
||||
#define GO(B, OP) \
|
||||
case B+0: \
|
||||
nextop = F8; \
|
||||
GETEB_OFFS(0, tlsdata); \
|
||||
GETGB; \
|
||||
EB->byte[0] = OP##8(emu, EB->byte[0], GB); \
|
||||
break; \
|
||||
case B+1: \
|
||||
nextop = F8; \
|
||||
GETED_OFFS(0, tlsdata); \
|
||||
GETGD; \
|
||||
if(rex.w) \
|
||||
ED->q[0] = OP##64(emu, ED->q[0], GD->q[0]); \
|
||||
else { \
|
||||
if(MODREG) \
|
||||
ED->q[0] = OP##32(emu, ED->dword[0], GD->dword[0]); \
|
||||
else \
|
||||
ED->dword[0] = OP##32(emu, ED->dword[0], GD->dword[0]); \
|
||||
} \
|
||||
break; \
|
||||
case B+2: \
|
||||
nextop = F8; \
|
||||
GETEB_OFFS(0, tlsdata); \
|
||||
GETGB; \
|
||||
GB = OP##8(emu, GB, EB->byte[0]); \
|
||||
break; \
|
||||
case B+3: \
|
||||
nextop = F8; \
|
||||
GETED_OFFS(0, tlsdata); \
|
||||
GETGD; \
|
||||
if(rex.w) \
|
||||
GD->q[0] = OP##64(emu, GD->q[0], ED->q[0]); \
|
||||
else \
|
||||
GD->q[0] = OP##32(emu, GD->dword[0], ED->dword[0]); \
|
||||
break; \
|
||||
case B+4: \
|
||||
R_AL = OP##8(emu, R_AL, F8); \
|
||||
break; \
|
||||
case B+5: \
|
||||
if(rex.w) \
|
||||
R_RAX = OP##64(emu, R_RAX, F32S64); \
|
||||
else \
|
||||
R_RAX = OP##32(emu, R_EAX, F32); \
|
||||
break;
|
||||
|
||||
case 0x33: /* XOR Gd,Ed */
|
||||
GO(0x00, add) /* ADD 0x00 -> 0x05 */
|
||||
GO(0x08, or) /* OR 0x08 -> 0x0D */
|
||||
GO(0x10, adc) /* ADC 0x10 -> 0x15 */
|
||||
GO(0x18, sbb) /* SBB 0x18 -> 0x1D */
|
||||
GO(0x20, and) /* AND 0x20 -> 0x25 */
|
||||
GO(0x28, sub) /* SUB 0x28 -> 0x2D */
|
||||
GO(0x30, xor) /* XOR 0x30 -> 0x35 */
|
||||
#undef GO
|
||||
case 0x0F:
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
|
||||
case 0x10:
|
||||
switch(rep) {
|
||||
case 1: /* MOVSD Gx, FS:Ex */
|
||||
nextop = F8;
|
||||
GETEX_OFFS(0, tlsdata);
|
||||
GETGX;
|
||||
GX->q[0] = EX->q[0];
|
||||
if((nextop&0xC0)!=0xC0) {
|
||||
// EX is not a register
|
||||
GX->q[1] = 0;
|
||||
}
|
||||
break;
|
||||
case 2: /* MOVSS Gx, FS:Ex */
|
||||
nextop = F8;
|
||||
GETEX_OFFS(0, tlsdata);
|
||||
GETGX;
|
||||
GX->ud[0] = EX->ud[0];
|
||||
if((nextop&0xC0)!=0xC0) {
|
||||
// EX is not a register (reg to reg only move 31:0)
|
||||
GX->ud[1] = GX->ud[2] = GX->ud[3] = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
switch(rep) {
|
||||
case 1: /* MOVSD Ex, Gx */
|
||||
nextop = F8;
|
||||
GETEX_OFFS(0, tlsdata);
|
||||
GETGX;
|
||||
EX->q[0] = GX->q[0];
|
||||
break;
|
||||
case 2: /* MOVSS FS:Ex, Gx */
|
||||
nextop = F8;
|
||||
GETEX_OFFS(0, tlsdata);
|
||||
GETGX;
|
||||
EX->ud[0] = GX->ud[0];
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x29: /* MOVAPS Ex,Gx */
|
||||
switch(rep) {
|
||||
case 0:
|
||||
nextop = F8;
|
||||
GETEX_OFFS(0, tlsdata);
|
||||
GETGX;
|
||||
EX->q[0] = GX->q[0];
|
||||
EX->q[1] = GX->q[1];
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x59:
|
||||
switch(rep) {
|
||||
case 2: /* MULSS Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX_OFFS(0, tlsdata);
|
||||
GETGX;
|
||||
GX->f[0] *= EX->f[0];
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x38:
|
||||
nextop = F8;
|
||||
GETEB_OFFS(0, tlsdata);
|
||||
GETGB;
|
||||
cmp8(emu, EB->byte[0], GB);
|
||||
break;
|
||||
case 0x39:
|
||||
nextop = F8;
|
||||
GETED_OFFS(0, tlsdata);
|
||||
GETGD;
|
||||
if(rex.w)
|
||||
GD->q[0] = xor64(emu, GD->q[0], ED->q[0]);
|
||||
cmp64(emu, ED->q[0], GD->q[0]);
|
||||
else
|
||||
GD->q[0] = xor32(emu, GD->dword[0], ED->dword[0]);
|
||||
cmp32(emu, ED->dword[0], GD->dword[0]);
|
||||
break;
|
||||
|
||||
case 0x3B:
|
||||
nextop = F8;
|
||||
GETED_OFFS(0, tlsdata);
|
||||
GETGD;
|
||||
if(rex.w)
|
||||
cmp64(emu, GD->q[0], ED->q[0]);
|
||||
else
|
||||
cmp32(emu, GD->dword[0], ED->dword[0]);
|
||||
break;
|
||||
|
||||
|
||||
case 0x66:
|
||||
opcode = F8;
|
||||
|
||||
while(opcode>=0x40 && opcode<=0x4F) {
|
||||
rex.rex = opcode;
|
||||
opcode = F8;
|
||||
}
|
||||
switch(opcode) {
|
||||
case 0x0F:
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
case 0xD6: /* MOVQ Ex,Gx */
|
||||
nextop = F8;
|
||||
GETEX_OFFS(0, tlsdata);
|
||||
GETGX;
|
||||
EX->q[0] = GX->q[0];
|
||||
if(MODREG)
|
||||
EX->q[1] = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x80: /* GRP Eb,Ib */
|
||||
nextop = F8;
|
||||
GETEB_OFFS(1, tlsdata);
|
||||
tmp8u = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: EB->byte[0] = add8(emu, EB->byte[0], tmp8u); break;
|
||||
case 1: EB->byte[0] = or8(emu, EB->byte[0], tmp8u); break;
|
||||
case 2: EB->byte[0] = adc8(emu, EB->byte[0], tmp8u); break;
|
||||
case 3: EB->byte[0] = sbb8(emu, EB->byte[0], tmp8u); break;
|
||||
case 4: EB->byte[0] = and8(emu, EB->byte[0], tmp8u); break;
|
||||
case 5: EB->byte[0] = sub8(emu, EB->byte[0], tmp8u); break;
|
||||
case 6: EB->byte[0] = xor8(emu, EB->byte[0], tmp8u); break;
|
||||
case 7: cmp8(emu, EB->byte[0], tmp8u); break;
|
||||
}
|
||||
break;
|
||||
case 0x81: /* GRP Ed,Id */
|
||||
case 0x83: /* GRP Ed,Ib */
|
||||
nextop = F8;
|
||||
@@ -138,6 +337,11 @@ int Run64(x64emu_t *emu, rex_t rex)
|
||||
GD->q[0] = ED->dword[0];
|
||||
break;
|
||||
|
||||
case 0xC6: /* MOV Eb,Ib */
|
||||
nextop = F8;
|
||||
GETEB_OFFS(1, tlsdata);
|
||||
EB->byte[0] = F8;
|
||||
break;
|
||||
case 0xC7: /* MOV Ed,Id */
|
||||
nextop = F8;
|
||||
GETED_OFFS(4, tlsdata);
|
||||
@@ -154,4 +358,4 @@ int Run64(x64emu_t *emu, rex_t rex)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
+49
-3
@@ -19,9 +19,8 @@
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
#include "bridge.h"
|
||||
//#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#include "../dynarec/arm64_lock.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
@@ -34,6 +33,7 @@ int Run66(x64emu_t *emu, rex_t rex, int rep)
|
||||
uint8_t tmp8u, tmp8u2;
|
||||
int16_t tmp16s;
|
||||
uint16_t tmp16u, tmp16u2;
|
||||
int32_t tmp32s;
|
||||
int64_t tmp64s;
|
||||
uint64_t tmp64u, tmp64u2, tmp64u3;
|
||||
reg64_t *oped, *opgd;
|
||||
@@ -210,7 +210,30 @@ int Run66(x64emu_t *emu, rex_t rex, int rep)
|
||||
nextop = F8;
|
||||
GETEW(0);
|
||||
GETGW;
|
||||
EW->word[0] = GW->word[0];
|
||||
if(rex.w)
|
||||
EW->q[0] = GW->q[0];
|
||||
else
|
||||
EW->word[0] = GW->word[0];
|
||||
break;
|
||||
|
||||
case 0x8B: /* MOV Gw,Ew */
|
||||
nextop = F8;
|
||||
GETEW(0);
|
||||
GETGW;
|
||||
if(rex.w)
|
||||
GW->q[0] = EW->q[0];
|
||||
else
|
||||
GW->word[0] = EW->word[0];
|
||||
break;
|
||||
|
||||
case 0x8D: /* LEA Gw,M */
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
if(rex.w)
|
||||
GD->q[0] = (uint64_t)ED;
|
||||
else
|
||||
GD->word[0] = (uint16_t)(uintptr_t)ED;
|
||||
break;
|
||||
|
||||
case 0x90: /* NOP */
|
||||
@@ -223,6 +246,20 @@ int Run66(x64emu_t *emu, rex_t rex, int rep)
|
||||
R_DX=((R_AX & 0x8000)?0xFFFF:0x0000);
|
||||
break;
|
||||
|
||||
case 0xA1: /* MOV EAX,Od */
|
||||
if(rex.w)
|
||||
R_RAX = *(uint64_t*)F64;
|
||||
else
|
||||
R_AX = *(uint16_t*)F64;
|
||||
break;
|
||||
|
||||
case 0xA3: /* MOV Od,EAX */
|
||||
if(rex.w)
|
||||
*(uint64_t*)F64 = R_RAX;
|
||||
else
|
||||
*(uint16_t*)F64 = R_AX;
|
||||
break;
|
||||
|
||||
case 0xA5: /* (REP) MOVSW */
|
||||
tmp8s = ACCESS_FLAG(F_DF)?-1:+1;
|
||||
tmp64u = (rep)?R_RCX:1L;
|
||||
@@ -528,6 +565,15 @@ int Run66(x64emu_t *emu, rex_t rex, int rep)
|
||||
case 0xDD: /* x87 opcdes */
|
||||
return Run66DD(emu, rex);
|
||||
|
||||
case 0xE8: /* CALL Id */
|
||||
tmp32s = F32S; // call is relative
|
||||
Push(emu, R_RIP);
|
||||
R_RIP += tmp32s;
|
||||
break;
|
||||
|
||||
case 0xF0: /* LOCK: */
|
||||
return Run66F0(emu, rex);
|
||||
|
||||
case 0xF7: /* GRP3 Ew(,Iw) */
|
||||
nextop = F8;
|
||||
tmp8u = (nextop>>3)&7;
|
||||
|
||||
+290
-20
@@ -19,10 +19,6 @@
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
#include "bridge.h"
|
||||
//#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
@@ -82,6 +78,18 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
GX->q[0] = GX->q[1];
|
||||
GX->q[1] = EX->q[1];
|
||||
break;
|
||||
case 0x16: /* MOVHPD Gx, Ed */
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGX;
|
||||
GX->q[1] = ED->q[0];
|
||||
break;
|
||||
case 0x17: /* MOVHPD Ed, Gx */
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGX;
|
||||
ED->q[0] = GX->q[1];
|
||||
break;
|
||||
|
||||
case 0x1F: /* NOP (multi-byte) */
|
||||
nextop = F8;
|
||||
@@ -159,6 +167,194 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
CLEAR_FLAG(F_OF); CLEAR_FLAG(F_AF); CLEAR_FLAG(F_SF);
|
||||
break;
|
||||
|
||||
case 0x38: // SSSE3 opcodes
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
case 0x00: /* PSHUFB */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
eax1 = *GX;
|
||||
for (int i=0; i<16; ++i) {
|
||||
if(EX->ub[i]&128)
|
||||
GX->ub[i] = 0;
|
||||
else
|
||||
GX->ub[i] = eax1.ub[EX->ub[i]&15];
|
||||
}
|
||||
break;
|
||||
case 0x01: /* PHADDW Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
for (int i=0; i<4; ++i)
|
||||
GX->sw[i] = GX->sw[i*2+0]+GX->sw[i*2+1];
|
||||
if(GX == EX) {
|
||||
GX->q[1] = GX->q[0];
|
||||
} else {
|
||||
for (int i=0; i<4; ++i)
|
||||
GX->sw[4+i] = EX->sw[i*2+0] + EX->sw[i*2+1];
|
||||
}
|
||||
break;
|
||||
case 0x02: /* PHADDD Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
GX->sd[0] += GX->sd[1];
|
||||
GX->sd[1] = GX->sd[2] + GX->sd[3];
|
||||
if(GX == EX) {
|
||||
GX->q[1] = GX->q[0];
|
||||
} else {
|
||||
GX->sd[2] = EX->sd[0] + EX->sd[1];
|
||||
GX->sd[3] = EX->sd[2] + EX->sd[3];
|
||||
}
|
||||
break;
|
||||
case 0x03: /* PHADDSW Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
for (int i=0; i<4; ++i) {
|
||||
tmp32s = GX->sw[i*2+0]+GX->sw[i*2+1];
|
||||
GX->sw[i] = (tmp32s<-32768)?-32768:((tmp32s>32767)?32767:tmp32s);
|
||||
}
|
||||
if(GX == EX) {
|
||||
GX->q[1] = GX->q[0];
|
||||
} else {
|
||||
for (int i=0; i<4; ++i) {
|
||||
tmp32s = EX->sw[i*2+0] + EX->sw[i*2+1];
|
||||
GX->sw[4+i] = (tmp32s<-32768)?-32768:((tmp32s>32767)?32767:tmp32s);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x04: /* PMADDUBSW Gx,Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
for (int i=0; i<8; ++i) {
|
||||
tmp32s = (int32_t)(GX->ub[i*2+0])*EX->sb[i*2+0] + (int32_t)(GX->ub[i*2+1])*EX->sb[i*2+1];
|
||||
GX->sw[i] = (tmp32s>32767)?32767:((tmp32s<-32768)?-32768:tmp32s);
|
||||
}
|
||||
break;
|
||||
case 0x05: /* PHSUBW Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
for (int i=0; i<4; ++i)
|
||||
GX->sw[i] = GX->sw[i*2+0] - GX->sw[i*2+1];
|
||||
if(GX == EX) {
|
||||
GX->q[1] = GX->q[0];
|
||||
} else {
|
||||
for (int i=0; i<4; ++i)
|
||||
GX->sw[4+i] = EX->sw[i*2+0] - EX->sw[i*2+1];
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0B: /* PMULHRSW Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
for (int i=0; i<8; ++i) {
|
||||
tmp32s = ((((int32_t)(GX->sw[i])*(int32_t)(EX->sw[i]))>>14) + 1)>>1;
|
||||
GX->uw[i] = tmp32s&0xffff;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x20: /* PMOVSXBW Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
for(int i=7; i>=0; --i)
|
||||
GX->sw[i] = EX->sb[i];
|
||||
break;
|
||||
case 0x21: /* PMOVSXBD Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
for(int i=3; i>=0; --i)
|
||||
GX->sd[i] = EX->sb[i];
|
||||
break;
|
||||
case 0x22: /* PMOVSXBQ Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
for(int i=1; i>=0; --i)
|
||||
GX->sq[i] = EX->sb[i];
|
||||
break;
|
||||
case 0x23: /* PMOVSXWD Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
for(int i=3; i>=0; --i)
|
||||
GX->sd[i] = EX->sw[i];
|
||||
break;
|
||||
case 0x24: /* PMOVSXWQ Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
for(int i=1; i>=0; --i)
|
||||
GX->sq[i] = EX->sw[i];
|
||||
break;
|
||||
case 0x25: /* PMOVSXDQ Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
for(int i=1; i>=0; --i)
|
||||
GX->sq[i] = EX->sd[i];
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x3A: // these are some SSE3 opcodes
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
case 0x0B: // ROUNDSD Gx, Ex, u8
|
||||
nextop = F8;
|
||||
GETEX(1);
|
||||
GETGX;
|
||||
tmp8u = F8; // ignoring bit 3 interupt thingy
|
||||
if(tmp8u&4)
|
||||
tmp8u = (emu->mxcsr>>13)&3;
|
||||
else
|
||||
tmp8u &= 3;
|
||||
switch(tmp8u) {
|
||||
case ROUND_Nearest:
|
||||
GX->d[0] = floor(EX->d[0]+0.5);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
GX->d[0] = floor(EX->d[0]);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
GX->d[0] = ceil(EX->d[0]);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
GX->d[0] = EX->d[0];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0F: // PALIGNR GX, EX, u8
|
||||
nextop = F8;
|
||||
GETEX(1);
|
||||
GETGX;
|
||||
tmp8u = F8;
|
||||
if(tmp8u>31)
|
||||
{GX->q[0] = GX->q[1] = 0;}
|
||||
else
|
||||
{
|
||||
for (int i=0; i<16; ++i, ++tmp8u)
|
||||
eax1.ub[i] = (tmp8u>15)?((tmp8u>31)?0:GX->ub[tmp8u-16]):EX->ub[tmp8u];
|
||||
GX->q[0] = eax1.q[0];
|
||||
GX->q[1] = eax1.q[1];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
GOCOND(0x40
|
||||
, nextop = F8;
|
||||
CHECK_FLAGS(emu);
|
||||
@@ -628,13 +824,20 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
nextop = F8;
|
||||
GETEW(0);
|
||||
GETGW;
|
||||
tmp32s = rex.w?GW->sdword[0]:GW->sword[0];
|
||||
tmp8u=tmp32s&(rex.w?63:15);
|
||||
tmp32s >>= (rex.w?6:4);
|
||||
if(!MODREG)
|
||||
{
|
||||
EW=(reg64_t*)(((uintptr_t)(EW))+(tmp32s<<(rex.w?3:1)));
|
||||
}
|
||||
if(rex.w) {
|
||||
if(EW->q[0] & (1LL<<(GW->q[0]&63)))
|
||||
if(EW->q[0] & (1LL<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
else
|
||||
CLEAR_FLAG(F_CF);
|
||||
} else {
|
||||
if(EW->word[0] & (1<<(GW->word[0]&15)))
|
||||
if(EW->word[0] & (1<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
else
|
||||
CLEAR_FLAG(F_CF);
|
||||
@@ -660,18 +863,25 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
nextop = F8;
|
||||
GETEW(0);
|
||||
GETGW;
|
||||
tmp32s = rex.w?GW->sdword[0]:GW->sword[0];
|
||||
tmp8u=tmp32s&(rex.w?63:15);
|
||||
tmp32s >>= (rex.w?6:4);
|
||||
if(!MODREG)
|
||||
{
|
||||
EW=(reg64_t*)(((uintptr_t)(EW))+(tmp32s<<(rex.w?3:1)));
|
||||
}
|
||||
if(rex.w) {
|
||||
if(EW->q[0] & (1LL<<(GW->q[0]&63)))
|
||||
if(EW->q[0] & (1LL<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
else {
|
||||
EW->q[0] |= (1LL<<(GW->q[0]&63));
|
||||
EW->q[0] |= (1LL<<tmp8u);
|
||||
CLEAR_FLAG(F_CF);
|
||||
}
|
||||
} else {
|
||||
if(EW->word[0] & (1<<(GW->word[0]&15)))
|
||||
if(EW->word[0] & (1<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
else {
|
||||
EW->word[0] |= (1<<(GW->word[0]&15));
|
||||
EW->word[0] |= (1<<tmp8u);
|
||||
CLEAR_FLAG(F_CF);
|
||||
}
|
||||
}
|
||||
@@ -727,31 +937,60 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
nextop = F8;
|
||||
GETEW(0);
|
||||
GETGW;
|
||||
tmp32s = rex.w?GW->sdword[0]:GW->sword[0];
|
||||
tmp8u=tmp32s&(rex.w?63:15);
|
||||
tmp32s >>= (rex.w?6:4);
|
||||
if(!MODREG)
|
||||
{
|
||||
EW=(reg64_t*)(((uintptr_t)(EW))+(tmp32s<<(rex.w?3:1)));
|
||||
}
|
||||
if(rex.w) {
|
||||
if(EW->q[0] & (1LL<<(GW->q[0]&63))) {
|
||||
if(EW->q[0] & (1LL<<tmp8u)) {
|
||||
SET_FLAG(F_CF);
|
||||
EW->q[0] ^= (1LL<<(GW->q[0]&63));
|
||||
EW->q[0] ^= (1LL<<tmp8u);
|
||||
} else
|
||||
CLEAR_FLAG(F_CF);
|
||||
} else {
|
||||
if(EW->word[0] & (1<<(GW->word[0]&15))) {
|
||||
if(EW->word[0] & (1<<tmp8u)) {
|
||||
SET_FLAG(F_CF);
|
||||
EW->word[0] ^= (1<<(GW->word[0]&15));
|
||||
EW->word[0] ^= (1<<tmp8u);
|
||||
} else
|
||||
CLEAR_FLAG(F_CF);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xB6: /* MOVZX Gw,Eb */
|
||||
nextop = F8;
|
||||
GETEB(0);
|
||||
GETGW;
|
||||
GW->word[0] = EB->byte[0];
|
||||
break;
|
||||
|
||||
case 0xBB: /* BTC Ew,Gw */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GETEW(0);
|
||||
GETGW;
|
||||
if(EW->word[0] & (1<<(GW->word[0]&15)))
|
||||
SET_FLAG(F_CF);
|
||||
else
|
||||
CLEAR_FLAG(F_CF);
|
||||
EW->word[0] ^= (1<<(GW->word[0]&15));
|
||||
tmp32s = rex.w?GW->sdword[0]:GW->sword[0];
|
||||
tmp8u=tmp32s&(rex.w?63:15);
|
||||
tmp32s >>= (rex.w?6:4);
|
||||
if(!MODREG)
|
||||
{
|
||||
EW=(reg64_t*)(((uintptr_t)(EW))+(tmp32s<<(rex.w?3:1)));
|
||||
}
|
||||
if(rex.w) {
|
||||
if(EW->q[0] & (1LL<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
else
|
||||
CLEAR_FLAG(F_CF);
|
||||
EW->q[0] ^= (1LL<<tmp8u);
|
||||
} else {
|
||||
if(EW->word[0] & (1<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
else
|
||||
CLEAR_FLAG(F_CF);
|
||||
EW->word[0] ^= (1<<tmp8u);
|
||||
}
|
||||
break;
|
||||
case 0xBC: /* BSF Ew,Gw */
|
||||
CHECK_FLAGS(emu);
|
||||
@@ -852,6 +1091,20 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC4: /* PINSRW Gx,Ew,Ib */
|
||||
nextop = F8;
|
||||
GETED(1);
|
||||
GETGX;
|
||||
tmp8u = F8;
|
||||
GX->uw[tmp8u&7] = ED->word[0]; // only low 16bits
|
||||
break;
|
||||
case 0xC5: /* PEXTRW Gw,Ex,Ib */
|
||||
nextop = F8;
|
||||
GETEX(1);
|
||||
GETGD;
|
||||
tmp8u = F8;
|
||||
GD->dword[0] = EX->uw[tmp8u&7]; // 16bits extract, 0 extended
|
||||
break;
|
||||
case 0xC6: /* SHUFPD Gx, Ex, Ib */
|
||||
nextop = F8;
|
||||
GETEX(1);
|
||||
@@ -1024,7 +1277,24 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
for (int i=0; i<8; ++i)
|
||||
GX->uw[i] = ((uint32_t)GX->uw[i] + EX->uw[i] + 1)>>1;
|
||||
break;
|
||||
|
||||
case 0xE4: /* PMULHUW Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
for(int i=0; i<8; ++i) {
|
||||
tmp32u = (uint32_t)GX->uw[i] * EX->uw[i];
|
||||
GX->uw[i] = (tmp32u>>16)&0xffff;
|
||||
}
|
||||
break;
|
||||
case 0xE5: /* PMULHW Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
for(int i=0; i<8; ++i) {
|
||||
tmp32s = (int32_t)GX->sw[i] * EX->sw[i];
|
||||
GX->uw[i] = (tmp32s>>16)&0xffff;
|
||||
}
|
||||
break;
|
||||
case 0xE6: /* CVTTPD2DQ Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
|
||||
@@ -19,10 +19,6 @@
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
#include "bridge.h"
|
||||
//#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
|
||||
@@ -18,12 +18,7 @@
|
||||
#include "x64trace.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
//#include "my_cpuid.h"
|
||||
#include "bridge.h"
|
||||
//#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
|
||||
@@ -18,12 +18,7 @@
|
||||
#include "x64trace.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
//#include "my_cpuid.h"
|
||||
#include "bridge.h"
|
||||
//#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64stack.h"
|
||||
#include "x64emu.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu_private.h"
|
||||
#include "x64run_private.h"
|
||||
#include "x64primop.h"
|
||||
#include "x64trace.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
#include "bridge.h"
|
||||
#include "dynarec/arm64_lock.h"
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
int Run66F0(x64emu_t *emu, rex_t rex)
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t nextop;
|
||||
uint16_t tmp16u2;
|
||||
int64_t tmp64s;
|
||||
uint64_t tmp64u, tmp64u2;
|
||||
reg64_t *oped;
|
||||
|
||||
opcode = F8;
|
||||
// REX prefix before the F0 are ignored
|
||||
rex.rex = 0;
|
||||
while(opcode>=0x40 && opcode<=0x4f) {
|
||||
rex.rex = opcode;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x81: /* GRP Ew,Iw */
|
||||
case 0x83: /* GRP Ew,Ib */
|
||||
nextop = F8;
|
||||
GETED((opcode==0x83)?1:2);
|
||||
tmp64s = (opcode==0x83)?(F8S):(F16S);
|
||||
tmp64u = (uint64_t)tmp64s;
|
||||
#ifdef DYNAREC
|
||||
if(rex.w) {
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: do { tmp64u2 = arm64_lock_read_dd(ED); tmp64u2 = add64(emu, tmp64u2, tmp64u);} while(arm64_lock_write_dd(ED, tmp64u2)); break;
|
||||
case 1: do { tmp64u2 = arm64_lock_read_dd(ED); tmp64u2 = or64(emu, tmp64u2, tmp64u);} while(arm64_lock_write_dd(ED, tmp64u2)); break;
|
||||
case 2: do { tmp64u2 = arm64_lock_read_dd(ED); tmp64u2 = adc64(emu, tmp64u2, tmp64u);} while(arm64_lock_write_dd(ED, tmp64u2)); break;
|
||||
case 3: do { tmp64u2 = arm64_lock_read_dd(ED); tmp64u2 = sbb64(emu, tmp64u2, tmp64u);} while(arm64_lock_write_dd(ED, tmp64u2)); break;
|
||||
case 4: do { tmp64u2 = arm64_lock_read_dd(ED); tmp64u2 = and64(emu, tmp64u2, tmp64u);} while(arm64_lock_write_dd(ED, tmp64u2)); break;
|
||||
case 5: do { tmp64u2 = arm64_lock_read_dd(ED); tmp64u2 = sub64(emu, tmp64u2, tmp64u);} while(arm64_lock_write_dd(ED, tmp64u2)); break;
|
||||
case 6: do { tmp64u2 = arm64_lock_read_dd(ED); tmp64u2 = xor64(emu, tmp64u2, tmp64u);} while(arm64_lock_write_dd(ED, tmp64u2)); break;
|
||||
case 7: cmp64(emu, ED->q[0], tmp64u); break;
|
||||
}
|
||||
} else {
|
||||
if(MODREG)
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: ED->word[0] = add16(emu, ED->word[0], tmp64u); break;
|
||||
case 1: ED->word[0] = or16(emu, ED->word[0], tmp64u); break;
|
||||
case 2: ED->word[0] = adc16(emu, ED->word[0], tmp64u); break;
|
||||
case 3: ED->word[0] = sbb16(emu, ED->word[0], tmp64u); break;
|
||||
case 4: ED->word[0] = and16(emu, ED->word[0], tmp64u); break;
|
||||
case 5: ED->word[0] = sub16(emu, ED->word[0], tmp64u); break;
|
||||
case 6: ED->word[0] = xor16(emu, ED->word[0], tmp64u); break;
|
||||
case 7: cmp16(emu, ED->word[0], tmp64u); break;
|
||||
}
|
||||
else
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: do { tmp16u2 = arm64_lock_read_h(ED); tmp16u2 = add16(emu, tmp16u2, tmp64u);} while(arm64_lock_write_h(ED, tmp16u2)); break;
|
||||
case 1: do { tmp16u2 = arm64_lock_read_h(ED); tmp16u2 = or16(emu, tmp16u2, tmp64u);} while(arm64_lock_write_h(ED, tmp16u2)); break;
|
||||
case 2: do { tmp16u2 = arm64_lock_read_h(ED); tmp16u2 = adc16(emu, tmp16u2, tmp64u);} while(arm64_lock_write_h(ED, tmp16u2)); break;
|
||||
case 3: do { tmp16u2 = arm64_lock_read_h(ED); tmp16u2 = sbb16(emu, tmp16u2, tmp64u);} while(arm64_lock_write_h(ED, tmp16u2)); break;
|
||||
case 4: do { tmp16u2 = arm64_lock_read_h(ED); tmp16u2 = and16(emu, tmp16u2, tmp64u);} while(arm64_lock_write_h(ED, tmp16u2)); break;
|
||||
case 5: do { tmp16u2 = arm64_lock_read_h(ED); tmp16u2 = sub16(emu, tmp16u2, tmp64u);} while(arm64_lock_write_h(ED, tmp16u2)); break;
|
||||
case 6: do { tmp16u2 = arm64_lock_read_h(ED); tmp16u2 = xor16(emu, tmp16u2, tmp64u);} while(arm64_lock_write_h(ED, tmp16u2)); break;
|
||||
case 7: cmp16(emu, ED->word[0], tmp64u); break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
if(rex.w) {
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: ED->q[0] = add64(emu, ED->q[0], tmp64u); break;
|
||||
case 1: ED->q[0] = or64(emu, ED->q[0], tmp64u); break;
|
||||
case 2: ED->q[0] = adc64(emu, ED->q[0], tmp64u); break;
|
||||
case 3: ED->q[0] = sbb64(emu, ED->q[0], tmp64u); break;
|
||||
case 4: ED->q[0] = and64(emu, ED->q[0], tmp64u); break;
|
||||
case 5: ED->q[0] = sub64(emu, ED->q[0], tmp64u); break;
|
||||
case 6: ED->q[0] = xor64(emu, ED->q[0], tmp64u); break;
|
||||
case 7: cmp64(emu, ED->q[0], tmp64u); break;
|
||||
}
|
||||
} else {
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: ED->word[0] = add16(emu, ED->word[0], tmp64u); break;
|
||||
case 1: ED->word[0] = or16(emu, ED->word[0], tmp64u); break;
|
||||
case 2: ED->word[0] = adc16(emu, ED->word[0], tmp64u); break;
|
||||
case 3: ED->word[0] = sbb16(emu, ED->word[0], tmp64u); break;
|
||||
case 4: ED->word[0] = and16(emu, ED->word[0], tmp64u); break;
|
||||
case 5: ED->word[0] = sub16(emu, ED->word[0], tmp64u); break;
|
||||
case 6: ED->word[0] = xor16(emu, ED->word[0], tmp64u); break;
|
||||
case 7: cmp16(emu, ED->word[0], tmp64u); break;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
+235
-7
@@ -19,30 +19,146 @@
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
#include "bridge.h"
|
||||
//#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
int Run67(x64emu_t *emu, rex_t rex)
|
||||
int Run67(x64emu_t *emu, rex_t rex, int rep)
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t nextop;
|
||||
int8_t tmp8s;
|
||||
uint8_t tmp8u;
|
||||
uint32_t tmp32u;
|
||||
uint64_t tmp64u;
|
||||
reg64_t *oped, *opgd;
|
||||
|
||||
opcode = F8;
|
||||
|
||||
// REX prefix before the F0 are ignored
|
||||
while(opcode==0x67)
|
||||
opcode = F8;
|
||||
|
||||
// REX prefix before the 67 are ignored
|
||||
rex.rex = 0;
|
||||
while(opcode>=0x40 && opcode<=0x4f) {
|
||||
rex.rex = opcode;
|
||||
opcode = F8;
|
||||
}
|
||||
while((opcode==0xF2) || (opcode==0xF3)) {
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
switch(opcode) {
|
||||
#define GO(B, OP) \
|
||||
case B+0: \
|
||||
nextop = F8; \
|
||||
GETEB32(0); \
|
||||
GETGB; \
|
||||
EB->byte[0] = OP##8(emu, EB->byte[0], GB); \
|
||||
break; \
|
||||
case B+1: \
|
||||
nextop = F8; \
|
||||
GETED32(0); \
|
||||
GETGD; \
|
||||
if(rex.w) \
|
||||
ED->q[0] = OP##64(emu, ED->q[0], GD->q[0]); \
|
||||
else { \
|
||||
if(MODREG) \
|
||||
ED->q[0] = OP##32(emu, ED->dword[0], GD->dword[0]); \
|
||||
else \
|
||||
ED->dword[0] = OP##32(emu, ED->dword[0], GD->dword[0]); \
|
||||
} \
|
||||
break; \
|
||||
case B+2: \
|
||||
nextop = F8; \
|
||||
GETEB32(0); \
|
||||
GETGB; \
|
||||
GB = OP##8(emu, GB, EB->byte[0]); \
|
||||
break; \
|
||||
case B+3: \
|
||||
nextop = F8; \
|
||||
GETED32(0); \
|
||||
GETGD; \
|
||||
if(rex.w) \
|
||||
GD->q[0] = OP##64(emu, GD->q[0], ED->q[0]); \
|
||||
else \
|
||||
GD->q[0] = OP##32(emu, GD->dword[0], ED->dword[0]); \
|
||||
break; \
|
||||
case B+4: \
|
||||
R_AL = OP##8(emu, R_AL, F8); \
|
||||
break; \
|
||||
case B+5: \
|
||||
if(rex.w) \
|
||||
R_RAX = OP##64(emu, R_RAX, F32S64); \
|
||||
else \
|
||||
R_RAX = OP##32(emu, R_EAX, F32); \
|
||||
break;
|
||||
|
||||
GO(0x00, add) /* ADD 0x00 -> 0x05 */
|
||||
GO(0x08, or) /* OR 0x08 -> 0x0D */
|
||||
case 0x0F:
|
||||
return Run670F(emu, rex, rep);
|
||||
GO(0x10, adc) /* ADC 0x10 -> 0x15 */
|
||||
GO(0x18, sbb) /* SBB 0x18 -> 0x1D */
|
||||
GO(0x20, and) /* AND 0x20 -> 0x25 */
|
||||
GO(0x28, sub) /* SUB 0x28 -> 0x2D */
|
||||
GO(0x30, xor) /* XOR 0x30 -> 0x35 */
|
||||
#undef GO
|
||||
|
||||
case 0x66:
|
||||
return Run6766(emu, rex, rep);
|
||||
|
||||
case 0x80: /* GRP Eb,Ib */
|
||||
nextop = F8;
|
||||
GETEB32(1);
|
||||
tmp8u = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: EB->byte[0] = add8(emu, EB->byte[0], tmp8u); break;
|
||||
case 1: EB->byte[0] = or8(emu, EB->byte[0], tmp8u); break;
|
||||
case 2: EB->byte[0] = adc8(emu, EB->byte[0], tmp8u); break;
|
||||
case 3: EB->byte[0] = sbb8(emu, EB->byte[0], tmp8u); break;
|
||||
case 4: EB->byte[0] = and8(emu, EB->byte[0], tmp8u); break;
|
||||
case 5: EB->byte[0] = sub8(emu, EB->byte[0], tmp8u); break;
|
||||
case 6: EB->byte[0] = xor8(emu, EB->byte[0], tmp8u); break;
|
||||
case 7: cmp8(emu, EB->byte[0], tmp8u); break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x88: /* MOV Eb,Gb */
|
||||
nextop = F8;
|
||||
GETEB32(0);
|
||||
GETGB;
|
||||
EB->byte[0] = GB;
|
||||
break;
|
||||
case 0x89: /* MOV Ed,Gd */
|
||||
nextop = F8;
|
||||
GETED32(0);
|
||||
GETGD;
|
||||
if(rex.w) {
|
||||
ED->q[0] = GD->q[0];
|
||||
} else {
|
||||
//if ED is a reg, than the opcode works like movzx
|
||||
if(MODREG)
|
||||
ED->q[0] = GD->dword[0];
|
||||
else
|
||||
ED->dword[0] = GD->dword[0];
|
||||
}
|
||||
break;
|
||||
case 0x8A: /* MOV Gb,Eb */
|
||||
nextop = F8;
|
||||
GETEB32(0);
|
||||
GETGB;
|
||||
GB = EB->byte[0];
|
||||
break;
|
||||
case 0x8B: /* MOV Gd,Ed */
|
||||
nextop = F8;
|
||||
GETED32(0);
|
||||
GETGD;
|
||||
if(rex.w)
|
||||
GD->q[0] = ED->q[0];
|
||||
else
|
||||
GD->q[0] = ED->dword[0];
|
||||
break;
|
||||
|
||||
case 0x8D: /* LEA Gd,M */
|
||||
nextop = F8;
|
||||
@@ -51,7 +167,48 @@ int Run67(x64emu_t *emu, rex_t rex)
|
||||
if(rex.w)
|
||||
GD->q[0] = (uint64_t)ED;
|
||||
else
|
||||
GD->q[0] = (uint32_t)(uintptr_t)ED;
|
||||
GD->q[0] = ((uintptr_t)ED)&0xffffffff;
|
||||
break;
|
||||
|
||||
case 0xC1: /* GRP2 Ed,Ib */
|
||||
nextop = F8;
|
||||
GETED32(1);
|
||||
tmp8u = F8/* & 0x1f*/; // masking done in each functions
|
||||
if(rex.w) {
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: ED->q[0] = rol64(emu, ED->q[0], tmp8u); break;
|
||||
case 1: ED->q[0] = ror64(emu, ED->q[0], tmp8u); break;
|
||||
case 2: ED->q[0] = rcl64(emu, ED->q[0], tmp8u); break;
|
||||
case 3: ED->q[0] = rcr64(emu, ED->q[0], tmp8u); break;
|
||||
case 4:
|
||||
case 6: ED->q[0] = shl64(emu, ED->q[0], tmp8u); break;
|
||||
case 5: ED->q[0] = shr64(emu, ED->q[0], tmp8u); break;
|
||||
case 7: ED->q[0] = sar64(emu, ED->q[0], tmp8u); break;
|
||||
}
|
||||
} else {
|
||||
if(MODREG)
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: ED->q[0] = rol32(emu, ED->dword[0], tmp8u); break;
|
||||
case 1: ED->q[0] = ror32(emu, ED->dword[0], tmp8u); break;
|
||||
case 2: ED->q[0] = rcl32(emu, ED->dword[0], tmp8u); break;
|
||||
case 3: ED->q[0] = rcr32(emu, ED->dword[0], tmp8u); break;
|
||||
case 4:
|
||||
case 6: ED->q[0] = shl32(emu, ED->dword[0], tmp8u); break;
|
||||
case 5: ED->q[0] = shr32(emu, ED->dword[0], tmp8u); break;
|
||||
case 7: ED->q[0] = sar32(emu, ED->dword[0], tmp8u); break;
|
||||
}
|
||||
else
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: ED->dword[0] = rol32(emu, ED->dword[0], tmp8u); break;
|
||||
case 1: ED->dword[0] = ror32(emu, ED->dword[0], tmp8u); break;
|
||||
case 2: ED->dword[0] = rcl32(emu, ED->dword[0], tmp8u); break;
|
||||
case 3: ED->dword[0] = rcr32(emu, ED->dword[0], tmp8u); break;
|
||||
case 4:
|
||||
case 6: ED->dword[0] = shl32(emu, ED->dword[0], tmp8u); break;
|
||||
case 5: ED->dword[0] = shr32(emu, ED->dword[0], tmp8u); break;
|
||||
case 7: ED->dword[0] = sar32(emu, ED->dword[0], tmp8u); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xE0: /* LOOPNZ */
|
||||
@@ -80,6 +237,77 @@ int Run67(x64emu_t *emu, rex_t rex)
|
||||
R_RIP += tmp8s;
|
||||
break;
|
||||
|
||||
case 0xF7: /* GRP3 Ed(,Id) */
|
||||
nextop = F8;
|
||||
tmp8u = (nextop>>3)&7;
|
||||
GETED32((tmp8u<2)?4:0);
|
||||
if(rex.w) {
|
||||
switch(tmp8u) {
|
||||
case 0:
|
||||
case 1: /* TEST Ed,Id */
|
||||
tmp64u = F32S64;
|
||||
test64(emu, ED->q[0], tmp64u);
|
||||
break;
|
||||
case 2: /* NOT Ed */
|
||||
ED->q[0] = not64(emu, ED->q[0]);
|
||||
break;
|
||||
case 3: /* NEG Ed */
|
||||
ED->q[0] = neg64(emu, ED->q[0]);
|
||||
break;
|
||||
case 4: /* MUL RAX,Ed */
|
||||
mul64_rax(emu, ED->q[0]);
|
||||
break;
|
||||
case 5: /* IMUL RAX,Ed */
|
||||
imul64_rax(emu, ED->q[0]);
|
||||
break;
|
||||
case 6: /* DIV Ed */
|
||||
div64(emu, ED->q[0]);
|
||||
break;
|
||||
case 7: /* IDIV Ed */
|
||||
idiv64(emu, ED->q[0]);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch(tmp8u) {
|
||||
case 0:
|
||||
case 1: /* TEST Ed,Id */
|
||||
tmp32u = F32;
|
||||
test32(emu, ED->dword[0], tmp32u);
|
||||
break;
|
||||
case 2: /* NOT Ed */
|
||||
if(MODREG)
|
||||
ED->q[0] = not32(emu, ED->dword[0]);
|
||||
else
|
||||
ED->dword[0] = not32(emu, ED->dword[0]);
|
||||
break;
|
||||
case 3: /* NEG Ed */
|
||||
if(MODREG)
|
||||
ED->q[0] = neg32(emu, ED->dword[0]);
|
||||
else
|
||||
ED->dword[0] = neg32(emu, ED->dword[0]);
|
||||
break;
|
||||
case 4: /* MUL EAX,Ed */
|
||||
mul32_eax(emu, ED->dword[0]);
|
||||
emu->regs[_AX].dword[1] = 0;
|
||||
break;
|
||||
case 5: /* IMUL EAX,Ed */
|
||||
imul32_eax(emu, ED->dword[0]);
|
||||
emu->regs[_AX].dword[1] = 0;
|
||||
break;
|
||||
case 6: /* DIV Ed */
|
||||
div32(emu, ED->dword[0]);
|
||||
emu->regs[_AX].dword[1] = 0;
|
||||
emu->regs[_DX].dword[1] = 0;
|
||||
break;
|
||||
case 7: /* IDIV Ed */
|
||||
idiv32(emu, ED->dword[0]);
|
||||
emu->regs[_AX].dword[1] = 0;
|
||||
emu->regs[_DX].dword[1] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64stack.h"
|
||||
#include "x64emu.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu_private.h"
|
||||
#include "x64run_private.h"
|
||||
#include "x64primop.h"
|
||||
#include "x64trace.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
#include "bridge.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm64_lock.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
int Run670F(x64emu_t *emu, rex_t rex, int rep)
|
||||
{
|
||||
(void)rep;
|
||||
uint8_t opcode;
|
||||
uint8_t nextop;
|
||||
uint8_t tmp8u; (void)tmp8u;
|
||||
int8_t tmp8s; (void)tmp8s;
|
||||
int32_t tmp32s, tmp32s2; (void)tmp32s; (void)tmp32s2;
|
||||
uint32_t tmp32u, tmp32u2; (void)tmp32u; (void)tmp32u2;
|
||||
uint64_t tmp64u, tmp64u2; (void)tmp64u; (void)tmp64u2;
|
||||
reg64_t *oped, *opgd; (void)oped; (void)opgd;
|
||||
sse_regs_t *opex, *opgx, eax1; (void)eax1;
|
||||
mmx87_regs_t *opem, *opgm, eam1; (void)opem; (void)opgm; (void)eam1;
|
||||
|
||||
opcode = F8;
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x2E: /* UCOMISS Gx, Ex */
|
||||
// same for now
|
||||
case 0x2F: /* COMISS Gx, Ex */
|
||||
if(rep) {
|
||||
return 1;
|
||||
}
|
||||
RESET_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GETEX32(0);
|
||||
GETGX;
|
||||
if(isnan(GX->f[0]) || isnan(EX->f[0])) {
|
||||
SET_FLAG(F_ZF); SET_FLAG(F_PF); SET_FLAG(F_CF);
|
||||
} else if(isgreater(GX->f[0], EX->f[0])) {
|
||||
CLEAR_FLAG(F_ZF); CLEAR_FLAG(F_PF); CLEAR_FLAG(F_CF);
|
||||
} else if(isless(GX->f[0], EX->f[0])) {
|
||||
CLEAR_FLAG(F_ZF); CLEAR_FLAG(F_PF); SET_FLAG(F_CF);
|
||||
} else {
|
||||
SET_FLAG(F_ZF); CLEAR_FLAG(F_PF); CLEAR_FLAG(F_CF);
|
||||
}
|
||||
CLEAR_FLAG(F_OF); CLEAR_FLAG(F_AF); CLEAR_FLAG(F_SF);
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64stack.h"
|
||||
#include "x64emu.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu_private.h"
|
||||
#include "x64run_private.h"
|
||||
#include "x64primop.h"
|
||||
#include "x64trace.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
#include "bridge.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm64_lock.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
int Run6766(x64emu_t *emu, rex_t rex, int rep)
|
||||
{
|
||||
// Hmmmm....
|
||||
(void)rep;
|
||||
uint8_t opcode;
|
||||
uint8_t nextop; (void)nextop;
|
||||
int8_t tmp8s; (void)tmp8s;
|
||||
uint8_t tmp8u, tmp8u2; (void)tmp8u; (void)tmp8u2;
|
||||
int16_t tmp16s; (void)tmp16s;
|
||||
uint16_t tmp16u, tmp16u2; (void)tmp16u; (void)tmp16u2;
|
||||
int32_t tmp32s; (void)tmp32s;
|
||||
int64_t tmp64s; (void)tmp64s;
|
||||
uint64_t tmp64u, tmp64u2, tmp64u3; (void)tmp64u; (void)tmp64u2; (void)tmp64u3;
|
||||
reg64_t *oped, *opgd; (void)oped; (void)opgd;
|
||||
|
||||
opcode = F8;
|
||||
|
||||
while((opcode==0x2E) || (opcode==0x66)) // ignoring CS: or multiple 0x66
|
||||
opcode = F8;
|
||||
|
||||
while((opcode==0xF2) || (opcode==0xF3)) {
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
// REX prefix before the 66 are ignored
|
||||
rex.rex = 0;
|
||||
while(opcode>=0x40 && opcode<=0x4f) {
|
||||
rex.rex = opcode;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x0F: /* more opcodes */
|
||||
return Run67660F(emu, rex);
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64stack.h"
|
||||
#include "x64emu.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu_private.h"
|
||||
#include "x64run_private.h"
|
||||
#include "x64primop.h"
|
||||
#include "x64trace.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
#include "bridge.h"
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
int Run67660F(x64emu_t *emu, rex_t rex)
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t nextop;
|
||||
int8_t tmp8s; (void)tmp8s;
|
||||
uint8_t tmp8u; (void)tmp8u;
|
||||
int16_t tmp16s; (void)tmp16s;
|
||||
uint16_t tmp16u; (void)tmp16u;
|
||||
int32_t tmp32s; (void)tmp32s;
|
||||
uint32_t tmp32u; (void)tmp32u;
|
||||
int64_t tmp64s; (void)tmp64s;
|
||||
uint64_t tmp64u; (void)tmp64u;
|
||||
reg64_t *oped, *opgd; (void)oped; (void)opgd;
|
||||
sse_regs_t *opex, *opgx;
|
||||
|
||||
opcode = F8;
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x6F: /* MOVDQA Gx,Ex */
|
||||
nextop = F8;
|
||||
GETEX32(0);
|
||||
GETGX;
|
||||
GX->q[0] = EX->q[0];
|
||||
GX->q[1] = EX->q[1];
|
||||
break;
|
||||
|
||||
case 0x76: /* PCMPEQD Gx,Ex */
|
||||
nextop = F8;
|
||||
GETEX32(0);
|
||||
GETGX;
|
||||
for (int i=0; i<4; ++i)
|
||||
GX->ud[i] = (GX->ud[i]==EX->ud[i])?0xffffffff:0;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
+400
-332
File diff suppressed because it is too large.
Load diff
@@ -81,11 +81,15 @@ reg64_t* GetEbO(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta, uintptr_t of
|
||||
reg64_t* GetEd(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta);
|
||||
reg64_t* GetEdO(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
|
||||
reg64_t* GetEd32O(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
|
||||
reg64_t* GetEb32O(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
|
||||
#define GetEw GetEd
|
||||
#define GetEw32O GetEd32O
|
||||
reg64_t* GetEw16(x64emu_t *emu, rex_t rex, uint8_t v);
|
||||
reg64_t* GetEw16off(x64emu_t *emu, rex_t rex, uint8_t v, uintptr_t offset);
|
||||
mmx87_regs_t* GetEm(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta);
|
||||
sse_regs_t* GetEx(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta);
|
||||
sse_regs_t* GetExO(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
|
||||
sse_regs_t* GetEx32O(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
|
||||
reg64_t* GetGd(x64emu_t *emu, rex_t rex, uint8_t v);
|
||||
#define GetGw GetGd
|
||||
reg64_t* GetGb(x64emu_t *emu, rex_t rex, uint8_t v);
|
||||
@@ -98,28 +102,28 @@ void UpdateFlags(x64emu_t *emu);
|
||||
#define RESET_FLAGS(emu) emu->df = d_none
|
||||
|
||||
int Run0F(x64emu_t *emu, rex_t rex);
|
||||
int Run64(x64emu_t *emu, rex_t rex);
|
||||
int Run64(x64emu_t *emu, rex_t rex, int seg);
|
||||
int Run66(x64emu_t *emu, rex_t rex, int rep);
|
||||
int Run660F(x64emu_t *emu, rex_t rex);
|
||||
int Run6664(x64emu_t *emu, rex_t rex);
|
||||
int Run66D9(x64emu_t *emu, rex_t rex);
|
||||
int Run66DD(x64emu_t *emu, rex_t rex);
|
||||
int Run67(x64emu_t *emu, rex_t rex);
|
||||
int Run66F0(x64emu_t *emu, rex_t rex);
|
||||
int Run67(x64emu_t *emu, rex_t rex, int rep);
|
||||
int Run670F(x64emu_t *emu, rex_t rex, int rep);
|
||||
int Run6766(x64emu_t *emu, rex_t rex, int rep);
|
||||
int Run67660F(x64emu_t *emu, rex_t rex);
|
||||
int RunD8(x64emu_t *emu, rex_t rex);
|
||||
int RunD9(x64emu_t *emu, rex_t rex);
|
||||
int RunDA(x64emu_t *emu, rex_t rex);
|
||||
int RunDB(x64emu_t *emu, rex_t rex);
|
||||
int RunDC(x64emu_t *emu, rex_t rex);
|
||||
int RunDD(x64emu_t *emu, rex_t rex);
|
||||
int RunDE(x64emu_t *emu, rex_t rex);
|
||||
int RunDF(x64emu_t *emu, rex_t rex);
|
||||
int RunF0(x64emu_t *emu, rex_t rex);
|
||||
int RunF20F(x64emu_t *emu, rex_t rex);
|
||||
int RunF30F(x64emu_t *emu, rex_t rex);
|
||||
//void Run66D9(x64emu_t *emu); // x87
|
||||
//void Run6766(x64emu_t *emu);
|
||||
//void RunGS(x64emu_t *emu);
|
||||
//void RunFS(x64emu_t *emu);
|
||||
//void RunFS66(x64emu_t *emu, uintptr_t tlsdata);
|
||||
//void RunLock66(x64emu_t *emu);
|
||||
|
||||
void x64Syscall(x64emu_t *emu);
|
||||
void x64Int3(x64emu_t* emu);
|
||||
@@ -137,4 +141,4 @@ const char* GetNativeName(void* p);
|
||||
void PrintTrace(x64emu_t* emu, uintptr_t ip, int dynarec);
|
||||
#endif
|
||||
|
||||
#endif //__X86RUN_PRIVATE_H_
|
||||
#endif //__X86RUN_PRIVATE_H_
|
||||
@@ -19,9 +19,6 @@
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
#include "bridge.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
|
||||
+2
-6
@@ -18,12 +18,7 @@
|
||||
#include "x64trace.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
//#include "my_cpuid.h"
|
||||
#include "bridge.h"
|
||||
//#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
@@ -196,7 +191,8 @@ int RunD9(x64emu_t *emu, rex_t rex)
|
||||
break;
|
||||
case 0xFD: /* FSCALE */
|
||||
// this could probably be done by just altering the exponant part of the float...
|
||||
ST0.d *= exp2(trunc(ST1.d));
|
||||
if(ST0.d!=0.0)
|
||||
ST0.d *= exp2(trunc(ST1.d));
|
||||
break;
|
||||
case 0xFE: /* FSIN */
|
||||
ST0.d = sin(ST0.d);
|
||||
|
||||
@@ -19,9 +19,6 @@
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
#include "bridge.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
|
||||
@@ -18,12 +18,7 @@
|
||||
#include "x64trace.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
//#include "my_cpuid.h"
|
||||
#include "bridge.h"
|
||||
//#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64stack.h"
|
||||
#include "x64emu.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu_private.h"
|
||||
#include "x64run_private.h"
|
||||
#include "x64primop.h"
|
||||
#include "x64trace.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
#include "bridge.h"
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
int RunDC(x64emu_t *emu, rex_t rex)
|
||||
{
|
||||
uint8_t nextop;
|
||||
reg64_t *oped;
|
||||
|
||||
nextop = F8;
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7: /* FADD */
|
||||
ST(nextop&7).d += ST0.d;
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF: /* FMUL */
|
||||
ST(nextop&7).d *= ST0.d;
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7: /* FCOM */
|
||||
fpu_fcom(emu, ST(nextop&7).d);
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF: /* FCOMP */
|
||||
fpu_fcom(emu, ST(nextop&7).d);
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7: /* FSUBR */
|
||||
ST(nextop&7).d = ST0.d -ST(nextop&7).d;
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF: /* FSUB */
|
||||
ST(nextop&7).d -= ST0.d;
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7: /* FDIVR */
|
||||
ST(nextop&7).d = ST0.d / ST(nextop&7).d;
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFA:
|
||||
case 0xFB:
|
||||
case 0xFC:
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF: /* FDIV */
|
||||
ST(nextop&7).d /= ST0.d;
|
||||
break;
|
||||
default:
|
||||
GETED(0);
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* FADD ST0, double */
|
||||
ST0.d += *(double*)ED;
|
||||
break;
|
||||
case 1: /* FMUL ST0, double */
|
||||
ST0.d *= *(double*)ED;
|
||||
break;
|
||||
case 2: /* FCOM ST0, double */
|
||||
fpu_fcom(emu, *(double*)ED);
|
||||
break;
|
||||
case 3: /* FCOMP ST0, double */
|
||||
fpu_fcom(emu, *(double*)ED);
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 4: /* FSUB ST0, double */
|
||||
ST0.d -= *(double*)ED;
|
||||
break;
|
||||
case 5: /* FSUBR ST0, double */
|
||||
ST0.d = *(double*)ED - ST0.d;
|
||||
break;
|
||||
case 6: /* FDIV ST0, double */
|
||||
ST0.d /= *(double*)ED;
|
||||
break;
|
||||
case 7: /* FDIVR ST0, double */
|
||||
ST0.d = *(double*)ED / ST0.d;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -19,9 +19,6 @@
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
#include "bridge.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64stack.h"
|
||||
#include "x64emu.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu_private.h"
|
||||
#include "x64run_private.h"
|
||||
#include "x64primop.h"
|
||||
#include "x64trace.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
#include "bridge.h"
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
int RunDE(x64emu_t *emu, rex_t rex)
|
||||
{
|
||||
uint8_t nextop;
|
||||
reg64_t *oped;
|
||||
|
||||
nextop = F8;
|
||||
switch(nextop) {
|
||||
case 0xC0: /* FADDP STx, ST0 */
|
||||
case 0xC1: /* FADDP ST1, ST0 */
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
ST(nextop&7).d += ST0.d;
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xC8: /* FMULP STx, ST0 */
|
||||
case 0xC9: /* FMULP ST1, ST0 */
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
ST(nextop&7).d *= ST0.d;
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7: /* FCOMP */
|
||||
fpu_fcom(emu, ST(nextop&7).d);
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
|
||||
case 0xD9: /* FCOMPP */
|
||||
fpu_fcom(emu, ST1.d);
|
||||
fpu_do_pop(emu);
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
|
||||
/*ST(1).d = ST0.d - ST(1).d;
|
||||
fpu_do_pop(emu);
|
||||
break;*/
|
||||
case 0xE0: /* FSUBRP STx, ST0 */
|
||||
case 0xE1: /* FSUBRP ST1, ST0 */
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
ST(nextop&7).d = ST0.d - ST(nextop&7).d;
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xE8: /* FSUBP STx, ST0 */
|
||||
case 0xE9: /* FSUBP ST1, ST0 */
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
ST(nextop&7).d -= ST0.d;
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xF0: /* FDIVRP STx, ST0 */
|
||||
case 0xF1: /* FDIVRP ST1, ST0 */
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
ST(nextop&7).d = ST0.d / ST(nextop&7).d;
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xF8: /* FDIVP STx, ST0 */
|
||||
case 0xF9: /* FDIVP ST1, ST0 */
|
||||
case 0xFA:
|
||||
case 0xFB:
|
||||
case 0xFC:
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
ST(nextop&7).d /= ST0.d;
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
|
||||
case 0xD8:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
return 1;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* FIADD ST0, Ew int */
|
||||
GETEW(0);
|
||||
ST0.d += EW->sword[0];
|
||||
break;
|
||||
case 1: /* FIMUL ST0, Ew int */
|
||||
GETEW(0);
|
||||
ST0.d *= EW->sword[0];
|
||||
break;
|
||||
case 4: /* FISUB ST0, Ew int */
|
||||
GETEW(0);
|
||||
ST0.d -= EW->sword[0];
|
||||
break;
|
||||
case 5: /* FISUBR ST0, Ew int */
|
||||
GETEW(0);
|
||||
ST0.d = (double)EW->sword[0] - ST0.d;
|
||||
break;
|
||||
case 6: /* FIDIV ST0, Ew int */
|
||||
GETEW(0);
|
||||
ST0.d /= EW->sword[0];
|
||||
break;
|
||||
case 7: /* FIDIVR ST0, Ew int */
|
||||
GETEW(0);
|
||||
ST0.d = (double)EW->sword[0] / ST0.d;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
+2
-7
@@ -18,12 +18,7 @@
|
||||
#include "x64trace.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
//#include "my_cpuid.h"
|
||||
#include "bridge.h"
|
||||
//#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
@@ -167,7 +162,7 @@ int RunDF(x64emu_t *emu, rex_t rex)
|
||||
break;
|
||||
case 7: /* FISTP i64 */
|
||||
GETED(0);
|
||||
if(STll(0).ref==ST(0).q)
|
||||
if(STll(0).ref==ST(0).sq)
|
||||
ED->sq[0] = STll(0).ll;
|
||||
else {
|
||||
if(isgreater(ST0.d, (double)(int64_t)0x7fffffffffffffffLL) || isless(ST0.d, -(double)(int64_t)0x7fffffffffffffffLL) || !isfinite(ST0.d))
|
||||
@@ -182,4 +177,4 @@ int RunDF(x64emu_t *emu, rex_t rex)
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
+513
-76
@@ -20,9 +20,8 @@
|
||||
#include "box64context.h"
|
||||
#include "my_cpuid.h"
|
||||
#include "bridge.h"
|
||||
//#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#include "../dynarec/arm64_lock.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
@@ -31,9 +30,11 @@ int RunF0(x64emu_t *emu, rex_t rex)
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t nextop;
|
||||
uint32_t tmp32u;
|
||||
uint8_t tmp8u;
|
||||
int32_t tmp32s; (void)tmp32s;
|
||||
uint32_t tmp32u, tmp32u2;
|
||||
int64_t tmp64s;
|
||||
uint64_t tmp64u;
|
||||
uint64_t tmp64u, tmp64u2;
|
||||
reg64_t *oped, *opgd;
|
||||
|
||||
opcode = F8;
|
||||
@@ -46,42 +47,57 @@ int RunF0(x64emu_t *emu, rex_t rex)
|
||||
|
||||
switch(opcode) {
|
||||
#ifdef DYNAREC
|
||||
#define GO(B, OP) \
|
||||
case B+0: \
|
||||
nextop = F8; \
|
||||
GETEB(0); \
|
||||
#define GO(B, OP) \
|
||||
case B+0: \
|
||||
nextop = F8; \
|
||||
GETEB(0); \
|
||||
GETGB; \
|
||||
do { \
|
||||
tmp8u = arm_lock_read_b(EB); \
|
||||
tmp8u = OP##8(emu, tmp8u, GB); \
|
||||
} while (arm_lock_write_b(EB, tmp8u)); \
|
||||
break; \
|
||||
case B+1: \
|
||||
nextop = F8; \
|
||||
GETED(0); \
|
||||
do { \
|
||||
tmp8u = arm64_lock_read_b(EB); \
|
||||
tmp8u = OP##8(emu, tmp8u, GB); \
|
||||
} while (arm64_lock_write_b(EB, tmp8u)); \
|
||||
break; \
|
||||
case B+1: \
|
||||
nextop = F8; \
|
||||
GETED(0); \
|
||||
GETGD; \
|
||||
do { \
|
||||
tmp32u = arm_lock_read_d(ED); \
|
||||
tmp32u = OP##32(emu, tmp32u, GD.dword[0]); \
|
||||
} while (arm_lock_write_d(ED, tmp32u)); \
|
||||
break; \
|
||||
case B+2: \
|
||||
nextop = F8; \
|
||||
GETEB(0); \
|
||||
if(rex.w) { \
|
||||
do { \
|
||||
tmp64u = arm64_lock_read_dd(ED); \
|
||||
tmp64u = OP##64(emu, tmp64u, GD->q[0]); \
|
||||
} while (arm64_lock_write_dd(ED, tmp64u)); \
|
||||
} else { \
|
||||
do { \
|
||||
tmp32u = arm64_lock_read_d(ED); \
|
||||
tmp32u = OP##32(emu, tmp32u, GD->dword[0]); \
|
||||
} while (arm64_lock_write_d(ED, tmp32u)); \
|
||||
if(MODREG) \
|
||||
ED->dword[1] = 0; \
|
||||
} \
|
||||
break; \
|
||||
case B+2: \
|
||||
nextop = F8; \
|
||||
GETEB(0); \
|
||||
GETGB; \
|
||||
GB = OP##8(emu, GB, EB->byte[0]); \
|
||||
break; \
|
||||
case B+3: \
|
||||
nextop = F8; \
|
||||
GETED(0); \
|
||||
GB = OP##8(emu, GB, EB->byte[0]); \
|
||||
break; \
|
||||
case B+3: \
|
||||
nextop = F8; \
|
||||
GETED(0); \
|
||||
GETGD; \
|
||||
GD.dword[0] = OP##32(emu, GD.dword[0], ED->dword[0]); \
|
||||
break; \
|
||||
case B+4: \
|
||||
R_AL = OP##8(emu, R_AL, F8); \
|
||||
break; \
|
||||
case B+5: \
|
||||
R_EAX = OP##32(emu, R_EAX, F32); \
|
||||
if(rex.w) \
|
||||
GD->q[0] = OP##64(emu, GD->q[0], ED->q[0]); \
|
||||
else \
|
||||
GD->q[0] = OP##32(emu, GD->dword[0], ED->dword[0]); \
|
||||
break; \
|
||||
case B+4: \
|
||||
R_AL = OP##8(emu, R_AL, F8); \
|
||||
break; \
|
||||
case B+5: \
|
||||
if(rex.w) \
|
||||
R_RAX = OP##64(emu, R_RAX, F32S64); \
|
||||
else \
|
||||
R_RAX = OP##32(emu, R_EAX, F32); \
|
||||
break;
|
||||
#else
|
||||
#define GO(B, OP) \
|
||||
@@ -152,36 +168,158 @@ int RunF0(x64emu_t *emu, rex_t rex)
|
||||
opcode = F8;
|
||||
switch (opcode) {
|
||||
|
||||
case 0xAB: /* BTS Ed,Gd */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
tmp8u = GD->byte[0];
|
||||
if(!MODREG)
|
||||
{
|
||||
ED=(reg64_t*)(((uint32_t*)(ED))+(tmp8u>>5));
|
||||
}
|
||||
#ifdef DYNAREC
|
||||
if(rex.w) {
|
||||
tmp8u&=63;
|
||||
if(MODREG) {
|
||||
if(ED->q[0] & (1LL<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
else {
|
||||
ED->q[0] |= (1LL<<tmp8u);
|
||||
CLEAR_FLAG(F_CF);
|
||||
}
|
||||
} else
|
||||
do {
|
||||
tmp64u = arm64_lock_read_dd(ED);
|
||||
if(tmp64u & (1LL<<tmp8u)) {
|
||||
SET_FLAG(F_CF);
|
||||
tmp32s = 0;
|
||||
} else {
|
||||
tmp64u |= (1LL<<tmp8u);
|
||||
CLEAR_FLAG(F_CF);
|
||||
tmp32s = arm64_lock_write_dd(ED, tmp64u);
|
||||
}
|
||||
} while(tmp32s);
|
||||
} else {
|
||||
tmp8u&=31;
|
||||
if(MODREG) {
|
||||
if(ED->dword[0] & (1<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
else {
|
||||
ED->dword[0] |= (1<<tmp8u);
|
||||
CLEAR_FLAG(F_CF);
|
||||
}
|
||||
ED->dword[1] = 0;
|
||||
} else
|
||||
do {
|
||||
tmp32u = arm64_lock_read_d(ED);
|
||||
if(tmp32u & (1<<tmp8u)) {
|
||||
SET_FLAG(F_CF);
|
||||
tmp32s = 0;
|
||||
} else {
|
||||
tmp32u |= (1<<tmp8u);
|
||||
CLEAR_FLAG(F_CF);
|
||||
tmp32s = arm64_lock_write_d(ED, tmp32u);
|
||||
}
|
||||
} while(tmp32s);
|
||||
}
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
if(rex.w) {
|
||||
tmp8u&=63;
|
||||
if(ED->q[0] & (1LL<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
else {
|
||||
ED->q[0] |= (1LL<<tmp8u);
|
||||
CLEAR_FLAG(F_CF);
|
||||
}
|
||||
} else {
|
||||
tmp8u&=31;
|
||||
if(ED->dword[0] & (1<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
else {
|
||||
ED->dword[0] |= (1<<tmp8u);
|
||||
CLEAR_FLAG(F_CF);
|
||||
}
|
||||
if(MODREG)
|
||||
ED->dword[1] = 0;
|
||||
}
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0xB0: /* CMPXCHG Eb,Gb */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GETGB;
|
||||
GETEB(0);
|
||||
#ifdef DYNAREC
|
||||
do {
|
||||
tmp8u = arm64_lock_read_b(EB);
|
||||
cmp8(emu, R_AL, tmp8u);
|
||||
if(ACCESS_FLAG(F_ZF)) {
|
||||
tmp32s = arm64_lock_write_b(EB, GB);
|
||||
} else {
|
||||
R_AL = tmp8u;
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
cmp8(emu, R_AL, EB->byte[0]);
|
||||
if(ACCESS_FLAG(F_ZF)) {
|
||||
EB->byte[0] = GB;
|
||||
} else {
|
||||
R_AL = EB->byte[0];
|
||||
}
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
case 0xB1: /* CMPXCHG Ed,Gd */
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
#ifdef DYNAREC
|
||||
if(((uintptr_t)ED)&3) {
|
||||
if(rex.w)
|
||||
if(((uintptr_t)ED)&7) {
|
||||
do {
|
||||
tmp64u = ED->q[0] & ~0xffLL;
|
||||
tmp64u |= arm64_lock_read_b(ED);
|
||||
cmp64(emu, R_RAX, tmp64u);
|
||||
if(ACCESS_FLAG(F_ZF)) {
|
||||
tmp32s = arm64_lock_write_b(ED, GD->q[0]&0xff);
|
||||
if(!tmp32s)
|
||||
ED->q[0] = GD->q[0];
|
||||
} else {
|
||||
R_RAX = tmp64u;
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
} else
|
||||
do {
|
||||
tmp64u = arm64_lock_read_dd(ED);
|
||||
cmp64(emu, R_RAX, tmp64u);
|
||||
if(ACCESS_FLAG(F_ZF)) {
|
||||
tmp32s = arm64_lock_write_dd(ED, GD->q[0]);
|
||||
} else {
|
||||
R_RAX = tmp64u;
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
else {
|
||||
do {
|
||||
tmp32u = ED->dword[0] & ~0xff;
|
||||
tmp32u |= arm_lock_read_b(ED);
|
||||
tmp32u = arm64_lock_read_d(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]);
|
||||
tmp32s = arm64_lock_write_d(ED, GD->dword[0]);
|
||||
} else {
|
||||
R_EAX = tmp32u;
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
emu->regs[_AX].dword[1] = 0;
|
||||
if(MODREG)
|
||||
ED->dword[1] = 0;
|
||||
}
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
@@ -199,6 +337,69 @@ int RunF0(x64emu_t *emu, rex_t rex)
|
||||
} else {
|
||||
R_EAX = ED->dword[0];
|
||||
}
|
||||
emu->regs[_AX].dword[1] = 0;
|
||||
if(MODREG)
|
||||
ED->dword[1] = 0;
|
||||
}
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0xB3: /* BTR Ed,Gd */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
tmp8u = GD->byte[0];
|
||||
if(!MODREG)
|
||||
{
|
||||
ED=(reg64_t*)(((uint32_t*)(ED))+(tmp8u>>5));
|
||||
}
|
||||
tmp8u&=rex.w?63:31;
|
||||
#ifdef DYNAREC
|
||||
if(rex.w)
|
||||
do {
|
||||
tmp64u = arm64_lock_read_dd(ED);
|
||||
if(tmp64u & (1LL<<tmp8u)) {
|
||||
SET_FLAG(F_CF);
|
||||
tmp64u ^= (1LL<<tmp8u);
|
||||
tmp32s = arm64_lock_write_dd(ED, tmp64u);
|
||||
} else {
|
||||
CLEAR_FLAG(F_CF);
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
else {
|
||||
do {
|
||||
tmp32u = arm64_lock_read_d(ED);
|
||||
if(tmp32u & (1<<tmp8u)) {
|
||||
SET_FLAG(F_CF);
|
||||
tmp32u ^= (1<<tmp8u);
|
||||
tmp32s = arm64_lock_write_d(ED, tmp32u);
|
||||
} else {
|
||||
CLEAR_FLAG(F_CF);
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
if(MODREG)
|
||||
ED->dword[1] = 0;
|
||||
}
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
if(rex.w) {
|
||||
if(ED->q[0] & (1<<tmp8u)) {
|
||||
SET_FLAG(F_CF);
|
||||
ED->q[0] ^= (1<<tmp8u);
|
||||
} else
|
||||
CLEAR_FLAG(F_CF);
|
||||
} else {
|
||||
if(ED->dword[0] & (1<<tmp8u)) {
|
||||
SET_FLAG(F_CF);
|
||||
ED->dword[0] ^= (1<<tmp8u);
|
||||
} else
|
||||
CLEAR_FLAG(F_CF);
|
||||
if(MODREG)
|
||||
ED->dword[1] = 0;
|
||||
}
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
@@ -209,20 +410,30 @@ int RunF0(x64emu_t *emu, rex_t rex)
|
||||
GETED(0);
|
||||
GETGD;
|
||||
#ifdef DYNAREC
|
||||
if(((uintptr_t)ED)&3) {
|
||||
if(rex.w) {
|
||||
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;
|
||||
tmp64u = arm64_lock_read_dd(ED);
|
||||
tmp64u2 = add64(emu, tmp64u, GD->q[0]);
|
||||
} while(arm64_lock_write_dd(ED, tmp64u2));
|
||||
GD->q[0] = tmp64u;
|
||||
} else {
|
||||
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 |= arm64_lock_read_b(ED);
|
||||
tmp32u2 = add32(emu, tmp32u, GD->dword[0]);
|
||||
} while(arm64_lock_write_b(ED, tmp32u2&0xff));
|
||||
ED->dword[0] = tmp32u2;
|
||||
} else {
|
||||
do {
|
||||
tmp32u = arm64_lock_read_d(ED);
|
||||
tmp32u2 = add32(emu, tmp32u, GD->dword[0]);
|
||||
} while(arm64_lock_write_d(ED, tmp32u2));
|
||||
}
|
||||
GD->q[0] = tmp32u;
|
||||
if(MODREG)
|
||||
ED->dword[1] = 0;
|
||||
}
|
||||
GD.dword[0] = tmp32u;
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
if(rex.w) {
|
||||
@@ -232,7 +443,7 @@ int RunF0(x64emu_t *emu, rex_t rex)
|
||||
} else {
|
||||
tmp32u = add32(emu, ED->dword[0], GD->dword[0]);
|
||||
GD->q[0] = ED->dword[0];
|
||||
if((nextop&0xC0)==0xC0)
|
||||
if(MODREG)
|
||||
ED->q[0] = tmp32u;
|
||||
else
|
||||
ED->dword[0] = tmp32u;
|
||||
@@ -241,11 +452,77 @@ int RunF0(x64emu_t *emu, rex_t rex)
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0xC7: /* CMPXCHG8B Gq */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
#ifdef DYNAREC
|
||||
if(rex.w)
|
||||
do {
|
||||
arm64_lock_read_dq(&tmp64u, &tmp64u2, ED);
|
||||
if(R_RAX == tmp64u && R_RDX == tmp64u2) {
|
||||
SET_FLAG(F_ZF);
|
||||
tmp32s = arm64_lock_write_dq(R_RBX, R_RCX, ED);
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
R_RAX = tmp64u;
|
||||
R_RDX = tmp64u2;
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
else
|
||||
do {
|
||||
tmp64u = arm64_lock_read_dd(ED);
|
||||
if((R_EAX == (tmp64u&0xffffffff)) && (R_EDX == ((tmp64u>>32)&0xffffffff))) {
|
||||
SET_FLAG(F_ZF);
|
||||
tmp32s = arm64_lock_write_dd(ED, R_EBX|(((uint64_t)R_ECX)<<32));
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
R_RAX = tmp64u&0xffffffff;
|
||||
R_RDX = (tmp64u>>32)&0xffffffff;
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
if(rex.w) {
|
||||
tmp64u = ED->q[0];
|
||||
tmp64u2= ED->q[1];
|
||||
if(R_RAX == tmp64u && R_RDX == tmp64u2) {
|
||||
SET_FLAG(F_ZF);
|
||||
ED->q[0] = R_RBX;
|
||||
ED->q[1] = R_RCX;
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
R_RAX = tmp64u;
|
||||
R_RDX = tmp64u2;
|
||||
}
|
||||
} else {
|
||||
tmp32u = ED->dword[0];
|
||||
tmp32u2= ED->dword[1];
|
||||
if(R_EAX == tmp32u && R_EDX == tmp32u2) {
|
||||
SET_FLAG(F_ZF);
|
||||
ED->dword[0] = R_EBX;
|
||||
ED->dword[1] = R_ECX;
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
R_RAX = tmp32u;
|
||||
R_RDX = tmp32u2;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x66:
|
||||
return Run66F0(emu, rex); // more opcode F0 66 and 66 F0 is the same
|
||||
|
||||
case 0x81: /* GRP Ed,Id */
|
||||
case 0x83: /* GRP Ed,Ib */
|
||||
nextop = F8;
|
||||
@@ -256,15 +533,40 @@ int RunF0(x64emu_t *emu, rex_t rex)
|
||||
} else
|
||||
tmp64u = F32S64;
|
||||
#ifdef DYNAREC
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: do { tmp32u2 = arm_lock_read_d(ED);} while(arm_lock_write_d(ED, add32(emu, tmp32u2, tmp32u))); break;
|
||||
case 1: do { tmp32u2 = arm_lock_read_d(ED);} while(arm_lock_write_d(ED, or32(emu, tmp32u2, tmp32u))); break;
|
||||
case 2: do { tmp32u2 = arm_lock_read_d(ED);} while(arm_lock_write_d(ED, adc32(emu, tmp32u2, tmp32u))); break;
|
||||
case 3: do { tmp32u2 = arm_lock_read_d(ED);} while(arm_lock_write_d(ED, sbb32(emu, tmp32u2, tmp32u))); break;
|
||||
case 4: do { tmp32u2 = arm_lock_read_d(ED);} while(arm_lock_write_d(ED, and32(emu, tmp32u2, tmp32u))); break;
|
||||
case 5: do { tmp32u2 = arm_lock_read_d(ED);} while(arm_lock_write_d(ED, sub32(emu, tmp32u2, tmp32u))); break;
|
||||
case 6: do { tmp32u2 = arm_lock_read_d(ED);} while(arm_lock_write_d(ED, xor32(emu, tmp32u2, tmp32u))); break;
|
||||
case 7: cmp32(emu, ED->dword[0], tmp32u); break;
|
||||
if(rex.w) {
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: do { tmp64u2 = arm64_lock_read_dd(ED); tmp64u2 = add64(emu, tmp64u2, tmp64u);} while(arm64_lock_write_dd(ED, tmp64u2)); break;
|
||||
case 1: do { tmp64u2 = arm64_lock_read_dd(ED); tmp64u2 = or64(emu, tmp64u2, tmp64u);} while(arm64_lock_write_dd(ED, tmp64u2)); break;
|
||||
case 2: do { tmp64u2 = arm64_lock_read_dd(ED); tmp64u2 = adc64(emu, tmp64u2, tmp64u);} while(arm64_lock_write_dd(ED, tmp64u2)); break;
|
||||
case 3: do { tmp64u2 = arm64_lock_read_dd(ED); tmp64u2 = sbb64(emu, tmp64u2, tmp64u);} while(arm64_lock_write_dd(ED, tmp64u2)); break;
|
||||
case 4: do { tmp64u2 = arm64_lock_read_dd(ED); tmp64u2 = and64(emu, tmp64u2, tmp64u);} while(arm64_lock_write_dd(ED, tmp64u2)); break;
|
||||
case 5: do { tmp64u2 = arm64_lock_read_dd(ED); tmp64u2 = sub64(emu, tmp64u2, tmp64u);} while(arm64_lock_write_dd(ED, tmp64u2)); break;
|
||||
case 6: do { tmp64u2 = arm64_lock_read_dd(ED); tmp64u2 = xor64(emu, tmp64u2, tmp64u);} while(arm64_lock_write_dd(ED, tmp64u2)); break;
|
||||
case 7: cmp64(emu, ED->q[0], tmp64u); break;
|
||||
}
|
||||
} else {
|
||||
if(MODREG)
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: ED->q[0] = add32(emu, ED->dword[0], tmp64u); break;
|
||||
case 1: ED->q[0] = or32(emu, ED->dword[0], tmp64u); break;
|
||||
case 2: ED->q[0] = adc32(emu, ED->dword[0], tmp64u); break;
|
||||
case 3: ED->q[0] = sbb32(emu, ED->dword[0], tmp64u); break;
|
||||
case 4: ED->q[0] = and32(emu, ED->dword[0], tmp64u); break;
|
||||
case 5: ED->q[0] = sub32(emu, ED->dword[0], tmp64u); break;
|
||||
case 6: ED->q[0] = xor32(emu, ED->dword[0], tmp64u); break;
|
||||
case 7: cmp32(emu, ED->dword[0], tmp64u); break;
|
||||
}
|
||||
else
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: do { tmp32u2 = arm64_lock_read_d(ED); tmp32u2 = add32(emu, tmp32u2, tmp64u);} while(arm64_lock_write_d(ED, tmp32u2)); break;
|
||||
case 1: do { tmp32u2 = arm64_lock_read_d(ED); tmp32u2 = or32(emu, tmp32u2, tmp64u);} while(arm64_lock_write_d(ED, tmp32u2)); break;
|
||||
case 2: do { tmp32u2 = arm64_lock_read_d(ED); tmp32u2 = adc32(emu, tmp32u2, tmp64u);} while(arm64_lock_write_d(ED, tmp32u2)); break;
|
||||
case 3: do { tmp32u2 = arm64_lock_read_d(ED); tmp32u2 = sbb32(emu, tmp32u2, tmp64u);} while(arm64_lock_write_d(ED, tmp32u2)); break;
|
||||
case 4: do { tmp32u2 = arm64_lock_read_d(ED); tmp32u2 = and32(emu, tmp32u2, tmp64u);} while(arm64_lock_write_d(ED, tmp32u2)); break;
|
||||
case 5: do { tmp32u2 = arm64_lock_read_d(ED); tmp32u2 = sub32(emu, tmp32u2, tmp64u);} while(arm64_lock_write_d(ED, tmp32u2)); break;
|
||||
case 6: do { tmp32u2 = arm64_lock_read_d(ED); tmp32u2 = xor32(emu, tmp32u2, tmp64u);} while(arm64_lock_write_d(ED, tmp32u2)); break;
|
||||
case 7: cmp32(emu, ED->dword[0], tmp64u); break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
@@ -306,9 +608,144 @@ int RunF0(x64emu_t *emu, rex_t rex)
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0x87: /* XCHG Ed,Gd */
|
||||
nextop = F8;
|
||||
#ifdef DYNAREC
|
||||
GETED(0);
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
if(rex.w) {
|
||||
tmp64u = GD->q[0];
|
||||
GD->q[0] = ED->q[0];
|
||||
ED->q[0] = tmp64u;
|
||||
} else {
|
||||
tmp32u = GD->dword[0];
|
||||
GD->q[0] = ED->dword[0];
|
||||
ED->q[0] = tmp32u;
|
||||
}
|
||||
} else {
|
||||
if(rex.w) {
|
||||
GD->q[0] = arm64_lock_xchg(ED, GD->q[0]);
|
||||
} else {
|
||||
do {
|
||||
tmp32u = arm64_lock_read_d(ED);
|
||||
} while(arm64_lock_write_d(ED, GD->dword[0]));
|
||||
GD->q[0] = tmp32u;
|
||||
}
|
||||
}
|
||||
#else
|
||||
GETED(0);
|
||||
GETGD;
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
if(rex.w) {
|
||||
tmp64u = GD->q[0];
|
||||
GD->q[0] = ED->q[0];
|
||||
ED->q[0] = tmp64u;
|
||||
} else {
|
||||
tmp32u = GD->dword[0];
|
||||
GD->q[0] = ED->dword[0];
|
||||
if(MODREG)
|
||||
ED->q[0] = tmp32u;
|
||||
else
|
||||
ED->dword[0] = tmp32u;
|
||||
}
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
case 0xFF: /* GRP 5 Ed */
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* INC Ed */
|
||||
#ifdef DYNAREC
|
||||
if(rex.w)
|
||||
if(((uintptr_t)ED)&7) {
|
||||
// unaligned
|
||||
do {
|
||||
tmp64u = ED->q[0] & 0xffffffffffffff00LL;
|
||||
tmp64u |= arm64_lock_read_b(ED);
|
||||
tmp64u = inc64(emu, tmp64u);
|
||||
} while(arm64_lock_write_b(ED, tmp64u&0xff));
|
||||
ED->q[0] = tmp64u;
|
||||
}
|
||||
else
|
||||
do {
|
||||
tmp64u = arm64_lock_read_dd(ED);
|
||||
} while(arm64_lock_write_dd(ED, inc64(emu, tmp64u)));
|
||||
else {
|
||||
if((uintptr_t)ED&3) {
|
||||
//meh.
|
||||
do {
|
||||
tmp32u = ED->dword[0];
|
||||
tmp32u &=~0xff;
|
||||
tmp32u |= arm64_lock_read_b(ED);
|
||||
tmp32u = inc32(emu, tmp32u);
|
||||
} while(arm64_lock_write_b(ED, tmp32u&0xff));
|
||||
ED->dword[0] = tmp32u;
|
||||
} else {
|
||||
do {
|
||||
tmp32u = arm64_lock_read_d(ED);
|
||||
} while(arm64_lock_write_d(ED, inc32(emu, tmp32u)));
|
||||
}
|
||||
if(MODREG) ED->dword[1] = 0;
|
||||
}
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
if(rex.w) {
|
||||
ED->q[0] = inc64(emu, ED->q[0]);
|
||||
} else {
|
||||
if(MODREG)
|
||||
ED->q[0] = inc32(emu, ED->dword[0]);
|
||||
else
|
||||
ED->dword[0] = inc32(emu, ED->dword[0]);
|
||||
}
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
case 1: /* DEC Ed */
|
||||
#ifdef DYNAREC
|
||||
if(rex.w)
|
||||
if(((uintptr_t)ED)&7) {
|
||||
// unaligned
|
||||
do {
|
||||
tmp64u = ED->q[0] & 0xffffffffffffff00LL;
|
||||
tmp64u |= arm64_lock_read_b(ED);
|
||||
tmp64u = dec64(emu, tmp64u);
|
||||
} while(arm64_lock_write_b(ED, tmp64u&0xff));
|
||||
ED->q[0] = tmp64u;
|
||||
}
|
||||
else
|
||||
do {
|
||||
tmp64u = arm64_lock_read_dd(ED);
|
||||
} while(arm64_lock_write_dd(ED, dec64(emu, tmp64u)));
|
||||
else {
|
||||
do {
|
||||
tmp32u = arm64_lock_read_d(ED);
|
||||
} while(arm64_lock_write_d(ED, dec32(emu, tmp32u)));
|
||||
if(MODREG) ED->dword[1] = 0;
|
||||
}
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
if(rex.w) {
|
||||
ED->q[0] = dec64(emu, ED->q[0]);
|
||||
} else {
|
||||
if(MODREG)
|
||||
ED->q[0] = dec32(emu, ED->dword[0]);
|
||||
else
|
||||
ED->dword[0] = dec32(emu, ED->dword[0]);
|
||||
}
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
printf_log(LOG_NONE, "Illegal Opcode 0xF0 0xFF 0x%02X 0x%02X\n", nextop, PK(0));
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_ILLEGAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
+15
-5
@@ -19,10 +19,6 @@
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
#include "bridge.h"
|
||||
//#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
@@ -57,6 +53,12 @@ int RunF20F(x64emu_t *emu, rex_t rex)
|
||||
GETGX;
|
||||
EX->q[0] = GX->q[0];
|
||||
break;
|
||||
case 0x12: /* MOVDDUP Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
GX->q[1] = GX->q[0] = EX->q[0];
|
||||
break;
|
||||
|
||||
case 0x2A: /* CVTSI2SD Gx, Ed */
|
||||
nextop = F8;
|
||||
@@ -114,6 +116,7 @@ int RunF20F(x64emu_t *emu, rex_t rex)
|
||||
GD->sdword[0] = EX->d[0];
|
||||
break;
|
||||
}
|
||||
GD->dword[1] = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -258,7 +261,14 @@ int RunF20F(x64emu_t *emu, rex_t rex)
|
||||
GX->q[1] = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
case 0xF0: /* LDDQU Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
memcpy(GX, EX, 16);
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
+45
-7
@@ -18,12 +18,7 @@
|
||||
#include "x64trace.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
//#include "my_cpuid.h"
|
||||
#include "bridge.h"
|
||||
//#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
@@ -33,6 +28,8 @@ int RunF30F(x64emu_t *emu, rex_t rex)
|
||||
uint8_t nextop;
|
||||
int8_t tmp8s;
|
||||
uint8_t tmp8u;
|
||||
uint32_t tmp32u;
|
||||
uint64_t tmp64u;
|
||||
reg64_t *oped, *opgd;
|
||||
sse_regs_t *opex, *opgx, eax1;
|
||||
mmx87_regs_t *opem;
|
||||
@@ -46,7 +43,7 @@ int RunF30F(x64emu_t *emu, rex_t rex)
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
GX->ud[0] = EX->ud[0];
|
||||
if((nextop&0xC0)!=0xC0) {
|
||||
if(!MODREG) {
|
||||
// EX is not a register (reg to reg only move 31:0)
|
||||
GX->ud[1] = GX->ud[2] = GX->ud[3] = 0;
|
||||
}
|
||||
@@ -241,6 +238,42 @@ int RunF30F(x64emu_t *emu, rex_t rex)
|
||||
memcpy(EX, GX, 16); // unaligned...
|
||||
break;
|
||||
|
||||
case 0xBC: /* TZCNT Ed,Gd */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
if(rex.w) {
|
||||
tmp64u = ED->q[0];
|
||||
if(tmp64u) {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
tmp8u = 0;
|
||||
while(!(tmp64u&(1LL<<tmp8u))) ++tmp8u;
|
||||
GD->q[0] = tmp8u;
|
||||
CONDITIONAL_SET_FLAG(tmp8u==0, F_ZF);
|
||||
CLEAR_FLAG(F_CF);
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
SET_FLAG(F_CF);
|
||||
GD->q[0] = 64;
|
||||
}
|
||||
} else {
|
||||
tmp32u = ED->dword[0];
|
||||
if(tmp32u) {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
tmp8u = 0;
|
||||
while(!(tmp32u&(1<<tmp8u))) ++tmp8u;
|
||||
GD->dword[0] = tmp8u;
|
||||
CONDITIONAL_SET_FLAG(tmp8u==0, F_ZF);
|
||||
CLEAR_FLAG(F_CF);
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
SET_FLAG(F_CF);
|
||||
GD->dword[0] = 32;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC2: /* CMPSS Gx, Ex, Ib */
|
||||
nextop = F8;
|
||||
GETEX(1);
|
||||
@@ -276,8 +309,13 @@ int RunF30F(x64emu_t *emu, rex_t rex)
|
||||
GX->d[0] = EX->sd[0];
|
||||
break;
|
||||
|
||||
case 0x1E: /* NOP (multi-byte), endbr64 */
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
+264
-16
@@ -34,18 +34,23 @@
|
||||
#include "x64tls.h"
|
||||
|
||||
typedef struct x64_sigaction_s x64_sigaction_t;
|
||||
typedef struct x64_stack_s x64_stack_t;
|
||||
|
||||
int mkdir(const char *path, mode_t mode);
|
||||
|
||||
//int32_t my_getrandom(x64emu_t* emu, void* buf, uint32_t buflen, uint32_t flags);
|
||||
int of_convert(int flag);
|
||||
int32_t my_open(x64emu_t* emu, void* pathname, int32_t flags, uint32_t mode);
|
||||
ssize_t my_readlink(x64emu_t* emu, void* path, void* buf, size_t sz);
|
||||
int my_stat(x64emu_t *emu, void* filename, void* buf);
|
||||
|
||||
//int my_sigaction(x64emu_t* emu, int signum, const x86_sigaction_t *act, x86_sigaction_t *oldact);
|
||||
int my_sigaction(x64emu_t* emu, int signum, const x64_sigaction_t *act, x64_sigaction_t *oldact);
|
||||
int my_sigaltstack(x64emu_t* emu, const x64_stack_t* ss, x64_stack_t* oss);
|
||||
//int32_t my_execve(x64emu_t* emu, const char* path, char* const argv[], char* const envp[]);
|
||||
//void* my_mmap(x64emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, int offset);
|
||||
//void* my_mmap64(x64emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, int64_t offset);
|
||||
//int my_munmap(x64emu_t* emu, void* addr, unsigned long length);
|
||||
//int my_mprotect(x64emu_t* emu, void *addr, unsigned long len, int prot);
|
||||
void* my_mmap64(x64emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, int64_t offset);
|
||||
int my_munmap(x64emu_t* emu, void* addr, unsigned long length);
|
||||
int my_mprotect(x64emu_t* emu, void *addr, unsigned long len, int prot);
|
||||
void* my_mremap(x64emu_t* emu, void* old_addr, size_t old_size, size_t new_size, int flags, void* new_addr);
|
||||
|
||||
// cannot include <fcntl.h>, it conflict with some asm includes...
|
||||
#ifndef O_NONBLOCK
|
||||
@@ -56,19 +61,84 @@ int fcntl(int fd, int cmd, ... /* arg */ );
|
||||
|
||||
// Syscall table for x86_64 can be found
|
||||
typedef struct scwrap_s {
|
||||
int x64s;
|
||||
uint32_t x64s; // 32 bits?
|
||||
int nats;
|
||||
int nbpars;
|
||||
} scwrap_t;
|
||||
|
||||
scwrap_t syscallwrap[] = {
|
||||
//{ 0, __NR_read, 3 }, // wrapped so SA_RESTART can be handled by libc
|
||||
//{ 1, __NR_write, 3 }, // same
|
||||
//{ 2, __NR_open, 3 }, // flags need transformation
|
||||
//{ 3, __NR_close, 1 }, // wrapped so SA_RESTART can be handled by libc
|
||||
|
||||
//{ 0, __NR_read, 3 }, // wrapped so SA_RESTART can be handled by libc
|
||||
//{ 1, __NR_write, 3 }, // same
|
||||
//{ 2, __NR_open, 3 }, // flags need transformation
|
||||
//{ 3, __NR_close, 1 }, // wrapped so SA_RESTART can be handled by libc
|
||||
//{ 4, __NR_stat, 2 }, // Need to align struct stat
|
||||
//{ 9, __NR_mmap, 6}, // wrapped to track mmap
|
||||
//{ 10, __NR_mprotect, 3}, // same
|
||||
//{ 11, __NR_munmap, 2}, // same
|
||||
{ 5, __NR_fstat, 2},
|
||||
{ 186, __NR_gettid, 0 },
|
||||
//{ 13, __NR_rt_sigaction, 4}, // wrapped to use my_ version
|
||||
{ 14, __NR_rt_sigprocmask, 4},
|
||||
{ 16, __NR_ioctl, 3},
|
||||
{ 20, __NR_writev, 3},
|
||||
#ifdef __NR_access
|
||||
{ 21, __NR_access, 2},
|
||||
#endif
|
||||
#ifdef __NR_pipe
|
||||
{ 22, __NR_pipe, 1},
|
||||
#endif
|
||||
#ifdef __NR_select
|
||||
{ 23, __NR_select, 5},
|
||||
#endif
|
||||
//{ 25, __NR_mremap, 5}, // wrapped to track protection
|
||||
{ 39, __NR_getpid, 0},
|
||||
{ 46, __NR_sendmsg, 3},
|
||||
{ 47, __NR_recvmsg, 3},
|
||||
{ 53, __NR_socketpair, 4},
|
||||
#ifdef __NR_fork
|
||||
{ 57, __NR_fork, 0 }, // should wrap this one, because of the struct pt_regs (the only arg)?
|
||||
#endif
|
||||
{ 61, __NR_wait4, 4},
|
||||
{ 66, __NR_semctl, 4},
|
||||
#ifdef __NR_getdents
|
||||
{ 78, __NR_getdents, 3},
|
||||
#endif
|
||||
#ifdef __NR_mkdir
|
||||
{ 83, __NR_mkdir, 2},
|
||||
#endif
|
||||
#ifdef __NR_unlink
|
||||
{ 87, __NR_unlink, 1},
|
||||
#endif
|
||||
//{ 89, __NR_readlink, 3}, // not always existing, better use the wrapped version anyway
|
||||
{ 96, __NR_gettimeofday, 2},
|
||||
{ 97, __NR_getrlimit, 2},
|
||||
{ 101, __NR_ptrace, 4},
|
||||
{ 125, __NR_capget, 2},
|
||||
{ 126, __NR_capset, 2},
|
||||
{ 127, __NR_rt_sigpending, 2},
|
||||
//{ 131, __NR_sigaltstack, 2}, // wrapped to use my_sigaltstack
|
||||
{ 157, __NR_prctl, 5 }, // needs wrapping?
|
||||
//{ 158, __NR_arch_prctl, 2}, //need wrapping
|
||||
{ 186, __NR_gettid, 0 }, //0xBA
|
||||
{ 200, __NR_tkill, 2 },
|
||||
#ifdef __NR_time
|
||||
{ 201, __NR_time, 1},
|
||||
#endif
|
||||
{ 202, __NR_futex, 6},
|
||||
{ 217, __NR_getdents64, 3},
|
||||
{ 220, __NR_semtimedop, 4},
|
||||
{ 228, __NR_clock_gettime, 2},
|
||||
{ 229, __NR_clock_getres, 2},
|
||||
{ 230, __NR_clock_nanosleep, 4},
|
||||
{ 234, __NR_tgkill, 3},
|
||||
#ifdef __NR_inotify_init
|
||||
{ 253, __NR_inotify_init, 0}, //0xFD
|
||||
#endif
|
||||
{ 254, __NR_inotify_add_watch, 3},
|
||||
{ 255, __NR_inotify_rm_watch, 2},
|
||||
{ 274, __NR_get_robust_list, 3},
|
||||
{ 294, __NR_inotify_init1, 1},
|
||||
{ 298, __NR_perf_event_open, 5},
|
||||
{ 318, __NR_getrandom, 3},
|
||||
};
|
||||
|
||||
struct mmap_arg_struct {
|
||||
@@ -80,6 +150,45 @@ struct mmap_arg_struct {
|
||||
unsigned long offset;
|
||||
};
|
||||
|
||||
#ifndef __NR_getdents
|
||||
typedef struct x86_linux_dirent_s {
|
||||
unsigned long d_ino;
|
||||
unsigned long d_off;
|
||||
unsigned short d_reclen;
|
||||
char d_name[];
|
||||
} x86_linux_dirent_t;
|
||||
|
||||
typedef struct nat_linux_dirent64_s {
|
||||
ino64_t d_ino;
|
||||
off64_t d_off;
|
||||
unsigned short d_reclen;
|
||||
unsigned char d_type;
|
||||
char d_name[];
|
||||
} nat_linux_dirent64_t;
|
||||
|
||||
ssize_t DirentFromDirent64(void* dest, void* source, ssize_t count)
|
||||
{
|
||||
nat_linux_dirent64_t *src = (nat_linux_dirent64_t*)source;
|
||||
x86_linux_dirent_t *dst = (x86_linux_dirent_t*)dest;
|
||||
ssize_t ret = count;
|
||||
while(count>0) {
|
||||
dst->d_ino = src->d_ino;
|
||||
dst->d_reclen = src->d_reclen+1;
|
||||
strcpy(dst->d_name, src->d_name);
|
||||
dst->d_off = src->d_off?(src->d_off+1):0;
|
||||
*(uint8_t*)((uintptr_t)dst + dst->d_reclen -2) = 0;
|
||||
*(uint8_t*)((uintptr_t)dst + dst->d_reclen -1) = src->d_type;
|
||||
|
||||
count -= src->d_reclen;
|
||||
ret += 1;
|
||||
src = (nat_linux_dirent64_t*)(((uintptr_t)src) + src->d_reclen);
|
||||
dst = (x86_linux_dirent_t*)(((uintptr_t)dst) + dst->d_reclen);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//struct x86_pt_regs {
|
||||
// long ebx;
|
||||
// long ecx;
|
||||
@@ -113,7 +222,7 @@ struct mmap_arg_struct {
|
||||
void EXPORT x64Syscall(x64emu_t *emu)
|
||||
{
|
||||
RESET_FLAGS(emu);
|
||||
uint32_t s = R_EAX;
|
||||
uint32_t s = R_EAX; // EAX? (syscalls only go up to 547 anyways)
|
||||
printf_log(LOG_DEBUG, "%p: Calling syscall 0x%02X (%d) %p %p %p %p %p %p", (void*)R_RIP, s, s, (void*)R_RDI, (void*)R_RSI, (void*)R_RDX, (void*)R_R10, (void*)R_R8, (void*)R_R9);
|
||||
// check wrapper first
|
||||
int cnt = sizeof(syscallwrap) / sizeof(scwrap_t);
|
||||
@@ -123,7 +232,7 @@ void EXPORT x64Syscall(x64emu_t *emu)
|
||||
switch(syscallwrap[i].nbpars) {
|
||||
case 0: *(int64_t*)&R_RAX = syscall(sc); break;
|
||||
case 1: *(int64_t*)&R_RAX = syscall(sc, R_RDI); break;
|
||||
case 2: if(s==33) {printf_log(LOG_DUMP, " => sys_access(\"%s\", %ld)\n", (char*)R_RDI, R_RSI);}; *(int64_t*)&R_RAX = syscall(sc, R_RDI, R_RSI); break;
|
||||
case 2: if(s==33) {printf_dump(LOG_DEBUG, " => sys_access(\"%s\", %ld)\n", (char*)R_RDI, R_RSI);}; *(int64_t*)&R_RAX = syscall(sc, R_RDI, R_RSI); break;
|
||||
case 3: *(int64_t*)&R_RAX = syscall(sc, R_RDI, R_RSI, R_RDX); break;
|
||||
case 4: *(int64_t*)&R_RAX = syscall(sc, R_RDI, R_RSI, R_RDX, R_R10); break;
|
||||
case 5: *(int64_t*)&R_RAX = syscall(sc, R_RDI, R_RSI, R_RDX, R_R10, R_R8); break;
|
||||
@@ -152,6 +261,84 @@ void EXPORT x64Syscall(x64emu_t *emu)
|
||||
case 3: // sys_close
|
||||
R_EAX = (uint32_t)close((int)R_EDI);
|
||||
break;
|
||||
case 4: // sys_stat
|
||||
R_EAX = (uint32_t)my_stat(emu, (void*)R_RDI, (void*)R_RSI);
|
||||
break;
|
||||
case 9: // sys_mmap
|
||||
R_RAX = (uintptr_t)my_mmap64(emu, (void*)R_RDI, R_RSI, (int)R_EDX, (int)R_R10d, (int)R_R8d, R_R9);
|
||||
break;
|
||||
case 10: // sys_mprotect
|
||||
R_EAX = (uint32_t)my_mprotect(emu, (void*)R_RDI, R_RSI, (int)R_EDX);
|
||||
break;
|
||||
case 11: // sys_munmap
|
||||
R_EAX = (uint32_t)my_munmap(emu, (void*)R_RDI, R_RSI);
|
||||
break;
|
||||
case 13: // sys_rt_sigaction
|
||||
R_EAX = (uint32_t)my_sigaction(emu, (int)R_EDI, (const x64_sigaction_t *)R_RSI, (x64_sigaction_t *)R_RDX/*, (size_t)R_R10*/);
|
||||
break;
|
||||
#ifndef __NR_access
|
||||
case 21: // sys_access
|
||||
R_EAX = (uint32_t)access((void*)R_RDI, R_ESI);
|
||||
break;
|
||||
#endif
|
||||
#ifndef __NR_pipe
|
||||
case 22:
|
||||
R_EAX = (uint32_t)pipe((void*)R_RDI);
|
||||
break;
|
||||
#endif
|
||||
#ifndef __NR_select
|
||||
case 23: // sys_select
|
||||
R_EAX = (uint32_t)select(R_RDI, (void*)R_RSI, (void*)R_RDX, (void*)R_R10, (void*)R_R8);
|
||||
break;
|
||||
#endif
|
||||
case 25: // sys_mremap
|
||||
R_RAX = (uintptr_t)my_mremap(emu, (void*)R_RDI, R_RSI, R_RDX, R_R10d, (void*)R_R8);
|
||||
break;
|
||||
#ifndef __NR_fork
|
||||
case 57:
|
||||
R_RAX = fork();
|
||||
break;
|
||||
#endif
|
||||
#ifndef __NR_getdents
|
||||
case 78:
|
||||
{
|
||||
size_t count = R_RDX;
|
||||
nat_linux_dirent64_t *d64 = (nat_linux_dirent64_t*)alloca(count);
|
||||
ssize_t ret = syscall(__NR_getdents64, R_EDI, d64, count);
|
||||
ret = DirentFromDirent64((void*)R_RSI, d64, ret);
|
||||
R_RAX = (uint64_t)ret;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifndef __NR_mkdir
|
||||
case 83: // sys_mkdir
|
||||
R_EAX = (uint32_t)mkdir((void*)R_RDI, R_ESI);
|
||||
break;
|
||||
#endif
|
||||
#ifndef __NR_unlink
|
||||
case 87: //sys_unlink
|
||||
R_EAX = (uint32_t)unlink((void*)R_RDI);
|
||||
break;
|
||||
#endif
|
||||
case 89: // sys_readlink
|
||||
R_RAX = (ssize_t)my_readlink(emu,(void*)R_RDI, (void*)R_RSI, (size_t)R_RDX);
|
||||
break;
|
||||
case 131: // sys_sigaltstack
|
||||
R_EAX = (uint32_t)my_sigaltstack(emu, (void*)R_RDI, (void*)R_RSI);
|
||||
break;
|
||||
case 158: // sys_arch_prctl
|
||||
R_EAX = (uint32_t)my_arch_prctl(emu, (int)R_EDI, (void*)R_RSI);
|
||||
break;
|
||||
#ifndef __NR_time
|
||||
case 201: // sys_time
|
||||
R_RAX = (uintptr_t)time((void*)R_RDI);
|
||||
break;
|
||||
#endif
|
||||
#ifndef __NR_inotify_init
|
||||
case 253:
|
||||
R_EAX = (int)syscall(__NR_inotify_init1, 0);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
printf_log(LOG_INFO, "Error: Unsupported Syscall 0x%02Xh (%d)\n", s, s);
|
||||
emu->quit = 1;
|
||||
@@ -164,13 +351,14 @@ void EXPORT x64Syscall(x64emu_t *emu)
|
||||
#define stack(n) (R_RSP+8+n)
|
||||
#define i32(n) *(int32_t*)stack(n)
|
||||
#define u32(n) *(uint32_t*)stack(n)
|
||||
#define i64(n) *(int64_t*)stack(n)
|
||||
#define u64(n) *(uint64_t*)stack(n)
|
||||
#define p(n) *(void**)stack(n)
|
||||
|
||||
uint32_t EXPORT my_syscall(x64emu_t *emu)
|
||||
uintptr_t EXPORT my_syscall(x64emu_t *emu)
|
||||
{
|
||||
uint32_t s = R_EDI;;
|
||||
printf_log(LOG_DUMP, "%p: Calling libc syscall 0x%02X (%d) %p %p %p %p %p\n", (void*)R_RIP, s, s, (void*)R_RSI, (void*)R_RDX, (void*)R_RCX, (void*)R_R8, (void*)R_R9);
|
||||
printf_dump(LOG_DEBUG, "%p: Calling libc syscall 0x%02X (%d) %p %p %p %p %p\n", (void*)R_RIP, s, s, (void*)R_RSI, (void*)R_RDX, (void*)R_RCX, (void*)R_R8, (void*)R_R9);
|
||||
// check wrapper first
|
||||
int cnt = sizeof(syscallwrap) / sizeof(scwrap_t);
|
||||
for (int i=0; i<cnt; i++) {
|
||||
@@ -200,6 +388,66 @@ uint32_t EXPORT my_syscall(x64emu_t *emu)
|
||||
return my_open(emu, (char*)R_RSI, of_convert(R_EDX), R_ECX);
|
||||
case 3: // sys_close
|
||||
return (uint32_t)close(R_ESI);
|
||||
case 4: // sys_stat
|
||||
return (uint32_t)my_stat(emu, (void*)R_RSI, (void*)R_RDX);
|
||||
case 9: // sys_mmap
|
||||
return (uintptr_t)my_mmap64(emu, (void*)R_RSI, R_RDX, (int)R_RCX, (int)R_R8d, (int)R_R9, i64(0));
|
||||
case 10: // sys_mprotect
|
||||
return (uint32_t)my_mprotect(emu, (void*)R_RSI, R_RDX, (int)R_ECX);
|
||||
case 11: // sys_munmap
|
||||
return (uint32_t)my_munmap(emu, (void*)R_RSI, R_RDX);
|
||||
case 13: // sys_rt_sigaction
|
||||
return (uint32_t)my_sigaction(emu, (int)R_ESI, (const x64_sigaction_t *)R_RDX, (x64_sigaction_t *)R_RCX/*, (size_t)R_R8*/);
|
||||
#ifndef __NR_access
|
||||
case 21: // sys_access
|
||||
return (uint32_t)access((void*)R_RSI, R_EDX);
|
||||
#endif
|
||||
#ifndef __NR_pipe
|
||||
case 22:
|
||||
return (uint32_t)pipe((void*)R_RSI);
|
||||
#endif
|
||||
#ifndef __NR_select
|
||||
case 23: // sys_select
|
||||
return (uint32_t)select(R_RSI, (void*)R_RDX, (void*)R_RCX, (void*)R_R8, (void*)R_R9);
|
||||
#endif
|
||||
case 25: // sys_mremap
|
||||
return (uintptr_t)my_mremap(emu, (void*)R_RSI, R_RDX, R_RCX, R_R8d, (void*)R_R9);
|
||||
#ifndef __NR_fork
|
||||
case 57:
|
||||
return fork();
|
||||
#endif
|
||||
#ifndef __NR_getdents
|
||||
case 78:
|
||||
{
|
||||
size_t count = R_RCX;
|
||||
nat_linux_dirent64_t *d64 = (nat_linux_dirent64_t*)alloca(count);
|
||||
ssize_t ret = syscall(__NR_getdents64, R_ESI, d64, count);
|
||||
ret = DirentFromDirent64((void*)R_RDX, d64, ret);
|
||||
return (uint64_t)ret;
|
||||
}
|
||||
#endif
|
||||
#ifndef __NR_mkdir
|
||||
case 83: // sys_mkdir
|
||||
return (uint32_t)mkdir((void*)R_RSI, R_EDX);
|
||||
#endif
|
||||
#ifndef __NR_unlink
|
||||
case 87: //sys_unlink
|
||||
return (uint32_t)unlink((void*)R_RSI);
|
||||
#endif
|
||||
case 89: // sys_readlink
|
||||
return (uintptr_t)my_readlink(emu,(void*)R_RSI, (void*)R_RDX, (size_t)R_RCX);
|
||||
case 131: // sys_sigaltstack
|
||||
return (uint32_t)my_sigaltstack(emu, (void*)R_RSI, (void*)R_RDX);
|
||||
case 158: // sys_arch_prctl
|
||||
return (uint32_t)my_arch_prctl(emu, (int)R_ESI, (void*)R_RDX);
|
||||
#ifndef __NR_time
|
||||
case 201: // sys_time
|
||||
return (uintptr_t)time((void*)R_RSI);
|
||||
#endif
|
||||
#ifndef __NR_inotify_init
|
||||
case 253:
|
||||
return (int)syscall(__NR_inotify_init1, 0);
|
||||
#endif
|
||||
default:
|
||||
printf_log(LOG_INFO, "Error: Unsupported libc Syscall 0x%02X (%d)\n", s, s);
|
||||
emu->quit = 1;
|
||||
|
||||
+59
-8
@@ -8,6 +8,7 @@
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "x64emu.h"
|
||||
#include "x64emu_private.h"
|
||||
#include "x64tls.h"
|
||||
#include "elfloader.h"
|
||||
|
||||
@@ -27,6 +28,7 @@ typedef struct thread_area_s
|
||||
static pthread_once_t thread_key_once0 = PTHREAD_ONCE_INIT;
|
||||
static pthread_once_t thread_key_once1 = PTHREAD_ONCE_INIT;
|
||||
static pthread_once_t thread_key_once2 = PTHREAD_ONCE_INIT;
|
||||
static pthread_once_t thread_key_once3 = PTHREAD_ONCE_INIT;
|
||||
|
||||
static void thread_key_alloc0() {
|
||||
pthread_key_create(&my_context->segtls[0].key, NULL);
|
||||
@@ -37,6 +39,9 @@ static void thread_key_alloc1() {
|
||||
static void thread_key_alloc2() {
|
||||
pthread_key_create(&my_context->segtls[2].key, NULL);
|
||||
}
|
||||
static void thread_key_alloc3() {
|
||||
pthread_key_create(&my_context->segtls[3].key, NULL);
|
||||
}
|
||||
|
||||
uint32_t my_set_thread_area(thread_area_t* td)
|
||||
{
|
||||
@@ -123,12 +128,57 @@ uint32_t my_modify_ldt(x64emu_t* emu, int op, thread_area_t* td, int size)
|
||||
pthread_setspecific(my_context->segtls[idx].key, (void*)my_context->segtls[idx].base);
|
||||
*/
|
||||
|
||||
ResetSegmentsCache(thread_get_emu());
|
||||
ResetSegmentsCache(emu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define POS_TLS 0x50
|
||||
int my_arch_prctl(x64emu_t *emu, int code, void* addr)
|
||||
{
|
||||
#define ARCH_SET_GS 0x1001
|
||||
#define ARCH_GET_GS 0x1004
|
||||
switch(code) {
|
||||
case ARCH_GET_GS:
|
||||
*(void**)addr = GetSegmentBase(emu->segs[_GS]);
|
||||
return 0;
|
||||
case ARCH_SET_GS:
|
||||
if(emu->segs[_GS]!=(0xa<<3)) {
|
||||
pthread_once(&thread_key_once3, thread_key_alloc3);
|
||||
emu->segs[_GS] = 0xa<<3;
|
||||
if(!default_gs)
|
||||
default_gs = 0xa<<3;
|
||||
}
|
||||
my_context->segtls[3].base = (uintptr_t)addr;
|
||||
my_context->segtls[3].limit = 0;
|
||||
my_context->segtls[3].present = 1;
|
||||
pthread_setspecific(my_context->segtls[3].key, (void*)my_context->segtls[3].base);
|
||||
return 0;
|
||||
}
|
||||
// other are unsupported
|
||||
printf_log(LOG_INFO, "warning, call to unsupported arch_prctl(0x%x, %p)\n", code, addr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#define POS_TLS 0x200
|
||||
/*
|
||||
tls record should looks like:
|
||||
void* tcb 0x00
|
||||
void* dtv 0x08
|
||||
void* self 0x10
|
||||
int multiple 0x18
|
||||
int gscope 0x1c
|
||||
void* sysinfo 0x20
|
||||
uintptr_t stack_guard 0x28
|
||||
uitnptr_t pointer_guard 0x30
|
||||
uint64_t vgetcpu[2] 0x38
|
||||
uint32_t features 0x48
|
||||
int unused 0x4c
|
||||
void* private[4] 0x50
|
||||
void* private_ss 0x70
|
||||
uintptr_t ssp_base 0x78
|
||||
.... padding .... 0x200?
|
||||
*/
|
||||
|
||||
static tlsdatasize_t* setupTLSData(box64context_t* context)
|
||||
{
|
||||
@@ -142,20 +192,21 @@ static tlsdatasize_t* setupTLSData(box64context_t* context)
|
||||
pthread_setspecific(context->tlskey, data);
|
||||
// copy canary...
|
||||
memset((void*)((uintptr_t)ptr+context->tlssize), 0, POS_TLS+dtsize); // set to 0 remining bytes
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x14), context->canary, sizeof(void*)); // put canary in place
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x28), context->canary, sizeof(void*)); // put canary in place
|
||||
uintptr_t tlsptr = (uintptr_t)ptr+context->tlssize;
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x0), &tlsptr, sizeof(void*));
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x10), &tlsptr, sizeof(void*)); // set tcb and self same address
|
||||
uintptr_t dtp = (uintptr_t)ptr+context->tlssize+POS_TLS;
|
||||
memcpy((void*)(tlsptr+sizeof(void*)), &dtp, sizeof(void*));
|
||||
if(dtsize) {
|
||||
for (size_t i=0; i<context->elfsize; ++i) {
|
||||
for (int i=0; i<context->elfsize; ++i) {
|
||||
// set pointer
|
||||
dtp = (uintptr_t)ptr + (context->tlssize + GetTLSBase(context->elfs[i]));
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+POS_TLS+i*16), &dtp, sizeof(void*));
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+POS_TLS+i*16+8), &i, sizeof(void*)); // index
|
||||
*(uint64_t*)((uintptr_t)ptr+context->tlssize+POS_TLS+i*16) = dtp;
|
||||
*(uint64_t*)((uintptr_t)ptr+context->tlssize+POS_TLS+i*16+8) = i; // index
|
||||
}
|
||||
}
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x10), &context->vsyscall, sizeof(void*)); // address of vsyscall
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x20), &context->vsyscall, sizeof(void*)); // address of vsyscall
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -203,7 +254,7 @@ void* GetSegmentBase(uint32_t desc)
|
||||
if(base==0x6)
|
||||
return GetSeg33Base();
|
||||
|
||||
if(base>6 && base<10 && my_context->segtls[base-7].present) {
|
||||
if(base>6 && base<11 && my_context->segtls[base-7].present) {
|
||||
void* ptr = pthread_getspecific(my_context->segtls[base-7].key);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,16 @@
|
||||
#include "x87emu_private.h"
|
||||
//#include "x64run_private.h"
|
||||
|
||||
void fpu_do_free(x64emu_t* emu, int i)
|
||||
{
|
||||
emu->p_regs[(emu->top+i)&7].tag = 0b11; // empty
|
||||
// check if all empty
|
||||
for(int j=0; j<8; ++j)
|
||||
if(emu->p_regs[j].tag != 0b11)
|
||||
return;
|
||||
emu->fpu_stack = 0;
|
||||
}
|
||||
|
||||
void reset_fpu(x64emu_t* emu)
|
||||
{
|
||||
memset(emu->mmx87, 0, sizeof(emu->mmx87));
|
||||
@@ -196,6 +206,21 @@ double FromLD(void* ld)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef HAVE_LD80BITS
|
||||
long double LD2localLD(void* ld)
|
||||
{
|
||||
// local implementation may not be try Quad precision, but double-double precision, so simple way to keep the 80bits precision in the conversion
|
||||
double ret;
|
||||
LD2D(ld, &ret);
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
long double LD2localLD(void* ld)
|
||||
{
|
||||
return *(long double*)ld;
|
||||
}
|
||||
#endif
|
||||
|
||||
void fpu_loadenv(x64emu_t* emu, char* p, int b16)
|
||||
{
|
||||
emu->cw = *(uint16_t*)p;
|
||||
|
||||
@@ -14,10 +14,6 @@ typedef struct x64emu_s x64emu_t;
|
||||
#define LN2 0.69314718055994531
|
||||
#define LG2 0.3010299956639812
|
||||
|
||||
//void Run66D9(x64emu_t *emu);
|
||||
//void Run66DD(x64emu_t *emu);
|
||||
//void RunDF(x64emu_t *emu);
|
||||
|
||||
#define ST0 emu->mmx87[emu->top]
|
||||
#define ST1 emu->mmx87[(emu->top+1)&7]
|
||||
#define ST(a) emu->mmx87[(emu->top+(a))&7]
|
||||
@@ -54,15 +50,7 @@ static inline void fpu_do_pop(x64emu_t* emu)
|
||||
emu->top = (emu->top+1)&7;
|
||||
}
|
||||
|
||||
static inline void fpu_do_free(x64emu_t* emu, int i)
|
||||
{
|
||||
emu->p_regs[(emu->top+i)&7].tag = 0b11; // empty
|
||||
// check if all empty
|
||||
for(int i=0; i<8; ++i)
|
||||
if(emu->p_regs[i].tag != 0b11)
|
||||
return;
|
||||
emu->fpu_stack = 0;
|
||||
}
|
||||
void fpu_do_free(x64emu_t* emu, int i);
|
||||
|
||||
void reset_fpu(x64emu_t* emu);
|
||||
|
||||
|
||||
@@ -8,6 +8,6 @@ int init_auxval(int argc, const char **argv, const char **env);
|
||||
#endif
|
||||
|
||||
unsigned long real_getauxval(unsigned long type);
|
||||
//unsigned long my_getauxval(x64emu_t* emu, unsigned long type);
|
||||
unsigned long my_getauxval(x64emu_t* emu, unsigned long type);
|
||||
|
||||
#endif //__AUXVAL_H__
|
||||
+19
-11
@@ -3,6 +3,7 @@
|
||||
#include <stdint.h>
|
||||
#include <pthread.h>
|
||||
#include "pathcoll.h"
|
||||
#include "dictionnary.h"
|
||||
|
||||
typedef struct elfheader_s elfheader_t;
|
||||
typedef struct cleanup_s cleanup_t;
|
||||
@@ -27,9 +28,10 @@ typedef struct dynablocklist_s dynablocklist_t;
|
||||
typedef struct mmaplist_s mmaplist_t;
|
||||
typedef struct kh_dynablocks_s kh_dynablocks_t;
|
||||
#endif
|
||||
#define DYNAMAP_SHIFT 16
|
||||
#define JMPTABL_SHIFT 16
|
||||
|
||||
typedef void* (*procaddess_t)(const char* name);
|
||||
typedef void* (*vkprocaddess_t)(void* instance, const char* name);
|
||||
|
||||
#define MAX_SIGNAL 64
|
||||
|
||||
@@ -48,6 +50,8 @@ typedef struct needed_libs_s {
|
||||
|
||||
void add_neededlib(needed_libs_t* needed, library_t* lib);
|
||||
void free_neededlib(needed_libs_t* needed);
|
||||
void add_dependedlib(needed_libs_t* depended, library_t* lib);
|
||||
void free_dependedlib(needed_libs_t* depended);
|
||||
|
||||
typedef struct base_segment_s {
|
||||
uintptr_t base;
|
||||
@@ -68,7 +72,7 @@ typedef struct box64context_s {
|
||||
uint32_t sel_serial; // will be increment each time selectors changes
|
||||
|
||||
zydis_t *zydis; // dlopen the zydis dissasembler
|
||||
void* box64lib; // dlopen on box86 itself
|
||||
void* box64lib; // dlopen on box64 itself
|
||||
|
||||
int argc;
|
||||
char** argv;
|
||||
@@ -77,10 +81,10 @@ typedef struct box64context_s {
|
||||
char** envv;
|
||||
|
||||
char* fullpath;
|
||||
char* box64path; // path of current box86 executable
|
||||
char* box64path; // path of current box64 executable
|
||||
|
||||
uint32_t stacksz;
|
||||
int stackalign;
|
||||
uint64_t stacksz;
|
||||
size_t stackalign;
|
||||
void* stack; // alocated stack
|
||||
|
||||
elfheader_t **elfs; // elf headers and memory
|
||||
@@ -94,6 +98,7 @@ typedef struct box64context_s {
|
||||
|
||||
lib_t *maplib; // lib and symbols handling
|
||||
lib_t *local_maplib; // libs and symbols openned has local (only collection of libs, no symbols)
|
||||
dic_t *versym; // dictionnary of versionned symbols
|
||||
|
||||
kh_threadstack_t *stacksizes; // stack sizes attributes for thread (temporary)
|
||||
bridge_t *system; // other bridges
|
||||
@@ -104,9 +109,6 @@ typedef struct box64context_s {
|
||||
procaddess_t glxprocaddress;
|
||||
kh_symbolmap_t *alwrappers; // the map of wrapper for alGetProcAddress
|
||||
kh_symbolmap_t *almymap; // link to the mysymbolmap if libOpenAL
|
||||
kh_symbolmap_t *vkwrappers; // the map of wrapper for VulkanProcs (TODO: check SDL2)
|
||||
kh_symbolmap_t *vkmymap; // link to the mysymbolmap of libGL
|
||||
vkprocaddess_t vkprocaddress;
|
||||
|
||||
pthread_mutex_t mutex_once;
|
||||
pthread_mutex_t mutex_once2;
|
||||
@@ -144,6 +146,7 @@ typedef struct box64context_s {
|
||||
library_t *asound;
|
||||
library_t *pulse;
|
||||
library_t *d3dadapter9;
|
||||
library_t *libglu;
|
||||
|
||||
int deferedInit;
|
||||
elfheader_t **deferedInitList;
|
||||
@@ -152,8 +155,8 @@ typedef struct box64context_s {
|
||||
|
||||
pthread_key_t tlskey; // then tls key to have actual tlsdata
|
||||
void* tlsdata; // the initial global tlsdata
|
||||
int32_t tlssize; // wanted size of tlsdata
|
||||
base_segment_t segtls[3]; // only handling 0/1/2 descriptors
|
||||
int64_t tlssize; // wanted size of tlsdata
|
||||
base_segment_t segtls[4]; // only handling 0/1/2 descriptors (3 is internal use)
|
||||
|
||||
uintptr_t *auxval_start;
|
||||
|
||||
@@ -196,4 +199,9 @@ int AddTLSPartition(box64context_t* context, int tlssize);
|
||||
void thread_set_emu(x64emu_t* emu);
|
||||
x64emu_t* thread_get_emu();
|
||||
|
||||
#endif //__BOX64CONTEXT_H_
|
||||
// unlock mutex that are locked by current thread (for signal handling). Return a mask of unlock mutex
|
||||
int unlockMutex();
|
||||
// relock the muxtex that were unlocked
|
||||
void relockMutex(int locks);
|
||||
|
||||
#endif //__BOX64CONTEXT_H_
|
||||
+40
-29
@@ -6,47 +6,58 @@
|
||||
|
||||
typedef struct box64context_s box64context_t;
|
||||
|
||||
//void* customMalloc(size_t size);
|
||||
//void* customCalloc(size_t n, size_t size);
|
||||
//void* customRealloc(void* p, size_t size);
|
||||
//void customFree(void* p);
|
||||
void* customMalloc(size_t size);
|
||||
void* customCalloc(size_t n, size_t size);
|
||||
void* customRealloc(void* p, size_t size);
|
||||
void customFree(void* p);
|
||||
|
||||
//#define kcalloc customCalloc
|
||||
//#define kmalloc customMalloc
|
||||
//#define krealloc customRealloc
|
||||
//#define kfree customFree
|
||||
#define kcalloc customCalloc
|
||||
#define kmalloc customMalloc
|
||||
#define krealloc customRealloc
|
||||
#define kfree customFree
|
||||
|
||||
#ifdef DYNAREC
|
||||
//typedef struct dynablock_s dynablock_t;
|
||||
//typedef struct dynablocklist_s dynablocklist_t;
|
||||
//// custom protection flag to mark Page that are Write protected for Dynarec purpose
|
||||
//uintptr_t AllocDynarecMap(dynablock_t* db, int size);
|
||||
//void FreeDynarecMap(dynablock_t* db, uintptr_t addr, uint32_t size);
|
||||
typedef struct dynablock_s dynablock_t;
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
// custom protection flag to mark Page that are Write protected for Dynarec purpose
|
||||
uintptr_t AllocDynarecMap(dynablock_t* db, size_t size);
|
||||
void FreeDynarecMap(dynablock_t* db, uintptr_t addr, size_t size);
|
||||
|
||||
//void addDBFromAddressRange(uintptr_t addr, uintptr_t size);
|
||||
//void cleanDBFromAddressRange(uintptr_t addr, uintptr_t size, int destroy);
|
||||
void addDBFromAddressRange(uintptr_t addr, size_t size);
|
||||
void cleanDBFromAddressRange(uintptr_t addr, size_t size, int destroy);
|
||||
|
||||
//dynablocklist_t* getDB(uintptr_t idx);
|
||||
//void addJumpTableIfDefault(void* addr, void* jmp);
|
||||
//void setJumpTableDefault(void* addr);
|
||||
//uintptr_t getJumpTable();
|
||||
//uintptr_t getJumpTableAddress(uintptr_t addr);
|
||||
dynablocklist_t* getDB(uintptr_t idx);
|
||||
void addJumpTableIfDefault64(void* addr, void* jmp);
|
||||
void setJumpTableDefault64(void* addr);
|
||||
int isJumpTableDefault64(void* addr);
|
||||
uintptr_t getJumpTable64();
|
||||
uintptr_t getJumpTableAddress64(uintptr_t addr);
|
||||
#endif
|
||||
|
||||
#define PROT_DYNAREC 0x80
|
||||
void updateProtection(uintptr_t addr, uintptr_t size, uint32_t prot);
|
||||
void setProtection(uintptr_t addr, uintptr_t size, uint32_t prot);
|
||||
#define PROT_DYNAREC 0x80
|
||||
#define PROT_ALLOC 0x40
|
||||
#define PROT_CUSTOM (PROT_DYNAREC|PROT_ALLOC)
|
||||
|
||||
void updateProtection(uintptr_t addr, size_t size, uint32_t prot);
|
||||
void setProtection(uintptr_t addr, size_t size, uint32_t prot);
|
||||
void freeProtection(uintptr_t addr, size_t size);
|
||||
uint32_t getProtection(uintptr_t addr);
|
||||
#ifdef DYNAREC
|
||||
//void protectDB(uintptr_t addr, uintptr_t size);
|
||||
//void protectDBnolock(uintptr_t addr, uintptr_t size);
|
||||
//void unprotectDB(uintptr_t addr, uintptr_t size);
|
||||
//void lockDB();
|
||||
//void unlockDB();
|
||||
void protectDB(uintptr_t addr, size_t size);
|
||||
void protectDBnolock(uintptr_t addr, size_t size);
|
||||
void unprotectDB(uintptr_t addr, size_t size);
|
||||
void lockDB();
|
||||
void unlockDB();
|
||||
#endif
|
||||
void* find32bitBlock(size_t size);
|
||||
void* findBlockNearHint(void* hint, size_t size);
|
||||
|
||||
// unlock mutex that are locked by current thread (for signal handling). Return a mask of unlock mutex
|
||||
int unlockCustommemMutex();
|
||||
// relock the muxtex that were unlocked
|
||||
void relockCustommemMutex(int locks);
|
||||
|
||||
void init_custommem_helper(box64context_t* ctx);
|
||||
void fini_custommem_helper(box64context_t* ctx);
|
||||
|
||||
#endif //__CUSTOM_MEM__H_
|
||||
#endif //__CUSTOM_MEM__H_
|
||||
+20
-7
@@ -4,19 +4,29 @@
|
||||
|
||||
typedef struct box64context_s box64context_t;
|
||||
extern int box64_log; // log level
|
||||
extern int box64_dump; // dump elf or not
|
||||
extern int box64_dynarec_log;
|
||||
extern int box64_dynarec;
|
||||
extern int box64_pagesize;
|
||||
extern int dlsym_error; // log dlsym error
|
||||
extern int trace_xmm; // include XMM reg in trace?
|
||||
extern int trace_emm; // include EMM reg in trace?
|
||||
#ifdef DYNAREC
|
||||
extern int box64_dynarec_dump;
|
||||
extern int box64_dynarec_trace;
|
||||
extern int box64_dynarec_forced;
|
||||
extern uintptr_t box64_nodynarec_start, box64_nodynarec_end;
|
||||
#endif
|
||||
extern int dlsym_error; // log dlsym error
|
||||
#ifdef HAVE_TRACE
|
||||
extern int trace_xmm; // include XMM reg in trace?
|
||||
extern int trace_emm; // include EMM reg in trace?
|
||||
extern int trace_regsdiff; // colorize standard registers on changes
|
||||
extern uintptr_t trace_start, trace_end;
|
||||
extern char* trace_func;
|
||||
#endif
|
||||
extern int allow_missing_libs;
|
||||
extern int box64_steam;
|
||||
extern int box64_nopulse; // disabling the use of wrapped pulseaudio
|
||||
extern int box64_nogtk; // disabling the use of wrapped gtk
|
||||
extern int box64_novulkan; // disabling the use of wrapped vulkan
|
||||
extern uintptr_t trace_start, trace_end;
|
||||
extern char* trace_func;
|
||||
extern uintptr_t fmod_smc_start, fmod_smc_end; // to handle libfmod (from Unreal) SMC (self modifying code)
|
||||
extern uint32_t default_gs;
|
||||
extern int jit_gdb; // launch gdb when a segfault is trapped
|
||||
@@ -24,13 +34,16 @@ extern int box64_tcmalloc_minimal; // when using tcmalloc_minimal
|
||||
#define LOG_NONE 0
|
||||
#define LOG_INFO 1
|
||||
#define LOG_DEBUG 2
|
||||
#define LOG_DUMP 3
|
||||
#define LOG_NEVER 3
|
||||
#define LOG_VERBOSE 3
|
||||
|
||||
extern FILE* ftrace;
|
||||
|
||||
#define printf_log(L, ...) do {if(L<=box64_log) {fprintf(ftrace, __VA_ARGS__); fflush(ftrace);}} while(0)
|
||||
|
||||
#define dynarec_log(L, ...) do {if(L<=box64_dynarec_log) {fprintf(ftrace, __VA_ARGS__); /*fflush(ftrace);*/}} while(0)
|
||||
#define printf_dump(L, ...) do {if(box64_dump || (L<=box64_log)) {fprintf(ftrace, __VA_ARGS__); fflush(ftrace);}} while(0)
|
||||
|
||||
#define dynarec_log(L, ...) do {if(L<=box64_dynarec_log) {fprintf(ftrace, __VA_ARGS__); fflush(ftrace);}} while(0)
|
||||
|
||||
#define EXPORT __attribute__((visibility("default")))
|
||||
#ifdef BUILD_DYNAMIC
|
||||
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
#ifndef __DICTIONNARY_H_
|
||||
#define __DICTIONNARY_H_
|
||||
#include <stdint.h>
|
||||
|
||||
typedef void dic_t;
|
||||
|
||||
dic_t *NewDictionnary();
|
||||
void FreeDictionnary(dic_t **dic);
|
||||
|
||||
const char* AddDictionnary(dic_t* dic, const char* s);
|
||||
int ExistDictionnary(dic_t* dic, const char* s);
|
||||
|
||||
#endif //__DICTIONNARY_H_
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
#ifndef __DYNABLOCK_H_
|
||||
#define __DYNABLOCK_H_
|
||||
|
||||
typedef struct x64emu_s x64emu_t;
|
||||
typedef struct dynablock_s dynablock_t;
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
typedef struct kh_dynablocks_s kh_dynablocks_t;
|
||||
|
||||
uint32_t X31_hash_code(void* addr, int len);
|
||||
dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int direct);
|
||||
void FreeDynablockList(dynablocklist_t** dynablocks);
|
||||
void FreeDynablock(dynablock_t* db);
|
||||
void MarkDynablock(dynablock_t* db);
|
||||
//return 1 if Dynareblock is empty
|
||||
int FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
|
||||
void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
|
||||
|
||||
dynablock_t* FindDynablockFromNativeAddress(void* addr); // defined in box64context.h
|
||||
dynablock_t* FindDynablockDynablocklist(void* addr, kh_dynablocks_t* dynablocks);
|
||||
|
||||
uintptr_t StartDynablockList(dynablocklist_t* db);
|
||||
uintptr_t EndDynablockList(dynablocklist_t* db);
|
||||
void MarkDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
|
||||
|
||||
// Handling of Dynarec block (i.e. an exectable chunk of x64 translated code)
|
||||
dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, dynablock_t** current); // return NULL if block is not found / cannot be created. Don't create if create==0
|
||||
dynablock_t* DBAlternateBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr);
|
||||
|
||||
// Create and Add an new dynablock in the list, handling direct/map
|
||||
dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* created);
|
||||
|
||||
#endif //__DYNABLOCK_H_
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
#ifndef __DYNAREC_ARM_H_
|
||||
#define __DYNAREC_ARM_H_
|
||||
|
||||
typedef struct dynablock_s dynablock_t;
|
||||
typedef struct x64emu_s x64emu_t;
|
||||
|
||||
void* FillBlock64(dynablock_t* block, uintptr_t addr);
|
||||
|
||||
#endif //__DYNAREC_ARM_H_
|
||||
Loaded 100 of 336 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user