mirror of
https://github.com/ptitSeb/box64.git
synced 2026-11-08 17:39:19 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60c6858916 | ||
|
|
c5e085bc96 | ||
|
|
8dc669bc33 | ||
|
|
8aed75a338 | ||
|
|
e486e2ce8d | ||
|
|
a1705da6da | ||
|
|
0092a029c4 | ||
|
|
176ef90258 | ||
|
|
f82a6b7b41 | ||
|
|
c79c42b62d | ||
|
|
91dd7adbfa | ||
|
|
de82f07277 | ||
|
|
0c8e0b6708 | ||
|
|
c71a840e74 | ||
|
|
2b5c25ef17 | ||
|
|
da34156267 | ||
|
|
113ef45c6c | ||
|
|
67dd40dc08 | ||
|
|
1e0fee739e | ||
|
|
d59a98ffe6 | ||
|
|
5e9429afe8 | ||
|
|
31fd0451d0 | ||
|
|
b56be08f95 | ||
|
|
b1923cadb5 | ||
|
|
0a955c1020 | ||
|
|
791efc9e79 | ||
|
|
f9bc94bfb8 | ||
|
|
72119ddfa4 | ||
|
|
d4afca9b5a | ||
|
|
219ac40a7d | ||
|
|
b9378fe4c1 | ||
|
|
3c05822011 | ||
|
|
02cad7b5fe | ||
|
|
1a85ec5fdb | ||
|
|
3e19cfe58e | ||
|
|
3d3c7437be | ||
|
|
c4b57774f0 | ||
|
|
f7acded7a1 | ||
|
|
cabcca2e31 | ||
|
|
cc3237a77d | ||
|
|
b65e02420f | ||
|
|
5a7761c294 | ||
|
|
ad332494d0 | ||
|
|
eb212cd27e | ||
|
|
b604dd0bcc | ||
|
|
c0b879c998 | ||
|
|
e473af1635 | ||
|
|
8d9c6b2d01 | ||
|
|
7cdcb6c4ef | ||
|
|
ca44d84e55 | ||
|
|
e73a3c3376 | ||
|
|
1f9973e623 | ||
|
|
9077f3d675 | ||
|
|
ce61d27d8d | ||
|
|
5c1dbc0104 | ||
|
|
aa55f67ee3 | ||
|
|
9516694c35 | ||
|
|
c6a9f239c4 | ||
|
|
a922acc4dd | ||
|
|
bfef8c9bbe | ||
|
|
3fe2843bb3 | ||
|
|
42b8378988 | ||
|
|
c6bd721d2e | ||
|
|
83eedef999 | ||
|
|
1411e7f9f6 | ||
|
|
5d42d9212f | ||
|
|
4a1e05524a | ||
|
|
fb5ac9c4cd | ||
|
|
ed4e33d888 | ||
|
|
c6dd73065d | ||
|
|
9ef48de1a8 | ||
|
|
692ad43285 | ||
|
|
d06ff478d1 | ||
|
|
83db04cdce | ||
|
|
d0a724bb08 | ||
|
|
8e9ac1b9ac | ||
|
|
272d4efd4b | ||
|
|
4610f451e9 | ||
|
|
0810859c21 | ||
|
|
93c447051c | ||
|
|
60b3f042a8 | ||
|
|
c5632360d6 | ||
|
|
a379b4aab8 | ||
|
|
3b8d6ef208 | ||
|
|
9705d5e38b | ||
|
|
2e59b56f16 | ||
|
|
d9f9e8e57a | ||
|
|
33a8befbcf | ||
|
|
4f66a419e3 | ||
|
|
65992746d3 | ||
|
|
cbd4c64084 | ||
|
|
081be61f88 | ||
|
|
b89ca87280 | ||
|
|
ca84f10921 | ||
|
|
2200c4af6b | ||
|
|
838dfa453c | ||
|
|
6f3d636226 | ||
|
|
f03792619a | ||
|
|
21b3292fff | ||
|
|
39ebeb2401 | ||
|
|
8f4e8ed1e7 | ||
|
|
0e10ead81a | ||
|
|
476612d8f8 | ||
|
|
bd769c9261 | ||
|
|
831f78a389 | ||
|
|
920edce73e | ||
|
|
7dc7b002c5 | ||
|
|
c74c9bd693 | ||
|
|
1daf15c525 | ||
|
|
108949345f | ||
|
|
69eb309031 | ||
|
|
e7f0c8cbe1 | ||
|
|
9c8b663d5b | ||
|
|
8309b63fb1 | ||
|
|
6d6de880eb | ||
|
|
a65bf79ad9 | ||
|
|
c192188b42 | ||
|
|
a3516ce655 | ||
|
|
8481db4735 | ||
|
|
b6390c3dbd | ||
|
|
0f914cf747 | ||
|
|
5fab7d2993 | ||
|
|
faee142876 | ||
|
|
215c63233a | ||
|
|
e5afcd14a9 | ||
|
|
96a7d1e7ec | ||
|
|
2d2a65b616 | ||
|
|
b5d32fe271 | ||
|
|
8a5a69818e | ||
|
|
56701220e9 | ||
|
|
6bf434a7ab | ||
|
|
d1e767d30c | ||
|
|
4874df25a2 | ||
|
|
f43868e4dc | ||
|
|
bc8227d2bd | ||
|
|
09e748d6c9 | ||
|
|
4038ad5ce5 | ||
|
|
973864e045 | ||
|
|
af694b57a2 | ||
|
|
07be0c6ef4 | ||
|
|
78a336c092 | ||
|
|
649c0f8055 | ||
|
|
87b66b8db8 | ||
|
|
a4ffa3de7a | ||
|
|
dd111f55f6 | ||
|
|
5db6264d8f | ||
|
|
4ce63c8caf | ||
|
|
727f8b1d9b | ||
|
|
35f2bcf296 | ||
|
|
7ebfe84489 | ||
|
|
4e645debaa | ||
|
|
821ab99bf7 | ||
|
|
282e242f5e | ||
|
|
13deb8d8d7 | ||
|
|
389992c330 | ||
|
|
0753c52bed | ||
|
|
24ce9b0f8d | ||
|
|
6e6f8412a5 | ||
|
|
853cdcdd31 | ||
|
|
f24ec20623 | ||
|
|
cdc7d695e9 | ||
|
|
d1cf754c6e | ||
|
|
d1f63fe260 | ||
|
|
53eee70c03 | ||
|
|
7b73ba551e | ||
|
|
af1176274a | ||
|
|
4c2ef9947a | ||
|
|
db7c9e96ea | ||
|
|
ee5398b3be | ||
|
|
3d3ab0fedc | ||
|
|
d21efb51ce | ||
|
|
bd4c742212 | ||
|
|
c821fd938c | ||
|
|
977caba4ca | ||
|
|
8b167a70b8 | ||
|
|
ecca96c03e | ||
|
|
49231a593a | ||
|
|
0338899804 | ||
|
|
810c2250c4 | ||
|
|
5ed210f0f3 | ||
|
|
7508390747 | ||
|
|
67620b7948 | ||
|
|
6c0500d1b6 | ||
|
|
7144efff4e | ||
|
|
3ae31c34f6 | ||
|
|
bc5072ed54 | ||
|
|
2aa7c45ca2 | ||
|
|
73467dc523 | ||
|
|
4ff744ef89 | ||
|
|
b8722b3537 | ||
|
|
caed2ae757 | ||
|
|
5ffdb8eeb4 | ||
|
|
90445f7f1d | ||
|
|
5a298c165e | ||
|
|
63ba377f6f | ||
|
|
a15cdb4c1d | ||
|
|
dff14a868f | ||
|
|
4304301701 | ||
|
|
2dd31b0a44 | ||
|
|
23e01808a2 | ||
|
|
b8300add62 | ||
|
|
97cb1e2080 | ||
|
|
e9d6735e52 | ||
|
|
9d8381041d | ||
|
|
5cf4226c13 | ||
|
|
5bb3d8a24d | ||
|
|
1de683efa4 | ||
|
|
3e705be6c8 | ||
|
|
6548ec1b43 | ||
|
|
e739a74705 | ||
|
|
c0d401fbfc | ||
|
|
7b813d03b9 | ||
|
|
93d06e8680 | ||
|
|
7f22b33f5a | ||
|
|
ceaacba1c2 | ||
|
|
6bee1dcecd | ||
|
|
3c28048038 | ||
|
|
fb02ae0e9a | ||
|
|
ffb293fe0a | ||
|
|
f46522572e | ||
|
|
2ecb87ddc3 | ||
|
|
a34530ebb7 | ||
|
|
0973e7009e | ||
|
|
d0d18441cf | ||
|
|
3f1c37aa76 | ||
|
|
8165342670 | ||
|
|
686c68a90d | ||
|
|
86dbf089cc | ||
|
|
9f3ea84b57 | ||
|
|
3f007d2dbb | ||
|
|
cde68af79a | ||
|
|
574e70642b | ||
|
|
ae156d9326 | ||
|
|
c08268d0ae | ||
|
|
0e4d031054 | ||
|
|
de15ee057a | ||
|
|
1d873cc701 | ||
|
|
bcde60b9e8 | ||
|
|
d6d2b2e756 | ||
|
|
4276573f67 | ||
|
|
fa3481ea8e | ||
|
|
ac54eceea5 | ||
|
|
e1c29bf2af | ||
|
|
0fe560ed7f | ||
|
|
23269040a6 | ||
|
|
b03649748a | ||
|
|
06851f8b98 | ||
|
|
893fc7c940 | ||
|
|
3819aecf07 | ||
|
|
a186b22d6e | ||
|
|
a43186d137 | ||
|
|
554f4889bc | ||
|
|
b584832e75 | ||
|
|
299c911330 | ||
|
|
6318b592a3 | ||
|
|
2b7e7fe6f6 | ||
|
|
bb8983b48a | ||
|
|
666861419d | ||
|
|
52d6c5ac88 | ||
|
|
5b89a2375a | ||
|
|
c0d19de08d | ||
|
|
27d85a737c | ||
|
|
277f542304 | ||
|
|
517a5b6844 | ||
|
|
d4f98902a0 | ||
|
|
eb289e8542 | ||
|
|
06754daf87 | ||
|
|
ee509f6350 | ||
|
|
6a7c6cba12 | ||
|
|
129f5e93fa | ||
|
|
629312b382 | ||
|
|
d31524691b | ||
|
|
ff6ec86f1c | ||
|
|
0c55facdd9 | ||
|
|
d9e1f91735 | ||
|
|
9f037fef60 | ||
|
|
0bc7100ea8 | ||
|
|
8698a58a60 | ||
|
|
a8151de2cb | ||
|
|
7a9005dae6 | ||
|
|
a77f8bf203 | ||
|
|
efc7877ffd | ||
|
|
3cb7632dc8 | ||
|
|
cde8e54b51 | ||
|
|
8ce1a2d605 | ||
|
|
d09379990b | ||
|
|
136318f98a | ||
|
|
1775844f45 | ||
|
|
987a663094 | ||
|
|
107dbd5645 | ||
|
|
bebd8f3c1a | ||
|
|
3be1e33339 | ||
|
|
91348f22be | ||
|
|
c9279061fa | ||
|
|
5bfe397c63 | ||
|
|
a202640da4 | ||
|
|
08fcdfa0fb | ||
|
|
51fb706781 | ||
|
|
92ed70f029 | ||
|
|
067b28be41 | ||
|
|
81b7fc519c | ||
|
|
24cc0c8422 | ||
|
|
8459ea0d31 | ||
|
|
494c245b59 | ||
|
|
d87f0ea728 | ||
|
|
dbdfc13a23 | ||
|
|
c19730f5e2 | ||
|
|
446e735825 | ||
|
|
0e47d1269c | ||
|
|
7dc5359c2b | ||
|
|
e394903ccf | ||
|
|
98bb78ae3a | ||
|
|
defe5ce594 | ||
|
|
713e3fa89d | ||
|
|
73f813279a | ||
|
|
0063cad60d | ||
|
|
3bb3f618b9 | ||
|
|
53195e3a25 | ||
|
|
09103aa52e | ||
|
|
ee63a9f368 | ||
|
|
9a73c15b84 | ||
|
|
b50dec9d92 | ||
|
|
9f8feb622e | ||
|
|
db156b41fb | ||
|
|
374583bb48 | ||
|
|
5d3c218b1b | ||
|
|
f34427e772 | ||
|
|
a1666986c6 | ||
|
|
b669177c83 | ||
|
|
1678d2b97a | ||
|
|
3564f41c48 | ||
|
|
72314a33ab | ||
|
|
9289b29504 | ||
|
|
de115b87df | ||
|
|
cfeb0626cc | ||
|
|
3f2c4ed794 | ||
|
|
978256179b | ||
|
|
742af765ba | ||
|
|
035d0aebc1 | ||
|
|
a5dbd58200 | ||
|
|
9073e1d47e | ||
|
|
ed1078dadf | ||
|
|
83dbd728ef | ||
|
|
31a6149b0f | ||
|
|
3d274fdfd9 | ||
|
|
8f3ec680c7 | ||
|
|
612e94be9d | ||
|
|
7a95c78ba0 | ||
|
|
5a2a546090 | ||
|
|
baf6fc8987 | ||
|
|
bf75d6496f | ||
|
|
fb7f134c06 | ||
|
|
067dcbc0f7 | ||
|
|
280bc969ce | ||
|
|
010b8a79cb | ||
|
|
4ec39ae323 | ||
|
|
ec7c654451 | ||
|
|
6022a61b3c | ||
|
|
975b489007 | ||
|
|
f8f1859a05 | ||
|
|
92f2a44b28 | ||
|
|
7585a984b2 | ||
|
|
789bf9c220 | ||
|
|
2e9bc93e1f | ||
|
|
e2a993a425 | ||
|
|
d0b5c79b81 | ||
|
|
95622ca964 | ||
|
|
76b63de754 | ||
|
|
58cdb1bda2 | ||
|
|
a530f56511 | ||
|
|
bf6e74ad8e | ||
|
|
c2253dafc0 | ||
|
|
389d159c7a | ||
|
|
21161ae38e | ||
|
|
aa074d7121 | ||
|
|
99d04e93a2 | ||
|
|
d6b9df6ca2 | ||
|
|
4fbeca0aa3 | ||
|
|
f19b89b263 | ||
|
|
0a908d78ca | ||
|
|
f2b8b06280 | ||
|
|
0cc04e5253 | ||
|
|
5e9a9b9867 | ||
|
|
68826baf3b | ||
|
|
cc26096c28 | ||
|
|
1c110080a8 | ||
|
|
7b67bbe698 | ||
|
|
7692371ccb | ||
|
|
534eb4ce88 | ||
|
|
c88b936233 | ||
|
|
32c229215a | ||
|
|
9c5cc38c9a | ||
|
|
12795ea491 | ||
|
|
c0b143043f | ||
|
|
40b849da23 | ||
|
|
4f18bd6293 | ||
|
|
702e92d4f4 | ||
|
|
40fa336829 | ||
|
|
fa93803b45 | ||
|
|
7201dbd477 | ||
|
|
40248c3e13 | ||
|
|
f2a0a1b62d | ||
|
|
dcb4bbb3e6 | ||
|
|
21c56e7898 | ||
|
|
7c74e7be35 | ||
|
|
bf5ec1eb57 | ||
|
|
342241a24d | ||
|
|
d047dcb983 | ||
|
|
0fc310f1c4 | ||
|
|
c6e14a562b | ||
|
|
a3f6a7ddbc | ||
|
|
c8c09d7e09 | ||
|
|
411163c73f | ||
|
|
b25aa07e11 | ||
|
|
bc72a506c1 | ||
|
|
8451c62b44 | ||
|
|
1f3729822a | ||
|
|
a27283aa9b | ||
|
|
1eb1bd6800 | ||
|
|
cda4af3403 | ||
|
|
93ea5bacb7 | ||
|
|
841c5c22e0 | ||
|
|
511446846f | ||
|
|
a79bf97b48 | ||
|
|
a78d5e2636 | ||
|
|
b6d2e3fb55 | ||
|
|
43850ac856 | ||
|
|
532b1697a6 | ||
|
|
a3f63a12f9 | ||
|
|
b2dfe64cea | ||
|
|
ff7dc072d1 | ||
|
|
b185afa29f | ||
|
|
742742fd48 | ||
|
|
5f6104a9d3 | ||
|
|
787198b30e | ||
|
|
3490c63259 | ||
|
|
8077d7bb0b | ||
|
|
b2c8c227ec | ||
|
|
ca8ff5fda9 | ||
|
|
a6f2d96557 | ||
|
|
948205e6f9 | ||
|
|
d90b6b7e51 | ||
|
|
e3e1ee313b | ||
|
|
dc5c049ed9 | ||
|
|
642260bdb6 | ||
|
|
bafa85e772 | ||
|
|
4f102a43fa | ||
|
|
2ac265d529 | ||
|
|
e261270eb8 | ||
|
|
d08bd0c619 | ||
|
|
cc833341e4 | ||
|
|
add0081b50 | ||
|
|
46fb9d6df1 | ||
|
|
e324942a07 | ||
|
|
b853012cb6 | ||
|
|
d64d7db5f5 | ||
|
|
d19a076f1e | ||
|
|
5ad314ba5a | ||
|
|
c7473dd7c9 | ||
|
|
abb9ab1bb6 | ||
|
|
8bc9baefd6 | ||
|
|
0fe835e087 | ||
|
|
e8ed41c763 | ||
|
|
d9cd0604cc | ||
|
|
afb2cc4a99 | ||
|
|
a72751914d | ||
|
|
9e3c5b1bf2 | ||
|
|
bf77789076 | ||
|
|
1b0d063cff | ||
|
|
24f8f47f76 | ||
|
|
7745457f9b | ||
|
|
660bbae9a8 | ||
|
|
c071e9b051 | ||
|
|
1c1bab8d6b | ||
|
|
8beb818100 | ||
|
|
1ff0a7c4e7 | ||
|
|
49991a3341 | ||
|
|
88af5ea07c | ||
|
|
63fbd64eb8 | ||
|
|
8337fd306a | ||
|
|
7df6dbeafb | ||
|
|
bf2d6b8999 | ||
|
|
5528cb9f16 | ||
|
|
d8bc6dcc1b | ||
|
|
c0ebc4cbb0 | ||
|
|
e3b6d6e6b2 | ||
|
|
a50b10b869 | ||
|
|
183704ab95 | ||
|
|
e654ed980a | ||
|
|
a4eb35371f | ||
|
|
0931f95e65 | ||
|
|
83997e1125 | ||
|
|
555a1184e4 | ||
|
|
f6b31f65ac | ||
|
|
fc67b208ad | ||
|
|
b6f83007eb | ||
|
|
6e82268704 | ||
|
|
4142cc296b | ||
|
|
e98b1e6716 | ||
|
|
fda8b96063 | ||
|
|
bb8e11e08d | ||
|
|
aee1fe1004 | ||
|
|
fbcd77a1a7 | ||
|
|
90f58dbcbe | ||
|
|
729d19ab24 | ||
|
|
ca9a1b6666 | ||
|
|
08aa003335 | ||
|
|
b0a56e2790 | ||
|
|
01f589885f | ||
|
|
038c940e8e | ||
|
|
20067c02bc | ||
|
|
efa3fa3aed | ||
|
|
e0908ced14 | ||
|
|
3068ca8908 | ||
|
|
88406332d2 | ||
|
|
6cb9561d96 | ||
|
|
3135ba57cd | ||
|
|
96420b959a | ||
|
|
15bda0af27 | ||
|
|
a076e9b0a8 | ||
|
|
0cb4fa67f1 | ||
|
|
bf79be222c | ||
|
|
1bb27f2b80 | ||
|
|
96dae29f4d | ||
|
|
4e0df627df | ||
|
|
15411c7c9e | ||
|
|
b4c389c374 | ||
|
|
44aeead296 | ||
|
|
5e0d4800d9 | ||
|
|
e1a8e8d82d | ||
|
|
4ae714089d | ||
|
|
3894da6242 | ||
|
|
2f74e6ebf8 | ||
|
|
c1aeb2244c | ||
|
|
d231851734 | ||
|
|
c4a68bcd43 | ||
|
|
1add5dac3e | ||
|
|
ec3786f862 | ||
|
|
0e761801de | ||
|
|
39f70c0956 | ||
|
|
0674636243 | ||
|
|
ea89d85845 | ||
|
|
0f3884afde | ||
|
|
7b3d4c6359 | ||
|
|
f9a8fa3854 | ||
|
|
575c86551e | ||
|
|
57bbac4923 | ||
|
|
7f8167e4e2 | ||
|
|
ebce5998de | ||
|
|
672a41a79c | ||
|
|
48b881f491 | ||
|
|
a6f0525a4c | ||
|
|
d9707926fa | ||
|
|
e38c663dea | ||
|
|
b1873b21b6 | ||
|
|
4c4d3dc9e7 | ||
|
|
c7e6777cc1 | ||
|
|
5336524129 | ||
|
|
de30d37ba9 | ||
|
|
e2b6e32fe9 | ||
|
|
f2573a5c02 | ||
|
|
96f8873f2c | ||
|
|
b3919fe819 | ||
|
|
9eeaaf0a03 | ||
|
|
9328ba79d1 | ||
|
|
0c7168648f | ||
|
|
26f8a756cb | ||
|
|
4174442558 | ||
|
|
452a390325 | ||
|
|
9fcb6e1f38 | ||
|
|
826f9cf2f3 | ||
|
|
c18fbfa106 | ||
|
|
cd695f735b | ||
|
|
0e3cd11a55 | ||
|
|
1236c16c83 | ||
|
|
66a47329db | ||
|
|
322f18926e | ||
|
|
5bbc241168 | ||
|
|
83925633e0 | ||
|
|
42943eab95 | ||
|
|
66bf32bafa | ||
|
|
aa42913ece | ||
|
|
e4e8a46424 | ||
|
|
dfe894a39b | ||
|
|
c80feac629 | ||
|
|
71c1ca3eb6 | ||
|
|
ffc99aa52e | ||
|
|
4b10506691 | ||
|
|
57f1f82d76 | ||
|
|
53f84817ba | ||
|
|
221527e0e1 | ||
|
|
501ab2bbe8 | ||
|
|
f78c5a2b18 | ||
|
|
962c3c25b6 | ||
|
|
ae6d6d753a | ||
|
|
3e764fdc45 | ||
|
|
f52ee794db | ||
|
|
34ece330f3 | ||
|
|
7adaf39f1a | ||
|
|
6392550208 | ||
|
|
98d705ed9b | ||
|
|
a356eb7abf | ||
|
|
e950872ec9 | ||
|
|
ab1fdbfead | ||
|
|
7ac8d7de22 | ||
|
|
f012e02b35 | ||
|
|
1ffbb7bf6b | ||
|
|
72927195fd | ||
|
|
e29326d8d0 | ||
|
|
b7bf1955b7 | ||
|
|
1057b88ba7 | ||
|
|
de21088bc4 | ||
|
|
d8698cdc84 | ||
|
|
1ae1906637 | ||
|
|
5a0fc820d4 | ||
|
|
a1f51ad7dc | ||
|
|
fbb89dcf10 | ||
|
|
736552a559 | ||
|
|
162abb0a32 | ||
|
|
a2cd8b72dc | ||
|
|
11aca3f0aa | ||
|
|
c312ca45bd | ||
|
|
f1dc84afef | ||
|
|
7cafe8311e | ||
|
|
9513053f74 | ||
|
|
bfea73d5d8 | ||
|
|
2ae1713ac1 | ||
|
|
fb2047853c | ||
|
|
3dec81b9eb | ||
|
|
b0fa2f5ec0 | ||
|
|
6c367f4a29 | ||
|
|
c8d4d3b69e | ||
|
|
a0234eed48 | ||
|
|
8cc3b54bcd | ||
|
|
d8630d5bdc | ||
|
|
82118c854c | ||
|
|
b1b558d244 | ||
|
|
6ef734960a | ||
|
|
244e3eafdf | ||
|
|
59e367a88e | ||
|
|
681f0ef111 | ||
|
|
098317ed29 | ||
|
|
30cc36abca | ||
|
|
58090c2c32 | ||
|
|
008f5913e9 | ||
|
|
349736b0a5 | ||
|
|
42e926e27c | ||
|
|
80be548b64 | ||
|
|
bb22be4f4f | ||
|
|
fab4c72285 | ||
|
|
9bb42fc5bf | ||
|
|
5d93fc58b3 | ||
|
|
ab633484cd | ||
|
|
5e69a69b8d | ||
|
|
50a9aef179 | ||
|
|
13bc7d17bf | ||
|
|
d8c328ec09 | ||
|
|
2a4c1d0aac | ||
|
|
6c4b88123a | ||
|
|
b78f3a8216 | ||
|
|
8f93b18469 | ||
|
|
a66725adc4 | ||
|
|
8d9d5f3fc3 | ||
|
|
9699198bcc | ||
|
|
aa163b5010 | ||
|
|
aacc392049 | ||
|
|
74b99b52ee | ||
|
|
c7b573dcff | ||
|
|
5b03a1e218 | ||
|
|
77db70f9b5 | ||
|
|
0379d02d8c |
No files matched your search
@@ -13,9 +13,9 @@ on:
|
||||
- X64
|
||||
- GENERIC_ARM
|
||||
- PHYTIUM
|
||||
- RK3288
|
||||
- RK3326
|
||||
- RK3399
|
||||
- RK3588
|
||||
- RPI4ARM64
|
||||
- SD845
|
||||
- TEGRAX1
|
||||
|
||||
@@ -27,13 +27,21 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [X64, OTHER_ARM, RISCV, RPI4ARM64, RK3326, RK3399, RK3288, TEGRAX1, PHYTIUM, SD845]
|
||||
platform: [X64, OTHER_ARM, RISCV, RPI4ARM64, RK3326, RK3399, RK3588, PHYTIUM, SD845]
|
||||
type: [Release, Trace]
|
||||
os: [ubuntu-latest]
|
||||
include:
|
||||
- platform: TEGRAX1
|
||||
type: Release
|
||||
os: ubuntu-20.04
|
||||
- platform: TEGRAX1
|
||||
type: Trace
|
||||
os: ubuntu-20.04
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: "Checkout Box64 Repository"
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: "Environment preparation"
|
||||
run: |
|
||||
@@ -90,7 +98,7 @@ jobs:
|
||||
ctest -j$(nproc)
|
||||
|
||||
- name: "Upload Artifact"
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: box64-${{ matrix.platform }}-${{ matrix.type }}
|
||||
path: build/box64
|
||||
@@ -55,6 +55,7 @@ dkms.conf
|
||||
build/
|
||||
build*/
|
||||
.vscode
|
||||
.cache
|
||||
.gdb_history
|
||||
src/git_head.h
|
||||
backup/
|
||||
|
||||
+140
-34
@@ -5,22 +5,27 @@ cmake_policy(SET CMP0065 NEW)
|
||||
SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
|
||||
SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
|
||||
|
||||
option(RPI3ARM64 "Set to ON if targeting an RaspberryPI3 device with multiarch arm64 and armhf" ${RPI3ARM64})
|
||||
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(RK3588 "Set to ON if targeting an Rockchip RK3588(S) based device" ${RK3588})
|
||||
option(ODROIDN2 "Set to ON if targeting an Odroid-N2 device" ${ODROIDN2})
|
||||
option(TEGRAX1 "Set to ON if targeting an Tegra X1 based device" ${TEGRAX1})
|
||||
option(PHYTIUM "Set to ON if targeting an Phytium (D2000 or FT2000/4) based device" ${PHYTIUM})
|
||||
option(SD845 "Set to ON if targeting a Snapragon 845 based device" ${SD845})
|
||||
option(M1 "Set to ON if targeting a AppleM1 running on Asahi computer" ${M1})
|
||||
option(LARCH64 "Set to ON if targeting an Loongarch64 based device" ${LARCH64})
|
||||
option(RV64 "Set to ON if targeting an RISCV RV64G based device" ${RV64})
|
||||
option(RV64 "Set to ON if targeting an RISC-V RV64GC based device" ${RV64})
|
||||
option(PPC64LE "Set to ON if targeting an PowerPC 64 LE based device" ${PPC64LE})
|
||||
option(LX2160A "Set to ON if targeting an LX2160A based device" ${LX2160A})
|
||||
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" OFF)
|
||||
option(NOGIT "Set to ON if not building from a git clone repo (like when building from a zip download from github)" ${NOGIT})
|
||||
option(BAD_SIGNAL "Set to ON to activate the workaround for incoherent si_info on SIGSEGV" ${BAD_SIGNAL})
|
||||
option(SW64 "Set ON if targeting an SW64 based device" ${SW64})
|
||||
|
||||
if(LARCH64)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
@@ -38,21 +43,33 @@ if(PPC64LE)
|
||||
set(ARM_DYNAREC OFF CACHE BOOL "")
|
||||
set(PAGE16K OFF CACHE BOOL "")
|
||||
endif()
|
||||
if(RK3399 OR ODROIDN2 OR RPI4ARM64 OR RK3326 OR TEGRAX1 OR PHYTIUM OR SD845 OR LX2160A OR M1)
|
||||
if(RK3399 OR RK3588 OR ODROIDN2 OR RPI3ARM64 OR RPI4ARM64 OR RK3326 OR TEGRAX1 OR PHYTIUM OR SD845 OR LX2160A OR M1)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
set(ARM_DYNAREC ON CACHE BOOL "")
|
||||
endif()
|
||||
if(RK3399 OR ODROIDN2 OR RPI4ARM64 OR RK3326 OR TEGRAX1 OR PHYTIUM OR SD845 OR LX2160A)
|
||||
if(RK3399 OR RK3588 OR ODROIDN2 OR RPI3ARM64 OR RPI4ARM64 OR RK3326 OR TEGRAX1 OR PHYTIUM OR SD845 OR LX2160A)
|
||||
set(PAGE16K OFF CACHE BOOL "")
|
||||
endif()
|
||||
if(RK3588)
|
||||
set(BAD_SIGNAL ON CACHE BOOL "")
|
||||
endif()
|
||||
if(M1 OR LARCH64)
|
||||
set(PAGE16K ON CACHE BOOL "")
|
||||
endif()
|
||||
if(SW64)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
set(PAGE8K 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})
|
||||
option(PAGE8K "Set to ON if host device have PageSize of 8K (instead of 4K)" ${PAGE8K})
|
||||
option(PAGE16K "Set to ON if host device have PageSize of 16K (instead of 4K)" ${PAGE16K})
|
||||
option(PAGE64K "Set to ON if host device have PageSize of 64K (instead of 4K)" ${PAGE64K})
|
||||
option(STATICBUILD "Set to ON to have a static build (Warning, not working)" ${STATICBUILD})
|
||||
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.12.2")
|
||||
find_package(PythonInterp 3)
|
||||
@@ -81,7 +98,12 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
|
||||
endif()
|
||||
|
||||
if(RPI4ARM64)
|
||||
if(RPI3ARM64)
|
||||
add_definitions(-DRPI)
|
||||
add_definitions(-DRPI3ARM64)
|
||||
add_definitions(-pipe -march=armv8-a+crc -mtune=cortex-a53)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc -mtune=cortex-a53")
|
||||
elseif(RPI4ARM64)
|
||||
add_definitions(-DRPI)
|
||||
add_definitions(-DRPI4ARM64)
|
||||
add_definitions(-pipe -march=armv8-a+crc -mtune=cortex-a72)
|
||||
@@ -92,8 +114,13 @@ elseif(RK3326)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a35+crypto")
|
||||
elseif(RK3399)
|
||||
add_definitions(-DRK3399)
|
||||
add_definitions(-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a72+crypto)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a72+crypto")
|
||||
add_definitions(-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a72.cortex-a53+crypto)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a72.cortex-a53+crypto")
|
||||
elseif(RK3588)
|
||||
add_definitions(-DRK3588)
|
||||
add_definitions(-pipe -mcpu=cortex-a76.cortex-a55+crypto)
|
||||
add_definitions(-DBAD_SIGNAL)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -mcpu=cortex-a76.cortex-a55+crypto")
|
||||
elseif(ODROIDN2)
|
||||
add_definitions(-DODROIDN2)
|
||||
add_definitions(-march=armv8-a+crc+simd+crypto -mcpu=cortex-a73.cortex-a53+crypto)
|
||||
@@ -120,22 +147,36 @@ elseif(LARCH64)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=loongarch64")
|
||||
elseif(RV64)
|
||||
add_definitions(-DRV64)
|
||||
add_definitions(-pipe -march=rv64g)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=rv64g")
|
||||
add_definitions(-pipe -march=rv64gc)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=rv64gc")
|
||||
elseif(PPC64LE)
|
||||
add_definitions(-DPPC64LE)
|
||||
elseif(LX2160A)
|
||||
add_definitions(-DLX2160A)
|
||||
add_definitions(-pipe -march=armv8-a+crypto+crc -mcpu=cortex-a72+crypto)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crypto+crc -mcpu=cortex-a72+crypto")
|
||||
elseif(SW64)
|
||||
add_definitions(-DSW64)
|
||||
elseif(ARM_DYNAREC)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto")
|
||||
endif()
|
||||
|
||||
if(BAD_SIGNAL)
|
||||
add_definitions(-DBAD_SIGNAL)
|
||||
endif()
|
||||
|
||||
if(PAGE8K)
|
||||
add_definitions(-DPAGE8K)
|
||||
endif()
|
||||
|
||||
if(PAGE16K)
|
||||
add_definitions(-DPAGE16K)
|
||||
endif()
|
||||
|
||||
if(PAGE64K)
|
||||
add_definitions(-DPAGE64K)
|
||||
endif()
|
||||
|
||||
if(NOGIT)
|
||||
add_definitions(-DNOGIT)
|
||||
endif()
|
||||
@@ -147,7 +188,7 @@ else()
|
||||
endif()
|
||||
|
||||
#set(BOX64_ELF_ADDRESS "0x500062800000") #random load address...
|
||||
set(BOX64_ELF_ADDRESS "0x64800000") #low address
|
||||
set(BOX64_ELF_ADDRESS "0x34800000") #low address
|
||||
|
||||
if(LD80BITS)
|
||||
add_definitions(-DHAVE_LD80BITS)
|
||||
@@ -202,6 +243,7 @@ set(ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/box64context.c"
|
||||
"${BOX64_ROOT}/src/build_info.c"
|
||||
"${BOX64_ROOT}/src/custommem.c"
|
||||
"${BOX64_ROOT}/src/mallochook.c"
|
||||
"${BOX64_ROOT}/src/steam.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec.c"
|
||||
"${BOX64_ROOT}/src/elfs/elfdwarf_private.c"
|
||||
@@ -259,6 +301,7 @@ set(ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/tools/gtkclass.c"
|
||||
"${BOX64_ROOT}/src/tools/pathcoll.c"
|
||||
"${BOX64_ROOT}/src/tools/fileutils.c"
|
||||
"${BOX64_ROOT}/src/tools/rcfile.c"
|
||||
"${BOX64_ROOT}/src/tools/wine_tools.c"
|
||||
"${BOX64_ROOT}/src/wrapped/generated/wrapper.c"
|
||||
)
|
||||
@@ -268,9 +311,11 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedalut.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedatk.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedatkbridge.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedatomic.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedatspi.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedbz2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcairo.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcairogobject.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcrashhandler.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcrypto.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcurl.c"
|
||||
@@ -280,9 +325,12 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedfaudio.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedflac.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedfontconfig.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedfreebl3.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedfreetype.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgbm.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgconf2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgcrypt.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgdk3.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgdkpixbuf2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgdkx112.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgio2.c"
|
||||
@@ -296,10 +344,12 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgstapp.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgstaudio.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgstbase.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgstgl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgstreamer.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgsttag.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgstvideo.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgthread2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgtk3.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgtkx112.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedkrb5.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedldlinux.c"
|
||||
@@ -309,11 +359,14 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibcups.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibdl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibdrm.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibegl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibform.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibformw.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibfuse.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibgl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibglu.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibglx.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibibus.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibice.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibm.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibncurses.c"
|
||||
@@ -334,6 +387,11 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibtinfo6.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibusb1.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibuuid.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibva.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibvadrm.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibvawayland.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibvax11.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibvdpau.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibvorbis.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibx11.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibx11xcb.c"
|
||||
@@ -343,11 +401,19 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbdri3.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbglx.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbkeysyms.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbicccm.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbimage.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbpresent.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbrandr.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbrender.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbrenderutil.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbshape.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbshm.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbsync.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbutil.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbxinerama.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbxfixes.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbxkb.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbxtest.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcomposite.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcursor.c"
|
||||
@@ -359,6 +425,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxi.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxmu.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxpm.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxpresent.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxrandr.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxrender.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxss.c"
|
||||
@@ -368,6 +435,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibz.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlzma.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedmpg123.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappednotify.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappednsl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappednspr4.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappednss3.c"
|
||||
@@ -388,6 +456,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl1sound.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl1ttf.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsecret1.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsoftokn3.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsmpeg.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl2image.c"
|
||||
@@ -398,11 +467,17 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsmime3.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsmpeg2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedssl3.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedtbbmalloc.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedtbbmallocproxy.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedtcmallocminimal.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedudev0.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedudev1.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedunwind.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedutil.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedvorbisfile.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedwaylandclient.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedwaylandcursor.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedwaylandegl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedxinerama.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedxkbcommon.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedxkbcommonx11.c"
|
||||
@@ -411,15 +486,21 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedldapr.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlber.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedvulkan.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedxshmfence.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedd3dadapter9.c"
|
||||
)
|
||||
|
||||
#set(WRAPPEDS_HEAD "${BOX64_ROOT}/src/wrapped/wrappedd3dadapter9_gen.h")
|
||||
# If BOX64_ROOT contains a ".c", the build breaks...
|
||||
string(REPLACE ".c" "_private.h" MODROOT ${BOX64_ROOT})
|
||||
set(WRAPPEDS_HEAD "${BOX64_ROOT}/src/wrapped/wrappedd3dadapter9_genvate.h")
|
||||
foreach(A ${WRAPPEDS})
|
||||
string(REPLACE ".c" "_private.h" B ${A})
|
||||
string(REPLACE ".c" "_private.h" C ${A})
|
||||
string(REPLACE "${MODROOT}" "${BOX64_ROOT}" B ${C})
|
||||
set(WRAPPEDS_HEAD ${WRAPPEDS_HEAD} ${B})
|
||||
set_source_files_properties(${A} PROPERTIES OBJECT_DEPENDS ${B})
|
||||
endforeach()
|
||||
|
||||
|
||||
set(WRAPPER "${BOX64_ROOT}/src/wrapped/generated/wrapper.c" "${BOX64_ROOT}/src/wrapped/generated/wrapper.h")
|
||||
|
||||
add_custom_command(
|
||||
@@ -457,6 +538,7 @@ if(ARM_DYNAREC)
|
||||
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_functions.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/arm64_printer.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_jmpnext.c"
|
||||
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/arm64_prolog.S"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/arm64_epilog.S"
|
||||
@@ -482,11 +564,12 @@ if(ARM_DYNAREC)
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_db.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_dc.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_dd.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_de.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_de.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_df.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_f0.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_660f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_6664.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_66f0.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_f20f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_f30f.c"
|
||||
)
|
||||
@@ -527,13 +610,13 @@ endif()
|
||||
if(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\""
|
||||
COMMAND sh -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\""
|
||||
COMMAND sh -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\">\"${BOX64_ROOT}/src/git_head.h\""
|
||||
DEPENDS ${ELFLOADER_SRC} ${WRAPPEDS}
|
||||
VERBATIM)
|
||||
endif()
|
||||
@@ -543,7 +626,11 @@ set_target_properties(${BOX64} PROPERTIES ENABLE_EXPORTS ON)
|
||||
add_dependencies(${BOX64} WRAPPERS)
|
||||
#add_dependencies(${BOX64} PRINTER)
|
||||
#target_link_libraries(${BOX64} c m dl rt pthread resolv)
|
||||
set_target_properties(${BOX64} PROPERTIES LINK_FLAGS "-Wl,--no-as-needed -lc -lm -ldl -lrt -lpthread -lresolv -Wl,--as-needed -pthread")
|
||||
if(STATICBUILD)
|
||||
set_target_properties(${BOX64} PROPERTIES LINK_FLAGS "-static -Wl,--no-as-needed -Wl,--whole-archive -Wl,--allow-multiple-definition -lm -ldl -lrt -lpthread -lresolv -lc -Wl,-defsym,_DYNAMIC=0 -pthread")
|
||||
else()
|
||||
set_target_properties(${BOX64} PROPERTIES LINK_FLAGS "-Wl,--no-as-needed -lc -lm -ldl -lrt -lpthread -lresolv -Wl,--as-needed -pthread")
|
||||
endif()
|
||||
if(DYNAREC)
|
||||
target_link_libraries(${BOX64} dynarec)
|
||||
endif()
|
||||
@@ -580,9 +667,11 @@ if(NOT _x86 AND NOT _x86_64)
|
||||
RUNTIME DESTINATION bin)
|
||||
configure_file(system/box64.conf.cmake system/box64.conf)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/system/box64.conf DESTINATION /etc/binfmt.d/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libstdc++.so.5 DESTINATION /usr/lib/x86_64-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libstdc++.so.6 DESTINATION /usr/lib/x86_64-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libgcc_s.so.1 DESTINATION /usr/lib/x86_64-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libpng12.so.0 DESTINATION /usr/lib/x86_64-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/system/box64.box64rc DESTINATION /etc/)
|
||||
endif()
|
||||
|
||||
if(NOT TARGET uninstall)
|
||||
@@ -625,92 +714,94 @@ endif()
|
||||
set(CPACK_DEBIAN_FILE_NAME "${BOX64}-${BOX64_MAJOR}.${BOX64_MINOR}.${BOX64_REVISION}_Linux-${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")
|
||||
INCLUDE(CPack)
|
||||
|
||||
add_test(test01 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
add_test(bootSyscall ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test01 -D TEST_OUTPUT=tmpfile01.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref01.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test02 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
add_test(bootSyscallC ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test02 -D TEST_OUTPUT=tmpfile02.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref02.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test03 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
add_test(printf ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test03 -D TEST_OUTPUT=tmpfile03.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref03.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test04 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
add_test(args ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test04 -D TEST_ARGS2=yeah -D TEST_OUTPUT=tmpfile04.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref04.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test05 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
add_test(maths1 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test05 -D TEST_ARGS2=7 -D TEST_OUTPUT=tmpfile05.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref05.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test06 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
add_test(threadsStart ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test06 -D TEST_OUTPUT=tmpfile06.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref06.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test07 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
add_test(trig ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test07 -D TEST_OUTPUT=tmpfile07.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref07.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test08 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
add_test(pi ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test08 -D TEST_OUTPUT=tmpfile08.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref08.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test09 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
add_test(fork ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test09 -D TEST_OUTPUT=tmpfile09.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref09.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test10 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
add_test(cppThreads ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test10 -D TEST_OUTPUT=tmpfile10.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref10.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test11 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
add_test(tlsData ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test11 -D TEST_OUTPUT=tmpfile11.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref11.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test12 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
add_test(fpu ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test12 -D TEST_OUTPUT=tmpfile12.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref12.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test13 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
add_test(contexts ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test13 -D TEST_OUTPUT=tmpfile13.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref13.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
#add_test(test14 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
#add_test(conditionalThreads ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test14 -D TEST_OUTPUT=tmpfile14.txt
|
||||
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref14.txt
|
||||
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test15 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
add_test(linkingIndirectNoversion ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test15 -D TEST_OUTPUT=tmpfile15.txt
|
||||
-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}
|
||||
add_test(sse_asm ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test16 -D TEST_OUTPUT=tmpfile16.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref16.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(sse ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
set_tests_properties(sse_asm PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTROUND=0")
|
||||
|
||||
add_test(sse_intrinsics ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test17 -D TEST_OUTPUT=tmpfile17.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref17.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(sse PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTNAN=0")
|
||||
set_tests_properties(sse_intrinsics PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTNAN=0;BOX64_DYNAREC_FASTROUND=0")
|
||||
|
||||
add_test(aes ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test18 -D TEST_OUTPUT=tmpfile18.txt
|
||||
@@ -722,7 +813,22 @@ add_test(backtrace ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref19.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests/extensions/*.c")
|
||||
add_test(irelative_reloc ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test20 -D TEST_OUTPUT=tmpfile20.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref20.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(longjumpInSignals ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test21 -D TEST_OUTPUT=tmpfile21.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref21.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(x87 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test22 -D TEST_OUTPUT=tmpfile22.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref22.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests/extensions/*.c")
|
||||
foreach(file ${extension_tests})
|
||||
get_filename_component(testname "${file}" NAME_WE)
|
||||
add_test(NAME "${testname}" COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
|
||||
Vendored
+69
@@ -1,3 +1,72 @@
|
||||
box64 (0.2.2) unstable; urgency=low
|
||||
|
||||
* Added a hacked version for overriden malloc/free functions, enabling libcef (and derivative) to work.
|
||||
* Added rcfile handling: box64 now read "/etc/box64.box64rc" and "~/.box64rc" and apply per process parameters
|
||||
* Added BOX64_DYNAREC_CALLRET to optimized CALL/RET opcode using semi-direct native CALL/RET (get more than 10% speedup)
|
||||
* Added BOX64_DYNAREC_FORWARD to allow bigger Dynarec block to be build (can get more then 30% of Speedup!)
|
||||
* Improved memory protection tracking and signal handling, again
|
||||
* Simplified mutex handling (faster, cleaner)
|
||||
* Reduce memory used by the memory tracking (memory almost divide by 4 is some critical use case)
|
||||
* Added d3dadaptor9 wrapping
|
||||
* More wrapped libs (especially on the gtk familly)
|
||||
* Improved/fixed some Syscall handling
|
||||
* Refactored Strong Memory Model emulation (faster and more accurate)
|
||||
* Added some more opcode to ARM64 Dynarec, and fixed some other
|
||||
* Some fixes to flags handling in the Dynarec on some special cases
|
||||
* Refactor library loading/unloading, with refcount.
|
||||
* Some special cases fixes for dlopen (fixes deadcells, maybe others too)
|
||||
* Improved mmap mapping, espcially with MAP_32BITS flag
|
||||
* More wrapped functions and syscalls
|
||||
* Lots of improvment in the Rounding of float & double (Dynarec and Interpretor), and proper handling of denormals when converting to/from 80 bits long double
|
||||
* Added specific suppport for RK3588 board (needed some hack in signal handling, probably due to the use of a non mainlined kernel)
|
||||
* More support on the RV64 port
|
||||
* More support to build under musl environment
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2023 10:20:33 -0500
|
||||
|
||||
box64 (0.2.0) unstable; urgency=low
|
||||
|
||||
* Wrapped more vulkan function, dxvk 2.0 now works
|
||||
* Added support for overriden malloc/free functions
|
||||
* Refactor Dynarec memory management, reducing memory footprint (from 20% to 40% of Dynarec size)
|
||||
* Improved elf loader
|
||||
* Improved dlsym handling with RTLD_NEXT
|
||||
* Added BOX64_DYNAREC_SAFEFLAGS to allow finetuning Dynarec generated code handling of flags accross function calls and returns.
|
||||
* Added BOX64_BASH to setup x86_64 bash binary, so shell script can be run in x86_64 world
|
||||
* Added BOX64_ROLLING_LOG to have details log only on crash
|
||||
* Work on alignment for some of pthread structures
|
||||
* More wrapped libraries in the gtk family
|
||||
* Some fixes on the Dynarec x87 code (fixing a bunch of games like ut2004 or Piczle Puzzle)
|
||||
* Improved TLS Size handling (Unity3D games now works)
|
||||
* More PageSize Compile options
|
||||
* Improved execv family of function to have better box64 integration
|
||||
* Added support for wrapped libfuse so AppImage works
|
||||
* Adjusted the binfmt integration so AppImage are automaticaly picked
|
||||
* Improved FAudio, SDL2, GL (and more) wrapping
|
||||
* More wrapped libs, like libEGL.so, to helps emulated Qt4/5 libs to load
|
||||
* Improved Signal Handling and memory protection traking
|
||||
* Some signature fixes to some wrapped functions (in libc)
|
||||
* Added more syscalls
|
||||
* Added a lot of new opcodes to the ARM64 Dynarec
|
||||
* docs: add instructions for Debian-based Linux by @ryanfortner in #306
|
||||
* Fix typos and arch type string by @archanox in #321
|
||||
* Fix grammar by @Jai-JAP in #326
|
||||
* Enable 64k page size by @martinmanyhats in #334
|
||||
* Align address when call mprotect by @wannacu in #336
|
||||
* Add wrapped functions needed for 'ls -l'. by @stiltr in #294
|
||||
* add 18.04 tegra X1 github actions by @theofficialgman in #345
|
||||
* change order of matrix (to preview better under checkmark dropdown by @theofficialgman in #346
|
||||
* Backport SDL_DYNAPI_entry wrapper from box86. by @JohnnyonFlame in #374
|
||||
* Add SW64 base support by @wannacu in #382
|
||||
* fix overzealous replace in wrappers pathnames by @NobodyNada in #415
|
||||
* Create X64WINE.md by @WheezyE in #423
|
||||
* src: asm: Rename lr & fp registers to their x-equivalents by @fredldotme in #426
|
||||
* Malloc override by @ptitSeb in #437
|
||||
* Remove dynablocklist by @ptitSeb in #438
|
||||
* Fix Pkgbuilds by @Jai-JAP in #452
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 17 Nov 2022 11:20:33 -0500
|
||||
|
||||
box64 (0.1.8) unstable; urgency=low
|
||||
|
||||
* Added an option to get generated -NAN on SSE2 operation
|
||||
|
||||
@@ -1,3 +1,60 @@
|
||||
v0.2.2
|
||||
======
|
||||
* Added a hacked version for overriden malloc/free functions, enabling libcef (and derivative) to work.
|
||||
=> Steam Large mode and new BigPicture are working
|
||||
=> Heroic Launcher is working
|
||||
* Added rcfile handling: box64 now read `/etc/box64.box64rc` and `~/.box64rc` and apply per process parameters
|
||||
=> Every program can be finetuned, for speed or just to make them work
|
||||
* Added BOX64_DYNAREC_CALLRET to optimized CALL/RET opcode using semi-direct native CALL/RET (get more than 10% speedup)
|
||||
* Added BOX64_DYNAREC_FORWARD to allow bigger Dynarec block to be build (can get more then 30% of Speedup!)
|
||||
* Improved memory protection tracking and signal handling, again
|
||||
* Box64 now return a custom name for the CPU instal of P4, build with Box64 and the cpu name it's running on
|
||||
* Simplified mutex handling (faster, cleaner)
|
||||
* Reduce memory used by the memory tracking (memory almost divide by 4 is some critical use case)
|
||||
* Added d3dadapter9 wrapping
|
||||
=> gallium nine is now supported on box64 too
|
||||
* More wrapped libs (especially on the gtk familly)
|
||||
* Improved/fixed some Syscall handling
|
||||
* Refactored Strong Memory Model emulation (faster and more accurate)
|
||||
* Added some more opcode to ARM64 Dynarec, and fixed some other
|
||||
* Some fixes to flags handling in the Dynarec on some special cases
|
||||
* Refactor library loading/unloading, with refcount.
|
||||
* Some special cases fixes for dlopen (fixes deadcells, maybe others too)
|
||||
* Improved mmap mapping, espcially with MAP_32BITS flag
|
||||
* More wrapped functions and syscalls
|
||||
* Lots of improvment in the Rounding of float & double (Dynarec and Interpretor), and proper handling of denormals when converting to/from 80 bits long double
|
||||
* Added specific suppport for RK3588 board (needed some hack in signal handling, probably due to the use of a non mainlined kernel)
|
||||
* More support on the RV64 port
|
||||
* More support to build under musl environment
|
||||
|
||||
v0.2.0
|
||||
======
|
||||
* Wrapped more vulkan function, dxvk 2.0 now works
|
||||
* Added support for overriden malloc/free functions
|
||||
* Refactor Dynarec memory management, reducing memory footprint (from 20% to 40% of Dynarec size)
|
||||
* Improved elf loader
|
||||
* Improved dlsym handling with RTLD_NEXT
|
||||
* Added BOX64_DYNAREC_SAFEFLAGS to allow finetuning Dynarec generated code handling of flags accross function calls and returns.
|
||||
* Added BOX64_BASH to setup x86_64 bash binary, so shell script can be run in x86_64 world
|
||||
* Added BOX64_ROLLING_LOG to have details log only on crash
|
||||
* Work on alignment for some of pthread structures
|
||||
* More wrapped libraries in the gtk family
|
||||
* Some fixes on the Dynarec x87 code (fixing a bunch of games like ut2004 or Piczle Puzzle)
|
||||
* Improved TLS Size handling (Unity3D games now works)
|
||||
* More PageSize Compile options
|
||||
* Improved `execv` family of function to have better box64 integration
|
||||
* Added support for wrapped libfuse so AppImage works
|
||||
* Adjusted the binfmt integration so AppImage are automaticaly picked
|
||||
* Improved FAudio, SDL2, GL (and more) wrapping
|
||||
* More wrapped libs, like libEGL.so, to helps emulated Qt4/5 libs to load
|
||||
* Improved Signal Handling and memory protection traking
|
||||
* Some signature fixes to some wrapped functions (in libc)
|
||||
* Added more syscalls
|
||||
* Added a lot of new opcodes to the ARM64 Dynarec
|
||||
=> Lot's of new games stat working, to name a few: Surviving Mars, Piczle Cross Adventure (using Proton experimental), UT2004, Obduction, Machinarium, Silicon Zero, Hacknet, Absolute Drift, Art of Rally, Dota2
|
||||
=> Some apps also runs now, like TeamSpeak 3 Client and Server or Discord
|
||||
=> The bash integration is usefull for device with no binfmt integration or for script that check the machine it's running on
|
||||
|
||||
v0.1.8
|
||||
======
|
||||
* Added an option to get generated -NAN on SSE2 operation
|
||||
|
||||
+74
-4
@@ -1,5 +1,17 @@
|
||||
Compiling
|
||||
Compiling/Installing
|
||||
----
|
||||
|
||||
#### Debian-based Linux
|
||||
You can use [@ryanfortner](https://github.com/ryanfortner)'s apt repository to install precompiled box64 debs, updated every 24 hours.
|
||||
|
||||
```
|
||||
sudo wget https://ryanfortner.github.io/box64-debs/box64.list -O /etc/apt/sources.list.d/box64.list
|
||||
wget -O- https://ryanfortner.github.io/box64-debs/KEY.gpg | sudo gpg --dearmor -o /usr/share/keyrings/box64-debs-archive-keyring.gpg
|
||||
sudo apt update && sudo apt install box64 -y
|
||||
```
|
||||
|
||||
Alternatively, you can generate your own package using the [instructions below](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#debian-packaging).
|
||||
|
||||
#### for RK3399
|
||||
|
||||
Using a 64bit OS:
|
||||
@@ -15,7 +27,47 @@ If it's the first install, you also need:
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
|
||||
#### for PI4
|
||||
#### for RK3588 / RK3588S
|
||||
|
||||
Using a 64bit OS:
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DRK3588=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 Raspberry Pi 3
|
||||
|
||||
Warning, you need a 64bit OS:
|
||||
|
||||
If building on the Pi, you will also need a large swap (3 GB+)
|
||||
[optionally reduce GPU memory to a minimum (e.g. 16 MB) using `raspi-config`
|
||||
(and reboot) before starting the build]:
|
||||
|
||||
You can use e.g. '`make -j4`' to speed up the build, but on a Pi 3 with 1GB memory you will likely
|
||||
run out of memory at some point and need to run the build again.
|
||||
Still, this can be faster if your build is attended.
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DRPI3ARM64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make
|
||||
# or e.g. make -j4
|
||||
sudo make install
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
|
||||
#### for Raspberry Pi 4
|
||||
|
||||
Warning, you need a 64bit OS:
|
||||
|
||||
@@ -47,6 +99,22 @@ If it's the first install, you also need:
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
|
||||
#### for ODROID N2/N2+
|
||||
|
||||
Using a 64bit OS:
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DODROIDN2=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 Snapdragon 845
|
||||
|
||||
Using a 64bit OS:
|
||||
@@ -101,6 +169,8 @@ sudo systemctl restart systemd-binfmt
|
||||
|
||||
`mkdir build; cd build; cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j$(nproc)`
|
||||
|
||||
You can also add `-DBAD_SIGNAL=ON` to the cmake command if you are on Linux Kernel mixed with Android, like on RK3588 or maybe Termux
|
||||
|
||||
#### for LoongArch
|
||||
|
||||
Using a 64bit OS:
|
||||
@@ -117,7 +187,7 @@ If it's the first install, you also need:
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
|
||||
#### for RISCV
|
||||
#### for RISC-V
|
||||
|
||||
Using a 64bit OS:
|
||||
|
||||
@@ -125,7 +195,7 @@ Using a 64bit OS:
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DRV64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make -j4
|
||||
make -j`nproc`
|
||||
sudo make install
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
|
||||
+15
-7
@@ -58,12 +58,19 @@ Note that many installer (mojo setup based) will fall back to "x86" when detecti
|
||||
|
||||
----
|
||||
|
||||
Notes about Box64 configuration
|
||||
----
|
||||
|
||||
Box64 now have configurations files. There are 2 files loaded. `/etc/box4.box64rc` and `~/.box64rc`. Both files have the same syntax, and is basicaly an ini files. Section in square brakets define the process name, and the rest is the env. var. to set. Looke at [Usage](USAGE.md) for detail on what parameters can be put. Box64 comes with a default file that should be installed for better stability. The file in in `system/box64.box64rc` and should be installed to `/etc/box64.box64rc` If, for some reasons, you don't want to install that file here, at least copy it to `~/.box64rc` or some game may not function correctly.
|
||||
Note that the priority is: `~/.bashrc` > `/etc/box64.box64rc` > command line
|
||||
So, your settings in `~/.bashrc` may override the setting from your command line...
|
||||
|
||||
----
|
||||
|
||||
Notes about Unity game emulation
|
||||
----
|
||||
|
||||
Running Unity games is a hit or miss for now. Unity uses Mono (which uses signals that are not always emulated in a 100% accurate way).
|
||||
You should also note that some Unity3D games require OpenGL 3+ which can be tricky to provide on ARM SBC (single-board computers).
|
||||
So, not all Unity games work and can require a high OpenGL profile, but many actualy work now.
|
||||
Running Unity games should just works, but you should also note that many Unity3D games require OpenGL 3+ which can be tricky to provide on ARM SBC (single-board computers). Also many newer Unity3D (like KSP) games use the BC7 compressed textures, wich is not supported on many ARM integrated GPU.
|
||||
Hint: on Pi4, use `MESA_GL_VERSION_OVERRIDE=3.2` and with Panfrost use `PAN_MESA_DEBUG=gl3` to use higher profile if the game starts then quits before showing anything.
|
||||
|
||||
----
|
||||
@@ -71,7 +78,7 @@ Hint: on Pi4, use `MESA_GL_VERSION_OVERRIDE=3.2` and with Panfrost use `PAN_MESA
|
||||
Notes about GTK programs
|
||||
----
|
||||
|
||||
GTK libraries are now wrapped on box64, bu only gtk2, not gtk3 (contrary to box86).
|
||||
GTK libraries are now wrapped on box64, both gtk2 and gtk3.
|
||||
|
||||
----
|
||||
|
||||
@@ -86,14 +93,15 @@ So, no Steam for now on box64.
|
||||
Notes about Wine
|
||||
----
|
||||
|
||||
Wine64 is supported on box64. Proton should also work. Be aware that 64-bit Wine also includes 32-bit components, to be able to run 32-bit Windows programs. The 32-bit apps will need box86 and will not run without it. On a system where both box64 and box86 are present and working, a wine 64-bit setup can run both 32-bit and 64-bit Windows programs (just use `wine` and `wine64` respectively)
|
||||
Wine64 is supported on box64. Proton should also work. Be aware that 64-bit Wine also includes 32-bit components, to be able to run 32-bit Windows programs. The 32-bit apps will need box86 and will not run without it. On a system where both box64 and box86 are present and working, a wine 64-bit setup can run both 32-bit and 64-bit Windows programs (just use `wine` and `wine64` respectively).
|
||||
Note that the new 32bits PE in 64bits process that the Wine time in currently implementing in Wine 7.+ is not yet supported. I tested Wine 7.5 64bits and it worked, but more recent version will probably just not work yet.
|
||||
|
||||
----
|
||||
|
||||
Notes about Vulkan
|
||||
----
|
||||
|
||||
Box64 wraps Vulkan libraries, but note that it as only been tested with a RX550 card, some extensions may be missing depending on your graphics card.
|
||||
Box64 wraps Vulkan libraries, but note that it as only been tested with a RX550 card, so some extensions may be missing depending on your graphics card.
|
||||
|
||||
----
|
||||
|
||||
@@ -104,7 +112,7 @@ I want to thank everyone who has contributed to box64 development.
|
||||
There are many ways to contribute: code contribution, financial, hardware and advertisement!
|
||||
So, in no particular order, I want to thank:
|
||||
* For their major code contribution: rajdakin, mogery
|
||||
* For their major financial contribution: FlyingFathead, stormchaser3000
|
||||
* For their major financial contribution: FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
|
||||
* For hardware contribution and LoongArch migration: [xiaoji](https://www.linuxgame.cn/), Deepin Beijing Develop Team
|
||||
* For their hardware contribution: [Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [StarFive](https://rvspace.org/)
|
||||
* For their continous advertisement of box64 project: salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS](https://twisteros.com/) team, [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg), ekianjo ([Boilingsteam](https://boilingsteam.com/))
|
||||
|
||||
+1
-1
@@ -109,7 +109,7 @@ Box64 包裝 Vulkan 庫。但請注意,它僅使用 RX550 卡進行了測試
|
||||
贡献方式有很多种:代码贡献、财务帮助、捐赠捐赠和广告合作!
|
||||
以下感谢不分先后:
|
||||
* 代码贡献:rajdakin, mogery
|
||||
* 财务帮助:FlyingFathead, stormchaser3000
|
||||
* 财务帮助:FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
|
||||
* 硬件捐赠:[Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [StarFive](https://rvspace.org/)
|
||||
* 硬件捐赠和LoongArch迁移:[xiaoji](https://www.linuxgame.cn)
|
||||
* 为本项目持续的宣传:salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS](https://twisteros.com/) team, [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg), ekianjo ([Boilingsteam](https://boilingsteam.com/))
|
||||
|
||||
+150
-39
@@ -3,145 +3,216 @@ Usage
|
||||
----
|
||||
|
||||
There are many environment variables to control Box64 behaviour.
|
||||
Env. var with * can also be put inside box64rc files
|
||||
|
||||
#### BOX64_LOG
|
||||
#### 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_ROLLING_LOG *
|
||||
Show last few wrapped function call when a Signal is caught
|
||||
* 0: No last function call printed (Default.)
|
||||
* 1: Last 16 wrapped functions calls printed when a signal is printed. Incompatible with BOX64_LOG>1 (may need BOX64_SHOWSEGV=1 also)
|
||||
* N: Last N wrapped functions calls printed when a signal is printed. Incompatible with BOX64_LOG>1 (may need BOX64_SHOWSEGV=1 also)
|
||||
|
||||
#### BOX64_NOBANNER
|
||||
Disables Box64 printing its version and build
|
||||
* 0 : Enable printing its banner. (Default.)
|
||||
* 1 : Disable printing its banner.
|
||||
|
||||
#### BOX64_LD_LIBRARY_PATH
|
||||
#### 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
|
||||
#### BOX64_PATH *
|
||||
Path to look for x86_64 executable. Default is current folder and `bin` in current folder.
|
||||
|
||||
#### BOX64_DLSYM_ERROR
|
||||
#### BOX64_DLSYM_ERROR *
|
||||
Enables/Disables the logging of `dlsym` errors.
|
||||
* 0 : Don't log `dlsym` errors. (Default.)
|
||||
* 1 : Log dlsym errors.
|
||||
|
||||
#### BOX64_TRACE_FILE
|
||||
#### 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
|
||||
End the filename with `+` to have thetrace appended instead of overwriten
|
||||
Use `stderr` to use this instead of default `stdout`
|
||||
|
||||
#### BOX64_TRACE
|
||||
#### 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
|
||||
#### 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
|
||||
#### 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
|
||||
#### 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
|
||||
#### 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.)
|
||||
* 0 : The EMM (i.e. MMX) register will not be logged with the general and x86 registers. (Default.)
|
||||
* 1 : Dump the EMM registers.
|
||||
|
||||
#### BOX64_TRACE_COLOR
|
||||
#### 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
|
||||
#### 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
|
||||
#### 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
|
||||
#### 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_SHOWSEGV
|
||||
#### BOX64_SHOWSEGV *
|
||||
Show Segfault signal even if a signal handler is present
|
||||
* 0 : Don"t force show the SIGSEGV analysis (Default.)
|
||||
* 1 : Show SIGSEGV detail, even if a signal handler is present
|
||||
|
||||
#### BOX64_X11THREADS
|
||||
#### BOX64_SHOWBT *
|
||||
Show some Backtrace (Nativ e and Emulated) whgen a signal (SEGV, ILL or BUS) is caught
|
||||
* 0 : Don"t show backtraces (Default.)
|
||||
* 1 : Show Backtrace detail (for native, box64 is rename as the x86_64 binary run)
|
||||
|
||||
#### 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
|
||||
#### 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
|
||||
#### 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
|
||||
#### 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
|
||||
#### BOX64_DYNAREC *
|
||||
Enables/Disables Box64's Dynarec.
|
||||
* 0 : Disables Dynarec.
|
||||
* 1 : Enable Dynarec. (Default.)
|
||||
|
||||
#### BOX64_DYNAREC_TRACE
|
||||
#### 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
|
||||
#### 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_DYNAREC_BIGBLOCK
|
||||
#### BOX64_DYNAREC_BIGBLOCK *
|
||||
Enables/Disables Box64's Dynarec building BigBlock.
|
||||
* 0 : Don't try to build block as big as possible (can help program using lots of thread and a JIT, like C#/Unity) (Default when libmonobdwgc-2.0.so is loaded)
|
||||
* 1 : Build Dynarec block as big as possible (Default.)
|
||||
* 2 : Build Dynarec block bigger (don't stop when block overlaps, but only for blocks in elf memory)
|
||||
* 3 : Build Dynarec block bigger (don't stop when block overlaps, for all type of memory)
|
||||
|
||||
#### BOX64_DYNAREC_STRONGMEM
|
||||
#### BOX64_DYNAREC_FORWARD *
|
||||
Define Box64's Dynarec max allowed forward value when building Block.
|
||||
* 0 : No forward value. When current block end, don't try to go further even if there are previous forward jumps
|
||||
* XXX : Allow up to XXXX bytes of gap when building a Block after the block end to next forward jump (Default: 128)
|
||||
|
||||
#### BOX64_DYNAREC_STRONGMEM *
|
||||
Enable/Disable simulation of Strong Memory model
|
||||
* 0 : Don't try anything special (Default.)
|
||||
* 1 : Enable some Memory Barrier when reading from memory (on some MOV opcode) to simulate Strong Memory Model while trying to limit performance impact (Default when libmonobdwgc-2.0.so is loaded)
|
||||
* 2 : Enable some Memory Barrier when reading from memory (on some MOV opcode) to simulate Strong Memory Model
|
||||
|
||||
#### BOX64_DYNAREC_X87DOUBLE
|
||||
#### BOX64_DYNAREC_X87DOUBLE *
|
||||
Force the use of Double for x87 emulation
|
||||
* 0 : Try to use float when possible for x87 emulation (faster)
|
||||
* 0 : Try to use float when possible for x87 emulation (default, faster)
|
||||
* 1 : Only use Double for x87 emulation (slower, may be needed for some specific games, like Crysis)
|
||||
|
||||
#### BOX64_DYNAREC_FASTNAN
|
||||
#### BOX64_DYNAREC_FASTNAN *
|
||||
Enable/Disable generation of -NAN
|
||||
* 0 : Generate -NAN like on x86 (Default.)
|
||||
* 1 : Don't do anything special with NAN, to go as fast as possible (was default before this option exsted)
|
||||
* 0 : Generate -NAN like on x86
|
||||
* 1 : Don't do anything special with NAN, to go as fast as possible (default, faster)
|
||||
|
||||
#### BOX64_LIBGL
|
||||
#### BOX64_DYNAREC_FASTROUND *
|
||||
Enable/Disable generation of precise x86 rounding
|
||||
* 0 : Generate float/double -> int rounding like on x86
|
||||
* 1 : Don't do anything special with edge case Rounding, to go as fast as possible (no INF/NAN/Overflow -> MIN_INT conversion) (default, faster)
|
||||
|
||||
#### BOX64_DYNAREC_SAFEFLAGS *
|
||||
Handling of flags on CALL/RET opcodes
|
||||
* 0 : Treat CALL/RET as if it never needs any flags (faster but not advised)
|
||||
* 1 : most of RET will need flags, most of CALLS will not (Default)
|
||||
* 2 : All CALL/RET will need flags (slower, but might be needed. Automatically enabled for Vara.exe)
|
||||
|
||||
#### BOX64_DYNAREC_CALLRET *
|
||||
Optimisation of CALL/RET opcodes (not compatible with jit/dynarec/smc)
|
||||
* 0 : Don't optimize CALL/RET, use Jump Table for boths (Default)
|
||||
* 1 : Try to optimized CALL/RET, skipping the use of the JumpTable when possible (will crash if blacks are invalidate, so probably incompatible with JIT/Dynarec)
|
||||
|
||||
#### BOX64_DYNAREC_HOTPAGE *
|
||||
Handling of HotPage (Page beeing both executed and writen)
|
||||
* 0 : Don't track hotpage
|
||||
* 1-255 : Track HotPage, and disable execution of a page beeing writen for N attempts (default is 4)
|
||||
|
||||
#### BOX64_DYNAREC_FASTPAGE *
|
||||
Will use a faster handling of HotPage (Page beeing both executed and writen)
|
||||
* 0 : use regular hotpage (Default)
|
||||
* 1 : Use faster hotpage, taking the risk of running obsolete JIT code (might be faster, but more prone to crash)
|
||||
|
||||
#### BOX64_DYNAREC_BLEEDING_EDGE *
|
||||
Detect MonoBleedingEdge and apply conservative settings
|
||||
* 0 : Don't detect MonoBleedingEdge
|
||||
* 1 : Detect MonoBleedingEdge, and apply BIGBLOCK=0 STRONGMEM=1 if detected (Default)
|
||||
|
||||
#### BOX64_DYNAREC_WAIT *
|
||||
Behavior with FillBlock is not availble (FillBlock build Dynarec blocks and is not multithreaded)
|
||||
* 0 : Dynarec will not wait for FillBlock to ready and use Interpreter instead (might speedup a bit massive multithread or JIT programs)
|
||||
* 1 : Dynarec will wait for FillBlock to be ready (Default)
|
||||
|
||||
#### BOX64_SSE_FLUSHTO0 *
|
||||
Handling of SSE Flush to 0 flags
|
||||
* 0 : Just track the flag (Default)
|
||||
* 1 : Direct apply of SSE Flush to 0 flag
|
||||
|
||||
#### BOX64_X87_NO80BITS *
|
||||
Handling of x87 80bits long double
|
||||
* 0 : Try to handle 80bits long double as precise as possible (Default)
|
||||
* 1 : Handle them as double
|
||||
|
||||
#### BOX64_LIBCEF *
|
||||
Detect libcef and apply malloc_hack settings
|
||||
* 0 : Don't detect libcef
|
||||
* 1 : Detect libcef, and apply MALLOC_HACK=2 if detected (Default)
|
||||
|
||||
#### 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
|
||||
@@ -150,42 +221,66 @@ Enable/Disable generation of -NAN
|
||||
* 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
|
||||
#### 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
|
||||
#### 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_PREFER_WRAPPED
|
||||
#### BOX64_PREFER_WRAPPED *
|
||||
Box64 will use wrapped libs even if the lib is specified with absolute path
|
||||
* 0 : Try to use emulated libs when they are defined with absolute path (Default.)
|
||||
* 1 : Use Wrapped native libs even if path is absolute
|
||||
|
||||
#### BOX64_PREFER_EMULATED
|
||||
#### BOX64_PREFER_EMULATED *
|
||||
Box64 will prefer emulated libs first (execpt for glibc, alsa, pulse, GL, vulkan and X11
|
||||
* 0 : Native libs are prefered (Default.)
|
||||
* 1 : Emulated libs are prefered (Default for program running inside pressure-vessel)
|
||||
|
||||
#### BOX64_NOPULSE
|
||||
#### BOX64_CRASHHANDLER *
|
||||
Box64 will use a dummy crashhandler.so library
|
||||
* 0 : Use Emulated crashhandler.so library if needed
|
||||
* 1 : Use an internal dummy (completly empty) crashhandler.so library (defaut)
|
||||
|
||||
#### BOX64_MALLOC_HACK *
|
||||
How Box64 will handle hooking of malloc operators
|
||||
* 0 : Don't allow malloc operator to be redirected, rewriting code to use regular function (Default)
|
||||
* 1 : Allow malloc operator to be redirected (not advised)
|
||||
* 2 : Like 0, but track special mmap / free (some redirected functions were inlined and cannot be redirected)
|
||||
|
||||
#### BOX64_NOPULSE *
|
||||
Disables the load of pulseaudio libraries.
|
||||
* 0 : Load pulseaudio libraries if found. (Default.)
|
||||
* 1 : Disables the load of pulse audio libraries (libpulse and libpulse-simple), both the native library and the x86 library
|
||||
|
||||
#### BOX64_NOGTK
|
||||
#### BOX64_NOGTK *
|
||||
Disables the loading of wrapped GTK libraries.
|
||||
* 0 : Load wrapped GTK libraries if found. (Default.)
|
||||
* 1 : Disables loading wrapped GTK libraries.
|
||||
|
||||
#### BOX64_NOVULKAN
|
||||
#### BOX64_NOVULKAN *
|
||||
Disables the load of vulkan libraries.
|
||||
* 0 : Load vulkan libraries if found.
|
||||
* 1 : Disables the load of vulkan libraries, both the native and the i386 version (can be useful on Pi4, where the vulkan driver is not quite there yet.)
|
||||
|
||||
#### BOX64_JITGDB
|
||||
#### BOX64_BASH *
|
||||
Define x86_64 bash to launch script
|
||||
* yyyy
|
||||
Will use yyyy as x86_64 bash to launch script. yyyy needs to be a full path to a valid x86_64 version of bash
|
||||
|
||||
#### BOX64_ENV
|
||||
* XXX=yyyy
|
||||
will add XXX=yyyy env. var.
|
||||
|
||||
#### BOX64_ENV1
|
||||
* XXX=yyyy
|
||||
will add XXX=yyyy env. var. and continue with BOX86_ENV2 ... until var doesn't exist
|
||||
|
||||
#### 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)
|
||||
@@ -195,3 +290,19 @@ Disables the load of vulkan libraries.
|
||||
* 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)
|
||||
|
||||
#### BOX64_NORCFILES
|
||||
If the env var exist, no rc files (like /etc/box64.box64rc and ~/.box64rc) will be loaded
|
||||
|
||||
----
|
||||
|
||||
Those variables are only valid inside a rcfile:
|
||||
----
|
||||
|
||||
#### BOX64_NOSANDBOX
|
||||
* 0 : Nothing special
|
||||
* 1 : Added "--no-sandbox" to command line arguments (usefull for chrome based programs)
|
||||
|
||||
#### BOX64_EXIT
|
||||
* 0 : Nothing special
|
||||
* 1 : Just exit, don't try to run the program
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
# Installing Wine64
|
||||
Running Wine64/Wine with Box64/Box86 allows x64/x86 Windows programs to run on 64-bit ARM Linux devices.
|
||||
- Box64 needs `wine-amd64` to be installed **manually** on ARM64 (aarch64) devices. This will run 64-bit Windows programs (aka x86_64).
|
||||
- Box86 needs `wine-i386` to be installed **manually** on ARM32 (armhf) devices (or on ARM64 with multiarch or chroot). This will run 32-bit Windows programs (aka x86).
|
||||
- _Note that `wine:arm64` and `wine:armhf` will not work with Box64/Box86. Your device's package manager might try to install those if you ask it to install wine._
|
||||
|
||||
See installation steps below (in the [Examples](#examples) section).
|
||||
|
||||
## Overview
|
||||
The general procedure for installing Wine64 & Wine for Box64 & Box86 is to...
|
||||
- Download all the install files for the version of Wine you wish to install
|
||||
- Unzip or dpkg the install files into one folder
|
||||
- Move that folder to the directory that you wish Wine to run from (often `~/wine/` by default)
|
||||
- Go to `/usr/local/bin` and make symlinks or scripts that will point to your main wine binaries.
|
||||
- Boot wine to create a new wineprefix.
|
||||
- Download winetricks (which is just a complicated bash script), make it executable, then copy it to `/usr/local/bin`.
|
||||
|
||||
## Examples
|
||||
### Installing Wine64 & Wine for Box64 & Box86 on Raspberry Pi OS from WineHQ .deb files
|
||||
_Links from the [WineHQ repo](https://dl.winehq.org/wine-builds/debian/dists/)_
|
||||
|
||||
This install method allows you to install different versions of Wine64/Wine. You may install any version/branch of Wine that you wish.
|
||||
```
|
||||
# NOTE: Can only run on aarch64 (since box64 can only run on aarch64)
|
||||
# box64 runs wine-amd64, box86 runs wine-i386.
|
||||
|
||||
### User-defined Wine version variables ################
|
||||
# - Replace the variables below with your system's info.
|
||||
# - Note that we need the amd64 version for Box64 even though we're installing it on our ARM processor.
|
||||
# - Note that we need the i386 version for Box86 even though we're installing it on our ARM processor.
|
||||
# - Wine download links from WineHQ: https://dl.winehq.org/wine-builds/
|
||||
|
||||
local branch="devel" #example: devel, staging, or stable (wine-staging 4.5+ requires libfaudio0:i386)
|
||||
local version="7.1" #example: "7.1"
|
||||
local id="debian" #example: debian, ubuntu
|
||||
local dist="bullseye" #example (for debian): bullseye, buster, jessie, wheezy, ${VERSION_CODENAME}, etc
|
||||
local tag="-1" #example: -1 (some wine .deb files have -1 tag on the end and some don't)
|
||||
|
||||
########################################################
|
||||
|
||||
# Clean up any old wine instances
|
||||
wineserver -k # stop any old wine installations from running
|
||||
rm -rf ~/.cache/wine # remove any old wine-mono/wine-gecko install files
|
||||
rm -rf ~/.local/share/applications/wine # remove any old program shortcuts
|
||||
|
||||
# Backup any old wine installs
|
||||
rm -rf ~/wine-old 2>/dev/null; mv ~/wine ~/wine-old 2>/dev/null
|
||||
rm -rf ~/.wine-old 2>/dev/null; mv ~/.wine ~/.wine-old 2>/dev/null
|
||||
sudo mv /usr/local/bin/wine /usr/local/bin/wine-old 2>/dev/null
|
||||
sudo mv /usr/local/bin/wine64 /usr/local/bin/wine-old 2>/dev/null
|
||||
sudo mv /usr/local/bin/wineboot /usr/local/bin/wineboot-old 2>/dev/null
|
||||
sudo mv /usr/local/bin/winecfg /usr/local/bin/winecfg-old 2>/dev/null
|
||||
sudo mv /usr/local/bin/wineserver /usr/local/bin/wineserver-old 2>/dev/null
|
||||
|
||||
# Wine download links from WineHQ: https://dl.winehq.org/wine-builds/
|
||||
LNKA="https://dl.winehq.org/wine-builds/${id}/dists/${dist}/main/binary-amd64/" #amd64-wine links
|
||||
DEB_A1="wine-${branch}-amd64_${version}~${dist}${tag}_amd64.deb" #wine64 main bin
|
||||
DEB_A2="wine-${branch}_${version}~${dist}${tag}_amd64.deb" #wine64 support files (required for wine64 / can work alongside wine_i386 main bin)
|
||||
#DEB_A3="winehq-${branch}_${version}~${dist}${tag}_amd64.deb" #shortcuts & docs
|
||||
LNKB="https://dl.winehq.org/wine-builds/${id}/dists/${dist}/main/binary-i386/" #i386-wine links
|
||||
DEB_B1="wine-${branch}-i386_${version}~${dist}${tag}_i386.deb" #wine_i386 main bin
|
||||
DEB_B2="wine-${branch}_${version}~${dist}${tag}_i386.deb" #wine_i386 support files (required for wine_i386 if no wine64 / CONFLICTS WITH wine64 support files)
|
||||
#DEB_B3="winehq-${branch}_${version}~${dist}${tag}_i386.deb" #shortcuts & docs
|
||||
|
||||
# Install amd64-wine (64-bit) alongside i386-wine (32-bit)
|
||||
echo -e "Downloading wine . . ."
|
||||
wget -q ${LNKA}${DEB_A1}
|
||||
wget -q ${LNKA}${DEB_A2}
|
||||
wget -q ${LNKB}${DEB_B1}
|
||||
echo -e "Extracting wine . . ."
|
||||
dpkg-deb -x ${DEB_A1} wine-installer
|
||||
dpkg-deb -x ${DEB_A2} wine-installer
|
||||
dpkg-deb -x ${DEB_B1} wine-installer
|
||||
echo -e "Installing wine . . ."
|
||||
mv wine-installer/opt/wine* ~/wine
|
||||
|
||||
# Download wine dependencies
|
||||
# - these packages are needed for running box86/wine-i386 on a 64-bit RPiOS via multiarch
|
||||
sudo dpkg --add-architecture armhf && sudo apt-get update # enable multi-arch
|
||||
sudo apt-get install -y libasound2:armhf libc6:armhf libglib2.0-0:armhf libgphoto2-6:armhf libgphoto2-port12:armhf \
|
||||
libgstreamer-plugins-base1.0-0:armhf libgstreamer1.0-0:armhf libldap-2.4-2:armhf libopenal1:armhf libpcap0.8:armhf \
|
||||
libpulse0:armhf libsane1:armhf libudev1:armhf libusb-1.0-0:armhf libvkd3d1:armhf libx11-6:armhf libxext6:armhf \
|
||||
libasound2-plugins:armhf ocl-icd-libopencl1:armhf libncurses6:armhf libncurses5:armhf libcap2-bin:armhf libcups2:armhf \
|
||||
libdbus-1-3:armhf libfontconfig1:armhf libfreetype6:armhf libglu1-mesa:armhf libglu1:armhf libgnutls30:armhf \
|
||||
libgssapi-krb5-2:armhf libkrb5-3:armhf libodbc1:armhf libosmesa6:armhf libsdl2-2.0-0:armhf libv4l-0:armhf \
|
||||
libxcomposite1:armhf libxcursor1:armhf libxfixes3:armhf libxi6:armhf libxinerama1:armhf libxrandr2:armhf \
|
||||
libxrender1:armhf libxxf86vm1 libc6:armhf libcap2-bin:armhf # to run wine-i386 through box86:armhf on aarch64
|
||||
# This list found by downloading...
|
||||
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-i386/wine-devel-i386_7.1~bullseye-1_i386.deb
|
||||
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-i386/winehq-devel_7.1~bullseye-1_i386.deb
|
||||
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-i386/wine-devel_7.1~bullseye-1_i386.deb
|
||||
# then `dpkg-deb -I package.deb`. Read output, add `:armhf` to packages in dep list, then try installing them on Pi aarch64.
|
||||
|
||||
# - these packages are needed for running box64/wine-amd64 on RPiOS (box64 only runs on 64-bit OS's)
|
||||
sudo apt-get install -y libasound2:arm64 libc6:arm64 libglib2.0-0:arm64 libgphoto2-6:arm64 libgphoto2-port12:arm64 \
|
||||
libgstreamer-plugins-base1.0-0:arm64 libgstreamer1.0-0:arm64 libldap-2.4-2:arm64 libopenal1:arm64 libpcap0.8:arm64 \
|
||||
libpulse0:arm64 libsane1:arm64 libudev1:arm64 libunwind8:arm64 libusb-1.0-0:arm64 libvkd3d1:arm64 libx11-6:arm64 libxext6:arm64 \
|
||||
ocl-icd-libopencl1:arm64 libasound2-plugins:arm64 libncurses6:arm64 libncurses5:arm64 libcups2:arm64 \
|
||||
libdbus-1-3:arm64 libfontconfig1:arm64 libfreetype6:arm64 libglu1-mesa:arm64 libgnutls30:arm64 \
|
||||
libgssapi-krb5-2:arm64 libjpeg62-turbo:arm64 libkrb5-3:arm64 libodbc1:arm64 libosmesa6:arm64 libsdl2-2.0-0:arm64 libv4l-0:arm64 \
|
||||
libxcomposite1:arm64 libxcursor1:arm64 libxfixes3:arm64 libxi6:arm64 libxinerama1:arm64 libxrandr2:arm64 \
|
||||
libxrender1:arm64 libxxf86vm1:arm64 libc6:arm64 libcap2-bin:arm64
|
||||
# This list found by downloading...
|
||||
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-amd64/wine-devel_7.1~bullseye-1_amd64.deb
|
||||
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-amd64/wine-devel-amd64_7.1~bullseye-1_amd64.deb
|
||||
# then `dpkg-deb -I package.deb`. Read output, add `:arm64` to packages in dep list, then try installing them on Pi aarch64.
|
||||
|
||||
# These packages are needed for running wine-staging on RPiOS (Credits: chills340)
|
||||
sudo apt install libstb0 -y
|
||||
cd ~/Downloads
|
||||
wget -r -l1 -np -nd -A "libfaudio0_*~bpo10+1_i386.deb" http://ftp.us.debian.org/debian/pool/main/f/faudio/ # Download libfaudio i386 no matter its version number
|
||||
dpkg-deb -xv libfaudio0_*~bpo10+1_i386.deb libfaudio
|
||||
sudo cp -TRv libfaudio/usr/ /usr/
|
||||
rm libfaudio0_*~bpo10+1_i386.deb # clean up
|
||||
rm -rf libfaudio # clean up
|
||||
|
||||
# Install symlinks
|
||||
sudo ln -s ~/wine/bin/wine /usr/local/bin/wine
|
||||
sudo ln -s ~/wine/bin/wine64 /usr/local/bin/wine64
|
||||
sudo ln -s ~/wine/bin/wineboot /usr/local/bin/wineboot
|
||||
sudo ln -s ~/wine/bin/winecfg /usr/local/bin/winecfg
|
||||
sudo ln -s ~/wine/bin/wineserver /usr/local/bin/wineserver
|
||||
sudo chmod +x /usr/local/bin/wine /usr/local/bin/wine64 /usr/local/bin/wineboot /usr/local/bin/winecfg /usr/local/bin/wineserver
|
||||
```
|
||||
|
||||
## Installing winetricks
|
||||
Winetricks is a bash script which makes it easier to install & configure any desired Windows core system software packages which may be dependencies for certain Windows programs. You can either install it with `apt`, or manually using the steps below.
|
||||
|
||||
```
|
||||
sudo apt-get install cabextract -y # winetricks needs this installed
|
||||
sudo mv /usr/local/bin/winetricks /usr/local/bin/winetricks-old # Backup old winetricks
|
||||
cd ~/Downloads && wget https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks # Download
|
||||
sudo chmod +x winetricks && sudo mv winetricks /usr/local/bin/ # Install
|
||||
```
|
||||
|
||||
Whenever we run winetricks, we must tell Box86 to supress its info banner, otherwise winetricks will crash. Box86's info banner can be suppressed using the `BOX86_NOBANNER=1` environment variable before invoking winetricks (example: `BOX86_NOBANNER=1 winetricks`).
|
||||
|
||||
If `apt` installed a desktop menu shortcut for winetricks (or if you make your own desktop shortcut for winetricks) then you may need to edit that shortcut to include Box86's BOX86_NOBANNER=1 env var. With your favorite text editor, edit `/usr/share/applications/winetricks.desktop` and change `Exec=winetricks --gui` to `Exec=env BOX86_NOBANNER=1 winetricks --gui`.
|
||||
|
||||
## Example commands
|
||||
Creating a 64-bit wineprefix:
|
||||
`wine64 wineboot` or `wine wineboot` (wineprefix is created in `~/.wine/`)
|
||||
`WINEPREFIX="$HOME/prefix64" wine wineboot` (wineprefix is created in `~/prefix64/`) _Note: You will need to invoke `WINEPREFIX="$HOME/prefix64"` before every command to use this wineprefix._
|
||||
|
||||
Creating a 32-bit wineprefix:
|
||||
`WINEARCH=win32 wine wineboot` (wineprefix is created in `~/.wine/`)
|
||||
|
||||
Fore-quitting wine:
|
||||
`wineserver -k`
|
||||
|
||||
Running Wine Configuration:
|
||||
`winecfg`
|
||||
|
||||
Using winetricks:
|
||||
`winetricks -q corefonts vcrun2010 dotnet20sp1`
|
||||
_This command will silently install three packages in series: Windows core fonts, VC++ 2010 Runtimes, and .NET 2.0 SP1. `-q` is the "install silent/quiet" command._
|
||||
|
||||
Invoking Box86's logging features (with `BOX86_LOG=1` or similar) will cause winetricks to crash.
|
||||
|
||||
For a list of all the different Windows packages & libraries that winetricks can help you install, run `winetricks list-all`
|
||||
|
||||
## Other notes
|
||||
|
||||
### Wineprefixes (and Wine initialization)
|
||||
When you first run or boot Wine (`wine wineboot`), Wine will create a new user environment within which to install Windows software. This user environment is called a "wineprefix" (or "wine bottle") and is located (by default) in `~/.wine` (note that Linux folders with a `.` in front of them are "hidden" folders). Think of a wineprefix as Wine's virtual 'harddrive' where it installs software and saves settings. Wineprefixes are portable and deletable. For more Wine documentation, see [WineHQ](https://www.winehq.org/documentation).
|
||||
|
||||
If you at any point corrupt something inside your default wineprefix, you can start "fresh" by deleting your `~/.wine` directory (with the `rm -rf ~/.wine` command) and boot wine again to create a new default wineprefix.
|
||||
|
||||
### Transplanting wineprefixes
|
||||
If software isn't installing in Wine with Box86, but is installing for you in Wine on a regular x86 Linux computer, you can copy a wineprefix from your x86 Linux computer to the device you're running Box86 on. This is most easily done by tarring the `~/.wine` folder on your x86 Linux computer (`tar -cvf winebottle.tar ~/.wine`), transferring the tar file to your device, then un-tarring the tar file (`tar -xf winebottle.tar`) on your device running Box86 & Wine. Tarring the wineprefix preserves any symlinks that are inside it.
|
||||
|
||||
### Swapping out different versions of Wine
|
||||
Some versions of Wine work better with certain software. It is best to install a version of Wine that is known to work with the software you would like to run. There are three main development branches of Wine you can pick from, referred to as wine-stable, wine-devel, and wine-staging. _Note that the wine-staging branch requires extra installation steps on Raspberry Pi._
|
||||
|
||||
Your entire Wine installation can reside within a single folder on your Linux computer. TwisterOS assumes that your Wine installation is located inside the `~/wine/` directory. The actual directory where you put your `wine` folder doesn't matter as long as you have symlinks within the `/usr/local/bin/` directory which point to the `wine` folder so that Linux can find Wine when you type `wine` into the terminal).
|
||||
|
||||
You can change which version of Wine you are running simply by renaming your old `wine` and `.wine` folders to something else, then putting a new `wine` folder (containing your new version of Wine) in its place. Running `wine wineboot` again will migrate a wineprefix from an older version of Wine to be usable by the newer version of Wine you just installed. You can check which version of Wine you're running with the `wine --version` command.
|
||||
@@ -23,7 +23,7 @@ prepare() {
|
||||
cd "${srcdir}/${pkgname%-arm64-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -35,10 +35,4 @@ build() {
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-arm64-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -23,7 +23,7 @@ prepare() {
|
||||
cd "${srcdir}/${pkgname%-arm64-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=Debug
|
||||
cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -35,10 +35,4 @@ build() {
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-arm64-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -23,7 +23,7 @@ prepare() {
|
||||
cd "${srcdir}/${pkgname%-lx2160a-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DLX2160A=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
cmake .. -DLX2160A=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -35,10 +35,4 @@ build() {
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-lx2160a-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -23,7 +23,7 @@ prepare() {
|
||||
cd "${srcdir}/${pkgname%-lx2160a-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DLX2160A=1 -DCMAKE_BUILD_TYPE=Debug
|
||||
cmake .. -DLX2160A=1 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -35,10 +35,4 @@ build() {
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-lx2160a-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -23,7 +23,7 @@ prepare() {
|
||||
cd "${srcdir}/${pkgname%-rk3399-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -35,10 +35,4 @@ build() {
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-rk3399-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -23,7 +23,7 @@ prepare() {
|
||||
cd "${srcdir}/${pkgname%-rk3399-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=Debug
|
||||
cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -35,10 +35,4 @@ build() {
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-rk3399-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -23,7 +23,7 @@ prepare() {
|
||||
cd "${srcdir}/${pkgname%-rpi-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DRPI4ARM64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
cmake .. -DRPI4ARM64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -35,10 +35,4 @@ build() {
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-rpi-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -23,7 +23,7 @@ prepare() {
|
||||
cd "${srcdir}/${pkgname%-rpi-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DRPI4ARM64=1 -DCMAKE_BUILD_TYPE=Debug
|
||||
cmake .. -DRPI4ARM64=1 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -35,10 +35,4 @@ build() {
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-rpi-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -23,7 +23,7 @@ prepare() {
|
||||
cd "${srcdir}/${pkgname%-tegra-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DTEGRAX1=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
cmake .. -DTEGRAX1=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -35,10 +35,4 @@ build() {
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-tegra-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -23,7 +23,7 @@ prepare() {
|
||||
cd "${srcdir}/${pkgname%-tegra-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DTEGRAX1=1 -DCMAKE_BUILD_TYPE=Debug
|
||||
cmake .. -DTEGRAX1=1 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -35,10 +35,4 @@ build() {
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-tegra-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -22,7 +22,7 @@ prepare() {
|
||||
cd "${srcdir}/${pkgname%-x64-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -34,10 +34,4 @@ build() {
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-x64-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -22,7 +22,7 @@ prepare() {
|
||||
cd "${srcdir}/${pkgname%-x64-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=Debug
|
||||
cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -34,10 +34,4 @@ build() {
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-x64-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
+226
-106
@@ -145,10 +145,20 @@ wrappedtestundefs.h:
|
||||
|
||||
# TODO: Add /.F.*A/ automatic generation (and suppression)
|
||||
|
||||
class FunctionConvention(object):
|
||||
def __init__(self, ident: str, convname: str, valid_chars: List[str]) -> None:
|
||||
self.ident = ident
|
||||
self.name = convname
|
||||
self.values = valid_chars
|
||||
# Free letters: B FG J QR T XYZab e gh jk mno qrst xyz
|
||||
conventions = {
|
||||
'F': FunctionConvention('F', "System V", ['E', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'V', 'O', 'S', 'N', 'M', 'H', 'P', 'A']),
|
||||
'W': FunctionConvention('W', "Windows", ['E', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'K', 'l', 'L', 'p', 'V', 'O', 'S', 'N', 'M', 'P', 'A'])
|
||||
}
|
||||
sortedvalues = ['E', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'V', 'O', 'S', 'N', 'M', 'H', 'P', 'A', '0', '1']
|
||||
assert(all(all(c not in conv.values[:i] and c in sortedvalues for i, c in enumerate(conv.values)) for conv in conventions.values()))
|
||||
|
||||
class FunctionType(str):
|
||||
values: List[str] = ['E', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'V', 'O', 'S', 'N', 'M', 'H', 'P', 'A']
|
||||
|
||||
@staticmethod
|
||||
def validate(s: str, post: str) -> bool:
|
||||
if len(s) < 3:
|
||||
@@ -163,10 +173,13 @@ class FunctionType(str):
|
||||
# TODO: change *FEv into true functions (right now they are redirected to *FE)
|
||||
#chk_type = s[0] + s[3:]
|
||||
|
||||
if s[1] not in ["F"]:
|
||||
if s[1] not in conventions:
|
||||
raise NotImplementedError("Bad middle letter {0}{1}".format(s[1], post))
|
||||
|
||||
return all(c in FunctionType.values for c in chk_type) and (('v' not in chk_type[1:]) or (len(chk_type) == 2))
|
||||
return all(c in conventions[s[1]].values for c in chk_type) and (('v' not in chk_type[1:]) or (len(chk_type) == 2))
|
||||
|
||||
def get_convention(self) -> FunctionConvention:
|
||||
return conventions[self[1]]
|
||||
|
||||
def splitchar(self) -> List[int]:
|
||||
"""
|
||||
@@ -177,9 +190,9 @@ class FunctionType(str):
|
||||
of `values.index`.
|
||||
"""
|
||||
try:
|
||||
ret = [len(self), FunctionType.values.index(self[0])]
|
||||
ret = [len(self), ord(self.get_convention().ident), self.get_convention().values.index(self[0])]
|
||||
for c in self[2:]:
|
||||
ret.append(FunctionType.values.index(c))
|
||||
ret.append(self.get_convention().values.index(c))
|
||||
return ret
|
||||
except ValueError as e:
|
||||
raise ValueError("Value is " + self) from e
|
||||
@@ -187,8 +200,6 @@ class FunctionType(str):
|
||||
def __getitem__(self, i: Union[int, slice]) -> 'FunctionType':
|
||||
return FunctionType(super().__getitem__(i))
|
||||
|
||||
assert(all(c not in FunctionType.values[:i] for i, c in enumerate(FunctionType.values)))
|
||||
|
||||
RedirectType = NewType('RedirectType', FunctionType)
|
||||
DefineType = NewType('DefineType', str)
|
||||
|
||||
@@ -388,7 +399,10 @@ def readFiles(files: Iterable[Filename]) -> Tuple[JumbledGlobals, JumbledRedirec
|
||||
or match("sdl1mixer", "sdl2mixer") \
|
||||
or match("sdl1net", "sdl2net") \
|
||||
or match("sdl1ttf", "sdl2ttf") \
|
||||
or match("libc", "tcmallocminimal"):
|
||||
or match("libGL", "libEGL") \
|
||||
or match("libc", "tcmallocminimal") \
|
||||
or match("libc", "tbbmallocproxy") \
|
||||
or match("tcmallocminimal", "tbbmallocproxy"):
|
||||
continue
|
||||
|
||||
# Note: this test is very (too) simple. If it ever raises, comment
|
||||
@@ -459,7 +473,8 @@ def readFiles(files: Iterable[Filename]) -> Tuple[JumbledGlobals, JumbledRedirec
|
||||
gotype = ln.split("(")[0].strip()
|
||||
funname = ln.split(",")[0].split("(")[1].strip()
|
||||
ln = ln.split(",")[1].split(")")[0].strip()
|
||||
add_symbol_name(funname)
|
||||
if not filename.endswith("_genvate.h"):
|
||||
add_symbol_name(funname)
|
||||
except IndexError:
|
||||
raise NotImplementedError("Invalid GO command: {0}:{1}".format(
|
||||
filename, line[:-1]
|
||||
@@ -468,26 +483,40 @@ def readFiles(files: Iterable[Filename]) -> Tuple[JumbledGlobals, JumbledRedirec
|
||||
hasFlatStructure = False
|
||||
origLine = ln
|
||||
if not FunctionType.validate(ln, " ({0}:{1})".format(filename, line[:-1])):
|
||||
if (ln[0] in FunctionType.values) \
|
||||
# This needs more work
|
||||
old = RedirectType(FunctionType(ln))
|
||||
if (ln[0] in old.get_convention().values) \
|
||||
and ('v' not in ln[2:]) \
|
||||
and all((c in FunctionType.values) or (c in mystructs) for c in ln[2:]):
|
||||
and all((c in old.get_convention().values) or (c in mystructs) for c in ln[2:]):
|
||||
hasFlatStructure = True
|
||||
|
||||
for sn in mystructs:
|
||||
ln = ln.replace(sn, mystructs[sn][1])
|
||||
ln = ln[0] + 'F' + ln[2:] # In case a structure named 'F' is used
|
||||
mystructuses[RedirectType(FunctionType(origLine))] = FunctionType(ln)
|
||||
else:
|
||||
# This needs more work
|
||||
old = RedirectType(FunctionType(ln))
|
||||
acceptables = ['0', '1'] + FunctionType.values
|
||||
if any(c not in acceptables for c in ln[2:]):
|
||||
raise NotImplementedError("{0} ({1}:{2})".format(ln[2:], filename, line[:-1]))
|
||||
# Ok, this is acceptable: there is 0, 1 and/or void
|
||||
ln = ln[:2] + (ln[2:]
|
||||
.replace("v", "") # void -> nothing
|
||||
.replace("0", "i") # 0 -> integer
|
||||
.replace("1", "i")) # 1 -> integer
|
||||
assert(len(ln) >= 3)
|
||||
if old.get_convention().name == "System V":
|
||||
acceptables = ['0', '1'] + old.get_convention().values
|
||||
if any(c not in acceptables for c in ln[2:]):
|
||||
raise NotImplementedError("{0} ({1}:{2})".format(ln[2:], filename, line[:-1]))
|
||||
# Ok, this is acceptable: there is 0, 1 and/or void
|
||||
ln = ln[:2] + (ln[2:]
|
||||
.replace("v", "") # void -> nothing
|
||||
.replace("0", "i") # 0 -> integer
|
||||
.replace("1", "i")) # 1 -> integer
|
||||
assert(len(ln) >= 3)
|
||||
else:
|
||||
acceptables = ['0', '1', 'D', 'H'] + old.get_convention().values
|
||||
if any(c not in acceptables for c in ln[2:]):
|
||||
raise NotImplementedError("{0} ({1}:{2})".format(ln[2:], filename, line[:-1]))
|
||||
# Ok, this is acceptable: there is 0, 1 and/or void
|
||||
ln = ln[:2] + (ln[2:]
|
||||
.replace("v", "") # void -> nothing
|
||||
.replace("D", "p") # long double -> pointer
|
||||
.replace("H", "p") # unsigned __int128 -> pointer
|
||||
.replace("0", "i") # 0 -> integer
|
||||
.replace("1", "i")) # 1 -> integer
|
||||
assert(len(ln) >= 3)
|
||||
redirects.setdefault(str(dependants), {})
|
||||
redirects[str(dependants)][old] = FunctionType(ln)
|
||||
|
||||
@@ -522,6 +551,7 @@ def readFiles(files: Iterable[Filename]) -> Tuple[JumbledGlobals, JumbledRedirec
|
||||
typedefs.setdefault(RedirectType(FunctionType(origLine)), [])
|
||||
|
||||
# If the line is a structure metadata information...
|
||||
# FIXME: what happens with e.g. a Windows function?
|
||||
elif ln.startswith("//%S"):
|
||||
metadata = [e for e in ln.split() if e]
|
||||
if len(metadata) != 4:
|
||||
@@ -535,12 +565,12 @@ def readFiles(files: Iterable[Filename]) -> Tuple[JumbledGlobals, JumbledRedirec
|
||||
if metadata[3] == "":
|
||||
# If you need this, please open an issue (this is never actually called, empty strings are removed)
|
||||
raise NotImplementedError("Invalid structure metadata supply (empty replacement) ({0}:{1})".format(filename, line[:-1]))
|
||||
if any(c not in FunctionType.values for c in metadata[3]):
|
||||
if any(c not in conventions['F'].values for c in metadata[3]):
|
||||
# Note that replacement cannot be another structure type
|
||||
raise NotImplementedError("Invalid structure metadata supply (invalid replacement) ({0}:{1})".format(filename, line[:-1]))
|
||||
if metadata[1] in mystructs:
|
||||
raise NotImplementedError("Invalid structure nickname {0} (duplicate) ({1}/{2})".format(metadata[1], filename, line[:-1]))
|
||||
if (metadata[1] in FunctionType.values) or (metadata[1] in ['0', '1']):
|
||||
if (metadata[1] in conventions['F'].values) or (metadata[1] in ['0', '1']):
|
||||
raise NotImplementedError("Invalid structure nickname {0} (reserved) ({1}/{2})".format(metadata[1], filename, line[:-1]))
|
||||
|
||||
# OK, add into the database
|
||||
@@ -675,17 +705,21 @@ def sortArrays(gbl_tmp : JumbledGlobals, red_tmp : JumbledRedirects, filespec: J
|
||||
for k3 in gbl:
|
||||
gbl[k3].sort(key=FunctionType.splitchar)
|
||||
|
||||
FunctionType.values = FunctionType.values + ['0', '1']
|
||||
oldvals = { k: conventions[k].values for k in conventions }
|
||||
for k in conventions:
|
||||
conventions[k].values = sortedvalues
|
||||
for k3 in redirects:
|
||||
redirects[k3].sort(key=lambda v: v[0].splitchar() + v[1].splitchar())
|
||||
FunctionType.values = FunctionType.values[:-2]
|
||||
for k in conventions:
|
||||
conventions[k].values = oldvals[k]
|
||||
|
||||
sortedfilespec: SortedFilesSpecific = {}
|
||||
for fn in filespec:
|
||||
# Maybe do better?
|
||||
mystructs_vals: List[str] = sorted(filespec[fn][1].keys())
|
||||
if mystructs_vals != []:
|
||||
FunctionType.values = FunctionType.values + list(mystructs_vals)
|
||||
for k in conventions:
|
||||
conventions[k].values = conventions[k].values + list(mystructs_vals)
|
||||
|
||||
mytypedefs_vals: List[RedirectType] = sorted(filespec[fn][0].keys(), key=FunctionType.splitchar)
|
||||
sortedfilespec[fn] = (
|
||||
@@ -694,7 +728,8 @@ def sortArrays(gbl_tmp : JumbledGlobals, red_tmp : JumbledRedirects, filespec: J
|
||||
)
|
||||
|
||||
if mystructs_vals != []:
|
||||
FunctionType.values = FunctionType.values[:-len(mystructs_vals)]
|
||||
for k in conventions:
|
||||
conventions[k].values = conventions[k].values[:-len(mystructs_vals)]
|
||||
|
||||
return CustOrderedDict(gbl, gbl_idxs), CustOrderedDict(redirects, redirects_idxs), sortedfilespec
|
||||
|
||||
@@ -781,6 +816,8 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
|
||||
# Detect simple wrappings
|
||||
simple_wraps: Dict[ClausesStr, List[Tuple[FunctionType, int]]] = {}
|
||||
allowed_conv_ident = "F"
|
||||
allowed_conv = conventions[allowed_conv_ident]
|
||||
|
||||
# H could be allowed maybe?
|
||||
allowed_simply: str = "v"
|
||||
@@ -789,16 +826,18 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
|
||||
# Sanity checks
|
||||
forbidden_simple: str = "EDKVOSNMHPA"
|
||||
assert(len(allowed_simply) + len(allowed_regs) + len(allowed_fpr) + len(forbidden_simple) == len(FunctionType.values))
|
||||
assert(len(allowed_simply) + len(allowed_regs) + len(allowed_fpr) + len(forbidden_simple) == len(allowed_conv.values))
|
||||
assert(all(c not in allowed_regs for c in allowed_simply))
|
||||
assert(all(c not in allowed_simply + allowed_regs for c in allowed_fpr))
|
||||
assert(all(c not in allowed_simply + allowed_regs + allowed_fpr for c in forbidden_simple))
|
||||
assert(all(c in allowed_simply + allowed_regs + allowed_fpr + forbidden_simple for c in FunctionType.values))
|
||||
assert(all(c in allowed_simply + allowed_regs + allowed_fpr + forbidden_simple for c in allowed_conv.values))
|
||||
|
||||
def check_simple(v: FunctionType):
|
||||
def check_simple(v: FunctionType) -> Optional[int]:
|
||||
regs_count: int = 0
|
||||
fpr_count : int = 0
|
||||
|
||||
if v.get_convention() is not allowed_conv:
|
||||
return None
|
||||
if v[0] in forbidden_simple:
|
||||
return None
|
||||
for c in v[2:]:
|
||||
@@ -954,15 +993,21 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
|
||||
# Rewrite the wrapper.c file:
|
||||
# i and u should only be 32 bits
|
||||
# E v c w i I C W u U f d D K l L p V O S N M H P A
|
||||
td_types = ["x64emu_t*", "void", "int8_t", "int16_t", "int64_t", "int64_t", "uint8_t", "uint16_t", "uint64_t", "uint64_t", "float", "double", "long double", "double", "intptr_t", "uintptr_t", "void*", "void*", "int32_t", "void*", "...", "...", "unsigned __int128", "void*", "void*"]
|
||||
if len(FunctionType.values) != len(td_types):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(td_types) = {lentypes}".format(lenval=len(FunctionType.values), lentypes=len(td_types)))
|
||||
td_types = {
|
||||
# E v c w i I C W u U f d D K l L p V O S N M H P A
|
||||
'F': ["x64emu_t*", "void", "int8_t", "int16_t", "int64_t", "int64_t", "uint8_t", "uint16_t", "uint64_t", "uint64_t", "float", "double", "long double", "double", "intptr_t", "uintptr_t", "void*", "void*", "int32_t", "void*", "...", "...", "unsigned __int128", "void*", "void*"],
|
||||
# E v c w i I C W u U f d K l L p V O S N M P A
|
||||
'W': ["x64emu_t*", "void", "int8_t", "int16_t", "int64_t", "int64_t", "uint8_t", "uint16_t", "uint64_t", "uint64_t", "float", "double", "double", "intptr_t", "uintptr_t", "void*", "void*", "int32_t", "void*", "...", "...", "void*", "void*"]
|
||||
}
|
||||
assert(all(k in conventions for k in td_types))
|
||||
for k in conventions:
|
||||
if len(conventions[k].values) != len(td_types[k]):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(td_types) = {lentypes}".format(lenval=len(conventions[k].values), lentypes=len(td_types[k])))
|
||||
|
||||
def generate_typedefs(arr: Iterable[FunctionType], file) -> None:
|
||||
for v in arr:
|
||||
file.write("typedef " + td_types[FunctionType.values.index(v[0])] + " (*" + v + "_t)"
|
||||
+ "(" + ', '.join(td_types[FunctionType.values.index(t)] for t in v[2:]) + ");\n")
|
||||
file.write("typedef " + td_types[v.get_convention().ident][v.get_convention().values.index(v[0])] + " (*" + v + "_t)"
|
||||
+ "(" + ', '.join(td_types[v.get_convention().ident][v.get_convention().values.index(t)] for t in v[2:]) + ");\n")
|
||||
|
||||
with open(os.path.join(root, "src", "wrapped", "generated", "wrapper.c"), 'w') as file:
|
||||
file.write(files_header["wrapper.c"].format(lbr="{", rbr="}", version=ver))
|
||||
@@ -981,37 +1026,61 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
|
||||
# Helper variables
|
||||
# Return type template
|
||||
vals = [
|
||||
"\n#error Invalid return type: emulator\n", # E
|
||||
"fn({0});", # v
|
||||
"R_RAX=fn({0});", # c
|
||||
"R_RAX=fn({0});", # w
|
||||
"R_RAX=(int64_t)fn({0});", # i should be int32_t
|
||||
"R_RAX=(int64_t)fn({0});", # I
|
||||
"R_RAX=(unsigned char)fn({0});", # C
|
||||
"R_RAX=(unsigned short)fn({0});", # W
|
||||
"R_RAX=(uint64_t)fn({0});", # u should be uint32_t
|
||||
"R_RAX=fn({0});", # U
|
||||
"emu->xmm[0].f[0]=fn({0});", # f
|
||||
"emu->xmm[0].d[0]=fn({0});", # d
|
||||
"long double ld=fn({0}); fpu_do_push(emu); ST0val = ld;", # D
|
||||
"double db=fn({0}); fpu_do_push(emu); ST0val = db;", # K
|
||||
"R_RAX=(intptr_t)fn({0});", # l
|
||||
"R_RAX=(uintptr_t)fn({0});", # L
|
||||
"R_RAX=(uintptr_t)fn({0});", # p
|
||||
"\n#error Invalid return type: va_list\n", # V
|
||||
"\n#error Invalid return type: at_flags\n", # O
|
||||
"\n#error Invalid return type: _io_file*\n", # S
|
||||
"\n#error Invalid return type: ... with 1 arg\n", # N
|
||||
"\n#error Invalid return type: ... with 2 args\n", # M
|
||||
"unsigned __int128 u128 = fn({0}); R_RAX=(u128&0xFFFFFFFFFFFFFFFFL); R_RDX=(u128>>64)&0xFFFFFFFFFFFFFFFFL;", # H
|
||||
"\n#error Invalid return type: pointer in the stack\n", # P
|
||||
"\n#error Invalid return type: va_list\n", # A
|
||||
]
|
||||
vals = {
|
||||
conventions['F']: [
|
||||
"\n#error Invalid return type: emulator\n", # E
|
||||
"fn({0});", # v
|
||||
"R_RAX=fn({0});", # c
|
||||
"R_RAX=fn({0});", # w
|
||||
"R_RAX=(int64_t)fn({0});", # i should be int32_t
|
||||
"R_RAX=(int64_t)fn({0});", # I
|
||||
"R_RAX=(unsigned char)fn({0});", # C
|
||||
"R_RAX=(unsigned short)fn({0});", # W
|
||||
"R_RAX=(uint64_t)fn({0});", # u should be uint32_t
|
||||
"R_RAX=fn({0});", # U
|
||||
"emu->xmm[0].f[0]=fn({0});", # f
|
||||
"emu->xmm[0].d[0]=fn({0});", # d
|
||||
"long double ld=fn({0}); fpu_do_push(emu); ST0val = ld;", # D
|
||||
"double db=fn({0}); fpu_do_push(emu); ST0val = db;", # K
|
||||
"R_RAX=(intptr_t)fn({0});", # l
|
||||
"R_RAX=(uintptr_t)fn({0});", # L
|
||||
"R_RAX=(uintptr_t)fn({0});", # p
|
||||
"\n#error Invalid return type: va_list\n", # V
|
||||
"\n#error Invalid return type: at_flags\n", # O
|
||||
"\n#error Invalid return type: _io_file*\n", # S
|
||||
"\n#error Invalid return type: ... with 1 arg\n", # N
|
||||
"\n#error Invalid return type: ... with 2 args\n", # M
|
||||
"unsigned __int128 u128 = fn({0}); R_RAX=(u128&0xFFFFFFFFFFFFFFFFL); R_RDX=(u128>>64)&0xFFFFFFFFFFFFFFFFL;", # H
|
||||
"\n#error Invalid return type: pointer in the stack\n", # P
|
||||
"\n#error Invalid return type: va_list\n", # A
|
||||
],
|
||||
conventions['W']: [
|
||||
"\n#error Invalid return type: emulator\n", # E
|
||||
"fn({0});", # v
|
||||
"R_RAX=fn({0});", # c
|
||||
"R_RAX=fn({0});", # w
|
||||
"R_RAX=(int64_t)fn({0});", # i should be int32_t
|
||||
"R_RAX=(int64_t)fn({0});", # I
|
||||
"R_RAX=(unsigned char)fn({0});", # C
|
||||
"R_RAX=(unsigned short)fn({0});", # W
|
||||
"R_RAX=(uint64_t)fn({0});", # u should be uint32_t
|
||||
"R_RAX=fn({0});", # U
|
||||
"emu->xmm[0].f[0]=fn({0});", # f
|
||||
"emu->xmm[0].d[0]=fn({0});", # d
|
||||
"double db=fn({0}); fpu_do_push(emu); ST0val = db;", # K
|
||||
"R_RAX=(intptr_t)fn({0});", # l
|
||||
"R_RAX=(uintptr_t)fn({0});", # L
|
||||
"R_RAX=(uintptr_t)fn({0});", # p
|
||||
"\n#error Invalid return type: va_list\n", # V
|
||||
"\n#error Invalid return type: at_flags\n", # O
|
||||
"\n#error Invalid return type: _io_file*\n", # S
|
||||
"\n#error Invalid return type: ... with 1 arg\n", # N
|
||||
"\n#error Invalid return type: ... with 2 args\n", # M
|
||||
"\n#error Invalid return type: pointer in the stack\n", # P
|
||||
"\n#error Invalid return type: va_list\n", # A
|
||||
]
|
||||
}
|
||||
|
||||
# Name of the registers
|
||||
reg_arg = ["R_RDI", "R_RSI", "R_RDX", "R_RCX", "R_R8", "R_R9"]
|
||||
assert(len(reg_arg) == 6)
|
||||
# vreg: value is in a general register
|
||||
# E v c w i I C W u U f d D K l L p V O S N M H P A
|
||||
vreg = [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 2, 2, 0, 1]
|
||||
@@ -1132,26 +1201,35 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
"*(void**)(R_RSP + {p}), ", # P
|
||||
"*(void**)(R_RSP + {p}), ", # A
|
||||
]
|
||||
|
||||
|
||||
# Asserts
|
||||
if len(FunctionType.values) != len(vstack):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(vstack) = {lenvstack}".format(lenval=len(FunctionType.values), lenvstack=len(vstack)))
|
||||
if len(FunctionType.values) != len(vreg):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(vreg) = {lenvreg}".format(lenval=len(FunctionType.values), lenvreg=len(vreg)))
|
||||
if len(FunctionType.values) != len(vxmm):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(vxmm) = {lenvxmm}".format(lenval=len(FunctionType.values), lenvxmm=len(vxmm)))
|
||||
if len(FunctionType.values) != len(vother):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(vother) = {lenvother}".format(lenval=len(FunctionType.values), lenvother=len(vother)))
|
||||
if len(FunctionType.values) != len(arg_s):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(arg_s) = {lenargs}".format(lenval=len(FunctionType.values), lenargs=len(arg_s)))
|
||||
if len(FunctionType.values) != len(arg_r):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(arg_r) = {lenargr}".format(lenval=len(FunctionType.values), lenargr=len(arg_r)))
|
||||
if len(FunctionType.values) != len(arg_x):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(arg_x) = {lenargx}".format(lenval=len(FunctionType.values), lenargx=len(arg_x)))
|
||||
if len(FunctionType.values) != len(arg_o):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(arg_o) = {lenargo}".format(lenval=len(FunctionType.values), lenargo=len(arg_o)))
|
||||
if len(FunctionType.values) != len(vals):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(vals) = {lenvals}".format(lenval=len(FunctionType.values), lenvals=len(vals)))
|
||||
for k in conventions:
|
||||
assert all(v in conventions['F'].values for v in conventions[k].values), "a convention is not a subset of System V"
|
||||
assert all(vr == vs for (vr, vs) in zip(vreg, vstack) if vr != 0), "vreg and vstack are inconsistent"
|
||||
assert all(vx == vs for (vx, vs) in zip(vxmm, vstack) if vx != 0), "vxmm and vstack are inconsistent"
|
||||
assert all((vo == 0) == (vs != 0) for (vo, vs) in zip(vother, vstack)), "vother and vstack are inconsistent"
|
||||
if len(conventions['F'].values) != len(vstack):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(vstack) = {lenvstack}".format(lenval=len(conventions['F'].values), lenvstack=len(vstack)))
|
||||
if len(conventions['F'].values) != len(vreg):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(vreg) = {lenvreg}".format(lenval=len(conventions['F'].values), lenvreg=len(vreg)))
|
||||
if len(conventions['F'].values) != len(vxmm):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(vxmm) = {lenvxmm}".format(lenval=len(conventions['F'].values), lenvxmm=len(vxmm)))
|
||||
if len(conventions['F'].values) != len(vother):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(vother) = {lenvother}".format(lenval=len(conventions['F'].values), lenvother=len(vother)))
|
||||
if len(conventions['F'].values) != len(arg_s):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(arg_s) = {lenargs}".format(lenval=len(conventions['F'].values), lenargs=len(arg_s)))
|
||||
if len(conventions['F'].values) != len(arg_r):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(arg_r) = {lenargr}".format(lenval=len(conventions['F'].values), lenargr=len(arg_r)))
|
||||
if len(conventions['F'].values) != len(arg_x):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(arg_x) = {lenargx}".format(lenval=len(conventions['F'].values), lenargx=len(arg_x)))
|
||||
if len(conventions['F'].values) != len(arg_o):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(arg_o) = {lenargo}".format(lenval=len(conventions['F'].values), lenargo=len(arg_o)))
|
||||
for k in conventions:
|
||||
c = conventions[k]
|
||||
if c not in vals:
|
||||
raise NotImplementedError("[{k}]values not in vals".format(k=k, lenval=len(c.values), lenvals=len(vals[c])))
|
||||
if len(c.values) != len(vals[c]):
|
||||
raise NotImplementedError("len([{k}]values) = {lenval} != len(vals[...]) = {lenvals}".format(k=k, lenval=len(c.values), lenvals=len(vals[c])))
|
||||
# When arg_* is not empty, v* should not be 0
|
||||
if any(map(lambda v, a: (a != "") and (v == 0), vstack, arg_s)):
|
||||
raise NotImplementedError("Something in the stack has a null offset and a non-empty arg string")
|
||||
@@ -1172,7 +1250,8 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
raise NotImplementedError("Something can be in an XMM register but not in the stack")
|
||||
|
||||
# Helper functions to write the function definitions
|
||||
def function_args(args: FunctionType, d: int = 8, r: int = 0, x: int = 0) -> str:
|
||||
systemVconv = conventions['F']
|
||||
def function_args_systemV(args: FunctionType, d: int = 8, r: int = 0, x: int = 0) -> str:
|
||||
# args: string of argument types
|
||||
# d: delta (in the stack)
|
||||
# r: general register no
|
||||
@@ -1182,16 +1261,18 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
|
||||
# Redirections
|
||||
if args[0] == "0":
|
||||
return "0, " + function_args(args[1:], d, r, x)
|
||||
return "0, " + function_args_systemV(args[1:], d, r, x)
|
||||
elif args[0] == "1":
|
||||
return "1, " + function_args(args[1:], d, r, x)
|
||||
return "1, " + function_args_systemV(args[1:], d, r, x)
|
||||
|
||||
idx = FunctionType.values.index(args[0])
|
||||
if (r < 6) and (vreg[idx] > 0):
|
||||
idx = systemVconv.values.index(args[0])
|
||||
# Name of the registers
|
||||
reg_arg = ["R_RDI", "R_RSI", "R_RDX", "R_RCX", "R_R8", "R_R9"]
|
||||
if (r < len(reg_arg)) and (vreg[idx] > 0):
|
||||
ret = ""
|
||||
for _ in range(vreg[idx]):
|
||||
# There may be values in multiple registers
|
||||
if r < 6:
|
||||
if r < len(reg_arg):
|
||||
# Value is in a general register
|
||||
ret = ret + arg_r[idx].format(p=reg_arg[r])
|
||||
r = r + 1
|
||||
@@ -1199,23 +1280,59 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
# Remaining is in the stack
|
||||
ret = ret + arg_s[idx].format(p=d)
|
||||
d = d + 8
|
||||
return ret + function_args(args[1:], d, r, x)
|
||||
return ret + function_args_systemV(args[1:], d, r, x)
|
||||
elif (x < 8) and (vxmm[idx] > 0):
|
||||
# Value is in an XMM register
|
||||
return arg_x[idx].format(p=x) + function_args(args[1:], d, r, x+1)
|
||||
return arg_x[idx].format(p=x) + function_args_systemV(args[1:], d, r, x+1)
|
||||
elif vstack[idx] > 0:
|
||||
# Value is in the stack
|
||||
return arg_s[idx].format(p=d) + function_args(args[1:], d+8*vstack[idx], r, x)
|
||||
return arg_s[idx].format(p=d) + function_args_systemV(args[1:], d+8*vstack[idx], r, x)
|
||||
else:
|
||||
# Value is somewhere else
|
||||
return arg_o[idx].format(p=d) + function_args(args[1:], d, r, x)
|
||||
return arg_o[idx].format(p=d) + function_args_systemV(args[1:], d, r, x)
|
||||
# windowsconv = conventions['W']
|
||||
def function_args_windows(args: FunctionType, d: int = 40, r: int = 0) -> str:
|
||||
# args: string of argument types
|
||||
# d: delta (in the stack)
|
||||
# r: general register no
|
||||
# We can re-use vstack to know if we need to put a pointer or the value
|
||||
if len(args) == 0:
|
||||
return ""
|
||||
|
||||
# Redirections
|
||||
if args[0] == "0":
|
||||
return "0, " + function_args_windows(args[1:], d, r)
|
||||
elif args[0] == "1":
|
||||
return "1, " + function_args_windows(args[1:], d, r)
|
||||
|
||||
idx = systemVconv.values.index(args[0]) # Little hack to be able to re-use
|
||||
# Name of the registers
|
||||
reg_arg = ["R_RCX", "R_RDX", "R_R8", "R_R9"]
|
||||
if (r < len(reg_arg)) and (vstack[idx] == 1):
|
||||
# We use a register
|
||||
if vreg[idx] == 1:
|
||||
# Value is in a general register
|
||||
return arg_r[idx].format(p=reg_arg[r]) + function_args_windows(args[1:], d, r+1)
|
||||
else:
|
||||
# Remaining is in an XMM register
|
||||
return arg_x[idx].format(p=r) + function_args_windows(args[1:], d, r+1)
|
||||
elif vstack[idx] > 0:
|
||||
# Value is in the stack
|
||||
return arg_s[idx].format(p=d) + function_args_windows(args[1:], d+8*vstack[idx], r)
|
||||
else:
|
||||
# Value is somewhere else
|
||||
return arg_o[idx].format(p=d) + function_args_windows(args[1:], d, r)
|
||||
|
||||
def function_writer(f, N: FunctionType, W: str) -> None:
|
||||
# Write to f the function type N (real type W)
|
||||
|
||||
f.write("void {0}(x64emu_t *emu, uintptr_t fcn) {2} {1} fn = ({1})fcn; ".format(N, W, "{"))
|
||||
# Generic function
|
||||
f.write(vals[FunctionType.values.index(N[0])].format(function_args(N[2:])[:-2]) + " }\n")
|
||||
conv = N.get_convention()
|
||||
if conv is systemVconv:
|
||||
f.write(vals[conv][conv.values.index(N[0])].format(function_args_systemV(N[2:])[:-2]) + " }\n")
|
||||
else:
|
||||
f.write(vals[conv][conv.values.index(N[0])].format(function_args_windows(N[2:])[:-2]) + " }\n")
|
||||
|
||||
for k in gbls:
|
||||
if k != str(Clauses()):
|
||||
@@ -1273,13 +1390,15 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
file.write(files_guard["wrapper.h"].format(lbr="{", rbr="}", version=ver))
|
||||
|
||||
# Rewrite the *types.h files:
|
||||
td_types[FunctionType.values.index('A')] = "va_list"
|
||||
td_types[FunctionType.values.index('V')] = "..."
|
||||
orig_val_len = len(FunctionType.values)
|
||||
for k in conventions:
|
||||
td_types[k][conventions[k].values.index('A')] = "va_list"
|
||||
td_types[k][conventions[k].values.index('V')] = "..."
|
||||
orig_val_len = {k: len(conventions[k].values) for k in conventions}
|
||||
for fn in filesspec:
|
||||
for strc in fsp_tmp[fn][1]:
|
||||
FunctionType.values.append(strc)
|
||||
td_types.append(fsp_tmp[fn][1][strc][0])
|
||||
for k in conventions:
|
||||
conventions[k].values.append(strc)
|
||||
td_types[k].append(fsp_tmp[fn][1][strc][0])
|
||||
|
||||
with open(os.path.join(root, "src", "wrapped", "generated", fn + "types.h"), 'w') as file:
|
||||
file.write(files_header["fntypes.h"].format(lbr="{", rbr="}", version=ver, filename=fn))
|
||||
@@ -1303,8 +1422,9 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
file.write("#undef {defined}\n".format(defined=defined))
|
||||
file.write(files_guard["fnundefs.h"].format(lbr="{", rbr="}", version=ver, filename=fn))
|
||||
|
||||
FunctionType.values = FunctionType.values[:orig_val_len]
|
||||
td_types = td_types[:orig_val_len]
|
||||
for k in conventions:
|
||||
conventions[k].values = conventions[k].values[:orig_val_len[k]]
|
||||
td_types[k] = td_types[k][:orig_val_len[k]]
|
||||
|
||||
# Save the string for the next iteration, writing was successful
|
||||
with open(os.path.join(root, "src", "wrapped", "generated", "functions_list.txt"), 'w') as file:
|
||||
@@ -1318,6 +1438,6 @@ if __name__ == '__main__':
|
||||
if v == "--":
|
||||
limit.append(i)
|
||||
Define.defines = list(map(DefineType, sys.argv[2:limit[0]]))
|
||||
if main(sys.argv[1], sys.argv[limit[0]+1:], "2.1.0.16") != 0:
|
||||
if main(sys.argv[1], sys.argv[limit[0]+1:], "2.2.0.16") != 0:
|
||||
exit(2)
|
||||
exit(0)
|
||||
+79
-86
@@ -19,6 +19,8 @@
|
||||
#include "wrapper.h"
|
||||
#include "x64emu.h"
|
||||
#include "signals.h"
|
||||
#include "rcfile.h"
|
||||
#include "gltools.h"
|
||||
|
||||
EXPORTDYN
|
||||
void initAllHelpers(box64context_t* context)
|
||||
@@ -39,6 +41,7 @@ void finiAllHelpers(box64context_t* context)
|
||||
static int finied = 0;
|
||||
if(finied)
|
||||
return;
|
||||
DeleteParams();
|
||||
fini_pthread_helper(context);
|
||||
fini_signal_helper();
|
||||
fini_bridge_helper();
|
||||
@@ -63,8 +66,8 @@ void free_tlsdatasize(void* p)
|
||||
if(!p)
|
||||
return;
|
||||
tlsdatasize_t *data = (tlsdatasize_t*)p;
|
||||
free(data->tlsdata);
|
||||
free(p);
|
||||
box_free(data->ptr);
|
||||
box_free(p);
|
||||
}
|
||||
|
||||
void x64Syscall(x64emu_t *emu);
|
||||
@@ -73,14 +76,21 @@ int unlockMutex()
|
||||
{
|
||||
int ret = unlockCustommemMutex();
|
||||
int i;
|
||||
#ifdef DYNAREC
|
||||
uint32_t tid = (uint32_t)GetTID();
|
||||
#define GO(A, B) \
|
||||
i = (native_lock_storeifref2_d(&A, 0, tid)==tid); \
|
||||
if(i) { \
|
||||
ret|=(1<<B); \
|
||||
}
|
||||
#else
|
||||
#define GO(A, B) \
|
||||
i = checkUnlockMutex(&A); \
|
||||
if(i) { \
|
||||
ret|=(1<<B); \
|
||||
}
|
||||
#endif
|
||||
|
||||
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)
|
||||
@@ -100,10 +110,8 @@ void relockMutex(int locks)
|
||||
relockCustommemMutex(locks);
|
||||
#define GO(A, B) \
|
||||
if(locks&(1<<B)) \
|
||||
pthread_mutex_lock(&A); \
|
||||
mutex_trylock(&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)
|
||||
@@ -118,22 +126,24 @@ void relockMutex(int locks)
|
||||
|
||||
static void init_mutexes(box64context_t* context)
|
||||
{
|
||||
#ifndef DYNAREC
|
||||
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_trace, &attr);
|
||||
pthread_mutex_init(&context->mutex_tls, &attr);
|
||||
pthread_mutex_init(&context->mutex_thread, &attr);
|
||||
pthread_mutex_init(&context->mutex_bridge, &attr);
|
||||
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
#else
|
||||
native_lock_store(&context->mutex_trace, 0);
|
||||
native_lock_store(&context->mutex_tls, 0);
|
||||
native_lock_store(&context->mutex_thread, 0);
|
||||
native_lock_store(&context->mutex_bridge, 0);
|
||||
native_lock_store(&context->mutex_dyndump, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void atfork_child_box64context(void)
|
||||
@@ -142,6 +152,31 @@ static void atfork_child_box64context(void)
|
||||
init_mutexes(my_context);
|
||||
}
|
||||
|
||||
void freeCycleLog(box64context_t* ctx)
|
||||
{
|
||||
if(cycle_log) {
|
||||
for(int i=0; i<cycle_log; ++i) {
|
||||
box_free(ctx->log_call[i]);
|
||||
box_free(ctx->log_ret[i]);
|
||||
}
|
||||
box_free(ctx->log_call);
|
||||
box_free(ctx->log_ret);
|
||||
ctx->log_call = NULL;
|
||||
ctx->log_ret = NULL;
|
||||
}
|
||||
}
|
||||
void initCycleLog(box64context_t* context)
|
||||
{
|
||||
if(cycle_log) {
|
||||
context->log_call = (char**)box_calloc(cycle_log, sizeof(char*));
|
||||
context->log_ret = (char**)box_calloc(cycle_log, sizeof(char*));
|
||||
for(int i=0; i<cycle_log; ++i) {
|
||||
context->log_call[i] = (char*)box_calloc(256, 1);
|
||||
context->log_ret[i] = (char*)box_calloc(128, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
box64context_t *NewBox64Context(int argc)
|
||||
{
|
||||
@@ -152,7 +187,9 @@ box64context_t *NewBox64Context(int argc)
|
||||
}
|
||||
#endif
|
||||
// init and put default values
|
||||
box64context_t *context = my_context = (box64context_t*)calloc(1, sizeof(box64context_t));
|
||||
box64context_t *context = my_context = (box64context_t*)box_calloc(1, sizeof(box64context_t));
|
||||
|
||||
initCycleLog(context);
|
||||
|
||||
context->deferedInit = 1;
|
||||
context->sel_serial = 1;
|
||||
@@ -163,6 +200,8 @@ box64context_t *NewBox64Context(int argc)
|
||||
context->local_maplib = NewLibrarian(context, 1);
|
||||
context->versym = NewDictionnary();
|
||||
context->system = NewBridge();
|
||||
context->globaldefver = NewDefaultVersion();
|
||||
context->weakdefver = NewDefaultVersion();
|
||||
// create vsyscall
|
||||
context->vsyscall = AddBridge(context->system, vFEv, x64Syscall, 0, NULL);
|
||||
// create the vsyscalls
|
||||
@@ -178,7 +217,7 @@ box64context_t *NewBox64Context(int argc)
|
||||
context->dlprivate = NewDLPrivate();
|
||||
|
||||
context->argc = argc;
|
||||
context->argv = (char**)calloc(context->argc+1, sizeof(char*));
|
||||
context->argv = (char**)box_calloc(context->argc+1, sizeof(char*));
|
||||
|
||||
init_mutexes(context);
|
||||
pthread_atfork(NULL, NULL, atfork_child_box64context);
|
||||
@@ -195,6 +234,7 @@ box64context_t *NewBox64Context(int argc)
|
||||
return context;
|
||||
}
|
||||
|
||||
void freeALProcWrapper(box64context_t* context);
|
||||
EXPORTDYN
|
||||
void FreeBox64Context(box64context_t** context)
|
||||
{
|
||||
@@ -211,11 +251,13 @@ void FreeBox64Context(box64context_t** context)
|
||||
if(ctx->maplib)
|
||||
FreeLibrarian(&ctx->maplib, NULL);
|
||||
FreeDictionnary(&ctx->versym);
|
||||
FreeDefaultVersion(&ctx->globaldefver);
|
||||
FreeDefaultVersion(&ctx->weakdefver);
|
||||
|
||||
for(int i=0; i<ctx->elfsize; ++i) {
|
||||
FreeElfHeader(&ctx->elfs[i]);
|
||||
}
|
||||
free(ctx->elfs);
|
||||
box_free(ctx->elfs);
|
||||
|
||||
FreeCollection(&ctx->box64_path);
|
||||
FreeCollection(&ctx->box64_ld_lib);
|
||||
@@ -227,16 +269,16 @@ void FreeBox64Context(box64context_t** context)
|
||||
DeleteX64Trace(ctx);
|
||||
|
||||
if(ctx->deferedInitList)
|
||||
free(ctx->deferedInitList);
|
||||
box_free(ctx->deferedInitList);
|
||||
|
||||
free(ctx->argv);
|
||||
/*box_free(ctx->argv);*/
|
||||
|
||||
for (int i=0; i<ctx->envc; ++i)
|
||||
free(ctx->envv[i]);
|
||||
free(ctx->envv);
|
||||
/*for (int i=0; i<ctx->envc; ++i)
|
||||
box_free(ctx->envv[i]);
|
||||
box_free(ctx->envv);*/
|
||||
|
||||
if(ctx->atfork_sz) {
|
||||
free(ctx->atforks);
|
||||
box_free(ctx->atforks);
|
||||
ctx->atforks = NULL;
|
||||
ctx->atfork_sz = ctx->atfork_cap = 0;
|
||||
}
|
||||
@@ -252,8 +294,9 @@ void FreeBox64Context(box64context_t** context)
|
||||
|
||||
FreeDLPrivate(&ctx->dlprivate);
|
||||
|
||||
free(ctx->fullpath);
|
||||
free(ctx->box64path);
|
||||
box_free(ctx->fullpath);
|
||||
box_free(ctx->box64path);
|
||||
box_free(ctx->bashpath);
|
||||
|
||||
FreeBridge(&ctx->system);
|
||||
|
||||
@@ -261,7 +304,7 @@ void FreeBox64Context(box64context_t** context)
|
||||
freeALProcWrapper(ctx);
|
||||
|
||||
if(ctx->stack_clone)
|
||||
free(ctx->stack_clone);
|
||||
box_free(ctx->stack_clone);
|
||||
|
||||
|
||||
void* ptr;
|
||||
@@ -272,28 +315,27 @@ void FreeBox64Context(box64context_t** context)
|
||||
pthread_key_delete(ctx->tlskey);
|
||||
|
||||
if(ctx->tlsdata)
|
||||
free(ctx->tlsdata);
|
||||
box_free(ctx->tlsdata);
|
||||
|
||||
free_neededlib(&ctx->neededlibs);
|
||||
free_neededlib(ctx->neededlibs);
|
||||
ctx->neededlibs = NULL;
|
||||
|
||||
if(ctx->emu_sig)
|
||||
FreeX64Emu(&ctx->emu_sig);
|
||||
|
||||
finiAllHelpers(ctx);
|
||||
|
||||
pthread_mutex_destroy(&ctx->mutex_once);
|
||||
pthread_mutex_destroy(&ctx->mutex_once2);
|
||||
pthread_mutex_destroy(&ctx->mutex_trace);
|
||||
#ifndef DYNAREC
|
||||
pthread_mutex_destroy(&ctx->mutex_trace);
|
||||
pthread_mutex_destroy(&ctx->mutex_lock);
|
||||
#else
|
||||
pthread_mutex_destroy(&ctx->mutex_dyndump);
|
||||
#endif
|
||||
pthread_mutex_destroy(&ctx->mutex_tls);
|
||||
pthread_mutex_destroy(&ctx->mutex_thread);
|
||||
pthread_mutex_destroy(&ctx->mutex_bridge);
|
||||
#endif
|
||||
|
||||
free(ctx);
|
||||
freeCycleLog(ctx);
|
||||
|
||||
box_free(ctx);
|
||||
}
|
||||
|
||||
int AddElfHeader(box64context_t* ctx, elfheader_t* head) {
|
||||
@@ -301,7 +343,7 @@ int AddElfHeader(box64context_t* ctx, elfheader_t* head) {
|
||||
if(idx==ctx->elfcap) {
|
||||
// resize...
|
||||
ctx->elfcap += 16;
|
||||
ctx->elfs = (elfheader_t**)realloc(ctx->elfs, sizeof(elfheader_t*) * ctx->elfcap);
|
||||
ctx->elfs = (elfheader_t**)box_realloc(ctx->elfs, sizeof(elfheader_t*) * ctx->elfcap);
|
||||
}
|
||||
ctx->elfs[idx] = head;
|
||||
ctx->elfsize++;
|
||||
@@ -312,7 +354,7 @@ int AddElfHeader(box64context_t* ctx, elfheader_t* head) {
|
||||
int AddTLSPartition(box64context_t* context, int tlssize) {
|
||||
int oldsize = context->tlssize;
|
||||
context->tlssize += tlssize;
|
||||
context->tlsdata = realloc(context->tlsdata, context->tlssize);
|
||||
context->tlsdata = box_realloc(context->tlsdata, context->tlssize);
|
||||
memmove(context->tlsdata+tlssize, context->tlsdata, oldsize); // move to the top, using memmove as regions will probably overlap
|
||||
memset(context->tlsdata, 0, tlssize); // fill new space with 0 (not mandatory)
|
||||
// clean GS segment for current emu
|
||||
@@ -325,52 +367,3 @@ int AddTLSPartition(box64context_t* context, int tlssize) {
|
||||
return -context->tlssize; // negative offset
|
||||
}
|
||||
|
||||
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*));
|
||||
}
|
||||
needed->libs[needed->size++] = lib;
|
||||
}
|
||||
|
||||
void free_neededlib(needed_libs_t* needed)
|
||||
{
|
||||
if(!needed)
|
||||
return;
|
||||
needed->cap = 0;
|
||||
needed->size = 0;
|
||||
if(needed->libs)
|
||||
free(needed->libs);
|
||||
needed->libs = NULL;
|
||||
}
|
||||
|
||||
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 1
|
||||
#define BOX64_REVISION 8
|
||||
#define BOX64_MINOR 2
|
||||
#define BOX64_REVISION 2
|
||||
|
||||
#endif //__BOX64_VERSION_H_
|
||||
+706
-557
File diff suppressed because it is too large.
Load diff
@@ -24,6 +24,7 @@
|
||||
#define xR15 25
|
||||
#define xFlags 26
|
||||
#define xRIP 27
|
||||
#define xSavedSP 28
|
||||
// 32bits version
|
||||
#define wEAX xRAX
|
||||
#define wECX xRCX
|
||||
@@ -196,7 +197,7 @@
|
||||
|
||||
// ADR
|
||||
#define ADR_gen(immlo, immhi, Rd) ((immlo)<<29 | 0b10000<<24 | (immhi)<<5 | (Rd))
|
||||
#define ADR_S20(Rd, imm) EMIT(ADR_gen((imm)&3, ((imm)>>2)&0x7ffff, (Rd))
|
||||
#define ADR_S20(Rd, imm) EMIT(ADR_gen((imm)&3, ((imm)>>2)&0x7ffff, (Rd)))
|
||||
|
||||
// LDR
|
||||
#define LDR_gen(size, op1, imm9, op2, Rn, Rt) ((size)<<30 | 0b111<<27 | (op1)<<24 | 0b01<<22 | (imm9)<<12 | (op2)<<10 | (Rn)<<5 | (Rt))
|
||||
@@ -265,6 +266,13 @@
|
||||
#define STRH_U12(Rt, Rn, imm12) EMIT(ST_gen(0b01, 0b01, ((uint32_t)((imm12)>>1))&0xfff, Rn, Rt))
|
||||
#define STRxw_U12(Rt, Rn, imm12) EMIT(ST_gen((rex.w)?0b11:0b10, 0b01, ((uint32_t)((imm12)>>(2+rex.w)))&0xfff, Rn, Rt))
|
||||
|
||||
#define STU_gen(size, opc, imm9, Rn, Rt) ((size)<<30 | 0b111<<27 | (opc)<<22 | ((imm9)&0x1ff)<<12 | (Rn)<<5 | (Rt))
|
||||
#define STURx_I9(Rt, Rn, imm9) EMIT(STU_gen(0b11, 0b00, imm9, Rn, Rt))
|
||||
#define STURw_I9(Rt, Rn, imm9) EMIT(STU_gen(0b10, 0b00, imm9, Rn, Rt))
|
||||
#define STURxw_I9(Rt, Rn, imm9) EMIT(STU_gen((rex.w)?0b11:0b10, 0b00, imm9, Rn, Rt))
|
||||
#define STURH_I9(Rt, Rn, imm9) EMIT(STU_gen(0b01, 0b00, imm9, Rn, Rt))
|
||||
#define STURB_I9(Rt, Rn, imm9) EMIT(STU_gen(0b00, 0b00, imm9, Rn, Rt))
|
||||
|
||||
#define STR_REG_gen(size, Rm, option, S, Rn, Rt) ((size)<<30 | 0b111<<27 | 0b00<<22 | 1<<21 | (Rm)<<16 | (option)<<13 | (S)<<12 | (0b10)<<10 | (Rn)<<5 | (Rt))
|
||||
#define STRx_REG(Rt, Rn, Rm) EMIT(STR_REG_gen(0b11, Rm, 0b011, 0, Rn, Rt))
|
||||
#define STRx_REG_LSL3(Rt, Rn, Rm) EMIT(STR_REG_gen(0b11, Rm, 0b011, 1, Rn, Rt))
|
||||
@@ -280,23 +288,23 @@
|
||||
|
||||
#define LDPx_S7_postindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(1, 1, 0b01, (((uint32_t)(imm))>>3)&0x7f, Rt2, Rn, Rt))
|
||||
#define LDPw_S7_postindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(0, 1, 0b01, (((uint32_t)(imm))>>2)&0x7f, Rt2, Rn, Rt))
|
||||
#define LDPxw_S7_postindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(rex.w, 1, 0b01, (((uint32_t)(imm))>>(2+rex.w)), Rt2, Rn, Rt))
|
||||
#define LDPxw_S7_postindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(rex.w, 1, 0b01, (((uint32_t)(imm))>>(2+rex.w))&0x7f, Rt2, Rn, Rt))
|
||||
#define LDPx_S7_preindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(1, 1, 0b11, (((uint32_t)(imm))>>3)&0x7f, Rt2, Rn, Rt))
|
||||
#define LDPw_S7_preindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(0, 1, 0b11, (((uint32_t)(imm))>>2)&0x7f, Rt2, Rn, Rt))
|
||||
#define LDPxw_S7_preindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(rex.w, 1, 0b11, (((uint32_t)(imm))>>(2+rex.w)), Rt2, Rn, Rt))
|
||||
#define LDPxw_S7_preindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(rex.w, 1, 0b11, (((uint32_t)(imm))>>(2+rex.w))&0x7f, Rt2, Rn, Rt))
|
||||
#define LDPx_S7_offset(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(1, 1, 0b10, (((uint32_t)(imm))>>3)&0x7f, Rt2, Rn, Rt))
|
||||
#define LDPw_S7_offset(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(0, 1, 0b10, (((uint32_t)(imm))>>2)&0x7f, Rt2, Rn, Rt))
|
||||
#define LDPxw_S7_offset(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(rex.w, 1, 0b10, (((uint32_t)(imm))>>(2+rex.w)), Rt2, Rn, Rt))
|
||||
#define LDPxw_S7_offset(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(rex.w, 1, 0b10, (((uint32_t)(imm))>>(2+rex.w))&0x7f, Rt2, Rn, Rt))
|
||||
|
||||
#define STPx_S7_postindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(1, 0, 0b01, (((uint32_t)(imm))>>3)&0x7f, Rt2, Rn, Rt))
|
||||
#define STPw_S7_postindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(0, 0, 0b01, (((uint32_t)(imm))>>2)&0x7f, Rt2, Rn, Rt))
|
||||
#define STPxw_S7_postindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(rex.w, 0, 0b01, (((uint32_t)(imm))>>(2+rex.w)), Rt2, Rn, Rt))
|
||||
#define STPxw_S7_postindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(rex.w, 0, 0b01, (((uint32_t)(imm))>>(2+rex.w))&0x7f, Rt2, Rn, Rt))
|
||||
#define STPx_S7_preindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(1, 0, 0b11, (((uint32_t)(imm))>>3)&0x7f, Rt2, Rn, Rt))
|
||||
#define STPw_S7_preindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(0, 0, 0b11, (((uint32_t)(imm))>>2)&0x7f, Rt2, Rn, Rt))
|
||||
#define STPxw_S7_preindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(rex.w, 0, 0b11, (((uint32_t)(imm))>>(2+rex.w)), Rt2, Rn, Rt))
|
||||
#define STPxw_S7_preindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(rex.w, 0, 0b11, (((uint32_t)(imm))>>(2+rex.w))&0x7f, Rt2, Rn, Rt))
|
||||
#define STPx_S7_offset(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(1, 0, 0b10, (((uint32_t)(imm))>>3)&0x7f, Rt2, Rn, Rt))
|
||||
#define STPw_S7_offset(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(0, 0, 0b10, (((uint32_t)(imm))>>2)&0x7f, Rt2, Rn, Rt))
|
||||
#define STPxw_S7_offset(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(rex.w, 0, 0b10, (((uint32_t)(imm))>>(2+rex.w)), Rt2, Rn, Rt))
|
||||
#define STPxw_S7_offset(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(rex.w, 0, 0b10, (((uint32_t)(imm))>>(2+rex.w))&0x7f, Rt2, Rn, Rt))
|
||||
|
||||
// PUSH / POP helper
|
||||
#define POP1(reg) LDRx_S9_postindex(reg, xRSP, 8)
|
||||
@@ -359,6 +367,10 @@
|
||||
#define DMB_gen(CRm) (0b1101010100<<22 | 0b011<<16 | 0b0011<<12 | (CRm)<<8 | 1<<7 | 0b01<<5 | 0b11111)
|
||||
#define DMB_ISH() EMIT(DMB_gen(0b1011))
|
||||
|
||||
// Break
|
||||
#define BRK_gen(imm16) (0b11010100<<24 | 0b001<<21 | (((imm16)&0xffff)<<5))
|
||||
#define BRK(imm16) EMIT(BRK_gen(imm16))
|
||||
|
||||
// BR and Branches
|
||||
#define BR_gen(Z, op, A, M, Rn, Rm) (0b1101011<<25 | (Z)<<24 | (op)<<21 | 0b11111<<16 | (A)<<11 | (M)<<10 | (Rn)<<5 | (Rm))
|
||||
#define BR(Rn) EMIT(BR_gen(0, 0b00, 0, 0, Rn, 0))
|
||||
@@ -644,6 +656,10 @@
|
||||
#define REV16w(Rd, Rn) EMIT(REV_gen(0, 0b01, Rn, Rd))
|
||||
#define REV16x(Rd, Rn) EMIT(REV_gen(1, 0b01, Rn, Rd))
|
||||
|
||||
// UDF
|
||||
#define UDF_gen(imm16) ((imm16)&0xffff)
|
||||
#define UDF(imm16) EMIT(UDF_gen(imm16))
|
||||
|
||||
// MRS
|
||||
#define MRS_gen(L, o0, op1, CRn, CRm, op2, Rt) (0b1101010100<<22 | (L)<<21 | 1<<20 | (o0)<<19 | (op1)<<16 | (CRn)<<12 | (CRm)<<8 | (op2)<<5 | (Rt))
|
||||
// mrs x0, nzcv : 1101010100 1 1 1 011 0100 0010 000 00000 o0=1(op0=3), op1=0b011(3) CRn=0b0100(4) CRm=0b0010(2) op2=0
|
||||
@@ -679,7 +695,9 @@
|
||||
|
||||
// VLDR
|
||||
#define VMEM_gen(size, opc, imm12, Rn, Rt) ((size)<<30 | 0b111<<27 | 1<<26 | 0b01<<24 | (opc)<<22 | (imm12)<<10 | (Rn)<<5 | (Rt))
|
||||
// imm14 must be 3-aligned
|
||||
// imm13 must be 1-aligned
|
||||
#define VLDR16_U12(Ht, Rn, imm13) EMIT(VMEM_gen(0b01, 0b01, ((uint32_t)((imm13)>>1))&0xfff, Rn, Ht))
|
||||
// imm14 must be 2-aligned
|
||||
#define VLDR32_U12(Dt, Rn, imm14) EMIT(VMEM_gen(0b10, 0b01, ((uint32_t)((imm14)>>2))&0xfff, Rn, Dt))
|
||||
// imm15 must be 3-aligned
|
||||
#define VLDR64_U12(Dt, Rn, imm15) EMIT(VMEM_gen(0b11, 0b01, ((uint32_t)((imm15)>>3))&0xfff, Rn, Dt))
|
||||
@@ -691,22 +709,22 @@
|
||||
#define VSTR64_U12(Dt, Rn, imm15) EMIT(VMEM_gen(0b11, 0b00, ((uint32_t)(imm15>>3))&0xfff, Rn, Dt))
|
||||
// imm16 must be 4-aligned
|
||||
#define VSTR128_U12(Qt, Rn, imm16) EMIT(VMEM_gen(0b00, 0b10, ((uint32_t)((imm16)>>4))&0xfff, Rn, Qt))
|
||||
// (imm14) must be 1-aligned
|
||||
#define VSTR16_U12(Ht, Rn, imm14) EMIT(VMEM_gen(0b01, 0b00, ((uint32_t)(imm14>>1))&0xfff, Rn, Ht))
|
||||
// (imm13) must be 1-aligned
|
||||
#define VSTR16_U12(Ht, Rn, imm13) EMIT(VMEM_gen(0b01, 0b00, ((uint32_t)(imm13>>1))&0xfff, Rn, Ht))
|
||||
|
||||
#define VMEMUR_vector(size, opc, imm9, Rn, Rt) ((size)<<30 | 0b111<<27 | 1<<26 | (opc)<<22 | (imm9)<<12 | (Rn)<<5 | (Rt))
|
||||
// signed offset, no alignement!
|
||||
#define VLDR8_I9(Vt, Rn, imm9) EMIT(VMEMUR(0b00, 0b01, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VLDR16_I9(Vt, Rn, imm9) EMIT(VMEMUR(0b01, 0b01, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VLDR32_I9(Vt, Rn, imm9) EMIT(VMEMUR(0b10, 0b01, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VLDR64_I9(Vt, Rn, imm9) EMIT(VMEMUR(0b11, 0b01, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VLDR128_I9(Vt, Rn, imm9) EMIT(VMEMUR(0b00, 0b11, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VLDR8_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b00, 0b01, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VLDR16_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b01, 0b01, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VLDR32_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b10, 0b01, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VLDR64_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b11, 0b01, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VLDR128_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b00, 0b11, (imm9)&0b111111111, Rn, Vt))
|
||||
// signed offset, no alignement!
|
||||
#define VSTR8_I9(Vt, Rn, imm9) EMIT(VMEMUR(0b00, 0b00, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VSTR16_I9(Vt, Rn, imm9) EMIT(VMEMUR(0b01, 0b00, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VSTR32_I9(Vt, Rn, imm9) EMIT(VMEMUR(0b10, 0b00, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VSTR64_I9(Vt, Rn, imm9) EMIT(VMEMUR(0b11, 0b00, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VSTR128_I9(Vt, Rn, imm9) EMIT(VMEMUR(0b00, 0b10, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VSTR8_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b00, 0b00, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VSTR16_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b01, 0b00, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VSTR32_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b10, 0b00, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VSTR64_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b11, 0b00, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VSTR128_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b00, 0b10, (imm9)&0b111111111, Rn, Vt))
|
||||
|
||||
#define VMEMW_gen(size, opc, imm9, op2, Rn, Rt) ((size)<<30 | 0b111<<27 | 1<<26 | (opc)<<22 | (imm9)<<12 | (op2)<<10 | 0b01<<10 | (Rn)<<5 | (Rt))
|
||||
#define VLDR64_S9_postindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b01, (imm9)&0x1ff, 0b01, Rn, Rt))
|
||||
@@ -721,18 +739,18 @@
|
||||
#define VMEM_REG_gen(size, opc, Rm, option, S, Rn, Rt) ((size)<<30 | 0b111<<27 | 1<<26 | (opc)<<22 | 1<<21 | (Rm)<<16 | (option)<<13 | (S)<<12 | 0b10<<10 | (Rn)<<5 | (Rt))
|
||||
|
||||
#define VLDR32_REG(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b10, 0b01, Rm, 0b011, 0, Rn, Dt))
|
||||
#define VLDR32_REG_LSL3(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b10, 0b01, Rm, 0b011, 1, Rn, Dt))
|
||||
#define VLDR32_REG_LSL2(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b10, 0b01, Rm, 0b011, 1, Rn, Dt))
|
||||
#define VLDR64_REG(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b11, 0b01, Rm, 0b011, 0, Rn, Dt))
|
||||
#define VLDR64_REG_LSL3(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b11, 0b01, Rm, 0b011, 1, Rn, Dt))
|
||||
#define VLDR128_REG(Qt, Rn, Rm) EMIT(VMEM_REG_gen(0b00, 0b11, Rm, 0b011, 0, Rn, Dt))
|
||||
#define VLDR128_REG_LSL4(Qt, Rn, Rm) EMIT(VMEM_REG_gen(0b00, 0b11, Rm, 0b011, 1, Rn, Dt))
|
||||
#define VLDR128_REG(Qt, Rn, Rm) EMIT(VMEM_REG_gen(0b00, 0b11, Rm, 0b011, 0, Rn, Qt))
|
||||
#define VLDR128_REG_LSL4(Qt, Rn, Rm) EMIT(VMEM_REG_gen(0b00, 0b11, Rm, 0b011, 1, Rn, Qt))
|
||||
|
||||
#define VSTR32_REG(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b10, 0b00, Rm, 0b011, 0, Rn, Dt))
|
||||
#define VSTR32_REG_LSL3(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b10, 0b00, Rm, 0b011, 1, Rn, Dt))
|
||||
#define VSTR32_REG_LSL2(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b10, 0b00, Rm, 0b011, 1, Rn, Dt))
|
||||
#define VSTR64_REG(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b11, 0b00, Rm, 0b011, 0, Rn, Dt))
|
||||
#define VSTR64_REG_LSL3(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b11, 0b00, Rm, 0b011, 1, Rn, Dt))
|
||||
#define VSTR128_REG(Qt, Rn, Rm) EMIT(VMEM_REG_gen(0b00, 0b10, Rm, 0b011, 0, Rn, Dt))
|
||||
#define VSTR128_REG_LSL4(Qt, Rn, Rm) EMIT(VMEM_REG_gen(0b00, 0b10, Rm, 0b011, 1, Rn, Dt))
|
||||
#define VSTR128_REG(Qt, Rn, Rm) EMIT(VMEM_REG_gen(0b00, 0b10, Rm, 0b011, 0, Rn, Qt))
|
||||
#define VSTR128_REG_LSL4(Qt, Rn, Rm) EMIT(VMEM_REG_gen(0b00, 0b10, Rm, 0b011, 1, Rn, Qt))
|
||||
|
||||
#define VLDR_PC_gen(opc, imm19, Rt) ((opc)<<30 | 0b011<<27 | 1<<26 | (imm19)<<5 | (Rt))
|
||||
#define VLDR32_literal(Vt, imm19) EMIT(VLDR_PC_gen(0b00, ((imm19)>>2)&0x7FFFF, Vt))
|
||||
@@ -1224,7 +1242,9 @@
|
||||
#define SCVTFDx(Dd, Xn) EMIT(SCVTF_scalar(1, 0b01, 0b00, 0b010, Xn, Dd))
|
||||
|
||||
#define SCVTF_vector_scalar(U, sz, Rn, Rd) (1<<30 | (U)<<29 | 0b11110<<24 | (sz)<<22 | 0b10000<<17 | 0b11101<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
// Convert Vn from i32 to Vd float
|
||||
#define SCVTFSS(Vd, Vn) EMIT(SCVTF_vector_scalar(0, 0, Vn, Vd))
|
||||
// Convert Vn from i64 to Vd double
|
||||
#define SCVTFDD(Vd, Vn) EMIT(SCVTF_vector_scalar(0, 1, Vn, Vd))
|
||||
|
||||
#define SCVTF_vector(Q, U, sz, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b01110<<24 | (sz)<<22 | 0b10000<<17 | 0b11101<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
@@ -1239,6 +1259,11 @@
|
||||
#define VFRINTISQ(Vd,Vn) EMIT(FRINT_vector(1, 1, 1, 0, 1, Vn, Vd))
|
||||
#define VFRINTIDQ(Vd,Vn) EMIT(FRINT_vector(1, 1, 1, 1, 1, Vn, Vd))
|
||||
|
||||
#define FRINTI_scalar(type, Rn, Rd) (0b11110<<24 | (type)<<22 | 1<<21 | 0b001<<18 | 0b111<<15 | 0b10000<<10 | (Rn)<<5 | (Rd))
|
||||
#define FRINTIS(Sd, Sn) EMIT(FRINTI_scalar(0b00, Sn, Sd))
|
||||
#define FRINTID(Dd, Dn) EMIT(FRINTI_scalar(0b01, Dn, Dd))
|
||||
|
||||
|
||||
#define FRINTxx_scalar(type, op, Rn, Rd) (0b11110<<24 | (type)<<22 | 1<<21 | 0b0100<<17 | (op)<<15 | 0b10000<<10 | (Rn)<<5 | (Rd))
|
||||
#define FRINT32ZS(Sd, Sn) EMIT(FRINTxx_scalar(0b00, 0b00, Sn, Sd))
|
||||
#define FRINT32ZD(Dd, Dn) EMIT(FRINTxx_scalar(0b01, 0b00, Dn, Dd))
|
||||
@@ -1340,13 +1365,13 @@
|
||||
//Use Rm[] to pick from Rn, Rn+1, Rn+2, Rn+3 element and store in Rd. Out-of-range element gets 0
|
||||
#define VTBLQ4_8(Rd, Rn, Rm) EMIT(TBL_gen(1, Rm, 0b11, 0, Rn, Rd))
|
||||
//Use Rm[] to pick from Rn element and store in Rd. Out-of-range element stay untouched
|
||||
#define VTBXQ1_8(Rd, Rn, Rm) EMIT(TBL_gen(1, Rm, 0b00, 0, Rn, Rd))
|
||||
#define VTBXQ1_8(Rd, Rn, Rm) EMIT(TBL_gen(1, Rm, 0b00, 1, Rn, Rd))
|
||||
//Use Rm[] to pick from Rn, Rn+1 element and store in Rd. Out-of-range element stay untouched
|
||||
#define VTBXQ2_8(Rd, Rn, Rm) EMIT(TBL_gen(1, Rm, 0b01, 0, Rn, Rd))
|
||||
#define VTBXQ2_8(Rd, Rn, Rm) EMIT(TBL_gen(1, Rm, 0b01, 1, Rn, Rd))
|
||||
//Use Rm[] to pick from Rn, Rn+1, Rn+2 element and store in Rd. Out-of-range element stay untouched
|
||||
#define VTBXQ3_8(Rd, Rn, Rm) EMIT(TBL_gen(1, Rm, 0b10, 0, Rn, Rd))
|
||||
#define VTBXQ3_8(Rd, Rn, Rm) EMIT(TBL_gen(1, Rm, 0b10, 1, Rn, Rd))
|
||||
//Use Rm[] to pick from Rn, Rn+1, Rn+2, Rn+3 element and store in Rd. Out-of-range element stay untouched
|
||||
#define VTBXQ4_8(Rd, Rn, Rm) EMIT(TBL_gen(1, Rm, 0b11, 0, Rn, Rd))
|
||||
#define VTBXQ4_8(Rd, Rn, Rm) EMIT(TBL_gen(1, Rm, 0b11, 1, Rn, Rd))
|
||||
|
||||
// TRN
|
||||
#define TRN_gen(Q, size, Rm, op, Rn, Rd) ((Q)<<30 | 0b001110<<24 | (size)<<22 | (Rm)<<16 | (op)<<14 | 0b10<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
@@ -1760,7 +1785,7 @@
|
||||
#define SQDMULHQ_16(Vd, Vn, Vm) EMIT(QDMULH_vector(1, 0, 0b01, Vm, Vn, Vd))
|
||||
#define SQDMULHQ_32(Vd, Vn, Vm) EMIT(QDMULH_vector(1, 0, 0b10, Vm, Vn, Vd))
|
||||
|
||||
// AES extensions
|
||||
// AES extension
|
||||
#define AES_gen(D, Rn, Rd) (0b01001110<<24 | 0b00<<22 | 0b10100<<17 | 0b0010<<13 | (D)<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
#define AESD(Vd, Vn) EMIT(AES_gen(1, Vn, Vd))
|
||||
#define AESE(Vd, Vn) EMIT(AES_gen(0, Vn, Vd))
|
||||
@@ -1769,4 +1794,11 @@
|
||||
#define AESIMC(Vd, Vn) EMIT(AESMC_gen(1, Vn, Vd))
|
||||
#define AESMC(Vd, Vn) EMIT(AESMC_gen(0, Vn, Vd))
|
||||
|
||||
// PMULL extension is PMULL_128
|
||||
#define PMULL_gen(Q, size, Rm, Rn, Rd) (0<<31 | (Q)<<30 | 0b001110<<24 | (size)<<22 | 1<<21 | (Rm)<<16 | 0b1110<<12 | (Rn)<<5 | (Rd))
|
||||
#define PMULL(Rd, Rn, Rm) EMIT(PMULL_gen(0, 0b00, Rm, Rn, Rd))
|
||||
#define PMULL2(Rd, Rn, Rm) EMIT(PMULL_gen(1, 0b00, Rm, Rn, Rd))
|
||||
#define PMULL_128(Rd, Rn, Rm) EMIT(PMULL_gen(0, 0b11, Rm, Rn, Rd))
|
||||
#define PMULL2_128(Rd, Rn, Rm) EMIT(PMULL_gen(1, 0b11, Rm, Rn, Rd))
|
||||
|
||||
#endif //__ARM64_EMITTER_H__
|
||||
@@ -19,18 +19,19 @@ arm64_epilog:
|
||||
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
|
||||
add sp, x28, 0
|
||||
//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 x27, x28, [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
|
||||
ldp x30, x29, [sp], 16 // saved lr
|
||||
//end, return...
|
||||
ret
|
||||
|
||||
@@ -38,17 +39,18 @@ arm64_epilog:
|
||||
.global arm64_epilog_fast
|
||||
arm64_epilog_fast:
|
||||
//restore all used register
|
||||
add sp, x28, 0
|
||||
//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 x27, x28, [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
|
||||
ldp x30, x29, [sp], 16 // saved lr
|
||||
//end, return...
|
||||
ret
|
||||
+119
-16
@@ -16,9 +16,17 @@
|
||||
.global arm64_lock_read_dq
|
||||
.global arm64_lock_write_dq
|
||||
.global arm64_lock_xchg
|
||||
.global arm64_lock_xchg_d
|
||||
.global arm64_lock_storeifnull
|
||||
.global arm64_lock_storeifnull_d
|
||||
.global arm64_lock_storeifref
|
||||
|
||||
.global arm64_lock_storeifref_d
|
||||
.global arm64_lock_storeifref2_d
|
||||
.global arm64_lock_decifnot0b
|
||||
.global arm64_lock_storeb
|
||||
.global arm64_lock_incif0
|
||||
.global arm64_lock_decifnot0
|
||||
.global arm64_lock_store
|
||||
|
||||
arm64_lock_read_b:
|
||||
dmb ish
|
||||
@@ -96,36 +104,131 @@ arm64_lock_xchg_0:
|
||||
ldaxr x2, [x0]
|
||||
stlxr w3, x1, [x0]
|
||||
cbnz w3, arm64_lock_xchg_0
|
||||
dmb ish
|
||||
mov x0, x2
|
||||
ret
|
||||
|
||||
arm64_lock_xchg_d:
|
||||
dmb ish
|
||||
arm64_lock_xchg_d_0:
|
||||
// address is x0, value is x1, return old value in x0
|
||||
ldaxr w2, [x0]
|
||||
stlxr w3, w1, [x0]
|
||||
cbnz w3, arm64_lock_xchg_d_0
|
||||
mov w0, w2
|
||||
ret
|
||||
|
||||
arm64_lock_storeifnull:
|
||||
dmb ish
|
||||
arm64_lock_storeifnull_0:
|
||||
// address is x0, value is x1, x1 store to x0 only if [x0] is 0. return new [x0] value (so x1 or old value)
|
||||
1:
|
||||
// address is x0, value is x1, x1 store to x0 only if [x0] is 0. return old [x0] value
|
||||
ldaxr x2, [x0]
|
||||
cbnz x2, arm64_lock_storeifnull_exit
|
||||
mov x2, x1
|
||||
stlxr w3, x2, [x0]
|
||||
cbnz w3, arm64_lock_storeifnull_0
|
||||
arm64_lock_storeifnull_exit:
|
||||
dmb ish
|
||||
cbnz x2, 2f
|
||||
stlxr w3, x1, [x0]
|
||||
cbnz w3, 1b
|
||||
2:
|
||||
mov x0, x2
|
||||
ret
|
||||
|
||||
arm64_lock_storeifnull_d:
|
||||
dmb ish
|
||||
1:
|
||||
// address is x0, value is w1, w1 store to x0 only if [x0] is 0. return old [x0] value
|
||||
ldaxr w2, [x0]
|
||||
cbnz w2, 2f
|
||||
stlxr w3, w1, [x0]
|
||||
cbnz w3, 1b
|
||||
2:
|
||||
dmb ish
|
||||
mov w0, w2
|
||||
ret
|
||||
|
||||
arm64_lock_storeifref:
|
||||
dmb ish
|
||||
arm64_lock_storeifref_0:
|
||||
// address is x0, value is x1, x1 store to x0 only if [x0] is x3. return new [x0] value (so x1 or old value)
|
||||
1:
|
||||
// address is x0, value is x1, x1 store to x0 only if [x0] is x2. return new [x0] value (so x1 or old value)
|
||||
ldaxr x3, [x0]
|
||||
cmp x2, x3
|
||||
bne arm64_lock_storeifref_exit
|
||||
bne 2f
|
||||
stlxr w4, x1, [x0]
|
||||
cbnz w4, arm64_lock_storeifref_0
|
||||
cbnz w4, 1b
|
||||
mov x0, x1
|
||||
ret
|
||||
arm64_lock_storeifref_exit:
|
||||
dmb ish
|
||||
2:
|
||||
mov x0, x3
|
||||
ret
|
||||
|
||||
arm64_lock_storeifref_d:
|
||||
dmb ish
|
||||
1:
|
||||
// address is x0, value is w1, w1 store to x0 only if [x0] is w2. return new [x0] value (so x1 or old value)
|
||||
ldaxr w3, [x0]
|
||||
cmp w2, w3
|
||||
bne 2f
|
||||
stlxr w4, w1, [x0]
|
||||
cbnz w4, 1b
|
||||
mov w0, w1
|
||||
ret
|
||||
2:
|
||||
mov w0, w3
|
||||
ret
|
||||
|
||||
arm64_lock_storeifref2_d:
|
||||
dmb ish
|
||||
1:
|
||||
// address is x0, value is w1, w1 store to x0 only if [x0] is w2. return old [x0] value
|
||||
ldaxr w3, [x0]
|
||||
cmp w2, w3
|
||||
bne 2f
|
||||
stlxr w4, w1, [x0]
|
||||
cbnz w4, 1b
|
||||
2:
|
||||
mov w0, w3
|
||||
ret
|
||||
|
||||
arm64_lock_decifnot0b:
|
||||
dmb ish
|
||||
1:
|
||||
ldaxrb w1, [x0]
|
||||
cmp w1, #0
|
||||
beq 2f
|
||||
sub w1, w1, #1
|
||||
stlxrb w2, w1, [x0]
|
||||
cbnz w2, 1b
|
||||
2:
|
||||
ret
|
||||
|
||||
arm64_lock_storeb:
|
||||
strb w1, [x0]
|
||||
dmb ish
|
||||
ret
|
||||
|
||||
arm64_lock_decifnot0:
|
||||
dmb ish
|
||||
1:
|
||||
ldaxr w1, [x0]
|
||||
cmp w1, #0
|
||||
beq 2f
|
||||
sub w3, w1, #1
|
||||
stlxr w2, w3, [x0]
|
||||
cbnz w2, 1b
|
||||
2:
|
||||
mov w0, w1
|
||||
ret
|
||||
|
||||
arm64_lock_incif0:
|
||||
dmb ish
|
||||
1:
|
||||
ldaxr w1, [x0]
|
||||
cmp w1, #0
|
||||
bne 2f
|
||||
add w3, w1, #1
|
||||
stlxr w2, w3, [x0]
|
||||
cbnz w2, 1b
|
||||
2:
|
||||
mov w0, w1
|
||||
ret
|
||||
|
||||
arm64_lock_store:
|
||||
str w1, [x0]
|
||||
dmb ish
|
||||
ret
|
||||
@@ -30,10 +30,37 @@ 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)
|
||||
// Atomicaly exchange value at [p] with val, return old p
|
||||
extern uint32_t arm64_lock_xchg_d(void* p, uint32_t val);
|
||||
|
||||
// Atomicaly store value to [p] only if [p] is NULL. Return old [p] value
|
||||
extern uint32_t arm64_lock_storeifnull_d(void*p, uint32_t val);
|
||||
|
||||
// Atomicaly store value to [p] only if [p] is NULL. Return old [p] value
|
||||
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);
|
||||
|
||||
// Atomicaly store value to [p] only if [p] is ref. Return new [p] value (so val or old)
|
||||
extern uint32_t arm64_lock_storeifref_d(void*p, uint32_t val, uint32_t ref);
|
||||
|
||||
// Atomicaly store value to [p] only if [p] is ref. Return new [p] value (so val or old)
|
||||
extern uint32_t arm64_lock_storeifref2_d(void*p, uint32_t val, uint32_t ref);
|
||||
|
||||
// decrement atomicaly the byte at [p] (but only if p not 0)
|
||||
extern void arm64_lock_decifnot0b(void*p);
|
||||
|
||||
// atomic store (with memory barrier)
|
||||
extern void arm64_lock_storeb(void*p, uint8_t b);
|
||||
|
||||
// increment atomicaly the int at [p] only if it was 0. Return the old value of [p]
|
||||
extern int arm64_lock_incif0(void*p);
|
||||
|
||||
// decrement atomicaly the int at [p] (but only if p not 0)
|
||||
extern int arm64_lock_decifnot0(void*p);
|
||||
|
||||
// atomic store (with memory barrier)
|
||||
extern void arm64_lock_store(void*p, uint32_t v);
|
||||
|
||||
#endif //__ARM64_LOCK__H__
|
||||
@@ -9,6 +9,8 @@
|
||||
.extern LinkNext
|
||||
|
||||
.global arm64_next
|
||||
|
||||
.8byte 0 // NULL pointer before arm64_next, for getDB
|
||||
arm64_next:
|
||||
// emu is r0
|
||||
// IP address is r1
|
||||
@@ -20,7 +22,7 @@ arm64_next:
|
||||
stp x16, x17, [sp, (8 * 8)]
|
||||
stp x18, x27, [sp, (8 * 10)] // also save x27(rip) to allow change in LinkNext
|
||||
|
||||
mov x2, lr // "from" is in lr, so put in x2
|
||||
mov x2, x30 // "from" is in lr, so put in x2
|
||||
add x3, sp, 8*11 // x3 is address to change rip
|
||||
// call the function
|
||||
bl LinkNext
|
||||
|
||||
@@ -25,7 +25,7 @@ typedef struct arm64_print_s {
|
||||
|
||||
uint64_t DecodeBitMasks(int N, int imms, int immr)
|
||||
{
|
||||
int len = 31-__builtin_clz(N<<6 | ((~imms)&0b111111));
|
||||
int len = 31-__builtin_clz((N<<6) | ((~imms)&0b111111));
|
||||
if(len<1) return 0;
|
||||
int levels = (1<<len) - 1;
|
||||
int s = imms & levels;
|
||||
@@ -776,7 +776,7 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "10011011U10mmmmm011111nnnnnddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%cMULH %s, %s, %s", a.U?'U':'S', Xt[Rd], Wt[Rn], Wt[Rm]);
|
||||
snprintf(buff, sizeof(buff), "%cMULH %s, %s, %s", a.U?'U':'S', Xt[Rd], Xt[Rn], Xt[Rm]);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "f0011011000mmmmm0aaaaannnnnddddd", &a)) {
|
||||
@@ -1140,8 +1140,8 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
else if(sf==0 && type==0 && rmode==0 && opcd==6) {snprintf(buff, sizeof(buff), "FMOV %s, S%d", Wt[Rn], Rd);}
|
||||
else if(sf==1 && type==1 && rmode==0 && opcd==7) {snprintf(buff, sizeof(buff), "FMOV D%d, %s", Rd, Xt[Rn]);}
|
||||
else if(sf==1 && type==2 && rmode==1 && opcd==7) {snprintf(buff, sizeof(buff), "FMOV V%d.D[1], %s", Rd, Xt[Rn]);}
|
||||
else if(sf==1 && type==1 && rmode==0 && opcd==6) {snprintf(buff, sizeof(buff), "FMOV %s, S%d", Xt[Rn], Rd);}
|
||||
else if(sf==1 && type==2 && rmode==1 && opcd==6) {snprintf(buff, sizeof(buff), "FMOV %s, V%d.D[1]", Xt[Rn], Rd);}
|
||||
else if(sf==1 && type==1 && rmode==0 && opcd==6) {snprintf(buff, sizeof(buff), "FMOV %s, D%d", Xt[Rd], Rn);}
|
||||
else if(sf==1 && type==2 && rmode==1 && opcd==6) {snprintf(buff, sizeof(buff), "FMOV %s, V%d.D[1]", Xt[Rd], Rn);}
|
||||
else snprintf(buff, sizeof(buff), "FMOV ????");
|
||||
return buff;
|
||||
}
|
||||
@@ -1351,6 +1351,17 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "AES%sMC V%d.16B, V%d.16B", sf?"I":"", Rd, Rn);
|
||||
return buff;
|
||||
}
|
||||
// PMULL
|
||||
if(isMask(opcode, "0Q001110ff1mmmmm111000nnnnnddddd", &a)) {
|
||||
const char* Y[] = {"8B", "16B", "??", "??", "??", "??", "1D", "2D"};
|
||||
const char* Z[] = {"8H", "??", "??", "1Q"};
|
||||
int sz = sf;
|
||||
const char* Vn = Y[(sz<<1)|a.Q];
|
||||
const char* Vd = Z[sz];
|
||||
snprintf(buff, sizeof(buff), "PMULL%s V%d.%s, V%d.%s, V%d.%s", a.Q?"2":"", Rd, Vd, Rn, Vn, Rm, Vn);
|
||||
return buff;
|
||||
}
|
||||
|
||||
// DMB ISH
|
||||
if(isMask(opcode, "11010101000000110011nnnn10111111", &a)) {
|
||||
snprintf(buff, sizeof(buff), "DMB %s", (Rn==0b1011)?"ISH":"???");
|
||||
|
||||
@@ -6,16 +6,18 @@
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.extern arm64_next
|
||||
|
||||
.global arm64_prolog
|
||||
arm64_prolog:
|
||||
//save all 18 used register
|
||||
stp lr, fp, [sp, -16]! // save lr
|
||||
stp x30, x29, [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 x27, X28, [sp, (8 * 8)]
|
||||
stp d8, d9, [sp, (8 *10)]
|
||||
stp d10, d11, [sp, (8 *12)]
|
||||
stp d12, d13, [sp, (8 *14)]
|
||||
@@ -31,5 +33,10 @@ arm64_prolog:
|
||||
ldp x22, x23, [x0, (8 * 12)]
|
||||
ldp x24, x25, [x0, (8 * 14)]
|
||||
ldp x26, x27, [x0, (8 * 16)]
|
||||
// Push a jump next on the stack
|
||||
adr x28, arm64_next
|
||||
stp x28, xzr, [sp, -16]!
|
||||
// Save old xSP in x28
|
||||
add x28, sp, 16
|
||||
//jump to function
|
||||
br x1
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "custommem.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
@@ -39,12 +40,16 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uint64_t u64;
|
||||
uint8_t wback, wb1, wb2, wb;
|
||||
int64_t fixedaddress;
|
||||
int lock;
|
||||
int cacheupd = 0;
|
||||
|
||||
opcode = F8;
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(wb);
|
||||
MAYUSE(lock);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
switch(opcode) {
|
||||
case 0x00:
|
||||
@@ -103,7 +108,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETEB(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_or8(dyn, ninst, x1, x2, x4, x2);
|
||||
emit_or8(dyn, ninst, x1, x2, x4, x5);
|
||||
EBBACK;
|
||||
break;
|
||||
case 0x09:
|
||||
@@ -526,14 +531,16 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG) { // reg <= reg
|
||||
SXTWx(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
LDRSW_U12(gd, ed, fixedaddress);
|
||||
}
|
||||
} else {
|
||||
if(MODREG) { // reg <= reg
|
||||
MOVw_REG(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
LDRw_U12(gd, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
@@ -555,7 +562,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
i64 = F32S;
|
||||
if(PK(0)==0xC3) {
|
||||
MESSAGE(LOG_DUMP, "PUSH then RET, using indirect\n");
|
||||
TABLE64(x3, ip+1);
|
||||
TABLE64(x3, addr-4);
|
||||
LDRSW_U12(x1, x3, 0);
|
||||
PUSH1(x1);
|
||||
} else {
|
||||
@@ -648,11 +655,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
i32 = dyn->insts[ninst].epilog-(dyn->native_size); \
|
||||
Bcond(NO, i32); \
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1) { \
|
||||
if(!dyn->insts[ninst].x64.barrier) \
|
||||
if(!(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT)) \
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst); \
|
||||
} else { \
|
||||
fpuCacheTransform(dyn, ninst, x1, x2, x3); \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size);\
|
||||
B(i32); \
|
||||
} \
|
||||
@@ -856,16 +863,16 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
BFIx(gb1, x1, gb2*8, 8);
|
||||
BFIx(eb1, x4, eb2*8, 8);
|
||||
} else {
|
||||
DMB_ISH();
|
||||
SMDMB();
|
||||
GETGB(x4);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
// do the swap with exclusive locking
|
||||
LDAXRB(x1, ed);
|
||||
// do the swap 14 -> strb(ed), 1 -> gd
|
||||
// do the swap 4 -> strb(ed), 1 -> gd
|
||||
STLXRB(x3, x4, ed);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
DMB_ISH();
|
||||
SMDMB();
|
||||
BFIx(gb1, x1, gb2*8, 8);
|
||||
}
|
||||
break;
|
||||
@@ -880,8 +887,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVxw_REG(ed, x1);
|
||||
} else {
|
||||
GETGD;
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
DMB_ISH();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
SMDMB();
|
||||
TSTx_mask(ed, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE);
|
||||
MARKLOCK;
|
||||
@@ -893,7 +900,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
LDRxw_U12(x1, ed, 0);
|
||||
STRxw_U12(gd, ed, 0);
|
||||
MARK2;
|
||||
DMB_ISH();
|
||||
SMDMB();
|
||||
MOVxw_REG(gd, x1);
|
||||
}
|
||||
break;
|
||||
@@ -925,8 +932,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
BFIx(eb1, gd, eb2*8, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff, 0, rex, &lock, 0, 0);
|
||||
STRB_U12(gd, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
case 0x89:
|
||||
@@ -936,12 +944,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, &lock, 0, 0);
|
||||
STRxw_U12(gd, ed, fixedaddress);
|
||||
if(box64_dynarec_strongmem &&
|
||||
(dyn->insts[ninst].x64.barrier || box64_dynarec_strongmem>1 || (dyn->insts[ninst+1].x64.barrier || dyn->insts[ninst+1].x64.jmp))) {
|
||||
DMB_ISH();
|
||||
}
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
case 0x8A:
|
||||
@@ -971,11 +976,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = wback;
|
||||
}
|
||||
} else {
|
||||
if(box64_dynarec_strongmem &&
|
||||
(dyn->insts[ninst].x64.barrier || !ninst || box64_dynarec_strongmem>1 || (ninst && dyn->insts[ninst-1].x64.barrier))) {
|
||||
DMB_ISH();
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff, 0, rex, &lock, 0, 0);
|
||||
SMREADLOCK(lock);
|
||||
LDRB_U12(x4, wback, fixedaddress);
|
||||
ed = x4;
|
||||
}
|
||||
@@ -987,12 +989,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
MOVxw_REG(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
if(box64_dynarec_strongmem &&
|
||||
(dyn->insts[ninst].x64.barrier || !ninst || box64_dynarec_strongmem>1 || (ninst && dyn->insts[ninst-1].x64.barrier))) {
|
||||
DMB_ISH();
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, &lock, 0, 0);
|
||||
SMREADLOCK(lock);
|
||||
LDRxw_U12(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -1002,9 +1001,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if((nextop&0xC0)==0xC0) { // reg <= seg
|
||||
LDRH_U12(xRAX+(nextop&7)+(rex.b<<3), xEmu, offsetof(x64emu_t, segs[(nextop&0x38)>>3]));
|
||||
} else { // mem <= seg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
LDRH_U12(x3, xEmu, offsetof(x64emu_t, segs[(nextop&0x38)>>3]));
|
||||
STRH_U12(x3, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x8D:
|
||||
@@ -1014,7 +1014,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG) { // reg <= reg? that's an invalid operation
|
||||
DEFAULT;
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, gd, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, gd, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
if(gd!=ed) { // it's sometimes used as a 3 bytes NOP
|
||||
MOVxw_REG(gd, ed);
|
||||
}
|
||||
@@ -1029,7 +1029,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 0, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 0, rex, NULL, 0, 0);
|
||||
LDRH_U12(x1, ed, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
@@ -1039,11 +1040,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x8F:
|
||||
INST_NAME("POP Ed");
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
POP1(xRAX+(nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
POP1(x2); // so this can handle POP [ESP] and maybe some variant too
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
if(ed==xRSP) {
|
||||
STRx_U12(x2, ed, fixedaddress);
|
||||
} else {
|
||||
@@ -1136,12 +1137,14 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
u64 = F64;
|
||||
MOV64x(x1, u64);
|
||||
STRB_U12(xRAX, x1, 0);
|
||||
SMWRITE();
|
||||
break;
|
||||
case 0xA3:
|
||||
INST_NAME("MOV Od,EAX");
|
||||
u64 = F64;
|
||||
MOV64x(x1, u64);
|
||||
STRxw_U12(xRAX, x1, 0);
|
||||
SMWRITE();
|
||||
break;
|
||||
case 0xA4:
|
||||
if(rep) {
|
||||
@@ -1200,7 +1203,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 1:
|
||||
case 2:
|
||||
if(rep==1) {INST_NAME("REPNZ CMPSB");} else {INST_NAME("REPZ CMPSB");}
|
||||
SETFLAGS(X_ALL, SF_MAYSET);
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
CBZx_NEXT(xRCX);
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
@@ -1294,12 +1298,33 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xAD:
|
||||
if(rep) {
|
||||
INST_NAME("REP LODSD");
|
||||
} else {
|
||||
INST_NAME("LODSD");
|
||||
}
|
||||
LDRxw_U12(xRAX, xRSI, 0);
|
||||
BFIw(x2, xFlags, F_DF, 1);
|
||||
if(rex.w) {
|
||||
MOV32w(x1, 8);
|
||||
} else {
|
||||
MOV32w(x1, 4);
|
||||
}
|
||||
EORxw_REG_LSL(x1, x1, x2, rex.w?63:31);
|
||||
if(rep) {
|
||||
MULxw(x1, x1, xRCX);
|
||||
EORw_REG(xRCX, xRCX, xRCX);
|
||||
}
|
||||
ADDx_REG(xRSI, xRSI, x1);
|
||||
break;
|
||||
case 0xAE:
|
||||
switch(rep) {
|
||||
case 1:
|
||||
case 2:
|
||||
if(rep==1) {INST_NAME("REPNZ SCASB");} else {INST_NAME("REPZ SCASB");}
|
||||
SETFLAGS(X_ALL, SF_MAYSET);
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
CBZx_NEXT(xRCX);
|
||||
UBFXw(x1, xRAX, 0, 8);
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
@@ -1540,9 +1565,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETED(1);
|
||||
u8 = (F8)&(rex.w?0x3f:0x1f);
|
||||
emit_shr32c(dyn, ninst, rex, ed, u8, x3, x4);
|
||||
if(u8) {
|
||||
WBACK;
|
||||
}
|
||||
if(u8) { WBACK; }
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("SAR Ed, Ib");
|
||||
@@ -1550,16 +1573,16 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETED(1);
|
||||
u8 = (F8)&(rex.w?0x3f:0x1f);
|
||||
emit_sar32c(dyn, ninst, rex, ed, u8, x3, x4);
|
||||
if(u8) {
|
||||
WBACK;
|
||||
}
|
||||
if(u8) { WBACK; }
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xC2:
|
||||
INST_NAME("RETN");
|
||||
//SETFLAGS(X_ALL, SF_SET); // Hack, set all flags (to an unknown state...)
|
||||
READFLAGS(X_PEND); // lets play safe here too
|
||||
if(box64_dynarec_safeflags) {
|
||||
READFLAGS(X_PEND); // lets play safe here too
|
||||
}
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
i32 = F16;
|
||||
retn_to_epilog(dyn, ninst, i32);
|
||||
@@ -1569,7 +1592,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xC3:
|
||||
INST_NAME("RET");
|
||||
// SETFLAGS(X_ALL, SF_SET); // Hack, set all flags (to an unknown state...)
|
||||
READFLAGS(X_PEND); // so instead, force the defered flags, so it's not too slow, and flags are not lost
|
||||
if(box64_dynarec_safeflags) {
|
||||
READFLAGS(X_PEND); // so instead, force the defered flags, so it's not too slow, and flags are not lost
|
||||
}
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
ret_to_epilog(dyn, ninst);
|
||||
*need_epilog = 0;
|
||||
@@ -1592,10 +1617,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV32w(x3, u8);
|
||||
BFIx(eb1, x3, eb2*8, 8);
|
||||
} else { // mem <= u8
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff, 0, rex, 0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff, 0, rex, &lock, 0, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x3, u8);
|
||||
STRB_U12(x3, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
case 0xC7:
|
||||
@@ -1606,10 +1632,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV64xw(ed, i64);
|
||||
} else { // mem <= i32
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, 4);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, &lock, 0, 4);
|
||||
i64 = F32S;
|
||||
MOV64xw(x3, i64);
|
||||
STRxw_U12(x3, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1640,13 +1667,14 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
x87_forget(dyn, ninst, x3, x4, 0);
|
||||
sse_purge07cache(dyn, ninst, x3);
|
||||
tmp = isSimpleWrapper(*(wrapper_t*)(addr));
|
||||
if(box64_log<2 && tmp) {
|
||||
if((box64_log<2 && !cycle_log) && tmp) {
|
||||
//GETIP(ip+3+8+8); // read the 0xCC
|
||||
call_n(dyn, ninst, *(void**)(addr+8), tmp);
|
||||
addr+=8+8;
|
||||
} else {
|
||||
GETIP(ip+1); // read the 0xCC
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
ADDx_U12(x1, xEmu, (uint32_t)offsetof(x64emu_t, ip)); // setup addr as &emu->ip
|
||||
CALL_S(x64Int3, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
addr+=8+8;
|
||||
@@ -1813,7 +1841,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
MOV32w(x2, 1);
|
||||
GETEDW(x4, x1, 0);
|
||||
CALL_(rcl32, ed, x4);
|
||||
CALL_(rex.w?((void*)rcl64):((void*)rcl32), ed, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 3:
|
||||
@@ -1823,7 +1851,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
MOV32w(x2, 1);
|
||||
GETEDW(x4, x1, 0);
|
||||
CALL_(rcr32, ed, x4);
|
||||
CALL_(rex.w?((void*)rcr64):((void*)rcr32), ed, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 4:
|
||||
@@ -1863,7 +1891,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
MOV64xw(x4, (rex.w?64:32));
|
||||
SUBx_REG(x3, x4, x3);
|
||||
GETEDW(x4, x2, 0);
|
||||
GETED(0);
|
||||
if(!rex.w && MODREG) {MOVw_REG(ed, ed);}
|
||||
B_NEXT(cEQ);
|
||||
RORxw_REG(ed, ed, x3);
|
||||
@@ -1887,7 +1915,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
ANDSw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
GETEDW(x4, x2, 0);
|
||||
GETED(0);
|
||||
if(!rex.w && MODREG) {MOVw_REG(ed, ed);}
|
||||
B_NEXT(cEQ);
|
||||
RORxw_REG(ed, ed, x3);
|
||||
@@ -2001,7 +2029,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xDD:
|
||||
addr = dynarec64_DD(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
break;
|
||||
|
||||
case 0xDE:
|
||||
addr = dynarec64_DE(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
break;
|
||||
case 0xDF:
|
||||
addr = dynarec64_DF(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
break;
|
||||
@@ -2014,11 +2044,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
i32 = dyn->insts[ninst].epilog-(dyn->native_size); \
|
||||
if(Z) {CBNZx(xRCX, i32);} else {CBZx(xRCX, i32);}; \
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1) { \
|
||||
if(!dyn->insts[ninst].x64.barrier) \
|
||||
if(!(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT)) \
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst); \
|
||||
} else { \
|
||||
fpuCacheTransform(dyn, ninst, x1, x2, x3); \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
|
||||
Bcond(c__, i32); \
|
||||
} \
|
||||
@@ -2077,18 +2107,28 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags to "dont'care" state
|
||||
BARRIER(BARRIER_FULL);
|
||||
//BARRIER_NEXT(BARRIER_FULL);
|
||||
TABLE64(x2, addr);
|
||||
if(dyn->last_ip && (addr-dyn->last_ip<0x1000)) {
|
||||
ADDx_U12(x2, xRIP, addr-dyn->last_ip);
|
||||
} else {
|
||||
TABLE64(x2, addr);
|
||||
}
|
||||
PUSH1(x2);
|
||||
MESSAGE(LOG_DUMP, "Native Call to %s (retn=%d)\n", GetNativeName(GetNativeFnc(dyn->insts[ninst].natcall-1)), dyn->insts[ninst].retn);
|
||||
// calling a native function
|
||||
sse_purge07cache(dyn, ninst, x3);
|
||||
if(box64_log<2 && dyn->insts[ninst].natcall && (tmp=isSimpleWrapper(*(wrapper_t*)(dyn->insts[ninst].natcall+2)))) {
|
||||
if((box64_log<2 && !cycle_log) && dyn->insts[ninst].natcall)
|
||||
tmp=isSimpleWrapper(*(wrapper_t*)(dyn->insts[ninst].natcall+2));
|
||||
else
|
||||
tmp=0;
|
||||
if((box64_log<2 && !cycle_log) && dyn->insts[ninst].natcall && tmp) {
|
||||
//GETIP(ip+3+8+8); // read the 0xCC
|
||||
call_n(dyn, ninst, *(void**)(dyn->insts[ninst].natcall+2+8), tmp);
|
||||
POP1(xRIP); // pop the return address
|
||||
dyn->last_ip = addr;
|
||||
} else {
|
||||
GETIP_(dyn->insts[ninst].natcall); // read the 0xCC already
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
ADDx_U12(x1, xEmu, (uint32_t)offsetof(x64emu_t, ip)); // setup addr as &emu->ip
|
||||
CALL_S(x64Int3, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
TABLE64(x3, dyn->insts[ninst].natcall);
|
||||
@@ -2107,21 +2147,39 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MARK;
|
||||
LOAD_XEMU_REM(); // load remaining register, has they have changed
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
dyn->last_ip = addr;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if(ninst && dyn->insts[ninst-1].x64.set_flags) {
|
||||
if((box64_dynarec_safeflags>1) || (ninst && dyn->insts[ninst-1].x64.set_flags)) {
|
||||
READFLAGS(X_PEND); // that's suspicious
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags to "dont'care" state
|
||||
}
|
||||
// regular call
|
||||
BARRIER(BARRIER_FULL);
|
||||
//BARRIER_NEXT(1);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
if(box64_dynarec_callret && box64_dynarec_bigblock>1) {
|
||||
BARRIER(BARRIER_FULL);
|
||||
} else {
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}
|
||||
TABLE64(x2, addr);
|
||||
PUSH1(x2);
|
||||
if(box64_dynarec_callret) {
|
||||
// Push actual return address
|
||||
if(addr < (dyn->start+dyn->isize)) {
|
||||
// there is a next...
|
||||
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0;
|
||||
ADR_S20(x4, j64);
|
||||
} else {
|
||||
j64 = getJumpTableAddress64(addr);
|
||||
TABLE64(x4, j64);
|
||||
LDRx_U12(x4, x4, 0);
|
||||
}
|
||||
STPx_S7_preindex(x4, x2, xSP, -16);
|
||||
}
|
||||
if(addr+i32==0) { // self modifying code maybe? so use indirect address fetching
|
||||
TABLE64(x4, addr-4);
|
||||
LDRx_U12(x4, x4, 0);
|
||||
@@ -2148,7 +2206,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
jump_to_next(dyn, addr+i32, 0, ninst);
|
||||
} else {
|
||||
// inside the block
|
||||
fpuCacheTransform(dyn, ninst, x1, x2, x3);
|
||||
CacheTransform(dyn, ninst, CHECK_CACHE(), x1, x2, x3);
|
||||
tmp = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size);
|
||||
if(tmp==4) {
|
||||
NOP;
|
||||
@@ -2245,7 +2303,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("NOT Ed");
|
||||
GETED(4);
|
||||
GETED(0);
|
||||
MVNxw_REG(ed, ed);
|
||||
WBACK;
|
||||
break;
|
||||
@@ -2378,6 +2436,18 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xF8:
|
||||
INST_NAME("CLC");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
BFCx(xFlags, F_CF, 1);
|
||||
break;
|
||||
case 0xF9:
|
||||
INST_NAME("STC");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
ORRx_mask(xFlags, xFlags, 1, 0, 0); // xFlags | 1
|
||||
break;
|
||||
|
||||
case 0xFC:
|
||||
INST_NAME("CLD");
|
||||
@@ -2428,7 +2498,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 2: // CALL Ed
|
||||
INST_NAME("CALL Ed");
|
||||
PASS2IF(((ninst && dyn->insts[ninst-1].x64.set_flags)
|
||||
PASS2IF((box64_dynarec_safeflags>1) ||
|
||||
((ninst && dyn->insts[ninst-1].x64.set_flags)
|
||||
|| ((ninst>1) && dyn->insts[ninst-2].x64.set_flags)), 1)
|
||||
{
|
||||
READFLAGS(X_PEND); // that's suspicious
|
||||
@@ -2436,19 +2507,34 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET); //Hack to put flag in "don't care" state
|
||||
}
|
||||
GETEDx(0);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
//BARRIER_NEXT(BARRIER_FULL);
|
||||
if(!dyn->insts || ninst==dyn->size-1) {
|
||||
if(box64_dynarec_callret && box64_dynarec_bigblock>1) {
|
||||
BARRIER(BARRIER_FULL);
|
||||
} else {
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}
|
||||
GETIP_(addr);
|
||||
if(box64_dynarec_callret) {
|
||||
// Push actual return address
|
||||
if(addr < (dyn->start+dyn->isize)) {
|
||||
// there is a next...
|
||||
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0;
|
||||
ADR_S20(x4, j64);
|
||||
} else {
|
||||
j64 = getJumpTableAddress64(addr);
|
||||
TABLE64(x4, j64);
|
||||
LDRx_U12(x4, x4, 0);
|
||||
}
|
||||
STPx_S7_preindex(x4, xRIP, xSP, -16);
|
||||
}
|
||||
PUSH1(xRIP);
|
||||
jump_to_next(dyn, 0, ed, ninst);
|
||||
break;
|
||||
case 4: // JMP Ed
|
||||
INST_NAME("JMP Ed");
|
||||
BARRIER(BARRIER_FULL);
|
||||
READFLAGS(X_PEND);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
GETEDx(0);
|
||||
jump_to_next(dyn, 0, ed, ninst);
|
||||
*need_epilog = 0;
|
||||
|
||||
@@ -24,44 +24,6 @@
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
#define GETG \
|
||||
gd = ((nextop&0x38)>>3)+(rex.r<<3) \
|
||||
|
||||
#define GETGX(a, w) \
|
||||
gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg(dyn, ninst, x1, gd, w)
|
||||
|
||||
#define GETGX_empty(a) \
|
||||
gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg_empty(dyn, ninst, x1, gd)
|
||||
|
||||
#define GETEX(a, w, D) \
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), w); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, D); \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
VLDR128_U12(a, ed, fixedaddress); \
|
||||
}
|
||||
|
||||
#define GETGM(a) \
|
||||
gd = ((nextop&0x38)>>3); \
|
||||
a = mmx_get_reg(dyn, ninst, x1, x2, x3, gd)
|
||||
|
||||
#define GETEM(a, D) \
|
||||
if(MODREG) { \
|
||||
a = mmx_get_reg(dyn, ninst, x1, x2, x3, (nextop&7)); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, D); \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
VLDR64_U12(a, ed, fixedaddress); \
|
||||
}
|
||||
|
||||
#define PUTEM(a) \
|
||||
if(!MODREG) { \
|
||||
VSTR64_U12(a, ed, fixedaddress); \
|
||||
}
|
||||
|
||||
uintptr_t dynarec64_0F(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;
|
||||
@@ -72,6 +34,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uint8_t wback, wb2;
|
||||
uint8_t eb1, eb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1;
|
||||
int q0, q1;
|
||||
int d0, d1;
|
||||
@@ -88,6 +51,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
#if STEP > 1
|
||||
static const int8_t mask_shift8[] = { -7, -6, -5, -4, -3, -2, -1, 0 };
|
||||
#endif
|
||||
@@ -102,10 +66,15 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(arm_ud, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
|
||||
case 0x05:
|
||||
INST_NAME("SYSCALL");
|
||||
SMEND();
|
||||
GETIP(addr);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL_S(x64Syscall, -1);
|
||||
@@ -122,6 +91,14 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
case 0x09:
|
||||
INST_NAME("WBINVD");
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags in "don't care" state
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(arm_ud, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
|
||||
case 0x0B:
|
||||
@@ -130,6 +107,10 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(arm_ud, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
|
||||
case 0x0D:
|
||||
@@ -137,7 +118,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch((nextop>>3)&7) {
|
||||
case 1:
|
||||
INST_NAME("PREFETCHW");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff, 7, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff, 7, rex, NULL, 0, 0);
|
||||
PST_L1_STREAM_U12(ed, fixedaddress);
|
||||
break;
|
||||
default: //???
|
||||
@@ -156,7 +137,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress); // no alignment issue with ARMv8 NEON :)
|
||||
}
|
||||
break;
|
||||
@@ -170,8 +152,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
@@ -184,7 +167,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
INST_NAME("MOVLPS Gx,Ex");
|
||||
GETGX(v0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
VLD1_64(v0, 0, ed);
|
||||
}
|
||||
break;
|
||||
@@ -196,13 +180,15 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1);
|
||||
VMOVeD(v1, 0, v0, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
VST1_64(v0, 0, ed); // better to use VST1 than VSTR_64, to avoid NEON->VFPU transfert I assume
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x14:
|
||||
INST_NAME("UNPCKLPS Gx, Ex");
|
||||
nextop = F8;
|
||||
SMREAD();
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(v0, 1);
|
||||
VZIP1Q_32(v0, v0, q0);
|
||||
@@ -210,6 +196,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x15:
|
||||
INST_NAME("UNPCKHPS Gx, Ex");
|
||||
nextop = F8;
|
||||
SMREAD();
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(v0, 1);
|
||||
VZIP2Q_32(v0, v0, q0);
|
||||
@@ -223,8 +210,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VMOVeD(v0, 1, v1, 0);
|
||||
} else {
|
||||
INST_NAME("MOVHPS Gx,Ex");
|
||||
SMREAD();
|
||||
GETGX(v0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
VLD1_64(v0, 1, ed);
|
||||
}
|
||||
break;
|
||||
@@ -236,8 +224,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1);
|
||||
VMOVeD(v1, 0, v0, 1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
VST1_64(v0, 1, ed);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x18:
|
||||
@@ -248,22 +237,22 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("PREFETCHh Ed");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff, 7, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff, 7, rex, NULL, 0, 0);
|
||||
PLD_L1_STREAM_U12(ed, fixedaddress);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("PREFETCHh Ed");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff, 7, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff, 7, rex, NULL, 0, 0);
|
||||
PLD_L1_KEEP_U12(ed, fixedaddress);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("PREFETCHh Ed");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff, 7, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff, 7, rex, NULL, 0, 0);
|
||||
PLD_L2_KEEP_U12(ed, fixedaddress);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("PREFETCHh Ed");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff, 7, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff, 7, rex, NULL, 0, 0);
|
||||
PLD_L3_KEEP_U12(ed, fixedaddress);
|
||||
break;
|
||||
default:
|
||||
@@ -289,7 +278,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -303,8 +293,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -318,7 +309,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -334,7 +325,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
s0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
|
||||
} else {
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
}
|
||||
FCMPS(v0, s0);
|
||||
@@ -386,6 +378,33 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SQRDMULH_16(q0, q0, q1);
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
INST_NAME("MOVBE Gd, Ed");
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
REVxw(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
LDRxw_U12(gd, ed, fixedaddress);
|
||||
REVxw(gd, gd);
|
||||
}
|
||||
break;
|
||||
case 0xF1:
|
||||
INST_NAME("MOVBE Ed, Gd");
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg
|
||||
REVxw(xRAX+(nextop&7)+(rex.b<<3), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
REVxw(x1, gd);
|
||||
STRxw_U12(x1, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
@@ -424,7 +443,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
CSELxw(gd, ed, gd, YES); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0); \
|
||||
Bcond(NO, +8); \
|
||||
LDRxw_U12(gd, ed, fixedaddress); \
|
||||
if(!rex.w) {MOVw_REG(gd, gd);} \
|
||||
@@ -437,7 +456,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
MOV32w(gd, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
// EX is an xmm reg
|
||||
GETEX(q0, 0, 0);
|
||||
VMOVQDto(x1, q0, 0);
|
||||
@@ -452,7 +471,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
BFIx(gd, x1, 3, 1);
|
||||
} else {
|
||||
// EX is memory
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, (0xfff<<3)-8, 7, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, (0xfff<<3)-8, 7, rex, NULL, 0, 0);
|
||||
LDRx_U12(x1, ed, fixedaddress+0);
|
||||
LSRx(x1, x1, 31);
|
||||
BFIx(gd, x1, 0, 1);
|
||||
@@ -655,7 +675,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v1 = mmx_get_reg(dyn, ninst, x1, x2, x3, (nextop&7));
|
||||
VMOVeD(q0, 1, v1, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
VLD1_64(q0, 1, ed);
|
||||
}
|
||||
SQXTUN_8(v0, q0);
|
||||
@@ -664,37 +684,36 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("PUNPCKHBW Gm,Em");
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 1);
|
||||
GETEM(q1, 0);
|
||||
VZIP2_8(q0, q0, q1);
|
||||
break;
|
||||
case 0x69:
|
||||
INST_NAME("PUNPCKHWD Gm,Em");
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 1);
|
||||
GETEM(q1, 0);
|
||||
VZIP2_16(q0, q0, q1);
|
||||
break;
|
||||
case 0x6A:
|
||||
INST_NAME("PUNPCKHDQ Gm,Em");
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 1);
|
||||
GETEM(q1, 0);
|
||||
VZIP2_32(q0, q0, q1);
|
||||
break;
|
||||
case 0x6B:
|
||||
INST_NAME("PACKSSDW Gm,Em");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VMOVeD(q0, 0, v0, 0);
|
||||
if(MODREG) {
|
||||
GETEM(v1, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VMOVeD(q0, 1, v1, 0);
|
||||
} else {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
VLD1_64(q0, 1, ed);
|
||||
}
|
||||
VMOVeD(q0, 0, v0, 0);
|
||||
SQXTN_16(v0, q0);
|
||||
break;
|
||||
|
||||
@@ -708,11 +727,12 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.w) {
|
||||
FMOVDx(v0, ed);
|
||||
} else {
|
||||
VEOR(v0, v0, v0);
|
||||
FMOVSw(v0, ed);
|
||||
}
|
||||
} else {
|
||||
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
if(rex.w) {
|
||||
VLDR64_U12(v0, ed, fixedaddress);
|
||||
} else {
|
||||
@@ -730,7 +750,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VMOVeD(v0, 0, v1, 0);
|
||||
} else {
|
||||
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -798,7 +818,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
} else {
|
||||
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 1);
|
||||
u8 = F8;
|
||||
if (u8) {
|
||||
i32 = -1;
|
||||
@@ -828,25 +848,21 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else if(u8) {
|
||||
VSHR_16(q0, q0, u8);
|
||||
}
|
||||
if(!MODREG) {
|
||||
VSTR64_U12(q0, ed, fixedaddress);
|
||||
}
|
||||
PUTEM(q0);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("PSRAW Ex, Ib");
|
||||
INST_NAME("PSRAW Em, Ib");
|
||||
GETEM(q0, 1);
|
||||
u8 = F8;
|
||||
if(u8>15) u8=15;
|
||||
if(u8) {
|
||||
VSSHR_16(q0, q0, u8);
|
||||
}
|
||||
if(!MODREG) {
|
||||
VSTR64_U12(q0, ed, fixedaddress);
|
||||
}
|
||||
PUTEM(q0);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("PSLLW Ex, Ib");
|
||||
INST_NAME("PSLLW Em, Ib");
|
||||
GETEM(q0, 1);
|
||||
u8 = F8;
|
||||
if(u8) {
|
||||
@@ -855,9 +871,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
VSHL_16(q0, q0, u8);
|
||||
}
|
||||
if(!MODREG) {
|
||||
VSTR64_U12(q0, ed, fixedaddress);
|
||||
}
|
||||
PUTEM(q0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -878,9 +892,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else if(u8) {
|
||||
VSHR_32(d0, d0, u8);
|
||||
}
|
||||
if(!MODREG) {
|
||||
VSTR64_U12(d0, ed, fixedaddress);
|
||||
}
|
||||
PUTEM(d0);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
@@ -891,9 +903,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(u8) {
|
||||
VSSHR_32(d0, d0, u8);
|
||||
}
|
||||
if(!MODREG) {
|
||||
VSTR64_U12(d0, ed, fixedaddress);
|
||||
}
|
||||
PUTEM(d0);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("PSLLD Em, Ib");
|
||||
@@ -905,9 +915,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
VSHL_32(d0, d0, u8);
|
||||
}
|
||||
if(!MODREG) {
|
||||
VSTR64_U12(d0, ed, fixedaddress);
|
||||
}
|
||||
PUTEM(d0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -983,18 +991,19 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xRAX + (nextop&7) + (rex.b<<3);
|
||||
if(rex.w) {
|
||||
VMOVQDto(ed, v0, 0);
|
||||
FMOVxD(ed, v0);
|
||||
} else {
|
||||
VMOVSto(ed, v0, 0);
|
||||
FMOVwS(ed, v0);
|
||||
MOVxw_REG(ed, ed);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
if(rex.w) {
|
||||
VSTR64_U12(v0, ed, fixedaddress);
|
||||
} else {
|
||||
VSTR32_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x7F:
|
||||
@@ -1005,8 +1014,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v1 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, nextop&7);
|
||||
VMOV(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VSTR64_U12(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1022,11 +1032,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
i32 = dyn->insts[ninst].epilog-(dyn->native_size); \
|
||||
Bcond(NO, i32); \
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1) { \
|
||||
if(!dyn->insts[ninst].x64.barrier) \
|
||||
if(!(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT)) \
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
|
||||
jump_to_next(dyn, addr+i32_, 0, ninst); \
|
||||
} else { \
|
||||
fpuCacheTransform(dyn, ninst, x1, x2, x3); \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
|
||||
B(i32); \
|
||||
} \
|
||||
@@ -1055,8 +1065,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} \
|
||||
BFIx(eb1, x3, eb2, 8); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff, 0, rex, 0, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff, 0, rex, NULL, 0, 0); \
|
||||
STRB_U12(x3, ed, fixedaddress); \
|
||||
SMWRITE(); \
|
||||
}
|
||||
|
||||
GOCOND(0x90, "SET", "Eb");
|
||||
@@ -1076,7 +1087,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
ASRxw(x1, gd, 5+rex.w); // r1 = (gd>>5)
|
||||
ADDx_REG_LSL(x3, wback, x1, 2+rex.w); //(&ed)+=r1*4;
|
||||
LDRxw_U12(x1, x3, fixedaddress);
|
||||
@@ -1123,7 +1135,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
ASRxw(x1, gd, 5+rex.w); // r1 = (gd>>5)
|
||||
ADDx_REG_LSL(x3, wback, x1, 2+rex.w); //(&ed)+=r1*4;
|
||||
LDRxw_U12(x1, x3, fixedaddress);
|
||||
@@ -1148,6 +1161,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CSELxw(ed, ed, x4, cNE);
|
||||
if(wback) {
|
||||
STRxw_U12(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
case 0xAC:
|
||||
@@ -1177,12 +1191,15 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
if((nextop&0xF8)==0xE8) {
|
||||
INST_NAME("LFENCE");
|
||||
SMDMB();
|
||||
} else
|
||||
if((nextop&0xF8)==0xF0) {
|
||||
INST_NAME("MFENCE");
|
||||
SMDMB();
|
||||
} else
|
||||
if((nextop&0xF8)==0xF8) {
|
||||
INST_NAME("SFENCE");
|
||||
SMDMB();
|
||||
} else {
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
@@ -1192,7 +1209,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(rex.w?((void*)fpu_fxsave64):((void*)fpu_fxsave32), -1);
|
||||
}
|
||||
@@ -1204,7 +1221,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(rex.w?((void*)fpu_fxrstor64):((void*)fpu_fxrstor32), -1);
|
||||
}
|
||||
@@ -1213,17 +1230,29 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("LDMXCSR Md");
|
||||
GETED(0);
|
||||
STRw_U12(ed, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
if(box64_sse_flushto0) {
|
||||
MRS_fpcr(x1); // get fpscr
|
||||
LSRw_IMM(x3, ed, 15); // get FZ bit
|
||||
BFIw(x1, x3, 24, 1); // inject FZ bit
|
||||
EORw_REG_LSR(x3, x3, ed, 1); // FZ xor DAZ
|
||||
BFIw(x1, x3, 1, 1); // inject AH bit
|
||||
MSR_fpcr(x1); // put new fpscr
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("STMXCSR Md");
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
LDRw_U12(ed, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
LDRw_U12(x4, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
STRw_U12(x4, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
LDRw_U12(x4, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
STRw_U12(x4, ed, fixedaddress);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("CLFLUSH Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization?\n");
|
||||
GETED(0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
CALL_(arm_clflush, -1, 0);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -1272,7 +1301,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
ASRxw(x1, gd, 5+rex.w); // r1 = (gd>>5)
|
||||
ADDx_REG_LSL(x3, wback, x1, 2+rex.w); //(&ed)+=r1*4;
|
||||
LDRxw_U12(x1, x3, fixedaddress);
|
||||
@@ -1297,6 +1327,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CSELxw(ed, ed, x4, cEQ);
|
||||
if(wback) {
|
||||
STRxw_U12(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1315,7 +1346,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
UBFXxw(gd, eb1, eb2*8, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff, 0, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff, 0, rex, NULL, 0, 0);
|
||||
LDRB_U12(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -1327,7 +1359,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
UBFXxw(gd, ed, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
LDRH_U12(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -1343,17 +1376,14 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xff0<<2, 3, rex, 0, 1);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 1);
|
||||
LDRxw_U12(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
u8 = F8;
|
||||
u8&=rex.w?0x3f:0x1f;
|
||||
if(u8) {
|
||||
LSRxw(x1, ed, u8);
|
||||
ed = x1;
|
||||
}
|
||||
BFIw(xFlags, ed, F_CF, 1);
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("BTS Ed, Ib");
|
||||
@@ -1363,23 +1393,20 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xff0<<2, 3, rex, 0, 1);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 1);
|
||||
LDRxw_U12(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
u8 = F8;
|
||||
u8&=(rex.w?0x3f:0x1f);
|
||||
if(u8) {
|
||||
LSRxw(x4, ed, u8);
|
||||
} else {
|
||||
MOVw_REG(x4, ed);
|
||||
}
|
||||
BFIw(xFlags, x4, F_CF, 1);
|
||||
TBNZ_MARK3(x4, 0); // bit already set, jump to next instruction
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
TBNZ_MARK3(xFlags, 0); // bit already set, jump to next instruction
|
||||
MOV32w(x4, 1);
|
||||
EORxw_REG_LSL(ed, ed, x4, u8);
|
||||
if(wback) {
|
||||
STRxw_U12(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
MARK3;
|
||||
break;
|
||||
@@ -1391,23 +1418,20 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xff0<<2, 3, rex, 0, 1);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 1);
|
||||
LDRxw_U12(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
u8 = F8;
|
||||
u8&=(rex.w?0x3f:0x1f);
|
||||
if(u8) {
|
||||
LSRxw(x4, ed, u8);
|
||||
} else {
|
||||
MOVw_REG(x4, ed);
|
||||
}
|
||||
BFIw(xFlags, x4, F_CF, 1);
|
||||
TBZ_MARK3(x4, 0); // bit already clear, jump to next instruction
|
||||
//MOVW(x14, 1); // already 0x01
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
TBZ_MARK3(xFlags, 0); // bit already clear, jump to next instruction
|
||||
MOV32w(x4, 1);
|
||||
EORxw_REG_LSL(ed, ed, x4, u8);
|
||||
if(wback) {
|
||||
STRxw_U12(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
MARK3;
|
||||
break;
|
||||
@@ -1419,22 +1443,19 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xff0<<2, 3, rex, 0, 1);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 1);
|
||||
LDRxw_U12(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
u8 = F8;
|
||||
u8&=(rex.w?0x3f:0x1f);
|
||||
if(u8) {
|
||||
LSRxw(x4, ed, u8);
|
||||
} else {
|
||||
MOVw_REG(x4, ed);
|
||||
}
|
||||
BFIw(xFlags, x4, F_CF, 1);
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
MOV32w(x4, 1);
|
||||
EORxw_REG_LSL(ed, ed, x4, u8);
|
||||
if(wback) {
|
||||
STRxw_U12(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
MARK3;
|
||||
break;
|
||||
@@ -1452,7 +1473,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
ASRxw(x1, gd, 5+rex.w); // r1 = (gd>>5)
|
||||
ADDx_REG_LSL(x3, wback, x1, 2+rex.w); //(&ed)+=r1*4;
|
||||
LDRxw_U12(x1, x3, fixedaddress);
|
||||
@@ -1476,6 +1498,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
EORxw_REG(ed, ed, x4);
|
||||
if(wback) {
|
||||
STRxw_U12(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
case 0xBC:
|
||||
@@ -1524,7 +1547,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
SBFXxw(gd, wback, wb2, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, 0xfff, 0, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, 0xfff, 0, rex, NULL, 0, 0);
|
||||
LDRSBxw_U12(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -1536,7 +1560,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
SXTHxw(gd, ed);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
LDRSHxw_U12(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -1579,7 +1604,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
STRxw_U12(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -1592,7 +1617,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
VMOVQHfrom(v0, u8, ed);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, rex, 0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, rex, NULL, 0, 1);
|
||||
u8 = (F8)&3;
|
||||
VLD1_16(v0, u8, wback);
|
||||
}
|
||||
@@ -1606,7 +1631,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
u8 = (F8)&3;
|
||||
VMOVHto(gd, v0, u8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, rex, 0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, rex, NULL, 0, 1);
|
||||
u8 = (F8)&3;
|
||||
LDRH_U12(gd, wback, u8*2);
|
||||
}
|
||||
@@ -1615,27 +1640,38 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("SHUFPS Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
if(!MODREG)
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 1);
|
||||
u8 = F8;
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
// first two elements from Gx
|
||||
for(int i=0; i<2; ++i) {
|
||||
VMOVeS(d0, i, v0, (u8>>(i*2)&3));
|
||||
}
|
||||
// second two from Ex
|
||||
if(MODREG) {
|
||||
if(!MODREG) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 1);
|
||||
v1 = -1; // to avoid a warning
|
||||
} else
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
for(int i=2; i<4; ++i) {
|
||||
VMOVeS(d0, i, v1, (u8>>(i*2)&3));
|
||||
}
|
||||
u8 = F8;
|
||||
if(v0==v1 && (u8&0x3)==((u8>>2)&3) && (u8&0xf)==((u8>>4)&0xf)) {
|
||||
VDUPQ_32(v0, v0, u8&3);
|
||||
} else if(v0==v1 && (u8==0xe0)) { // easy special case
|
||||
VMOVeS(v0, 1, v0, 0);
|
||||
} else if(v0==v1 && (u8==0xe5)) { // easy special case
|
||||
VMOVeS(v0, 0, v0, 1);
|
||||
} else {
|
||||
for(int i=2; i<4; ++i) {
|
||||
ADDx_U12(x2, ed, (u8>>(i*2)&3)*4);
|
||||
VLD1_32(d0, i, x2);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
// first two elements from Gx
|
||||
for(int i=0; i<2; ++i) {
|
||||
VMOVeS(d0, i, v0, (u8>>(i*2))&3);
|
||||
}
|
||||
// second two from Ex
|
||||
if(MODREG) {
|
||||
for(int i=2; i<4; ++i) {
|
||||
VMOVeS(d0, i, v1, (u8>>(i*2))&3);
|
||||
}
|
||||
} else {
|
||||
SMREAD();
|
||||
for(int i=2; i<4; ++i) {
|
||||
ADDx_U12(x2, ed, ((u8>>(i*2))&3)*4);
|
||||
VLD1_32(d0, i, x2);
|
||||
}
|
||||
}
|
||||
VMOVQ(v0, d0);
|
||||
}
|
||||
VMOVQ(v0, d0);
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
@@ -1771,14 +1807,14 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
|
||||
case 0xE7:
|
||||
INST_NAME("MOVNTQ Em, Gm"); // Non Temporal par not handled for now
|
||||
INST_NAME("MOVNTQ Em, Gm");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
v0 = mmx_get_reg(dyn, ninst, x1, x2, x3, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VSTR64_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -1824,7 +1860,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
gd = ((nextop&0x38)>>3);
|
||||
if(MODREG && ((nextop&7))==gd) {
|
||||
// special case for PXOR Gx, Gx
|
||||
// special case for PXOR Gm, Gm
|
||||
q0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
|
||||
VEOR(q0, q0, q0);
|
||||
} else {
|
||||
@@ -1847,7 +1883,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
|
||||
case 0xF5:
|
||||
INST_NAME("PMADDWD Gx, Ex");
|
||||
INST_NAME("PMADDWD Gm, Em");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
GETEM(v1, 0);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "custommem.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
@@ -91,7 +92,8 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} 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);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
ADDx_REG(x4, x4, ed);
|
||||
VLDR64_U12(v0, x4, fixedaddress); // upper part reseted
|
||||
}
|
||||
@@ -101,13 +103,15 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+ (rex.b<<3);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
|
||||
q0 = sse_get_reg(dyn, ninst, x1, ed, 0);
|
||||
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);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
ADDx_REG(x4, x4, ed);
|
||||
VLDR32_U12(v0, x4, fixedaddress);
|
||||
}
|
||||
@@ -129,9 +133,10 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
ADDx_REG(x4, x4, ed);
|
||||
VSTR128_U12(v0, x4, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
@@ -145,9 +150,10 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
ADDx_REG(x4, x4, ed);
|
||||
VSTR64_U12(v0, x4, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
@@ -156,13 +162,15 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 1);
|
||||
ed = (nextop&7)+ (rex.b<<3);
|
||||
q0 = sse_get_reg(dyn, ninst, x1, ed, 1);
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
ADDx_REG(x4, x4, ed);
|
||||
VSTR32_U12(v0, x4, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -182,7 +190,8 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
ADDx_REG(x4, x4, ed);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
@@ -194,56 +203,69 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
|
||||
case 0xAF:
|
||||
INST_NAME("IMUL Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
GETGD;
|
||||
GETEDO(x4, 0);
|
||||
if(rex.w) {
|
||||
// 64bits imul
|
||||
UFLAG_IF {
|
||||
SMULH(x3, gd, ed);
|
||||
MULx(gd, gd, ed);
|
||||
UFLAG_OP1(x3);
|
||||
UFLAG_RES(gd);
|
||||
UFLAG_DF(x3, d_imul64);
|
||||
} else {
|
||||
MULxw(gd, gd, ed);
|
||||
}
|
||||
} else {
|
||||
// 32bits imul
|
||||
UFLAG_IF {
|
||||
SMULL(gd, gd, ed);
|
||||
UFLAG_RES(gd);
|
||||
LSRx(x3, gd, 32);
|
||||
UFLAG_OP1(x3);
|
||||
UFLAG_DF(x3, d_imul32);
|
||||
MOVw_REG(gd, gd);
|
||||
} else {
|
||||
MULxw(gd, gd, ed);
|
||||
}
|
||||
switch(rep) {
|
||||
case 0:
|
||||
INST_NAME("IMUL Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
GETGD;
|
||||
GETEDO(x4, 0);
|
||||
if(rex.w) {
|
||||
// 64bits imul
|
||||
UFLAG_IF {
|
||||
SMULH(x3, gd, ed);
|
||||
MULx(gd, gd, ed);
|
||||
UFLAG_OP1(x3);
|
||||
UFLAG_RES(gd);
|
||||
UFLAG_DF(x3, d_imul64);
|
||||
} else {
|
||||
MULxw(gd, gd, ed);
|
||||
}
|
||||
} else {
|
||||
// 32bits imul
|
||||
UFLAG_IF {
|
||||
SMULL(gd, gd, ed);
|
||||
UFLAG_RES(gd);
|
||||
LSRx(x3, gd, 32);
|
||||
UFLAG_OP1(x3);
|
||||
UFLAG_DF(x3, d_imul32);
|
||||
MOVw_REG(gd, gd);
|
||||
} else {
|
||||
MULxw(gd, gd, ed);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xB6:
|
||||
INST_NAME("MOVZX Gd, Eb");
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
if(rex.rex) {
|
||||
eb1 = xRAX+(nextop&7)+(rex.b<<3);
|
||||
eb2 = 0; \
|
||||
} else {
|
||||
ed = (nextop&7);
|
||||
eb1 = xRAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
}
|
||||
UBFXxw(gd, eb1, eb2*8, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
LDRB_REG(gd, ed, x4);
|
||||
switch(rep) {
|
||||
case 0:
|
||||
INST_NAME("MOVZX Gd, Eb");
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
if(rex.rex) {
|
||||
eb1 = xRAX+(nextop&7)+(rex.b<<3);
|
||||
eb2 = 0; \
|
||||
} else {
|
||||
ed = (nextop&7);
|
||||
eb1 = xRAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
}
|
||||
UBFXxw(gd, eb1, eb2*8, 8);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
LDRB_REG(gd, ed, x4);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -252,6 +274,16 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x2B:
|
||||
INST_NAME("SUB Gd, Seg:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x4, 0);
|
||||
emit_sub32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
break;
|
||||
|
||||
case 0x33:
|
||||
INST_NAME("XOR Gd, Seg:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -291,7 +323,8 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTWx(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
} else { // mem <= reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
LDRSW_REG(gd, ed, x4);
|
||||
}
|
||||
} else {
|
||||
@@ -299,14 +332,15 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVw_REG(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
} else { // mem <= reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
LDRw_REG(gd, ed, x4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x66:
|
||||
addr = dynarec64_6664(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
addr = dynarec64_6664(dyn, addr, ip, ninst, rex, seg, ok, need_epilog);
|
||||
break;
|
||||
|
||||
case 0x80:
|
||||
@@ -500,7 +534,8 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
LDRB_REG(x4, wback, x4);
|
||||
ed = x4;
|
||||
}
|
||||
@@ -514,8 +549,9 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
STRxw_REG(gd, ed, x4);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -527,7 +563,8 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
LDRxw_REG(gd, ed, x4);
|
||||
}
|
||||
break;
|
||||
@@ -549,10 +586,11 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x3, u8);
|
||||
STRB_REG(x3, ed, x4);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0xC7:
|
||||
@@ -564,10 +602,11 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, NULL, 0, 4);
|
||||
i64 = F32S;
|
||||
MOV64xw(x3, i64);
|
||||
STRxw_REG(x3, ed, x4);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -789,7 +828,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("NOT Ed");
|
||||
GETEDO(x6, 4);
|
||||
GETEDO(x6, 0);
|
||||
MVNxw_REG(ed, ed);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
@@ -937,7 +976,8 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 2: // CALL Ed
|
||||
INST_NAME("CALL Ed");
|
||||
PASS2IF(((ninst && dyn->insts[ninst-1].x64.set_flags)
|
||||
PASS2IF((box64_dynarec_safeflags>1) ||
|
||||
((ninst && dyn->insts[ninst-1].x64.set_flags)
|
||||
|| ((ninst>1) && dyn->insts[ninst-2].x64.set_flags)), 1)
|
||||
{
|
||||
READFLAGS(X_PEND); // that's suspicious
|
||||
@@ -945,18 +985,34 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET); //Hack to put flag in "don't care" state
|
||||
}
|
||||
GETEDOx(x6, 0);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
if(!dyn->insts || ninst==dyn->size-1) {
|
||||
if(box64_dynarec_callret && box64_dynarec_bigblock>1) {
|
||||
BARRIER(BARRIER_FULL);
|
||||
} else {
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}
|
||||
GETIP_(addr);
|
||||
if(box64_dynarec_callret) {
|
||||
// Push actual return address
|
||||
if(addr < (dyn->start+dyn->isize)) {
|
||||
// there is a next...
|
||||
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0;
|
||||
ADR_S20(x4, j64);
|
||||
} else {
|
||||
j64 = getJumpTableAddress64(addr);
|
||||
TABLE64(x4, j64);
|
||||
LDRx_U12(x4, x4, 0);
|
||||
}
|
||||
STPx_S7_preindex(x4, xRIP, xSP, -16);
|
||||
}
|
||||
PUSH1(xRIP);
|
||||
jump_to_next(dyn, 0, ed, ninst);
|
||||
break;
|
||||
case 4: // JMP Ed
|
||||
INST_NAME("JMP Ed");
|
||||
BARRIER(1);
|
||||
READFLAGS(X_PEND);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
GETEDOx(x6, 0);
|
||||
jump_to_next(dyn, 0, ed, ninst);
|
||||
*need_epilog = 0;
|
||||
|
||||
@@ -35,19 +35,21 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1;
|
||||
int64_t fixedaddress;
|
||||
int lock;
|
||||
MAYUSE(u8);
|
||||
MAYUSE(u16);
|
||||
MAYUSE(u64);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(lock);
|
||||
|
||||
while((opcode==0x2E) || (opcode==0x66)) // ignoring CS: or multiple 0x66
|
||||
while((opcode==0x2E) || (opcode==0x36) || (opcode==0x66)) // ignoring CS:, SS: or multiple 0x66
|
||||
opcode = F8;
|
||||
|
||||
while((opcode==0xF2) || (opcode==0xF3)) {
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
// REX prefix before the F0 are ignored
|
||||
// REX prefix before the 66 are ignored
|
||||
rex.rex = 0;
|
||||
while(opcode>=0x40 && opcode<=0x4f) {
|
||||
rex.rex = opcode;
|
||||
@@ -293,34 +295,27 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
|
||||
case 0x64:
|
||||
addr = dynarec64_6664(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
addr = dynarec64_6664(dyn, addr, ip, ninst, rex, _FS, ok, need_epilog);
|
||||
break;
|
||||
case 0x65:
|
||||
addr = dynarec64_6664(dyn, addr, ip, ninst, rex, _GS, 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");
|
||||
if(opcode==0x69) {
|
||||
INST_NAME("IMUL Gw,Ew,Iw");
|
||||
} else {
|
||||
INST_NAME("IMUL Gw,Ew,Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
nextop = F8;
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
GETSEW(x1, 1);
|
||||
i32 = F8S;
|
||||
GETSEW(x1, (opcode==0x69)?2:1);
|
||||
if(opcode==0x69) i32 = F16S; else i32 = F8S;
|
||||
MOV32w(x2, i32);
|
||||
MULw(x2, x2, x1);
|
||||
UFLAG_RES(x2);
|
||||
@@ -352,11 +347,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: //ADD
|
||||
if(opcode==0x81) {
|
||||
INST_NAME("ADD Ew, Iw");
|
||||
} else {
|
||||
INST_NAME("ADD Ew, Ib");
|
||||
}
|
||||
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;
|
||||
@@ -443,6 +434,35 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
|
||||
case 0x87:
|
||||
INST_NAME("(LOCK)XCHG Ew, Gw");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
GETGD;
|
||||
GETED(0);
|
||||
MOVxw_REG(x1, gd);
|
||||
BFIx(gd, ed, 0, 16);
|
||||
BFIx(ed, x1, 0, 16);
|
||||
} else {
|
||||
GETGD;
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
SMDMB();
|
||||
TSTx_mask(ed, 1, 0, 0); // mask=1
|
||||
B_MARK(cNE);
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, ed);
|
||||
STLXRH(x3, gd, ed);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
B_MARK2_nocond;
|
||||
MARK;
|
||||
LDRH_U12(x1, ed, 0);
|
||||
STRH_U12(gd, ed, 0);
|
||||
MARK2;
|
||||
SMDMB();
|
||||
BFIx(gd, x1, 0, 16);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x89:
|
||||
INST_NAME("MOV Ew, Gw");
|
||||
nextop = F8;
|
||||
@@ -453,8 +473,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
BFIx(ed, gd, 0, 16);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<1, 1, rex, &lock, 0, 0);
|
||||
STRH_U12(gd, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
case 0x8B:
|
||||
@@ -467,7 +488,8 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
BFIx(gd, ed, 0, 16);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<1, 1, rex, &lock, 0, 0);
|
||||
SMREADLOCK(lock);
|
||||
LDRH_U12(x1, ed, fixedaddress);
|
||||
BFIx(gd, x1, 0, 16);
|
||||
}
|
||||
@@ -511,6 +533,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
u64 = F64;
|
||||
MOV64x(x1, u64);
|
||||
STRH_U12(xRAX, x1, 0);
|
||||
SMWRITE();
|
||||
break;
|
||||
|
||||
case 0xA5:
|
||||
@@ -639,7 +662,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, (u8&0x1f));
|
||||
UFLAG_IF {MOV32w(x2, (u8&0x1f));}
|
||||
UFLAG_OP12(ed, x2)
|
||||
LSLw_IMM(ed, ed, u8&0x1f);
|
||||
EWBACK;
|
||||
@@ -652,7 +675,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, (u8&0x1f));
|
||||
UFLAG_IF {MOV32w(x2, (u8&0x1f));}
|
||||
UFLAG_OP12(ed, x2)
|
||||
LSRw_IMM(ed, ed, u8&0x1f);
|
||||
EWBACK;
|
||||
@@ -663,11 +686,11 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("SAR Ed, Ib");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
UFLAG_IF {MESSAGE(LOG_DUMP, "Need Optimization for flags\n");}
|
||||
GETSEW(x1, 0);
|
||||
GETSEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, (u8&0x1f));
|
||||
UFLAG_IF {MOV32w(x2, (u8&0x1f));}
|
||||
UFLAG_OP12(ed, x2)
|
||||
ASRw_REG(ed, ed, x2);
|
||||
ASRw(ed, ed, (u8&0x1f));
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_sar16);
|
||||
@@ -684,10 +707,11 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV32w(x1, u16);
|
||||
BFIx(ed, x1, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<1, 1, rex, 0, 2);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<1, 1, rex, &lock, 0, 2);
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
STRH_U12(x1, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -701,7 +725,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV32w(x2, 1);
|
||||
} else {
|
||||
INST_NAME("ROL Ew, CL");
|
||||
ANDSw_mask(x2, xRCX, 0, 0b00100);
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100);
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
@@ -715,7 +739,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV32w(x2, 1);
|
||||
} else {
|
||||
INST_NAME("ROR Ew, CL");
|
||||
ANDSw_mask(x2, xRCX, 0, 0b00100);
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100);
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
@@ -728,7 +752,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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);}
|
||||
if(opcode==0xD1) {MOV32w(x2, 1);} else {ANDw_mask(x2, xRCX, 0, 0b00100);}
|
||||
GETEW(x1, 0);
|
||||
CALL_(rcl16, x1, x3);
|
||||
EWBACK;
|
||||
@@ -738,7 +762,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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);}
|
||||
if(opcode==0xD1) {MOV32w(x2, 1);} else {ANDw_mask(x2, xRCX, 0, 0b00100);}
|
||||
GETEW(x1, 0);
|
||||
CALL_(rcr16, x1, x3);
|
||||
EWBACK;
|
||||
@@ -750,7 +774,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV32w(x4, 1);
|
||||
} else {
|
||||
INST_NAME("SHL Ew, CL");
|
||||
ANDSw_mask(x4, xRCX, 0, 0b00100);
|
||||
ANDw_mask(x4, xRCX, 0, 0b00100);
|
||||
}
|
||||
UFLAG_IF {MESSAGE(LOG_DUMP, "Need Optimization for flags\n");}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
@@ -767,7 +791,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV32w(x4, 1);
|
||||
} else {
|
||||
INST_NAME("SHR Ew, CL");
|
||||
ANDSw_mask(x4, xRCX, 0, 0b00100);
|
||||
ANDw_mask(x4, xRCX, 0, 0b00100);
|
||||
}
|
||||
UFLAG_IF {MESSAGE(LOG_DUMP, "Need Optimization for flags\n");}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
@@ -784,7 +808,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV32w(x4, 1);
|
||||
} else {
|
||||
INST_NAME("SAR Ew, CL");
|
||||
ANDSw_mask(x4, xRCX, 0, 0b00100);
|
||||
ANDw_mask(x4, xRCX, 0, 0b00100);
|
||||
}
|
||||
UFLAG_IF {MESSAGE(LOG_DUMP, "Need Optimization for flags\n");}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
@@ -798,6 +822,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
return dynarec64_66F0(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
|
||||
case 0xF7:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
@@ -847,17 +874,25 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("DIV Ew");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEW(x1, 0);
|
||||
CALL(div16, -1);
|
||||
UXTHw(x2, xRAX);
|
||||
BFIw(x2, xRDX, 16, 16);
|
||||
UDIVw(x3, x2, ed);
|
||||
MSUBw(x4, x3, ed, x2); // x4 = x2 mod ed (i.e. x2 - x3*ed)
|
||||
BFIx(xRAX, x3, 0, 16);
|
||||
BFIx(xRDX, x4, 0, 16);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("IDIV Ew");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEW(x1, 0);
|
||||
CALL(idiv16, -1);
|
||||
GETSEW(x1, 0);
|
||||
UXTHw(x2, xRAX);
|
||||
BFIw(x2, xRDX, 16, 16);
|
||||
SDIVw(x3, x2, ed);
|
||||
MSUBw(x4, x3, ed, x2); // x4 = x2 mod ed (i.e. x2 - x3*ed)
|
||||
BFIx(xRAX, x3, 0, 16);
|
||||
BFIx(xRDX, x4, 0, 16);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -22,26 +22,6 @@
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
// Get EX as a quad
|
||||
#define GETEX(a, w, D) \
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), w); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, D); \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
VLDR128_U12(a, ed, fixedaddress); \
|
||||
}
|
||||
|
||||
#define GETG gd = ((nextop&0x38)>>3)+(rex.r<<3)
|
||||
|
||||
#define GETGX(a, w) \
|
||||
gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg(dyn, ninst, x1, gd, w)
|
||||
|
||||
#define GETGX_empty(a) \
|
||||
gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg_empty(dyn, ninst, x1, gd)
|
||||
|
||||
uintptr_t dynarec64_660F(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;
|
||||
@@ -50,7 +30,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
uint8_t nextop, u8;
|
||||
int32_t i32;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2;
|
||||
int64_t j64;
|
||||
uint64_t tmp64u, tmp64u2;
|
||||
@@ -81,8 +61,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
SMREAD();
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -95,8 +76,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
@@ -108,7 +90,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
DEFAULT;
|
||||
return addr;
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
VLD1_64(v0, 0, ed);
|
||||
break;
|
||||
case 0x13:
|
||||
@@ -120,8 +103,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
DEFAULT;
|
||||
return addr;
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
VST1_64(v0, 0, ed);
|
||||
SMWRITE2();
|
||||
break;
|
||||
case 0x14:
|
||||
INST_NAME("UNPCKLPD Gx, Ex");
|
||||
@@ -131,7 +115,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
VMOVeD(v0, 1, v1, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
VLD1_64(v0, 1, ed);
|
||||
}
|
||||
break;
|
||||
@@ -141,10 +126,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(v0, 1);
|
||||
VMOVeD(v0, 0, v0, 1);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
VMOVeD(v0, 1, v1, 1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
ADDx_U12(ed, ed, 8);
|
||||
VLD1_64(v0, 1, ed);
|
||||
@@ -159,7 +145,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
DEFAULT;
|
||||
return addr;
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
VLD1_64(v0, 1, ed);
|
||||
break;
|
||||
case 0x17:
|
||||
@@ -171,8 +158,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
DEFAULT;
|
||||
return addr;
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
VST1_64(v0, 1, ed);
|
||||
SMWRITE2();
|
||||
break;
|
||||
|
||||
case 0x1F:
|
||||
@@ -191,8 +179,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
SMREAD();
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -206,8 +195,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -323,6 +313,21 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
SQRDMULHQ_16(q0, q0, q1);
|
||||
break;
|
||||
|
||||
case 0x10:
|
||||
INST_NAME("PBLENDVB Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
if(q0!=q1) {
|
||||
VSSHRQ_8(v1, v0, 7); // bit[7]-> bit[7..0]
|
||||
VBICQ(q0, q0, v1);
|
||||
VANDQ(v1, q1, v1);
|
||||
VORRQ(q0, q0, v1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x1C:
|
||||
INST_NAME("PABSB Gx,Ex");
|
||||
nextop = F8;
|
||||
@@ -439,14 +444,41 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
UXTL_32(q0, q1); // 32bits->64bits
|
||||
break;
|
||||
|
||||
case 0x38:
|
||||
INST_NAME("PMINSB Gx, Ex"); // SSE4 opcode!
|
||||
nextop = F8;
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX(q0, 1);
|
||||
SMINQ_8(q0, q0, q1);
|
||||
break;
|
||||
case 0x39:
|
||||
INST_NAME("PMINSD Gx, Ex"); // SSE4 opcode!
|
||||
nextop = F8;
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX(q0,1);
|
||||
GETGX(q0, 1);
|
||||
SMINQ_32(q0, q0, q1);
|
||||
break;
|
||||
|
||||
case 0x3A:
|
||||
INST_NAME("PMINUW Gx, Ex"); // SSE4 opcode!
|
||||
nextop = F8;
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX(q0, 1);
|
||||
UMINQ_16(q0, q0, q1);
|
||||
break;
|
||||
case 0x3B:
|
||||
INST_NAME("PMINUD Gx, Ex"); // SSE4 opcode!
|
||||
nextop = F8;
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX(q0, 1);
|
||||
UMINQ_32(q0, q0, q1);
|
||||
break;
|
||||
case 0x3C:
|
||||
INST_NAME("PMAXSB Gx, Ex"); // SSE4 opcode!
|
||||
nextop = F8;
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX(q0, 1);
|
||||
SMAXQ_8(q0, q0, q1);
|
||||
break;
|
||||
case 0x3D:
|
||||
INST_NAME("PMAXSD Gx, Ex"); // SSE4 opcode!
|
||||
nextop = F8;
|
||||
@@ -454,6 +486,20 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(q0, 1);
|
||||
SMAXQ_32(q0, q0, q1);
|
||||
break;
|
||||
case 0x3E:
|
||||
INST_NAME("PMAXUW Gx, Ex"); // SSE4 opcode!
|
||||
nextop = F8;
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX(q0, 1);
|
||||
UMAXQ_16(q0, q0, q1);
|
||||
break;
|
||||
case 0x3F:
|
||||
INST_NAME("PMAXUD Gx, Ex"); // SSE4 opcode!
|
||||
nextop = F8;
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX(q0, 1);
|
||||
UMAXQ_32(q0, q0, q1);
|
||||
break;
|
||||
|
||||
case 0xDB:
|
||||
INST_NAME("AESIMC Gx, Ex"); // AES-NI
|
||||
@@ -613,6 +659,15 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x20:
|
||||
INST_NAME("PINSRB Gx, ED, Ib");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETED(1);
|
||||
u8 = F8;
|
||||
VMOVQBfrom(q0, (u8&15), ed);
|
||||
break;
|
||||
|
||||
case 0x22:
|
||||
INST_NAME("PINSRD Gx, ED, Ib");
|
||||
nextop = F8;
|
||||
@@ -626,6 +681,74 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x44:
|
||||
INST_NAME("PCLMULQDQ Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
if(arm64_pmull) {
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 1);
|
||||
u8 = F8;
|
||||
switch (u8&0b00010001) {
|
||||
case 0b00000000:
|
||||
PMULL_128(q0, q0, q1);
|
||||
break;
|
||||
case 0b00010001:
|
||||
PMULL2_128(q0, q0, q1);
|
||||
break;
|
||||
case 0b00000001:
|
||||
VEXTQ_8(q0, q0, q0, 8); // Swap Up/Lower 64bits parts
|
||||
PMULL_128(q0, q0, q1);
|
||||
break;
|
||||
case 0b00010000:
|
||||
VEXTQ_8(q0, q0, q0, 8); // Swap Up/Lower 64bits parts
|
||||
PMULL2_128(q0, q0, q1);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd); // gx
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
sse_forget_reg(dyn, ninst, ed);
|
||||
MOV32w(x2, ed);
|
||||
MOV32w(x3, 0); //p = NULL
|
||||
} else {
|
||||
MOV32w(x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, 0, 0, rex, NULL, 0, 1);
|
||||
if(ed!=x3) {
|
||||
MOVx_REG(x3, ed);
|
||||
}
|
||||
}
|
||||
u8 = F8;
|
||||
MOV32w(x4, u8);
|
||||
CALL(arm_pclmul, -1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xDF:
|
||||
INST_NAME("AESKEYGENASSIST Gx, Ex, Ib"); // AES-NI
|
||||
nextop = F8;
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd); // gx
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
sse_forget_reg(dyn, ninst, ed);
|
||||
MOV32w(x2, ed);
|
||||
MOV32w(x3, 0); //p = NULL
|
||||
} else {
|
||||
MOV32w(x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, 0, 0, rex, NULL, 0, 1);
|
||||
if(ed!=x3) {
|
||||
MOVx_REG(x3, ed);
|
||||
}
|
||||
}
|
||||
u8 = F8;
|
||||
MOV32w(x4, u8);
|
||||
CALL(arm_aeskeygenassist, -1);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
@@ -639,7 +762,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(MODREG) { \
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<1, 1, rex, 0, 0); \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<1, 1, rex, NULL, 0, 0); \
|
||||
LDRH_U12(x1, ed, fixedaddress); \
|
||||
ed = x1; \
|
||||
} \
|
||||
@@ -660,11 +784,30 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
LSRx(gd, gd, 63);
|
||||
BFIx(gd, x1, 1, 1);
|
||||
break;
|
||||
|
||||
case 0x51:
|
||||
INST_NAME("SQRTPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX_empty(q1);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
// check if any input value was NAN
|
||||
VFCMEQQD(v0, q0, q0); // 0 if NAN, 1 if not NAN
|
||||
VFSQRTQD(q1, q0);
|
||||
VFCMEQQD(v1, q1, q1); // 0 => out is NAN
|
||||
VBICQ(v1, v0, v1); // forget it in any input was a NAN already
|
||||
VSHLQ_64(v1, v1, 63); // only keep the sign bit
|
||||
VORRQ(q1, q1, v1); // NAN -> -NAN
|
||||
} else {
|
||||
VFSQRTQD(q1, q0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x54:
|
||||
INST_NAME("ANDPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0,0);
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(v0, 1);
|
||||
VANDQ(v0, v0, q0);
|
||||
break;
|
||||
@@ -741,25 +884,10 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
#ifdef PRECISE_CVT
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
UBFXx(x1, x1, 13, 2); // extract round requested
|
||||
LSLx_REG(x1, x1, 3);
|
||||
// Construct a "switch case", with each case 2 instructions, so 8 bytes
|
||||
ADR(xLR, GETMARK);
|
||||
ADDx_REG(xLR, xLR, x1);
|
||||
B(xLR);
|
||||
MARK;
|
||||
VFCVTNSQS(v0, v1); // 0: Nearest (even)
|
||||
B_NEXT_nocond;
|
||||
VFCVTMSQS(v0, v1); // 1: Toward -inf
|
||||
B_NEXT_nocond;
|
||||
VFCVTPSQS(v0, v1); // 2: Toward +inf
|
||||
B_NEXT_nocond;
|
||||
VFCVTZSQS(v0, v1); // 3: Toward 0
|
||||
#else
|
||||
VFCVTNSQS(v0, v1);
|
||||
#endif
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
VFRINTISQ(v0, v1);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
VFCVTZSQS(v0, v0);
|
||||
break;
|
||||
case 0x5C:
|
||||
INST_NAME("SUBPD Gx, Ex");
|
||||
@@ -885,21 +1013,21 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("PUNPCKHBW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
VZIP2Q_8(q0, q0, q1);
|
||||
break;
|
||||
case 0x69:
|
||||
INST_NAME("PUNPCKHWD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
VZIP2Q_16(q0, q0, q1);
|
||||
break;
|
||||
case 0x6A:
|
||||
INST_NAME("PUNPCKHDQ Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
VZIP2Q_32(q0, q0, q1);
|
||||
break;
|
||||
case 0x6B:
|
||||
@@ -922,7 +1050,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
VMOVeD(v0, 1, v1, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
VLD1_64(v0, 1, ed);
|
||||
}
|
||||
break;
|
||||
@@ -935,7 +1063,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
VMOVeD(v0, 1, v1, 1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
ADDSx_U12(x1, ed, 8);
|
||||
VLD1_64(v0, 1, x1);
|
||||
}
|
||||
@@ -961,7 +1089,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -1035,7 +1164,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 1);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 1);
|
||||
u8 = F8;
|
||||
if (u8) {
|
||||
for (int i=0; i<4; ++i) {
|
||||
@@ -1064,9 +1194,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else if(u8) {
|
||||
VSHRQ_16(q0, q0, u8);
|
||||
}
|
||||
if(!MODREG) {
|
||||
VSTR128_U12(q0, ed, fixedaddress);
|
||||
}
|
||||
PUTEX(q0);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
@@ -1077,9 +1205,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(u8) {
|
||||
VSSHRQ_16(q0, q0, u8);
|
||||
}
|
||||
if(!MODREG) {
|
||||
VSTR128_U12(q0, ed, fixedaddress);
|
||||
}
|
||||
PUTEX(q0);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("PSLLW Ex, Ib");
|
||||
@@ -1091,9 +1217,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
VSHLQ_16(q0, q0, u8);
|
||||
}
|
||||
if(!MODREG) {
|
||||
VSTR128_U12(q0, ed, fixedaddress);
|
||||
}
|
||||
PUTEX(q0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -1114,9 +1238,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else if(u8) {
|
||||
VSHRQ_32(q0, q0, u8);
|
||||
}
|
||||
if(!MODREG) {
|
||||
VSTR128_U12(q0, ed, fixedaddress);
|
||||
}
|
||||
PUTEX(q0);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
@@ -1127,9 +1249,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(u8) {
|
||||
VSSHRQ_32(q0, q0, u8);
|
||||
}
|
||||
if(!MODREG) {
|
||||
VSTR128_U12(q0, ed, fixedaddress);
|
||||
}
|
||||
PUTEX(q0);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("PSLLD Ex, Ib");
|
||||
@@ -1141,9 +1261,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
VSHLQ_32(q0, q0, u8);
|
||||
}
|
||||
if(!MODREG) {
|
||||
VSTR128_U12(q0, ed, fixedaddress);
|
||||
}
|
||||
PUTEX(q0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -1163,9 +1281,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else if(u8) {
|
||||
VSHRQ_64(q0, q0, u8);
|
||||
}
|
||||
if(!MODREG) {
|
||||
VSTR128_U12(q0, ed, fixedaddress);
|
||||
}
|
||||
PUTEX(q0);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
@@ -1180,9 +1296,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VEORQ(q1, q1, q1);
|
||||
VEXTQ_8(q0, q0, q1, u8);
|
||||
}
|
||||
if(!MODREG) {
|
||||
VSTR128_U12(q0, ed, fixedaddress);
|
||||
}
|
||||
PUTEX(q0);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
@@ -1195,9 +1309,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
VSHLQ_64(q0, q0, u8);
|
||||
}
|
||||
if(!MODREG) {
|
||||
VSTR128_U12(q0, ed, fixedaddress);
|
||||
}
|
||||
PUTEX(q0);
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
@@ -1212,9 +1324,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VEORQ(q1, q1, q1);
|
||||
VEXTQ_8(q0, q1, q0, 16-u8);
|
||||
}
|
||||
if(!MODREG) {
|
||||
VSTR128_U12(q0, ed, fixedaddress);
|
||||
}
|
||||
PUTEX(q0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -1244,6 +1354,30 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VCMEQQ_32(v0, v0, q0);
|
||||
break;
|
||||
|
||||
case 0x7C:
|
||||
INST_NAME("HADDPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q1, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
// check if any input value was NAN
|
||||
// but need to mix low/high part
|
||||
VTRNQ1_64(v0, q1, q0);
|
||||
VTRNQ2_64(v1, q1, q0);
|
||||
VFMAXQD(v0, v0, v1); // propagate NAN
|
||||
VFCMEQQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFADDPQD(q1, q1, q0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
VFCMEQQD(v1, q1, q1); // 0 => out is NAN
|
||||
VBICQ(v1, v0, v1); // forget it in any input was a NAN already
|
||||
VSHLQ_64(v1, v1, 63); // only keep the sign bit
|
||||
VORRQ(q1, q1, v1); // NAN -> -NAN
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7E:
|
||||
INST_NAME("MOVD Ed,Gx");
|
||||
nextop = F8;
|
||||
@@ -1253,16 +1387,18 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
ed = xRAX + (nextop&7) + (rex.b<<3);
|
||||
VMOVQDto(ed, v0, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VSTR64_U12(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
} else {
|
||||
if(MODREG) {
|
||||
ed = xRAX + (nextop&7) + (rex.b<<3);
|
||||
VMOVSto(ed, v0, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VSTR32_U12(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1274,8 +1410,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1288,7 +1425,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<2, (1<<2)-1, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<2, (1<<2)-1, rex, NULL, 0, 0);
|
||||
SBFXw(x1, gd, 4, 12); // r1 = (gw>>4)
|
||||
ADDx_REG_LSL(x3, wback, x1, 1); //(&ed)+=r1*2;
|
||||
LDRH_U12(x1, x3, fixedaddress);
|
||||
@@ -1329,7 +1467,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<2, (1<<2)-1, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<2, (1<<2)-1, rex, NULL, 0, 0);
|
||||
SBFXw(x4, gd, 4, 12); // r1 = (gw>>4)
|
||||
ADDx_REG_LSL(x3, wback, x4, 1); //(&ed)+=r1*2;
|
||||
LDRH_U12(x4, x3, fixedaddress);
|
||||
@@ -1390,7 +1528,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<2, (1<<2)-1, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<2, (1<<2)-1, rex, NULL, 0, 0);
|
||||
SBFXw(x4, gd, 4, 12); // r1 = (gw>>4)
|
||||
ADDx_REG_LSL(x3, wback, x4, 1); //(&ed)+=r1*2;
|
||||
LDRH_U12(x4, x3, fixedaddress);
|
||||
@@ -1407,6 +1546,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
EORx_REG(ed, ed, x1);
|
||||
if(wback) {
|
||||
STRH_U12(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1424,7 +1564,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
UBFXxw(x1, eb1, eb2*8, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff, 0, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff, 0, rex, NULL, 0, 0);
|
||||
LDRB_U12(x1, ed, fixedaddress);
|
||||
}
|
||||
gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3); // GETGW
|
||||
@@ -1437,7 +1578,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
eb1 = xRAX+(nextop&7)+(rex.b<<3);
|
||||
UBFXxw(x1, eb1, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff>>1, 1, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff>>1, 1, rex, NULL, 0, 0);
|
||||
LDRH_U12(x1, ed, fixedaddress);
|
||||
}
|
||||
gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3); // GETGW
|
||||
@@ -1455,7 +1597,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<2, (1<<2)-1, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<2, (1<<2)-1, rex, NULL, 0, 0);
|
||||
SBFXw(x4, gd, 4, 12); // r1 = (gw>>4)
|
||||
ADDx_REG_LSL(x3, wback, x4, 1); //(&ed)+=r1*2;
|
||||
LDRH_U12(x4, x3, fixedaddress);
|
||||
@@ -1471,6 +1614,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
EORx_REG(ed, ed, x1);
|
||||
if(wback) {
|
||||
STRH_U12(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
case 0xBC:
|
||||
@@ -1523,7 +1667,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
SBFXw(x1, eb1, eb2, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff, 0, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff, 0, rex, NULL, 0, 0);
|
||||
LDRSBw_U12(x1, ed, fixedaddress);
|
||||
}
|
||||
BFIx(gd, x1, 0, 16);
|
||||
@@ -1570,7 +1715,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
VMOVQHfrom(v0, u8, ed);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, rex, 0, 1);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, rex, NULL, 0, 1);
|
||||
u8 = (F8)&7;
|
||||
VLD1_16(v0, u8, wback);
|
||||
}
|
||||
@@ -1584,7 +1730,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
u8 = (F8)&7;
|
||||
VMOVHto(gd, v0, u8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, rex, 0, 1);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, rex, NULL, 0, 1);
|
||||
u8 = (F8)&7;
|
||||
LDRH_U12(gd, wback, u8*2);
|
||||
}
|
||||
@@ -1680,8 +1827,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
FMOVD(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VSTR64_U12(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0xD7:
|
||||
@@ -1836,7 +1984,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
VFCVTNSQD(v0, v1); // convert double -> int64
|
||||
VFCVTZSQD(v0, v1); // convert double -> int64
|
||||
SQXTN_32(v0, v0); // convert int64 -> int32 with saturation in lower part, RaZ high part
|
||||
break;
|
||||
case 0xE7:
|
||||
@@ -1847,7 +1995,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -24,15 +24,17 @@
|
||||
|
||||
#define GETG gd = ((nextop&0x38)>>3)+(rex.r<<3)
|
||||
|
||||
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)
|
||||
uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int seg, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)rep; (void)need_epilog;
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
uint8_t gd, ed;
|
||||
int64_t j64;
|
||||
int v0, v1;
|
||||
int64_t fixedaddress;
|
||||
MAYUSE(j64);
|
||||
|
||||
// REX prefix before the 66 are ignored
|
||||
rex.rex = 0;
|
||||
@@ -51,7 +53,26 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0x0F:
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
|
||||
case 0x2E:
|
||||
// no special check...
|
||||
case 0x2F:
|
||||
if(opcode==0x2F) {INST_NAME("COMISD Gx, Ex");} else {INST_NAME("UCOMISD Gx, Ex");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn); \
|
||||
VLDR64_REG(v1, ed, x4);
|
||||
}
|
||||
FCMPD(v0, v1);
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
case 0xD6:
|
||||
INST_NAME("MOVQ Ex, Gx");
|
||||
nextop = F8;
|
||||
@@ -61,9 +82,10 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
FMOVD(v1, v0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, _FS);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
VSTR64_REG(v0, ed, x4);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -86,13 +108,14 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
}
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, _FS);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
if(rex.w) {
|
||||
STRx_REG(gd, ed, x4);
|
||||
} else {
|
||||
STRH_REG(gd, ed, x4);
|
||||
}
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -110,8 +133,9 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
}
|
||||
} else { // mem <= reg
|
||||
grab_segdata(dyn, addr, ninst, x4, _FS);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
if(rex.w) {
|
||||
LDRx_REG(gd, ed, x4);
|
||||
} else {
|
||||
|
||||
@@ -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_native.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_66F0(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, u8;
|
||||
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/66 are ignored
|
||||
rex.rex = 0;
|
||||
while(opcode>=0x40 && opcode<=0x4f) {
|
||||
rex.rex = opcode;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
switch(opcode) {
|
||||
case 0x09:
|
||||
INST_NAME("LOCK OR Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x5);
|
||||
SMDMB();
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
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, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_or16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
break;
|
||||
|
||||
case 0x0F:
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
|
||||
case 0xB1:
|
||||
INST_NAME("LOCK CMPXCHG Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
SMDMB();
|
||||
UXTHw(x6, xRAX);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = 0;
|
||||
UXTHw(x1, ed);
|
||||
CMPSxw_REG(x6, x1);
|
||||
B_MARK(cNE);
|
||||
BFIx(ed, gd, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
TSTx_mask(wback, 1, 0, 0); // mask=1
|
||||
B_MARK3(cNE);
|
||||
// Aligned version
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
CMPSw_REG(x6, x1);
|
||||
B_MARK(cNE);
|
||||
// EAX == Ed
|
||||
STLXRH(x4, gd, wback);
|
||||
CBNZx_MARKLOCK(x4);
|
||||
// done
|
||||
B_MARK_nocond;
|
||||
// Unaligned version
|
||||
MARK3;
|
||||
LDRH_U12(x1, wback, 0);
|
||||
LDAXRB(x3, wback); // dummy read, to arm the write...
|
||||
CMPSw_REG(x6, x1);
|
||||
B_MARK(cNE);
|
||||
// EAX == Ed
|
||||
STLXRB(x4, gd, wback);
|
||||
CBNZx_MARK3(x4);
|
||||
STRH_U12(gd, wback, 0);
|
||||
}
|
||||
MARK;
|
||||
// Common part (and fallback for EAX != Ed)
|
||||
UFLAG_IF {emit_cmp16(dyn, ninst, x6, x1, x3, x4, x5);}
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
SMDMB();
|
||||
break;
|
||||
|
||||
case 0xC1:
|
||||
INST_NAME("LOCK XADD Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3);
|
||||
UXTHx(x5, gd);
|
||||
SMDMB();
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
BFIx(gd, ed, 0, 16);
|
||||
emit_add16(dyn, ninst, x5, gd, x3, x4);
|
||||
BFIx(ed, x5, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
ADDxw_REG(x4, x1, x5);
|
||||
STLXRH(x3, x4, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
IFX(X_ALL|X_PEND) {
|
||||
MOVxw_REG(x2, x1);
|
||||
emit_add16(dyn, ninst, x2, x5, x3, x4);
|
||||
}
|
||||
BFIx(gd, x1, 0, 16);
|
||||
}
|
||||
SMDMB();
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
SMDMB();
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: //ADD
|
||||
if(opcode==0x81) {
|
||||
INST_NAME("LOCK ADD Ew, Iw");
|
||||
} else {
|
||||
INST_NAME("LOCK ADD 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_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, LOCK_LOCK, 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_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, 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_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, LOCK_LOCK, 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, LOCK_LOCK, 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, LOCK_LOCK, 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, LOCK_LOCK, 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, LOCK_LOCK, 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, LOCK_LOCK, 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);
|
||||
emit_cmp16(dyn, ninst, x6, x5, x3, x4, x6);
|
||||
} else {
|
||||
emit_cmp16_0(dyn, ninst, ed, x3, x4);
|
||||
}
|
||||
break;
|
||||
}
|
||||
SMDMB();
|
||||
break;
|
||||
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7)
|
||||
{
|
||||
case 0: // INC Ew
|
||||
INST_NAME("LOCK INC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
SMDMB();
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
UXTHw(x6, ed);
|
||||
emit_inc16(dyn, ninst, x6, x5, x3);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_inc16(dyn, ninst, x1, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
break;
|
||||
case 1: //DEC Ew
|
||||
INST_NAME("LOCK DEC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
SMDMB();
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
UXTHw(x6, ed);
|
||||
emit_dec16(dyn, ninst, x6, x5, x3);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_dec16(dyn, ninst, x1, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -38,18 +38,22 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
uint8_t gd, ed, wback, wb;
|
||||
uint8_t gd, ed, wback, wb, wb1, wb2, gb1, gb2;
|
||||
int64_t fixedaddress;
|
||||
int8_t i8;
|
||||
uint8_t u8;
|
||||
int32_t i32;
|
||||
int64_t j64, i64;
|
||||
int cacheupd = 0;
|
||||
int lock;
|
||||
int v0, v1, s0;
|
||||
MAYUSE(i32);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(v0);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(lock);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
// REX prefix before the 67 are ignored
|
||||
rex.rex = 0;
|
||||
@@ -64,6 +68,105 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
|
||||
switch(opcode) {
|
||||
case 0x00:
|
||||
INST_NAME("ADD Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_add8(dyn, ninst, x1, x2, x4, x5);
|
||||
EBBACK;
|
||||
break;
|
||||
case 0x01:
|
||||
INST_NAME("ADD Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_add32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 0x02:
|
||||
INST_NAME("ADD Gb, Eb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x2, 0);
|
||||
GETGB(x1);
|
||||
emit_add8(dyn, ninst, x1, x2, x3, x4);
|
||||
GBBACK;
|
||||
break;
|
||||
case 0x03:
|
||||
INST_NAME("ADD Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_add32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
break;
|
||||
case 0x04:
|
||||
INST_NAME("ADD AL, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u8 = F8;
|
||||
UXTBw(x1, xRAX);
|
||||
emit_add8c(dyn, ninst, x1, u8, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 8);
|
||||
break;
|
||||
case 0x05:
|
||||
INST_NAME("ADD EAX, Id");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i64 = F32S;
|
||||
emit_add32c(dyn, ninst, rex, xRAX, i64, x3, x4, x5);
|
||||
break;
|
||||
|
||||
case 0x08:
|
||||
INST_NAME("OR Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_or8(dyn, ninst, x1, x2, x4, x2);
|
||||
EBBACK;
|
||||
break;
|
||||
case 0x09:
|
||||
INST_NAME("OR Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_or32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 0x0A:
|
||||
INST_NAME("OR Gb, Eb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x2, 0);
|
||||
GETGB(x1);
|
||||
emit_or8(dyn, ninst, x1, x2, x3, x4);
|
||||
GBBACK;
|
||||
break;
|
||||
case 0x0B:
|
||||
INST_NAME("OR Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_or32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
break;
|
||||
case 0x0C:
|
||||
INST_NAME("OR AL, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u8 = F8;
|
||||
UXTBw(x1, xRAX);
|
||||
emit_or8c(dyn, ninst, x1, u8, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 8);
|
||||
break;
|
||||
case 0x0D:
|
||||
INST_NAME("OR EAX, Id");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i64 = F32S;
|
||||
emit_or32c(dyn, ninst, rex, xRAX, i64, x3, x4);
|
||||
break;
|
||||
|
||||
case 0x0F:
|
||||
opcode=F8;
|
||||
@@ -72,50 +175,67 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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, 0);
|
||||
if(MODREG) {
|
||||
s0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
|
||||
} 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);
|
||||
switch(rep) {
|
||||
case 0:
|
||||
if(opcode==0x2F) {INST_NAME("COMISS Gx, Ex");} else {INST_NAME("UCOMISS Gx, Ex");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
s0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
|
||||
} else {
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
SMREAD();
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
}
|
||||
FCMPS(v0, s0);
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x6F:
|
||||
INST_NAME("MOVQ Gm, Em");
|
||||
nextop = F8;
|
||||
GETGm;
|
||||
if(MODREG) {
|
||||
v1 = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7); // no rex.b on MMX
|
||||
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
|
||||
VMOVeD(v0, 0, v1, 0);
|
||||
} else {
|
||||
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VLDR64_U12(v0, ed, fixedaddress);
|
||||
switch(rep) {
|
||||
case 0:
|
||||
INST_NAME("MOVQ Gm, Em");
|
||||
nextop = F8;
|
||||
GETGm;
|
||||
if(MODREG) {
|
||||
v1 = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7); // no rex.b on MMX
|
||||
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
|
||||
VMOV(v0, v1);
|
||||
} else {
|
||||
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
|
||||
SMREAD();
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7F:
|
||||
INST_NAME("MOVQ Em, Gm");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
if(MODREG) {
|
||||
v1 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, nextop&7);
|
||||
VMOV(v1, v0);
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VSTR64_U12(v0, ed, fixedaddress);
|
||||
switch(rep) {
|
||||
case 0:
|
||||
INST_NAME("MOVQ Em, Gm");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
if(MODREG) {
|
||||
v1 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, nextop&7);
|
||||
VMOV(v1, v0);
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VSTR64_U12(v0, ed, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -124,6 +244,403 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x10:
|
||||
INST_NAME("ADC Eb, Gb");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_adc8(dyn, ninst, x1, x2, x4, x5);
|
||||
EBBACK;
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("ADC Ed, Gd");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_adc32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 0x12:
|
||||
INST_NAME("ADC Gb, Eb");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x2, 0);
|
||||
GETGB(x1);
|
||||
emit_adc8(dyn, ninst, x1, x2, x4, x3);
|
||||
GBBACK;
|
||||
break;
|
||||
case 0x13:
|
||||
INST_NAME("ADC Gd, Ed");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_adc32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
break;
|
||||
case 0x14:
|
||||
INST_NAME("ADC AL, Ib");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u8 = F8;
|
||||
UXTBw(x1, xRAX);
|
||||
emit_adc8c(dyn, ninst, x1, u8, x3, x4, x5);
|
||||
BFIx(xRAX, x1, 0, 8);
|
||||
break;
|
||||
case 0x15:
|
||||
INST_NAME("ADC EAX, Id");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i64 = F32S;
|
||||
MOV64xw(x1, i64);
|
||||
emit_adc32(dyn, ninst, rex, xRAX, x1, x3, x4);
|
||||
break;
|
||||
|
||||
case 0x18:
|
||||
INST_NAME("SBB Eb, Gb");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_sbb8(dyn, ninst, x1, x2, x4, x5);
|
||||
EBBACK;
|
||||
break;
|
||||
case 0x19:
|
||||
INST_NAME("SBB Ed, Gd");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_sbb32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 0x1A:
|
||||
INST_NAME("SBB Gb, Eb");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x2, 0);
|
||||
GETGB(x1);
|
||||
emit_sbb8(dyn, ninst, x1, x2, x3, x4);
|
||||
GBBACK;
|
||||
break;
|
||||
case 0x1B:
|
||||
INST_NAME("SBB Gd, Ed");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_sbb32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
break;
|
||||
case 0x1C:
|
||||
INST_NAME("SBB AL, Ib");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u8 = F8;
|
||||
UXTBw(x1, xRAX);
|
||||
emit_sbb8c(dyn, ninst, x1, u8, x3, x4, x5);
|
||||
BFIx(xRAX, x1, 0, 8);
|
||||
break;
|
||||
case 0x1D:
|
||||
INST_NAME("SBB EAX, Id");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i64 = F32S;
|
||||
MOV64xw(x2, i64);
|
||||
emit_sbb32(dyn, ninst, rex, xRAX, x2, x3, x4);
|
||||
break;
|
||||
|
||||
case 0x20:
|
||||
INST_NAME("AND Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_and8(dyn, ninst, x1, x2, x4, x5);
|
||||
EBBACK;
|
||||
break;
|
||||
case 0x21:
|
||||
INST_NAME("AND Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_and32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 0x22:
|
||||
INST_NAME("AND Gb, Eb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x2, 0);
|
||||
GETGB(x1);
|
||||
emit_and8(dyn, ninst, x1, x2, x3, x4);
|
||||
GBBACK;
|
||||
break;
|
||||
case 0x23:
|
||||
INST_NAME("AND Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_and32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
break;
|
||||
case 0x24:
|
||||
INST_NAME("AND AL, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u8 = F8;
|
||||
UXTBw(x1, xRAX);
|
||||
emit_and8c(dyn, ninst, x1, u8, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 8);
|
||||
break;
|
||||
case 0x25:
|
||||
INST_NAME("AND EAX, Id");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i64 = F32S;
|
||||
emit_and32c(dyn, ninst, rex, xRAX, i64, x3, x4);
|
||||
break;
|
||||
|
||||
case 0x28:
|
||||
INST_NAME("SUB Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_sub8(dyn, ninst, x1, x2, x4, x5);
|
||||
EBBACK;
|
||||
break;
|
||||
case 0x29:
|
||||
INST_NAME("SUB Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_sub32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 0x2A:
|
||||
INST_NAME("SUB Gb, Eb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x2, 0);
|
||||
GETGB(x1);
|
||||
emit_sub8(dyn, ninst, x1, x2, x3, x4);
|
||||
GBBACK;
|
||||
break;
|
||||
case 0x2B:
|
||||
INST_NAME("SUB Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_sub32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
break;
|
||||
case 0x2C:
|
||||
INST_NAME("SUB AL, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u8 = F8;
|
||||
UXTBw(x1, xRAX);
|
||||
emit_sub8c(dyn, ninst, x1, u8, x3, x4, x5);
|
||||
BFIx(xRAX, x1, 0, 8);
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("SUB EAX, Id");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i64 = F32S;
|
||||
emit_sub32c(dyn, ninst, rex, xRAX, i64, x3, x4, x5);
|
||||
break;
|
||||
|
||||
case 0x30:
|
||||
INST_NAME("XOR Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_xor8(dyn, ninst, x1, x2, x4, x5);
|
||||
EBBACK;
|
||||
break;
|
||||
case 0x31:
|
||||
INST_NAME("XOR Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_xor32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 0x32:
|
||||
INST_NAME("XOR Gb, Eb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x2, 0);
|
||||
GETGB(x1);
|
||||
emit_xor8(dyn, ninst, x1, x2, x3, x4);
|
||||
GBBACK;
|
||||
break;
|
||||
case 0x33:
|
||||
INST_NAME("XOR Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_xor32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
break;
|
||||
case 0x34:
|
||||
INST_NAME("XOR AL, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u8 = F8;
|
||||
UXTBw(x1, xRAX);
|
||||
emit_xor8c(dyn, ninst, x1, u8, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 8);
|
||||
break;
|
||||
case 0x35:
|
||||
INST_NAME("XOR EAX, Id");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i64 = F32S;
|
||||
emit_xor32c(dyn, ninst, rex, xRAX, i64, x3, x4);
|
||||
break;
|
||||
|
||||
case 0x38:
|
||||
INST_NAME("CMP Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
case 0x39:
|
||||
INST_NAME("CMP Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_cmp32(dyn, ninst, rex, ed, gd, x3, x4, x5);
|
||||
break;
|
||||
case 0x3A:
|
||||
INST_NAME("CMP Gb, Eb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x2, 0);
|
||||
GETGB(x1);
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
case 0x3B:
|
||||
INST_NAME("CMP Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_cmp32(dyn, ninst, rex, gd, ed, x3, x4, x5);
|
||||
break;
|
||||
case 0x3C:
|
||||
INST_NAME("CMP AL, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u8 = F8;
|
||||
UXTBw(x1, xRAX);
|
||||
if(u8) {
|
||||
MOV32w(x2, u8);
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
} else {
|
||||
emit_cmp8_0(dyn, ninst, x1, x3, x4);
|
||||
}
|
||||
break;
|
||||
case 0x3D:
|
||||
INST_NAME("CMP EAX, Id");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i64 = F32S;
|
||||
if(i64) {
|
||||
MOV64xw(x2, i64);
|
||||
emit_cmp32(dyn, ninst, rex, xRAX, x2, x3, x4, x5);
|
||||
} else
|
||||
emit_cmp32_0(dyn, ninst, rex, xRAX, x3, x4);
|
||||
break;
|
||||
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: //ADD
|
||||
if(opcode==0x81) {INST_NAME("ADD Ed, Id");} else {INST_NAME("ADD Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED32((opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_add32c(dyn, ninst, rex, ed, i64, x3, x4, x5);
|
||||
WBACK;
|
||||
break;
|
||||
case 1: //OR
|
||||
if(opcode==0x81) {INST_NAME("OR Ed, Id");} else {INST_NAME("OR Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED32((opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_or32c(dyn, ninst, rex, ed, i64, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 2: //ADC
|
||||
if(opcode==0x81) {INST_NAME("ADC Ed, Id");} else {INST_NAME("ADC Ed, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED32((opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
emit_adc32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 3: //SBB
|
||||
if(opcode==0x81) {INST_NAME("SBB Ed, Id");} else {INST_NAME("SBB Ed, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED32((opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
emit_sbb32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 4: //AND
|
||||
if(opcode==0x81) {INST_NAME("AND Ed, Id");} else {INST_NAME("AND Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED32((opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_and32c(dyn, ninst, rex, ed, i64, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 5: //SUB
|
||||
if(opcode==0x81) {INST_NAME("SUB Ed, Id");} else {INST_NAME("SUB Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED32((opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_sub32c(dyn, ninst, rex, ed, i64, x3, x4, x5);
|
||||
WBACK;
|
||||
break;
|
||||
case 6: //XOR
|
||||
if(opcode==0x81) {INST_NAME("XOR Ed, Id");} else {INST_NAME("XOR Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED32((opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_xor32c(dyn, ninst, rex, ed, i64, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 7: //CMP
|
||||
if(opcode==0x81) {INST_NAME("CMP Ed, Id");} else {INST_NAME("CMP Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED32((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 Ed, Gd");
|
||||
nextop=F8;
|
||||
@@ -131,8 +648,22 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG) { // reg <= reg
|
||||
MOVxw_REG(xRAX+(nextop&7)+(rex.b<<3), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, 0);
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, &lock, 0, 0);
|
||||
STRxw_U12(gd, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, Ed");
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
MOVxw_REG(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, &lock, 0, 0);
|
||||
SMREADLOCK(lock);
|
||||
LDRxw_U12(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -144,7 +675,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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);
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, gd, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=gd) {
|
||||
MOVw_REG(gd, ed);
|
||||
}
|
||||
@@ -223,7 +754,24 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 0xC7:
|
||||
INST_NAME("MOV Ed, Id");
|
||||
nextop=F8;
|
||||
if(MODREG) { // reg <= i32
|
||||
i64 = F32S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV64xw(ed, i64);
|
||||
} else { // mem <= i32
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, &lock, 0, 4);
|
||||
i64 = F32S;
|
||||
MOV64xw(x3, i64);
|
||||
STRxw_U12(x3, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
#define GO(NO, YES) \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(addr+i8, 1); \
|
||||
@@ -233,11 +781,11 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
i32 = dyn->insts[ninst].epilog-(dyn->native_size); \
|
||||
Bcond(NO, i32); \
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1) { \
|
||||
if(!dyn->insts[ninst].x64.barrier) \
|
||||
if(!(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT)) \
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst); \
|
||||
} else { \
|
||||
fpuCacheTransform(dyn, ninst, x1, x2, x3); \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size);\
|
||||
B(i32); \
|
||||
} \
|
||||
@@ -302,7 +850,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("NOT Ed");
|
||||
GETED32(4);
|
||||
GETED32(0);
|
||||
MVNxw_REG(ed, ed);
|
||||
WBACK;
|
||||
break;
|
||||
|
||||
@@ -185,7 +185,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FADD ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FADDS(v1, v1, s0);
|
||||
@@ -198,7 +198,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FMUL ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FMULS(v1, v1, s0);
|
||||
@@ -211,7 +211,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FCOM ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FCMPS(v1, s0);
|
||||
@@ -225,7 +225,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FCOMP ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FCMPS(v1, s0);
|
||||
@@ -240,7 +240,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FSUB ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, v1, s0);
|
||||
@@ -253,7 +253,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FSUBR ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, s0, v1);
|
||||
@@ -266,7 +266,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FDIV ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, v1, s0);
|
||||
@@ -279,7 +279,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FDIVR ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, s0, v1);
|
||||
|
||||
@@ -31,6 +31,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uint8_t nextop = F8;
|
||||
uint8_t ed;
|
||||
uint8_t wback, wb1;
|
||||
uint8_t u8;
|
||||
int64_t fixedaddress;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
@@ -71,6 +72,8 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xCF:
|
||||
INST_NAME("FXCH STx");
|
||||
// swap the cache value, not the double value itself :p
|
||||
x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_ST(nextop&7));
|
||||
x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
x87_swapreg(dyn, ninst, x1, x2, 0, nextop&7);
|
||||
// should set C1 to 0
|
||||
break;
|
||||
@@ -79,6 +82,24 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FNOP");
|
||||
break;
|
||||
|
||||
case 0xD8:
|
||||
INST_NAME("FSTPNCE ST0, ST0");
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
INST_NAME("FSTPNCE ST0, STx");
|
||||
// copy the cache value for st0 to stx
|
||||
x87_get_st_empty(dyn, ninst, x1, x2, nextop&7, X87_ST(nextop&7));
|
||||
x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
x87_swapreg(dyn, ninst, x1, x2, 0, nextop&7);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE0:
|
||||
INST_NAME("FCHS");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
@@ -252,21 +273,21 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xFC:
|
||||
INST_NAME("FRNDINT");
|
||||
#if 0
|
||||
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
|
||||
#else
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x3);
|
||||
VCVT_S32_F64(x1, v1); // limit to 32bits....
|
||||
VCVT_F64_S32(v1, x1);
|
||||
if(ST_IS_F(0)) {
|
||||
FRINTIS(v1, v1);
|
||||
} else {
|
||||
FRINTID(v1, v1);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
*/
|
||||
#endif
|
||||
break;
|
||||
case 0xFD:
|
||||
INST_NAME("FSCALE");
|
||||
@@ -294,14 +315,6 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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:
|
||||
@@ -315,14 +328,10 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0:
|
||||
INST_NAME("FLD ST0, float[ED]");
|
||||
v1 = x87_do_push(dyn, ninst, x1, box64_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0))
|
||||
s0 = v1;
|
||||
else
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLDR32_U12(v1, ed, fixedaddress);
|
||||
if(!ST_IS_F(0)) {
|
||||
FCVT_D_S(v1, s0);
|
||||
FCVT_D_S(v1, v1);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
@@ -334,27 +343,24 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 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, NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0))
|
||||
s0 = v1;
|
||||
else {
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
FCVT_S_D(s0, v1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
if(!ST_IS_F(0)) {
|
||||
FCVT_S_D(v1, v1);
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VSTR32_U12(s0, ed, fixedaddress);
|
||||
VSTR32_U12(v1, ed, fixedaddress);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FLDENV Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
@@ -365,14 +371,12 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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, 0, x1, x2, x3); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
@@ -381,7 +385,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FNSTCW Ew");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
ed = x1;
|
||||
wb1 = 1;
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, cw));
|
||||
|
||||
@@ -189,24 +189,18 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ed");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLDR32_U12(v1, ed, fixedaddress);
|
||||
SXTL_32(v1, v1); // i32 -> i64
|
||||
SCVTFDD(v1, v1); // i64 -> double
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FISTTP Ed, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
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;
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
ed = x1;
|
||||
FRINT32ZD(s0, v1);
|
||||
FCVTZSwD(ed, s0);
|
||||
WBACK;
|
||||
@@ -230,15 +224,10 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FIST Ed, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
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;
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
ed = x1;
|
||||
FRINT32XD(s0, v1);
|
||||
FCVTZSwD(ed, s0);
|
||||
WBACK;
|
||||
@@ -262,15 +251,10 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FISTP Ed, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
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;
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
ed = x1;
|
||||
FRINT32XD(s0, v1);
|
||||
FCVTZSwD(ed, s0);
|
||||
WBACK;
|
||||
@@ -293,34 +277,102 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
if((PK(0)==0xDB && ((PK(1)>>3)&7)==7) || (PK(0)>=0x40 && PK(0)<=0x4f && PK(1)==0xDB && ((PK(2)>>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; // 0xDB or rex
|
||||
if(nextop>=0x40 && nextop<=0x4f) {
|
||||
rex.rex = nextop;
|
||||
nextop = F8; //0xDB
|
||||
} else
|
||||
rex.rex = 0;
|
||||
nextop = F8; //modrm
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
STRx_U12(x5, ed, 0);
|
||||
STRH_U12(x6, ed, 8);
|
||||
} else {
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
if(box64_x87_no80bits) {
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v1, ed, fixedaddress);
|
||||
} else {
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
x87_do_push_empty(dyn, ninst, x3);
|
||||
CALL(arm_fld, -1);
|
||||
}
|
||||
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);
|
||||
if(box64_x87_no80bits) {
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VSTR64_U12(v1, wback, fixedaddress);
|
||||
} else {
|
||||
#if 0
|
||||
x87_forget(dyn, ninst, x1, x3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
CALL(arm_fstp, -1);
|
||||
#else
|
||||
// Painfully long, straight conversion from the C code, shoud be optimized
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
FMOVxD(x1, v1);
|
||||
// do special value first
|
||||
TSTx_mask(x1, 1, 0b00000, 0b111110); //0x7fffffffffffffffL
|
||||
B_MARK(cNE);
|
||||
// Zero
|
||||
LSRx(x3, x1, 63-15); //x3 = sign+exp
|
||||
MOVZw(x5, 0); // x5 = mantisse
|
||||
B_MARK3_nocond;
|
||||
MARK;
|
||||
// get sign, in main ouput x5 for sign+exp
|
||||
ANDx_mask(x5, x1, 1, 1, 0); //0x8000000000000000
|
||||
LSRx(x5, x5, 63-15); // x5 = sign
|
||||
// get exp
|
||||
LSRx(x3, x1, 52); // x3 = exp11
|
||||
ANDw_mask(x3, x3, 0, 0b1010); //0x7ff
|
||||
MOV32w(x4, 0x7ff);
|
||||
CMPSw_REG(x3, x4);
|
||||
B_MARK2(cNE);
|
||||
// NaN and Infinite
|
||||
ORRw_mask(x3, x5, 0, 0b1110); //x3 = sign | 0x7fff
|
||||
TSTx_mask(x1, 1, 0, 0b110011); //0x000fffffffffffffL
|
||||
ORRx_mask(x5, xZR, 1, 1, 0); //0x8000000000000000
|
||||
ORRx_mask(x4, xZR, 1, 0b10, 0b01); //0xc000000000000000
|
||||
CSELx(x5, x5, x4, cEQ); // x5 = mantisse
|
||||
B_MARK3_nocond;
|
||||
MARK2;
|
||||
// regular / denormals
|
||||
ANDx_mask(x1, x1, 1, 0, 0b110011); //0x000fffffffffffffL
|
||||
LSLx_IMM(x1, x1, 11); //x1 = mantisse missing "1"
|
||||
MOVZw(x4, 16383-1023); //BIAS80 - BIAS64
|
||||
CBZw(x3, 4+3*4); // exp11 == 0?
|
||||
// normals
|
||||
ADDw_REG(x3, x3, x4); // x3 = exp16
|
||||
ORRw_REG(x3, x3, x5); // x3 = sign | exp
|
||||
ORRx_mask(x5, x1, 1, 1, 0); //0x8000000000000000 x5 = mantisse
|
||||
B_MARK3_nocond;
|
||||
// denormals
|
||||
CLZx(x6, x1);
|
||||
ADDw_U12(x6, x6, 1); // "one"
|
||||
SUBw_REG(x3, x4, x6); // x3 = exp16
|
||||
ORRw_REG(x3, x3, x5); // x3 = sign | exp16
|
||||
LSLx_REG(x5, x1, x6); // x5 = mantisse
|
||||
MARK3;
|
||||
STRx_U12(x5, wback, 0);
|
||||
STRH_U12(x3, wback, 8);
|
||||
#endif
|
||||
}
|
||||
CALL(arm_fstp, -1);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -182,7 +182,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FADD ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 3, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v2, wback, fixedaddress);
|
||||
FADDD(v1, v1, v2);
|
||||
break;
|
||||
@@ -190,7 +190,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FMUL ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 3, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v2, wback, fixedaddress);
|
||||
FMULD(v1, v1, v2);
|
||||
break;
|
||||
@@ -198,7 +198,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FCOM ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 3, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v2, wback, fixedaddress);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
@@ -207,7 +207,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FCOMP ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 3, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v2, wback, fixedaddress);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
@@ -217,7 +217,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FSUB ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 3, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v2, wback, fixedaddress);
|
||||
FSUBD(v1, v1, v2);
|
||||
break;
|
||||
@@ -225,7 +225,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FSUBR ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 3, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v2, wback, fixedaddress);
|
||||
FSUBD(v1, v2, v1);
|
||||
break;
|
||||
@@ -233,7 +233,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FDIV ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 3, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v2, wback, fixedaddress);
|
||||
FDIVD(v1, v1, v2);
|
||||
break;
|
||||
@@ -241,7 +241,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FDIVR ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 3, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v2, wback, fixedaddress);
|
||||
FDIVD(v1, v2, v1);
|
||||
break;
|
||||
|
||||
@@ -33,10 +33,12 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
int64_t fixedaddress;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
int64_t j64;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(j64);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
@@ -83,6 +85,8 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xDF:
|
||||
INST_NAME("FSTP ST0, STx");
|
||||
// copy the cache value for st0 to stx
|
||||
x87_get_st_empty(dyn, ninst, x1, x2, nextop&7, X87_ST(nextop&7));
|
||||
x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
x87_swapreg(dyn, ninst, x1, x2, 0, nextop&7);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
@@ -157,29 +161,44 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0:
|
||||
INST_NAME("FLD double");
|
||||
v1 = x87_do_push(dyn, ninst, x3, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v1, ed, fixedaddress);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FISTTP i64, ST0");
|
||||
v1 = x87_do_push(dyn, ninst, x3, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
// those are ARM 8.5 opcode!
|
||||
FRINT64ZD(s0, v1);
|
||||
FCVTZSxD(x2, s0);
|
||||
STRx_U12(x2, ed, fixedaddress);
|
||||
#else
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
FRINTRRD(s0, v1, 3);
|
||||
FCVTZSxD(x2, s0);
|
||||
STRx_U12(x2, ed, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
ORRx_mask(x5, xZR, 1, 1, 0); //0x8000000000000000
|
||||
STRw_U12(x5, ed, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FST double");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VSTR64_U12(v1, ed, fixedaddress);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FSTP double");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VSTR64_U12(v1, ed, fixedaddress);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
@@ -187,7 +206,7 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FRSTOR m108byte");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(arm_frstor, -1);
|
||||
break;
|
||||
@@ -195,14 +214,14 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FSAVE m108byte");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(arm_fsave, -1);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FNSTSW m2byte");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x4, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x4, &fixedaddress, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
LDRw_U12(x2, xEmu, offsetof(x64emu_t, top));
|
||||
LDRH_U12(x3, xEmu, offsetof(x64emu_t, sw));
|
||||
if(dyn->n.x87stack) {
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
#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 "emu/x87emu_private.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_DE(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 wback;
|
||||
int64_t fixedaddress;
|
||||
int v1, v2;
|
||||
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FADDP STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
FADDS(v1, v1, v2);
|
||||
} else {
|
||||
FADDD(v1, v1, v2);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
INST_NAME("FMULP STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
FMULS(v1, v1, v2);
|
||||
} else {
|
||||
FMULD(v1, v1, v2);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
INST_NAME("FCOMP ST0, STx"); //yep
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
FCMPS(v1, v2);
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xD9:
|
||||
INST_NAME("FCOMPP ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
FCMPS(v1, v2);
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
INST_NAME("FSUBRP STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, v2, v1);
|
||||
} else {
|
||||
FSUBD(v1, v2, v1);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FSUBP STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, v1, v2);
|
||||
} else {
|
||||
FSUBD(v1, v1, v2);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
INST_NAME("FDIVRP STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, v2, v1);
|
||||
} else {
|
||||
FDIVD(v1, v2, v1);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFA:
|
||||
case 0xFB:
|
||||
case 0xFC:
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
INST_NAME("FDIVP STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, v1, v2);
|
||||
} else {
|
||||
FDIVD(v1, v1, v2);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
return 0;
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FIADD ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLDR16_U12(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FADDD(v1, v1, v2);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FIMUL ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLDR16_U12(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FMULD(v1, v1, v2);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FICOM ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLDR16_U12(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FICOMP ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLDR16_U12(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FISUB ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLDR16_U12(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FSUBD(v1, v1, v2);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FISUBR ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLDR16_U12(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FSUBD(v1, v2, v1);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FIDIV ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLDR16_U12(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FDIVD(v1, v1, v2);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FIDIVR ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLDR16_U12(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FDIVD(v1, v2, v1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -151,7 +151,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ew");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
LDRSHw_U12(x1, wback, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
SCVTFSw(v1, x1);
|
||||
@@ -162,7 +162,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 1:
|
||||
INST_NAME("FISTTP Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
@@ -197,7 +197,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FIST Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
@@ -233,7 +233,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FISTP Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
@@ -269,21 +269,21 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 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, x1, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 7, rex, NULL, 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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(fpu_fbst, -1);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
@@ -292,7 +292,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FISTP i64, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
@@ -308,7 +308,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VSTR64_U12(s0, wback, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
MOV64x(x5, 0x8000000000000000LL);
|
||||
ORRx_mask(x5, xZR, 1, 1, 0); //0x8000000000000000
|
||||
STRx_U12(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
|
||||
@@ -28,8 +28,6 @@ void emit_or32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3,
|
||||
{
|
||||
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);
|
||||
@@ -49,7 +47,7 @@ void emit_or32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3,
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
@@ -60,14 +58,11 @@ void emit_or32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3,
|
||||
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);}
|
||||
MOV64xw(s3, c);
|
||||
ORRxw_REG(s1, s1, s3);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
@@ -83,7 +78,7 @@ void emit_or32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
@@ -95,8 +90,6 @@ void emit_xor32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
{
|
||||
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);
|
||||
@@ -116,7 +109,7 @@ void emit_xor32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
@@ -127,14 +120,11 @@ void emit_xor32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
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);}
|
||||
MOV64xw(s3, c);
|
||||
EORxw_REG(s1, s1, s3);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
@@ -150,7 +140,7 @@ void emit_xor32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, in
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
@@ -162,8 +152,6 @@ void emit_and32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
{
|
||||
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);
|
||||
@@ -186,7 +174,7 @@ void emit_and32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
@@ -197,14 +185,11 @@ void emit_and32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
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);}
|
||||
MOV64xw(s3, c);
|
||||
IFX(X_ALL) {
|
||||
ANDSxw_REG(s1, s1, s3);
|
||||
} else {
|
||||
@@ -223,7 +208,7 @@ void emit_and32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, in
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
@@ -235,8 +220,6 @@ 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);
|
||||
@@ -268,8 +251,6 @@ 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);
|
||||
@@ -301,8 +282,6 @@ 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);
|
||||
@@ -334,8 +313,6 @@ 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);
|
||||
@@ -367,8 +344,6 @@ 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);
|
||||
@@ -403,8 +378,6 @@ 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);
|
||||
@@ -440,8 +413,6 @@ 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);
|
||||
@@ -519,8 +490,6 @@ 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);
|
||||
@@ -598,8 +567,6 @@ 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);
|
||||
@@ -612,9 +579,6 @@ void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
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);
|
||||
|
||||
@@ -77,7 +77,7 @@ void emit_add32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
void emit_add32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5)
|
||||
{
|
||||
MAYUSE(s5);
|
||||
if(s1==xRSP && (!dyn->insts || dyn->insts[ninst].x64.need_flags==X_PEND))
|
||||
if(s1==xRSP && (!dyn->insts || dyn->insts[ninst].x64.gen_flags==X_PEND))
|
||||
{
|
||||
// special case when doing math on ESP and only PEND is needed: ignoring it!
|
||||
if(c>=0 && c<0x1000) {
|
||||
@@ -157,8 +157,7 @@ void emit_sub32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
IFX(X_AF) {
|
||||
MVNxw_REG(s3, s1);
|
||||
ORRxw_REG(s3, s3, s2); // s3 = ~op1 | op2
|
||||
ORNxw_REG(s3, s2, s1); // s3 = ~op1 | op2
|
||||
BICxw(s4, s2, s1); // s4 = ~op1 & op2
|
||||
}
|
||||
IFX(X_ALL) {
|
||||
@@ -201,7 +200,7 @@ void emit_sub32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
void emit_sub32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5)
|
||||
{
|
||||
MAYUSE(s5);
|
||||
if(s1==xRSP && (!dyn->insts || dyn->insts[ninst].x64.need_flags==X_PEND))
|
||||
if(s1==xRSP && (!dyn->insts || dyn->insts[ninst].x64.gen_flags==X_PEND))
|
||||
{
|
||||
// special case when doing math on RSP and only PEND is needed: ignoring it!
|
||||
if(c>=0 && c<0x1000) {
|
||||
@@ -612,8 +611,7 @@ void emit_sub16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
IFX(X_AF|X_OF|X_CF) {
|
||||
MVNw_REG(s3, s1);
|
||||
ORRw_REG(s3, s3, s2); // s3 = ~op1 | op2
|
||||
ORNw_REG(s3, s2, s1); // s3 = ~op1 | op2
|
||||
BICw_REG(s4, s2, s1); // s4 = ~op1 & op2
|
||||
}
|
||||
|
||||
@@ -920,7 +918,11 @@ void emit_dec8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
ANDw_mask(s4, s3, 0, 0); // s4 = ~op1 & op2
|
||||
ORRw_mask(s3, s3, 0, 0); // s3 = ~op1 | op2
|
||||
}
|
||||
SUBSw_U12(s1, s1, 1);
|
||||
IFX(X_ZF) {
|
||||
SUBSw_U12(s1, s1, 1);
|
||||
} else {
|
||||
SUBw_U12(s1, s1, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -962,7 +964,11 @@ void emit_dec16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
IFX(X_AF|X_OF) {
|
||||
MVNw_REG(s4, s1);
|
||||
}
|
||||
SUBSw_U12(s1, s1, 1);
|
||||
IFX(X_ZF) {
|
||||
SUBSw_U12(s1, s1, 1);
|
||||
} else {
|
||||
SUBw_U12(s1, s1, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -1177,54 +1183,7 @@ void emit_adc8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4, in
|
||||
{
|
||||
MAYUSE(s5);
|
||||
MOV32w(s5, c&0xff);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s5, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_adc8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_AF | X_OF) {
|
||||
MOVw_REG(s4, s1);
|
||||
}
|
||||
MRS_nzvc(s3);
|
||||
BFIx(s3, xFlags, 29, 1); // set C
|
||||
MSR_nzvc(s3); // load CC into ARM CF
|
||||
ADCw_REG(s1, s1, s5);
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_AF|X_OF) {
|
||||
ORRw_REG(s3, s4, s5); // s3 = op1 | op2
|
||||
ANDw_REG(s4, s4, s5); // s4 = op1 & op2
|
||||
BICw_REG(s3, s3, s1); // s3 = (op1 | op2) & ~ res
|
||||
ORRw_REG(s3, s3, s4); // s4 = (op1 & op2) | ((op1 | op2) & ~ res)
|
||||
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_CF) {
|
||||
LSRw(s3, s1, 8);
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
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_adc8(dyn, ninst, s1, s5, s3, s4);
|
||||
}
|
||||
|
||||
// emit ADC16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
@@ -1246,7 +1205,7 @@ void emit_adc16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MSR_nzvc(s3); // load CC into ARM CF
|
||||
ADCw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
STRw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_AF|X_OF) {
|
||||
ORRw_REG(s3, s4, s2); // s3 = op1 | op2
|
||||
@@ -1536,55 +1495,7 @@ void emit_sbb8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4, in
|
||||
{
|
||||
MAYUSE(s5);
|
||||
MOV32w(s5, c&0xff);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s5, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_sbb8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
EORw_mask(s4, xFlags, 0, 0); // invert CC because it's reverted for SUB on ARM
|
||||
MRS_nzvc(s3);
|
||||
BFIx(s3, s4, 29, 1); // set C, bit 29
|
||||
MSR_nzvc(s3); // load CC into ARM CF
|
||||
IFX(X_AF|X_OF|X_CF) {
|
||||
MVNw_REG(s4, s1);
|
||||
}
|
||||
SBCw_REG(s1, s1, s5);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_AF|X_OF|X_CF) {
|
||||
ORRw_REG(s3, s4, s5); // s3 = ~op1 | op2
|
||||
ANDw_REG(s4, s4, s5); // s4 = ~op1 & op2
|
||||
ANDw_REG(s3, s3, s1); // s3 = (~op1 | op2) & res
|
||||
ORRw_REG(s3, s3, s4); // s3 = (~op1 & op2) | ((~op1 | op2) & res)
|
||||
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_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_sbb8(dyn, ninst, s1, s5, s3, s4);
|
||||
}
|
||||
|
||||
// emit SBB16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
@@ -1773,7 +1684,11 @@ void emit_neg16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
IFX(X_AF|X_OF) {
|
||||
MOVw_REG(s3, s1);
|
||||
}
|
||||
NEGSw_REG(s1, s1);
|
||||
IFX(X_ZF) {
|
||||
NEGSw_REG(s1, s1);
|
||||
} else {
|
||||
NEGw_REG(s1, s1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -1819,7 +1734,11 @@ void emit_neg8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
IFX(X_AF|X_OF) {
|
||||
MOVw_REG(s3, s1);
|
||||
}
|
||||
NEGSw_REG(s1, s1);
|
||||
IFX(X_ZF) {
|
||||
NEGSw_REG(s1, s1);
|
||||
} else {
|
||||
NEGw_REG(s1, s1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
@@ -37,14 +37,11 @@ void emit_shl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(F_OF) {
|
||||
IFX(X_OF) {
|
||||
CMPSxw_U12(s2, 0);
|
||||
IFX(F_OF) {
|
||||
Bcond(cNE, +8);
|
||||
BFCx(xFlags, F_OF, 1);
|
||||
}
|
||||
Bcond(cNE, +8+((dyn->insts[ninst].x64.gen_flags&X_PEND)?4:0));
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
IFX(X_PEND) {
|
||||
Bcond(cNE, +8);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
@@ -81,7 +78,7 @@ void emit_shl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
}
|
||||
|
||||
// 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)
|
||||
void emit_shl32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
@@ -92,8 +89,8 @@ void emit_shl32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, in
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(c==0) {
|
||||
IFX(F_OF) {
|
||||
BFCx(xFlags, F_OF, 1);
|
||||
IFX(X_OF) {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
@@ -175,11 +172,7 @@ void emit_shr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
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);
|
||||
}
|
||||
LSRxw(s4, s1, rex.w?62:30);
|
||||
EORw_REG_LSR(s4, s4, s4, 1);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
@@ -189,7 +182,7 @@ void emit_shr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
}
|
||||
|
||||
// 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)
|
||||
void emit_shr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
@@ -206,10 +199,8 @@ void emit_shr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, in
|
||||
return;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
if(c>1) {
|
||||
LSRxw(s3, s1, c-1);
|
||||
}
|
||||
BFIw(xFlags, (c>1)?s3:s1, 0, 1);
|
||||
LSRxw(s3, s1, c-1);
|
||||
BFIw(xFlags, s3, 0, 1);
|
||||
}
|
||||
LSRxw(s1, s1, c);
|
||||
IFX(X_PEND) {
|
||||
@@ -237,7 +228,7 @@ void emit_shr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, in
|
||||
}
|
||||
|
||||
// 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)
|
||||
void emit_sar32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
@@ -254,10 +245,8 @@ void emit_sar32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, in
|
||||
return;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
if(c>1) {
|
||||
ASRxw(s3, s1, c-1);
|
||||
}
|
||||
BFIw(xFlags, (c>1)?s3:s1, 0, 1);
|
||||
ASRxw(s3, s1, c-1);
|
||||
BFIw(xFlags, s3, 0, 1);
|
||||
}
|
||||
ASRxw(s1, s1, c);
|
||||
IFX(X_PEND) {
|
||||
@@ -278,13 +267,13 @@ void emit_sar32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, in
|
||||
}
|
||||
|
||||
// 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)
|
||||
void emit_rol32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_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);
|
||||
SET_DF(s4, rex.w?d_rol64:d_rol32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
@@ -310,7 +299,7 @@ void emit_rol32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, in
|
||||
}
|
||||
|
||||
// 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)
|
||||
void emit_ror32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
IFX(X_PEND) {
|
||||
@@ -344,7 +333,7 @@ void emit_ror32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, in
|
||||
}
|
||||
|
||||
// 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)
|
||||
void emit_shrd32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4)
|
||||
{
|
||||
c&=(rex.w?0x3f:0x1f);
|
||||
IFX(X_PEND) {
|
||||
@@ -363,10 +352,8 @@ void emit_shrd32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int3
|
||||
return;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
if(c>1) {
|
||||
LSRxw(s3, s1, c-1);
|
||||
}
|
||||
BFIw(xFlags, (c>1)?s3:s1, 0, 1);
|
||||
LSRxw(s3, s1, c-1);
|
||||
BFIw(xFlags, s3, 0, 1);
|
||||
}
|
||||
LSRxw(s3, s1, c);
|
||||
ORRxw_REG_LSL(s1, s3, s2, (rex.w?64:32)-c);
|
||||
@@ -394,7 +381,7 @@ void emit_shrd32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int3
|
||||
}
|
||||
}
|
||||
|
||||
void emit_shld32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int32_t c, int s3, int s4)
|
||||
void emit_shld32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4)
|
||||
{
|
||||
c&=(rex.w?0x3f:0x1f);
|
||||
IFX(X_PEND) {
|
||||
@@ -407,8 +394,8 @@ void emit_shld32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int3
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(c==0) {
|
||||
IFX(F_OF) {
|
||||
BFCx(xFlags, F_OF, 1);
|
||||
IFX(X_OF) {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
|
||||
@@ -85,19 +85,14 @@ void emit_cmp32_0(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int
|
||||
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));
|
||||
IFX(X_OF|X_AF|X_CF) {
|
||||
MOV32w(s4, (1<<F_OF)|(1<<F_AF)|(1<<F_CF));
|
||||
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);
|
||||
@@ -118,12 +113,15 @@ void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
} else {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
SUBw_REG(s5, s1, s2); // res = s1 - s2
|
||||
IFX(X_ZF) {
|
||||
SUBSw_REG(s5, s1, s2); // res = s1 - s2
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
@@ -316,11 +314,9 @@ void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFCw(xFlags, F_CF, 1);
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
ANDSw_REG(s5, s1, s2); // res = s1 & s2
|
||||
IFX_PENDOR0 {
|
||||
@@ -349,11 +345,9 @@ void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFCw(xFlags, F_CF, 1);
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
ANDSw_REG(s5, s1, s2); // res = s1 & s2
|
||||
IFX_PENDOR0 {
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -22,28 +22,6 @@
|
||||
#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, w, D) \
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), w); \
|
||||
} 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, w) gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg(dyn, ninst, x1, gd, w)
|
||||
|
||||
#define GETGX_empty(a) gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg_empty(dyn, ninst, x1, gd)
|
||||
|
||||
#define GETGM(a) \
|
||||
gd = ((nextop&0x38)>>3); \
|
||||
a = mmx_get_reg(dyn, ninst, x1, x2, x3, 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;
|
||||
@@ -59,10 +37,6 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
int d0, d1;
|
||||
int64_t fixedaddress;
|
||||
|
||||
#ifdef PRECISE_CVT
|
||||
int j32;
|
||||
MAYUSE(j32);
|
||||
#endif
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(q0);
|
||||
@@ -81,8 +55,9 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
d0 = sse_get_reg(dyn, ninst, x1, ed, 0);
|
||||
VMOVeD(v0, 0, d0, 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v0, ed, fixedaddress); // upper part reseted
|
||||
}
|
||||
break;
|
||||
@@ -96,8 +71,9 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
d0 = sse_get_reg(dyn, ninst, x1, ed, 1);
|
||||
VMOVeD(d0, 0, v0, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VSTR64_U12(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
@@ -109,8 +85,9 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVeD(v0, 0, d0, 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
VMOVeD(v0, 1, v0, 0);
|
||||
@@ -134,33 +111,47 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("CVTTSD2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEX(q0, 0, 0);
|
||||
GETEXSD(q0, 0, 0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
FCVTZSxwD(gd, q0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
ORRx_mask(gd, xZR, 1, 1, 0); //0x8000000000000000
|
||||
} else {
|
||||
MOV32w(gd, 0x80000000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("CVTSD2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEX(q0, 0, 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);
|
||||
// Construct a "switch case", with each case 2 instructions, so 8 bytes
|
||||
ADR(xLR, GETMARK);
|
||||
ADDx_REG(xLR, xLR, x1);
|
||||
B(xLR);
|
||||
MARK;
|
||||
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
|
||||
GETEXSD(q0, 0, 0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FRINTID(d1, q0);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
FCVTZSxwD(gd, d1);
|
||||
if(!box64_dynarec_fastround) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
ORRx_mask(gd, xZR, 1, 1, 0); //0x8000000000000000
|
||||
} else {
|
||||
MOV32w(gd, 0x80000000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -169,15 +160,15 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0, 0);
|
||||
GETEXSD(d0, 0, 0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
FCMLTD_0(v1, d0);
|
||||
SHL_64(v1, v1, 63);
|
||||
}
|
||||
FSQRTD(d1, d0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
FSQRTD(d1, d0);
|
||||
VORR(d1, d1, v1);
|
||||
} else {
|
||||
FSQRTD(d1, d0);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
break;
|
||||
@@ -187,20 +178,20 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0, 0);
|
||||
GETEXSD(d0, 0, 0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
// check if any input value was NAN
|
||||
FMAXD(v0, d0, d1); // propagate NAN
|
||||
FCMEQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
FADDD(v1, d1, d0); // the high part of the vector is erased...
|
||||
if(!box64_dynarec_fastnan) {
|
||||
FADDD(v1, d1, d0); // the high part of the vector is erased...
|
||||
FCMEQD(q0, v1, v1); // 0 => out is NAN
|
||||
VBIC(q0, v0, q0); // forget it in any input was a NAN already
|
||||
SHL_64(q0, q0, 63); // only keep the sign bit
|
||||
VORR(v1, v1, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FADDD(v1, d1, d0); // the high part of the vector is erased...
|
||||
}
|
||||
VMOVeD(d1, 0, v1, 0);
|
||||
break;
|
||||
@@ -209,20 +200,20 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0, 0);
|
||||
GETEXSD(d0, 0, 0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
// check if any input value was NAN
|
||||
FMAXD(v0, d0, d1); // propagate NAN
|
||||
FCMEQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
FMULD(v1, d1, d0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
FMULD(v1, d1, d0);
|
||||
FCMEQD(q0, v1, v1); // 0 => out is NAN
|
||||
VBIC(q0, v0, q0); // forget it in any input was a NAN already
|
||||
SHL_64(q0, q0, 63); // only keep the sign bit
|
||||
VORR(v1, v1, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FMULD(v1, d1, d0);
|
||||
}
|
||||
VMOVeD(d1, 0, v1, 0);
|
||||
break;
|
||||
@@ -230,7 +221,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("CVTSD2SS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(d0, 0, 0);
|
||||
GETEXSD(d0, 0, 0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FCVT_S_D(d1, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
@@ -241,20 +232,20 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0, 0);
|
||||
GETEXSD(d0, 0, 0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
// check if any input value was NAN
|
||||
FMAXD(v0, d0, d1); // propagate NAN
|
||||
FCMEQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
FSUBD(v1, d1, d0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
FSUBD(v1, d1, d0);
|
||||
FCMEQD(q0, v1, v1); // 0 => out is NAN
|
||||
VBIC(q0, v0, q0); // forget it in any input was a NAN already
|
||||
SHL_64(q0, q0, 63); // only keep the sign bit
|
||||
VORR(v1, v1, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FSUBD(v1, d1, d0);
|
||||
}
|
||||
VMOVeD(d1, 0, v1, 0);
|
||||
break;
|
||||
@@ -262,7 +253,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("MINSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
GETEXSD(v1, 0, 0);
|
||||
// MINSD: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
|
||||
#if 0
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
@@ -279,20 +270,20 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(v1, 0, 0);
|
||||
GETEXSD(v1, 0, 0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
// check if any input value was NAN
|
||||
FMAXD(d0, v0, v1); // propagate NAN
|
||||
FCMEQD(d0, d0, d0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
FDIVD(d1, v0, v1);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
FDIVD(d1, v0, v1);
|
||||
FCMEQD(q0, d1, d1); // 0 => out is NAN
|
||||
VBIC(q0, d0, q0); // forget it in any input was a NAN already
|
||||
SHL_64(q0, q0, 63); // only keep the sign bit
|
||||
VORR(d1, d1, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FDIVD(d1, v0, v1);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
break;
|
||||
@@ -300,7 +291,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("MAXSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
GETEXSD(v1, 0, 0);
|
||||
// MAXSD: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
|
||||
#if 0
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
@@ -343,7 +334,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VLDR128_U12(v1, ed, fixedaddress);
|
||||
}
|
||||
@@ -354,7 +345,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("CMPSD Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 1);
|
||||
GETEXSD(v1, 0, 1);
|
||||
u8 = F8;
|
||||
FCMPD(v0, v1);
|
||||
switch(u8&7) {
|
||||
@@ -374,7 +365,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("ADDSUBPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
GETEXSD(v1, 0, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
static float addsubps[4] = {-1.f, 1.f, -1.f, 1.f};
|
||||
MAYUSE(addsubps);
|
||||
@@ -387,14 +378,14 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("MOVDQ2Q Gm, Ex");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
GETEX(v1, 0, 0);
|
||||
GETEXSD(v1, 0, 0);
|
||||
VMOV(v0, v1);
|
||||
break;
|
||||
|
||||
case 0xE6:
|
||||
INST_NAME("CVTPD2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 0);
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
VFRINTIDQ(v0, v1);
|
||||
@@ -413,7 +404,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
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);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 7, rex, NULL, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -22,24 +22,6 @@
|
||||
#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, w, D) \
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), w); \
|
||||
} 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, w) gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg(dyn, ninst, x1, gd, w)
|
||||
|
||||
#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;
|
||||
@@ -75,7 +57,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
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);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLDR32_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -83,13 +66,14 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("MOVSS Ex, Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
|
||||
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 1);
|
||||
VMOVeS(q0, 0, v0, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VSTR32_U12(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
@@ -98,7 +82,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(MODREG) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VLDR128_U12(q1, ed, fixedaddress);
|
||||
}
|
||||
@@ -112,7 +97,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(MODREG) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VLDR128_U12(q1, ed, fixedaddress);
|
||||
}
|
||||
@@ -144,39 +130,54 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("CVTTSS2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEX(d0, 0, 0);
|
||||
GETEXSS(d0, 0, 0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
FCVTZSxwS(gd, d0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
ORRx_mask(gd, xZR, 1, 1, 0); //0x8000000000000000
|
||||
} else {
|
||||
MOV32w(gd, 0x80000000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("CVTSS2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEX(q0, 0, 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);
|
||||
// Construct a "switch case", with each case 2 instructions, so 8 bytes
|
||||
ADR(xLR, GETMARK);
|
||||
ADDx_REG(xLR, xLR, x1);
|
||||
B(xLR);
|
||||
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
|
||||
GETEXSS(q0, 0, 0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FRINTIS(d1, q0);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
FCVTZSxwS(gd, d1);
|
||||
if(!box64_dynarec_fastround) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
ORRx_mask(gd, xZR, 1, 1, 0); //0x8000000000000000
|
||||
} else {
|
||||
MOV32w(gd, 0x80000000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x51:
|
||||
INST_NAME("SQRTSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0, 0);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FSQRTS(d1, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
@@ -184,7 +185,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("RSQRTSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
GETEXSS(v1, 0, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
// so here: F32: Imm8 = abcd efgh that gives => aBbbbbbc defgh000 00000000 00000000
|
||||
@@ -201,7 +202,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("RCPSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
GETEXSS(v1, 0, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FMOVS_8(d0, 0b01110000); //1.0f
|
||||
FDIVS(d0, d0, v1);
|
||||
@@ -213,7 +214,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0, 0);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FADDS(d1, v0, d0); // the high part of the vector is erased...
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
@@ -222,7 +223,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0, 0);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FMULS(d1, v0, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
@@ -230,15 +231,15 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("CVTSS2SD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
GETEXSS(v1, 0, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FCVT_D_S(d0, v1);
|
||||
VMOVeD(v0, 0, d0, 0);
|
||||
break;
|
||||
case 0x5B:
|
||||
INST_NAME("CVTPS2DQ Gx, Ex");
|
||||
INST_NAME("CVTTPS2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(d0, 0, 0);
|
||||
GETEX(d0, 0, 0) ;
|
||||
GETGX_empty(v0);
|
||||
VFCVTZSQS(v0, d0);
|
||||
break;
|
||||
@@ -248,7 +249,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0, 0);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FSUBS(d1, v0, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
@@ -256,7 +257,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("MINSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
GETEXSS(v1, 0, 0);
|
||||
// MINSS: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
|
||||
#if 0
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
@@ -273,7 +274,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0, 0);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FDIVS(d1, v0, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
@@ -281,7 +282,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("MAXSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
GETEXSS(v1, 0, 0);
|
||||
// MAXSS: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
|
||||
#if 0
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
@@ -297,21 +298,21 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0x6F:
|
||||
INST_NAME("MOVDQU Gx,Ex");// no alignment constraint on NEON here, so same as MOVDQA
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
GETGX_empty(v0);
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x70:
|
||||
INST_NAME("PSHUFHW Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 1);
|
||||
GETEX(v1, 0, 1) ;
|
||||
GETGX(v0, 1);
|
||||
u8 = F8;
|
||||
// only high part need to be suffled. VTBL only handle 8bits value, so the 16bits suffles need to be changed in 8bits
|
||||
@@ -339,7 +340,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
FMOVD(v0, v1);
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -351,8 +353,9 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -364,12 +367,13 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
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
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_CF, 1); // CF = is source 0?
|
||||
RBITxw(x3, ed); // reverse
|
||||
CLZxw(gd, x3); // x2 gets leading 0 == TZCNT
|
||||
TSTxw_REG(gd, gd);
|
||||
CSETw(x1, cEQ);
|
||||
BFIw(xFlags, x1, F_ZF, 1); // ZF = is dest 0?
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1); // ZF = is dest 0?
|
||||
break;
|
||||
case 0xBD:
|
||||
INST_NAME("LZCNT Gd, Ed");
|
||||
@@ -379,18 +383,19 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETED(0);
|
||||
GETGD;
|
||||
TSTxw_REG(ed, ed);
|
||||
BFIw(xFlags, x1, F_CF, 1); // CF = is source 0?
|
||||
CLZxw(gd, x1); // x2 gets leading 0 == LZCNT
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_CF, 1); // CF = is source 0?
|
||||
CLZxw(gd, ed); // x2 gets leading 0 == LZCNT
|
||||
TSTxw_REG(gd, gd);
|
||||
CSETw(x1, cEQ);
|
||||
BFIw(xFlags, x1, F_ZF, 1); // ZF = is dest 0?
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1); // ZF = is dest 0?
|
||||
break;
|
||||
|
||||
case 0xC2:
|
||||
INST_NAME("CMPSS Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 1);
|
||||
GETEXSS(v1, 0, 1);
|
||||
u8 = F8;
|
||||
FCMPS(v0, v1);
|
||||
switch(u8&7) {
|
||||
@@ -415,7 +420,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VEORQ(v0, v0, v0); // usefull?
|
||||
VMOV(v0, v1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -423,14 +429,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0xE6:
|
||||
INST_NAME("CVTDQ2PD Gx, Ex");
|
||||
nextop = F8;
|
||||
// cannot use GETEX because we want 64bits not 32bits
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
} else {
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VLDR64_U12(v1, ed, fixedaddress);
|
||||
}
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
SXTL_32(v0, v1);
|
||||
|
||||
@@ -157,6 +157,11 @@ void arm_ud(x64emu_t* emu)
|
||||
emit_signal(emu, SIGILL, (void*)R_RIP, 0);
|
||||
}
|
||||
|
||||
void arm_priv(x64emu_t* emu)
|
||||
{
|
||||
emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
|
||||
}
|
||||
|
||||
void arm_fsave(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_savenv(emu, (char*)ed, 0);
|
||||
@@ -267,30 +272,29 @@ void arm_aesdlast(x64emu_t* emu, int xmm)
|
||||
emu->xmm[xmm].ub[i] = invsubbytes[eax1.ub[i]];
|
||||
|
||||
}
|
||||
static const uint8_t shiftrows[] = {0, 5,10,15, 4, 9,14, 3, 8,13, 2, 7,12, 1, 6,11};
|
||||
static const uint8_t subbytes[256] = {
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
|
||||
};
|
||||
void arm_aeselast(x64emu_t* emu, int xmm)
|
||||
{
|
||||
// A0 B1 C2 D3 E4 F5 G6 H7 I8 J9 Ka Lb Mc Nd Oe Pf
|
||||
// A F K P E J O D I N C H M B G L
|
||||
const uint8_t shiftrows[] = {0, 5,10,15, 4, 9,14, 3, 8,13, 2, 7,12, 1, 6,11};
|
||||
const uint8_t subbytes[256] = {
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
|
||||
};
|
||||
|
||||
sse_regs_t eax1;
|
||||
for(int i=0; i<16; ++i)
|
||||
eax1.ub[i] = emu->xmm[xmm].ub[shiftrows[i]];
|
||||
@@ -308,6 +312,46 @@ void arm_aese(x64emu_t* emu, int xmm)
|
||||
arm_aeselast(emu, xmm);
|
||||
arm_aesmc(emu, xmm);
|
||||
}
|
||||
void arm_aeskeygenassist(x64emu_t* emu, int gx, int ex, void* p, uint32_t u8)
|
||||
{
|
||||
sse_regs_t *EX = p?((sse_regs_t*)p):&emu->xmm[ex];
|
||||
sse_regs_t *GX = &emu->xmm[gx];
|
||||
for (int i = 4; i < 8; ++i)
|
||||
GX->ub[i] = subbytes[EX->ub[i]];
|
||||
for (int i = 12; i < 16; ++i)
|
||||
GX->ub[i] = subbytes[EX->ub[i]];
|
||||
GX->ud[0] = GX->ud[1];
|
||||
uint8_t tmp8u = GX->ub[4];
|
||||
GX->ud[1] = GX->ud[1] >> 8;
|
||||
GX->ub[7] = tmp8u;
|
||||
GX->ud[1] ^= u8;
|
||||
GX->ud[2] = GX->ud[3];
|
||||
tmp8u = GX->ub[12];
|
||||
GX->ud[3] = GX->ud[3] >> 8;
|
||||
GX->ub[15] = tmp8u;
|
||||
GX->ud[3] ^= u8;
|
||||
}
|
||||
|
||||
void arm_pclmul(x64emu_t* emu, int gx, int ex, void* p, uint32_t u8)
|
||||
{
|
||||
sse_regs_t *EX = p?((sse_regs_t*)p):&emu->xmm[ex];
|
||||
sse_regs_t *GX = &emu->xmm[gx];
|
||||
int g = (u8&1)?1:0;
|
||||
int e = (u8&0b10000)?1:0;
|
||||
__int128 result = 0;
|
||||
__int128 op2 = EX->q[e];
|
||||
for (int i=0; i<64; ++i)
|
||||
if(GX->q[g]&(1LL<<i))
|
||||
result ^= (op2<<i);
|
||||
|
||||
GX->q[0] = result&0xffffffffffffffffLL;
|
||||
GX->q[1] = (result>>64)&0xffffffffffffffffLL;
|
||||
}
|
||||
|
||||
void arm_clflush(x64emu_t* emu, void* p)
|
||||
{
|
||||
cleanDBFromAddressRange((uintptr_t)p, 8, 0);
|
||||
}
|
||||
|
||||
|
||||
#define XMM0 0
|
||||
@@ -351,6 +395,7 @@ int fpu_get_reg_emm(dynarec_arm_t* dyn, int emm)
|
||||
dyn->n.fpuused[EMM0 + emm] = 1;
|
||||
dyn->n.neoncache[EMM0 + emm].t = NEON_CACHE_MM;
|
||||
dyn->n.neoncache[EMM0 + emm].n = emm;
|
||||
dyn->n.news |= (1<<(EMM0 + emm));
|
||||
return EMM0 + emm;
|
||||
}
|
||||
// Get an XMM quad reg
|
||||
@@ -365,6 +410,7 @@ int fpu_get_reg_xmm(dynarec_arm_t* dyn, int t, int xmm)
|
||||
dyn->n.fpuused[i] = 1;
|
||||
dyn->n.neoncache[i].t = t;
|
||||
dyn->n.neoncache[i].n = xmm;
|
||||
dyn->n.news |= (1<<i);
|
||||
return i;
|
||||
}
|
||||
// Reset fpu regs counter
|
||||
@@ -585,7 +631,7 @@ int isCacheEmpty(dynarec_arm_t* dyn, int ninst) {
|
||||
|
||||
}
|
||||
|
||||
int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|
||||
static int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|
||||
int i2 = dyn->insts[ninst].x64.jmp_insts;
|
||||
if(i2<0)
|
||||
return 1;
|
||||
@@ -632,6 +678,48 @@ int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int flagsCacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|
||||
int jmp = dyn->insts[ninst].x64.jmp_insts;
|
||||
if(jmp<0)
|
||||
return 0;
|
||||
if(dyn->insts[ninst].f_exit.dfnone) // flags are fully known, nothing we can do more
|
||||
return 0;
|
||||
/* if((dyn->f.pending!=SF_SET)
|
||||
&& (dyn->f.pending!=SF_SET_PENDING)) {
|
||||
if(dyn->f.pending!=SF_PENDING) {*/
|
||||
switch (dyn->insts[jmp].f_entry.pending) {
|
||||
case SF_UNKNOWN: return 0;
|
||||
case SF_SET:
|
||||
if(dyn->insts[ninst].f_exit.pending!=SF_SET && dyn->insts[ninst].f_exit.pending!=SF_SET_PENDING)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
case SF_SET_PENDING:
|
||||
if(dyn->insts[ninst].f_exit.pending!=SF_SET
|
||||
&& dyn->insts[ninst].f_exit.pending!=SF_SET_PENDING
|
||||
&& dyn->insts[ninst].f_exit.pending!=SF_PENDING)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
case SF_PENDING:
|
||||
if(dyn->insts[ninst].f_exit.pending!=SF_SET
|
||||
&& dyn->insts[ninst].f_exit.pending!=SF_SET_PENDING
|
||||
&& dyn->insts[ninst].f_exit.pending!=SF_PENDING)
|
||||
return 1;
|
||||
else
|
||||
return (dyn->insts[jmp].f_entry.dfnone == dyn->insts[ninst].f_exit.dfnone)?0:1;
|
||||
}
|
||||
if(dyn->insts[jmp].f_entry.dfnone && !dyn->insts[ninst].f_exit.dfnone)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
int CacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|
||||
int ret = 0;
|
||||
if (fpuCacheNeedsTransform(dyn, ninst)) ret|=1;
|
||||
if (flagsCacheNeedsTransform(dyn, ninst)) ret|=2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void neoncacheUnwind(neoncache_t* cache)
|
||||
{
|
||||
if(cache->swapped) {
|
||||
|
||||
@@ -34,9 +34,13 @@ void arm_aese(x64emu_t* emu, int xmm);
|
||||
void arm_aesdlast(x64emu_t* emu, int xmm);
|
||||
void arm_aeselast(x64emu_t* emu, int xmm);
|
||||
void arm_aesimc(x64emu_t* emu, int xmm);
|
||||
void arm_aeskeygenassist(x64emu_t* emu, int gx, int ex, void* p, uint32_t u8);
|
||||
void arm_pclmul(x64emu_t* emu, int gx, int ex, void* p, uint32_t u8);
|
||||
|
||||
void arm_clflush(x64emu_t* emu, void* p);
|
||||
|
||||
void arm_ud(x64emu_t* emu);
|
||||
void arm_priv(x64emu_t* emu);
|
||||
|
||||
// Get an FPU scratch reg
|
||||
int fpu_get_scratch(dynarec_arm_t* dyn);
|
||||
@@ -68,7 +72,7 @@ void neoncache_promote_double(dynarec_arm_t* dyn, int ninst, int a);
|
||||
int neoncache_combine_st(dynarec_arm_t* dyn, int ninst, int a, int b); // with stack current dyn->n_stack*
|
||||
|
||||
// FPU Cache transformation (for loops)
|
||||
int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int i1);
|
||||
int CacheNeedsTransform(dynarec_arm_t* dyn, int i1);
|
||||
|
||||
// Undo the changes of a neoncache to get the status before the instruction
|
||||
void neoncacheUnwind(neoncache_t* cache);
|
||||
|
||||
@@ -27,10 +27,13 @@
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
/* setup r2 to address pointed by ED, also fixaddress is an optionnal delta in the range [-absmax, +absmax], with delta&mask==0 to be added to ed for LDR/STR */
|
||||
uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int absmax, uint32_t mask, rex_t rex, int s, int delta)
|
||||
uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int absmax, uint32_t mask, rex_t rex, int *l, int s, int delta)
|
||||
{
|
||||
MAYUSE(dyn); MAYUSE(ninst); MAYUSE(delta);
|
||||
|
||||
int lock = l?((l==LOCK_LOCK)?1:2):0;
|
||||
if(lock==2)
|
||||
*l = 0;
|
||||
uint8_t ret = x2;
|
||||
uint8_t scratch = x2;
|
||||
*fixaddress = 0;
|
||||
@@ -54,6 +57,10 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
*fixaddress = tmp;
|
||||
}
|
||||
} else {
|
||||
switch(lock) {
|
||||
case 1: addLockAddress(tmp); break;
|
||||
case 2: if(isLockAddress(tmp)) *l=1; break;
|
||||
}
|
||||
MOV64x(ret, tmp);
|
||||
}
|
||||
} else {
|
||||
@@ -73,13 +80,16 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
GETIP(addr+delta);
|
||||
ADDx_U12(ret, xRIP, tmp);
|
||||
} else if(tmp+addr+delta<0x1000000000000LL) { // 3 opcodes to load immediate is cheap enough
|
||||
tmp += addr+delta;
|
||||
MOV64x(ret, tmp);
|
||||
MOV64x(ret, tmp+addr+delta);
|
||||
} else {
|
||||
MOV64x(ret, tmp);
|
||||
GETIP(addr+delta);
|
||||
ADDx_REG(ret, ret, xRIP);
|
||||
}
|
||||
switch(lock) {
|
||||
case 1: addLockAddress(addr+delta+tmp); break;
|
||||
case 2: if(isLockAddress(addr+delta+tmp)) *l=1; break;
|
||||
}
|
||||
} else {
|
||||
ret = xRAX+(nextop&7)+(rex.b<<3);
|
||||
}
|
||||
@@ -156,10 +166,13 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
}
|
||||
|
||||
/* setup r2 to address pointed by ED, also fixaddress is an optionnal delta in the range [-absmax, +absmax], with delta&mask==0 to be added to ed for LDR/STR */
|
||||
uintptr_t geted32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int absmax, uint32_t mask, rex_t rex, int s, int delta)
|
||||
uintptr_t geted32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int absmax, uint32_t mask, rex_t rex, int* l, int s, int delta)
|
||||
{
|
||||
MAYUSE(dyn); MAYUSE(ninst); MAYUSE(delta);
|
||||
|
||||
int lock = l?((l==LOCK_LOCK)?1:2):0;
|
||||
if(lock==2)
|
||||
*l = 0;
|
||||
uint8_t ret = x2;
|
||||
uint8_t scratch = x2;
|
||||
*fixaddress = 0;
|
||||
@@ -183,6 +196,10 @@ uintptr_t geted32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
*fixaddress = tmp;
|
||||
}
|
||||
} else {
|
||||
switch(lock) {
|
||||
case 1: addLockAddress(tmp); break;
|
||||
case 2: if(isLockAddress(tmp)) *l=1; break;
|
||||
}
|
||||
MOV64x(ret, tmp);
|
||||
}
|
||||
} else {
|
||||
@@ -197,6 +214,10 @@ uintptr_t geted32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
MOV32w(ret, tmp);
|
||||
GETIP(addr+delta);
|
||||
ADDw_REG(ret, ret, xRIP);
|
||||
switch(lock) {
|
||||
case 1: addLockAddress(addr+delta+tmp); break;
|
||||
case 2: if(isLockAddress(addr+delta+tmp)) *l=1; break;
|
||||
}
|
||||
} else {
|
||||
ret = xRAX+(nextop&7)+(rex.b<<3);
|
||||
if(ret==hint) {
|
||||
@@ -368,6 +389,7 @@ void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
GETIP_(ip);
|
||||
}
|
||||
TABLE64(x2, (uintptr_t)arm64_epilog);
|
||||
SMEND();
|
||||
BR(x2);
|
||||
}
|
||||
|
||||
@@ -382,30 +404,31 @@ void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
}
|
||||
uintptr_t tbl = getJumpTable64();
|
||||
MAYUSE(tbl);
|
||||
TABLE64(x2, tbl);
|
||||
UBFXx(x3, xRIP, 48, JMPTABL_SHIFT);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, 32, JMPTABL_SHIFT);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, 16, JMPTABL_SHIFT);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, 0, JMPTABL_SHIFT);
|
||||
LDRx_REG_LSL3(x3, x2, x3);
|
||||
TABLE64(x3, tbl);
|
||||
UBFXx(x2, xRIP, JMPTABL_START3, JMPTABL_SHIFT3);
|
||||
LDRx_REG_LSL3(x3, x3, x2);
|
||||
UBFXx(x2, xRIP, JMPTABL_START2, JMPTABL_SHIFT2);
|
||||
LDRx_REG_LSL3(x3, x3, x2);
|
||||
UBFXx(x2, xRIP, JMPTABL_START1, JMPTABL_SHIFT1);
|
||||
LDRx_REG_LSL3(x3, x3, x2);
|
||||
UBFXx(x2, xRIP, JMPTABL_START0, JMPTABL_SHIFT0);
|
||||
LDRx_REG_LSL3(x2, x3, x2);
|
||||
} else {
|
||||
uintptr_t p = getJumpTableAddress64(ip);
|
||||
MAYUSE(p);
|
||||
TABLE64(x2, p);
|
||||
TABLE64(x3, p);
|
||||
GETIP_(ip);
|
||||
LDRx_U12(x3, x2, 0);
|
||||
LDRx_U12(x2, x3, 0);
|
||||
}
|
||||
if(reg!=x1) {
|
||||
MOVx_REG(x1, xRIP);
|
||||
}
|
||||
CLEARIP();
|
||||
#ifdef HAVE_TRACE
|
||||
//MOVx(x2, 15); no access to PC reg
|
||||
//MOVx(x3, 15); no access to PC reg
|
||||
#endif
|
||||
BLR(x3); // save LR...
|
||||
SMEND();
|
||||
BLR(x2); // save LR...
|
||||
}
|
||||
|
||||
void ret_to_epilog(dynarec_arm_t* dyn, int ninst)
|
||||
@@ -413,17 +436,28 @@ void ret_to_epilog(dynarec_arm_t* dyn, int ninst)
|
||||
MAYUSE(dyn); MAYUSE(ninst);
|
||||
MESSAGE(LOG_DUMP, "Ret to epilog\n");
|
||||
POP1(xRIP);
|
||||
MOVx_REG(x1, xRIP);
|
||||
SMEND();
|
||||
if(box64_dynarec_callret) {
|
||||
// pop the actual return address for ARM stack
|
||||
LDPx_S7_offset(x2, x6, xSP, 0);
|
||||
CBZx(x6, 5*4);
|
||||
ADDx_U12(xSP, xSP, 16);
|
||||
SUBx_REG(x6, x6, xRIP); // is it the right address?
|
||||
CBNZx(x6, 2*4);
|
||||
BLR(x2);
|
||||
// not the correct return address, regular jump
|
||||
}
|
||||
uintptr_t tbl = getJumpTable64();
|
||||
MOV64x(x2, tbl);
|
||||
UBFXx(x3, xRIP, 48, JMPTABL_SHIFT);
|
||||
UBFXx(x3, xRIP, JMPTABL_START3, JMPTABL_SHIFT3);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, 32, JMPTABL_SHIFT);
|
||||
UBFXx(x3, xRIP, JMPTABL_START2, JMPTABL_SHIFT2);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, 16, JMPTABL_SHIFT);
|
||||
UBFXx(x3, xRIP, JMPTABL_START1, JMPTABL_SHIFT1);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, 0, JMPTABL_SHIFT);
|
||||
UBFXx(x3, xRIP, JMPTABL_START0, JMPTABL_SHIFT0);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
MOVx_REG(x1, xRIP);
|
||||
BLR(x2); // save LR
|
||||
CLEARIP();
|
||||
}
|
||||
@@ -439,17 +473,28 @@ void retn_to_epilog(dynarec_arm_t* dyn, int ninst, int n)
|
||||
} else {
|
||||
ADDx_U12(xRSP, xRSP, n);
|
||||
}
|
||||
MOVx_REG(x1, xRIP);
|
||||
SMEND();
|
||||
if(box64_dynarec_callret) {
|
||||
// pop the actual return address for ARM stack
|
||||
LDPx_S7_offset(x2, x6, xSP, 0);
|
||||
CBZx(x6, 5*4);
|
||||
ADDx_U12(xSP, xSP, 16);
|
||||
SUBx_REG(x6, x6, xRIP); // is it the right address?
|
||||
CBNZx(x6, 2*4);
|
||||
BLR(x2);
|
||||
// not the correct return address, regular jump
|
||||
}
|
||||
uintptr_t tbl = getJumpTable64();
|
||||
MOV64x(x2, tbl);
|
||||
UBFXx(x3, xRIP, 48, JMPTABL_SHIFT);
|
||||
UBFXx(x3, xRIP, JMPTABL_START3, JMPTABL_SHIFT3);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, 32, JMPTABL_SHIFT);
|
||||
UBFXx(x3, xRIP, JMPTABL_START2, JMPTABL_SHIFT2);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, 16, JMPTABL_SHIFT);
|
||||
UBFXx(x3, xRIP, JMPTABL_START1, JMPTABL_SHIFT1);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, 0, JMPTABL_SHIFT);
|
||||
UBFXx(x3, xRIP, JMPTABL_START0, JMPTABL_SHIFT0);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
MOVx_REG(x1, xRIP);
|
||||
BLR(x2); // save LR
|
||||
CLEARIP();
|
||||
}
|
||||
@@ -482,6 +527,7 @@ void iret_to_epilog(dynarec_arm_t* dyn, int ninst, int is64bits)
|
||||
MOVx_REG(xRSP, x3);
|
||||
// Ret....
|
||||
MOV64x(x2, (uintptr_t)arm64_epilog); // epilog on purpose, CS might have changed!
|
||||
SMEND();
|
||||
BR(x2);
|
||||
CLEARIP();
|
||||
}
|
||||
@@ -804,7 +850,7 @@ void x87_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int
|
||||
if(next) {
|
||||
// need to check if a ST_F need local promotion
|
||||
if(neoncache_get_st_f(dyn, ninst, dyn->n.x87cache[i])>=0) {
|
||||
FCVT_S_D(0, dyn->n.x87reg[i]);
|
||||
FCVT_D_S(0, dyn->n.x87reg[i]);
|
||||
VSTR64_REG_LSL3(0, s1, s3); // save the value
|
||||
} else {
|
||||
VSTR64_REG_LSL3(dyn->n.x87reg[i], s1, s3); // save the value
|
||||
@@ -882,7 +928,7 @@ int x87_get_cache(dynarec_arm_t* dyn, int ninst, int populate, int s1, int s2, i
|
||||
ret = i;
|
||||
// found, setup and grab the value
|
||||
dyn->n.x87cache[ret] = st;
|
||||
dyn->n.x87reg[ret] = fpu_get_reg_x87(dyn, t, st);
|
||||
dyn->n.x87reg[ret] = fpu_get_reg_x87(dyn, NEON_CACHE_ST_D, st);
|
||||
if(populate) {
|
||||
ADDx_U12(s1, xEmu, offsetof(x64emu_t, x87));
|
||||
LDRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
@@ -939,7 +985,12 @@ void x87_refresh(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
ADDw_U12(s2, s2, st);
|
||||
ANDw_mask(s2, s2, 0, 2); //mask=7 // (emu->top + i)&7
|
||||
}
|
||||
VLDR64_REG_LSL3(dyn->n.x87reg[ret], s1, s2);
|
||||
if(dyn->n.neoncache[dyn->n.x87reg[ret]].t==NEON_CACHE_ST_F) {
|
||||
FCVT_D_S(31, dyn->n.x87reg[ret]);
|
||||
VSTR64_REG_LSL3(31, s1, s2);
|
||||
} else {
|
||||
VSTR64_REG_LSL3(dyn->n.x87reg[ret], s1, s2);
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "\t--------x87 Cache for ST%d\n", st);
|
||||
}
|
||||
|
||||
@@ -953,6 +1004,10 @@ void x87_forget(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
if(ret==-1) // nothing to do
|
||||
return;
|
||||
MESSAGE(LOG_DUMP, "\tForget x87 Cache for ST%d\n", st);
|
||||
#if STEP == 1
|
||||
if(dyn->n.neoncache[dyn->n.x87reg[ret]].t==NEON_CACHE_ST_F)
|
||||
neoncache_promote_double(dyn, ninst, st);
|
||||
#endif
|
||||
// prepare offset to fpu => s1
|
||||
ADDx_U12(s1, xEmu, offsetof(x64emu_t, x87));
|
||||
// Get top
|
||||
@@ -980,6 +1035,10 @@ void x87_reget_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
if(dyn->n.x87cache[i]==st) {
|
||||
// refresh the value
|
||||
MESSAGE(LOG_DUMP, "\tRefresh x87 Cache for ST%d\n", st);
|
||||
#if STEP == 1
|
||||
if(dyn->n.neoncache[dyn->n.x87reg[i]].t==NEON_CACHE_ST_F)
|
||||
neoncache_promote_double(dyn, ninst, st);
|
||||
#endif
|
||||
ADDx_U12(s1, xEmu, offsetof(x64emu_t, x87));
|
||||
LDRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
int a = st - dyn->n.x87stack;
|
||||
@@ -1042,7 +1101,8 @@ int x87_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
MAYUSE(dyn); MAYUSE(ninst);
|
||||
MAYUSE(s1); MAYUSE(s2);
|
||||
LDRw_U12(s1, xEmu, offsetof(x64emu_t, round));
|
||||
LDRw_U12(s1, xEmu, offsetof(x64emu_t, cw));
|
||||
BFXILw(s1, s1, 10, 2);
|
||||
UBFXw(s2, s1, 1, 1); // bit 1 of round in bit 0 (zero extented) of s2
|
||||
BFIw(s2, s1, 1, 1); // bit 0 of round in bit 1 of s2
|
||||
MRS_fpcr(s1); // get fpscr
|
||||
@@ -1057,7 +1117,7 @@ int sse_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
MAYUSE(dyn); MAYUSE(ninst);
|
||||
MAYUSE(s1); MAYUSE(s2);
|
||||
LDRH_U12(s1, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
LDRw_U12(s1, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
RBITw(s2, s1); // round is on bits 13-14 on x64,
|
||||
LSRw(s2, s2, 17); // but we want the reverse of that
|
||||
MRS_fpcr(s1); // get fpscr
|
||||
@@ -1227,10 +1287,10 @@ static void sse_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1)
|
||||
++old;
|
||||
}
|
||||
VSTR128_U12(dyn->n.ssecache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
|
||||
if(!next) {
|
||||
fpu_free_reg(dyn, dyn->n.ssecache[i].reg);
|
||||
dyn->n.ssecache[i].v = -1;
|
||||
}
|
||||
}
|
||||
if(!next) {
|
||||
fpu_free_reg(dyn, dyn->n.ssecache[i].reg);
|
||||
dyn->n.ssecache[i].v = -1;
|
||||
}
|
||||
}
|
||||
if(old!=-1) {
|
||||
@@ -1250,16 +1310,16 @@ static void sse_reflectcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
void fpu_pushcache(dynarec_arm_t* dyn, int ninst, int s1, int not07)
|
||||
{
|
||||
int start = not07?8:0;
|
||||
// only SSE regs needs to be push back to xEmu
|
||||
// only SSE regs needs to be push back to xEmu (needs to be "write")
|
||||
int n=0;
|
||||
for (int i=start; i<16; i++)
|
||||
if(dyn->n.ssecache[i].v!=-1)
|
||||
if((dyn->n.ssecache[i].v!=-1) && (dyn->n.ssecache[i].write))
|
||||
++n;
|
||||
if(!n)
|
||||
return;
|
||||
MESSAGE(LOG_DUMP, "\tPush XMM Cache (%d)------\n", n);
|
||||
for (int i=start; i<16; ++i)
|
||||
if(dyn->n.ssecache[i].v!=-1) {
|
||||
if((dyn->n.ssecache[i].v!=-1) && (dyn->n.ssecache[i].write)) {
|
||||
VSTR128_U12(dyn->n.ssecache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "\t------- Push XMM Cache (%d)\n", n);
|
||||
@@ -1268,7 +1328,7 @@ void fpu_pushcache(dynarec_arm_t* dyn, int ninst, int s1, int not07)
|
||||
void fpu_popcache(dynarec_arm_t* dyn, int ninst, int s1, int not07)
|
||||
{
|
||||
int start = not07?8:0;
|
||||
// only SSE regs needs to be pop back from xEmu
|
||||
// only SSE regs needs to be pop back from xEmu (don't need to be "write" this time)
|
||||
int n=0;
|
||||
for (int i=start; i<16; i++)
|
||||
if(dyn->n.ssecache[i].v!=-1)
|
||||
@@ -1413,7 +1473,7 @@ static void loadCache(dynarec_arm_t* dyn, int ninst, int stack_cnt, int s1, int
|
||||
}
|
||||
*s3_top += a;
|
||||
*s2_val = 0;
|
||||
ADDw_REG_LSL(s2, xEmu, s3, 3);
|
||||
ADDx_REG_LSL(s2, xEmu, s3, 3);
|
||||
VLDR64_U12(i, s2, offsetof(x64emu_t, x87));
|
||||
if(t==NEON_CACHE_ST_F) {
|
||||
FCVT_S_D(i, i);
|
||||
@@ -1460,7 +1520,7 @@ static void unloadCache(dynarec_arm_t* dyn, int ninst, int stack_cnt, int s1, in
|
||||
ANDw_mask(s3, s3, 0, 2); //mask=7 // (emu->top + i)&7
|
||||
}
|
||||
*s3_top += a;
|
||||
ADDw_REG_LSL(s2, xEmu, s3, 3);
|
||||
ADDx_REG_LSL(s2, xEmu, s3, 3);
|
||||
*s2_val = 0;
|
||||
if(t==NEON_CACHE_ST_F) {
|
||||
FCVT_D_S(i, i);
|
||||
@@ -1476,7 +1536,7 @@ static void unloadCache(dynarec_arm_t* dyn, int ninst, int stack_cnt, int s1, in
|
||||
cache->neoncache[i].v = 0;
|
||||
}
|
||||
|
||||
void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
#if STEP > 1
|
||||
int i2 = dyn->insts[ninst].x64.jmp_insts;
|
||||
@@ -1607,6 +1667,58 @@ void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
MESSAGE(LOG_DUMP, "\t---- Cache Transform\n");
|
||||
#endif
|
||||
}
|
||||
static void flagsCacheTransform(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
#if STEP > 1
|
||||
int j64;
|
||||
int jmp = dyn->insts[ninst].x64.jmp_insts;
|
||||
if(jmp<0)
|
||||
return;
|
||||
if(dyn->f.dfnone) // flags are fully known, nothing we can do more
|
||||
return;
|
||||
MESSAGE(LOG_DUMP, "\tFlags fetch ---- ninst=%d -> %d\n", ninst, jmp);
|
||||
int go = 0;
|
||||
switch (dyn->insts[jmp].f_entry.pending) {
|
||||
case SF_UNKNOWN: break;
|
||||
case SF_SET:
|
||||
if(dyn->f.pending!=SF_SET && dyn->f.pending!=SF_SET_PENDING)
|
||||
go = 1;
|
||||
break;
|
||||
case SF_SET_PENDING:
|
||||
if(dyn->f.pending!=SF_SET
|
||||
&& dyn->f.pending!=SF_SET_PENDING
|
||||
&& dyn->f.pending!=SF_PENDING)
|
||||
go = 1;
|
||||
break;
|
||||
case SF_PENDING:
|
||||
if(dyn->f.pending!=SF_SET
|
||||
&& dyn->f.pending!=SF_SET_PENDING
|
||||
&& dyn->f.pending!=SF_PENDING)
|
||||
go = 1;
|
||||
else
|
||||
go = (dyn->insts[jmp].f_entry.dfnone == dyn->f.dfnone)?0:1;
|
||||
break;
|
||||
}
|
||||
if(dyn->insts[jmp].f_entry.dfnone && !dyn->f.dfnone)
|
||||
go = 1;
|
||||
if(go) {
|
||||
if(dyn->f.pending!=SF_PENDING) {
|
||||
LDRw_U12(s1, xEmu, offsetof(x64emu_t, df));
|
||||
j64 = (GETMARK3)-(dyn->native_size);
|
||||
CBZw(s1, j64);
|
||||
}
|
||||
CALL_(UpdateFlags, -1, 0);
|
||||
MARK3;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd, int s1, int s2, int s3) {
|
||||
if(cacheupd&1)
|
||||
fpuCacheTransform(dyn, ninst, s1, s2, s3);
|
||||
if(cacheupd&2)
|
||||
flagsCacheTransform(dyn, ninst, s1);
|
||||
}
|
||||
|
||||
#ifdef HAVE_TRACE
|
||||
void fpu_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
|
||||
@@ -32,6 +32,33 @@
|
||||
#define PK64(a) *(uint64_t*)(addr+a)
|
||||
#define PKip(a) *(uint8_t*)(ip+a)
|
||||
|
||||
// Strong mem emulation helpers
|
||||
// Sequence of Read will trigger a DMB on "first" read if strongmem is 2
|
||||
// Squence of Write will trigger a DMB on "last" write if strongmem is 1
|
||||
// Opcode will read
|
||||
#define SMREAD() if(!dyn->smread && box64_dynarec_strongmem>1) {SMDMB();}
|
||||
// Opcode will read with option forced lock
|
||||
#define SMREADLOCK(lock) if(lock || (!dyn->smread && box64_dynarec_strongmem>1)) {SMDMB();}
|
||||
// Opcode migh read (depend on nextop)
|
||||
#define SMMIGHTREAD() if(!MODREG) {SMREAD();}
|
||||
// Opcode has wrote
|
||||
#define SMWRITE() dyn->smwrite=1
|
||||
// Opcode has wrote (strongmem>1 only)
|
||||
#define SMWRITE2() if(box64_dynarec_strongmem>1) dyn->smwrite=1
|
||||
// Opcode has wrote with option forced lock
|
||||
#define SMWRITELOCK(lock) if(lock) {SMDMB();} else dyn->smwrite=1
|
||||
// Opcode migh have wrote (depend on nextop)
|
||||
#define SMMIGHTWRITE() if(!MODREG) {SMWRITE();}
|
||||
// Start of sequence
|
||||
#define SMSTART() SMEND()
|
||||
// End of sequence
|
||||
#define SMEND() if(dyn->smwrite && box64_dynarec_strongmem) {DMB_ISH();} dyn->smwrite=0; dyn->smread=0;
|
||||
// Force a Data memory barrier (for LOCK: prefix)
|
||||
#define SMDMB() DMB_ISH(); dyn->smwrite=0; dyn->smread=1
|
||||
|
||||
//LOCK_* define
|
||||
#define LOCK_LOCK (int*)1
|
||||
|
||||
// GETGD get x64 register in gd
|
||||
#define GETGD gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3)
|
||||
//GETED can use r1 for ed, and r2 for wback. wback is 0 if ed is xEAX..xEDI
|
||||
@@ -39,7 +66,8 @@
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, D); \
|
||||
SMREAD() \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, D); \
|
||||
LDRxw_U12(x1, wback, fixedaddress); \
|
||||
ed = x1; \
|
||||
}
|
||||
@@ -47,7 +75,8 @@
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<3, 7, rex, 0, D); \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, D); \
|
||||
LDRx_U12(x1, wback, fixedaddress); \
|
||||
ed = x1; \
|
||||
}
|
||||
@@ -55,7 +84,8 @@
|
||||
ed = xEAX+(nextop&7)+(rex.b<<3); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, D); \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL,0, D); \
|
||||
LDRw_U12(x1, wback, fixedaddress); \
|
||||
ed = x1; \
|
||||
}
|
||||
@@ -65,7 +95,8 @@
|
||||
wb = x1; \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, D); \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, D); \
|
||||
LDRSW_U12(x1, wback, fixedaddress); \
|
||||
wb = ed = x1; \
|
||||
}
|
||||
@@ -73,7 +104,8 @@
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted32(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, D); \
|
||||
SMREAD(); \
|
||||
addr = geted32(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, D); \
|
||||
LDRxw_U12(x1, wback, fixedaddress); \
|
||||
ed = x1; \
|
||||
}
|
||||
@@ -83,7 +115,8 @@
|
||||
wb = x1; \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted32(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, D); \
|
||||
SMREAD(); \
|
||||
addr = geted32(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, D); \
|
||||
LDRSW_U12(x1, wback, fixedaddress); \
|
||||
wb = ed = x1; \
|
||||
}
|
||||
@@ -92,7 +125,8 @@
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, (hint==x2)?x1:x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, D); \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, (hint==x2)?x1:x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, D); \
|
||||
LDRxw_U12(hint, wback, fixedaddress); \
|
||||
ed = hint; \
|
||||
}
|
||||
@@ -100,7 +134,8 @@
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted32(dyn, addr, ninst, nextop, &wback, (hint==x2)?x1:x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, D); \
|
||||
SMREAD(); \
|
||||
addr = geted32(dyn, addr, ninst, nextop, &wback, (hint==x2)?x1:x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, D); \
|
||||
LDRxw_U12(hint, wback, fixedaddress); \
|
||||
ed = hint; \
|
||||
}
|
||||
@@ -110,7 +145,8 @@
|
||||
MOVxw_REG(ret, ed); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, hint, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, D); \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, hint, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, D); \
|
||||
ed = ret; \
|
||||
LDRxw_U12(ed, wback, fixedaddress); \
|
||||
}
|
||||
@@ -119,34 +155,35 @@
|
||||
MOVxw_REG(ret, ed); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted32(dyn, addr, ninst, nextop, &wback, hint, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, D); \
|
||||
SMREAD(); \
|
||||
addr = geted32(dyn, addr, ninst, nextop, &wback, hint, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, D); \
|
||||
ed = ret; \
|
||||
LDRxw_U12(ed, wback, fixedaddress); \
|
||||
}
|
||||
// Write back ed in wback (if wback not 0)
|
||||
#define WBACK if(wback) {STRxw_U12(ed, wback, fixedaddress);}
|
||||
#define WBACK if(wback) {STRxw_U12(ed, wback, fixedaddress); SMWRITE();}
|
||||
// Write back ed in wback (if wback not 0)
|
||||
#define WBACKx if(wback) {STRx_U12(ed, wback, fixedaddress);}
|
||||
#define WBACKx if(wback) {STRx_U12(ed, wback, fixedaddress); SMWRITE();}
|
||||
// Write back ed in wback (if wback not 0)
|
||||
#define WBACKw if(wback) {STRw_U12(ed, wback, fixedaddress);}
|
||||
// Send back wb to either ed or wback
|
||||
#define SBACK(wb) if(wback) {STRxw(wb, wback, fixedaddress);} else {MOVxw_REG(ed, wb);}
|
||||
#define WBACKw if(wback) {STRw_U12(ed, wback, fixedaddress); SMWRITE();}
|
||||
//GETEDO can use r1 for ed, and r2 for wback. wback is 0 if ed is xEAX..xEDI
|
||||
#define GETEDO(O, D) if(MODREG) { \
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, D); \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, NULL, 0, D); \
|
||||
LDRxw_REG(x1, wback, O); \
|
||||
ed = x1; \
|
||||
}
|
||||
#define WBACKO(O) if(wback) {STRxw_REG(ed, wback, O);}
|
||||
#define WBACKO(O) if(wback) {STRxw_REG(ed, wback, O); SMWRITE2();}
|
||||
//GETEDOx can use r1 for ed, and r2 for wback. wback is 0 if ed is xEAX..xEDI
|
||||
#define GETEDOx(O, D) if(MODREG) { \
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, D); \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, NULL, 0, D); \
|
||||
LDRx_REG(x1, wback, O); \
|
||||
ed = x1; \
|
||||
}
|
||||
@@ -156,7 +193,8 @@
|
||||
wb = x1; \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, D); \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, NULL, 0, D); \
|
||||
LDRSW_REG(x1, wback, O); \
|
||||
wb = ed = x1; \
|
||||
}
|
||||
@@ -175,7 +213,8 @@
|
||||
ed = i; \
|
||||
wb1 = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, w, &fixedaddress, 0xfff<<1, (1<<1)-1, rex, 0, D); \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, w, &fixedaddress, 0xfff<<1, (1<<1)-1, rex, NULL, 0, D); \
|
||||
LDRH_U12(i, wback, fixedaddress); \
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
@@ -187,7 +226,8 @@
|
||||
ed = i; \
|
||||
wb1 = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<1, (1<<1)-1, rex, 0, D); \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<1, (1<<1)-1, rex, NULL, 0, D); \
|
||||
LDRH_U12(i, wback, fixedaddress); \
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
@@ -199,15 +239,16 @@
|
||||
ed = i; \
|
||||
wb1 = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<1, (1<<1)-1, rex, 0, D); \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<1, (1<<1)-1, rex, NULL, 0, D); \
|
||||
LDRSHx_U12(i, wback, fixedaddress);\
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
}
|
||||
// Write ed back to original register / memory
|
||||
#define EWBACK if(wb1) {STRH_U12(ed, wback, fixedaddress);} else {BFIx(wback, ed, 0, 16);}
|
||||
#define EWBACK if(wb1) {STRH_U12(ed, wback, fixedaddress); SMWRITE();} else {BFIx(wback, ed, 0, 16);}
|
||||
// Write w back to original register / memory
|
||||
#define EWBACKW(w) if(wb1) {STRH_U12(w, wback, fixedaddress);} else {BFIx(wback, w, 0, 16);}
|
||||
#define EWBACKW(w) if(wb1) {STRH_U12(w, wback, fixedaddress); SMWRITE();} else {BFIx(wback, w, 0, 16);}
|
||||
// Write back gd in correct register
|
||||
#define GWBACK BFIx((xRAX+((nextop&0x38)>>3)+(rex.r<<3)), gd, 0, 16);
|
||||
//GETEB will use i for ed, and can use r3 for wback.
|
||||
@@ -224,7 +265,8 @@
|
||||
wb1 = 0; \
|
||||
ed = i; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff, 0, rex, 0, D); \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff, 0, rex, NULL, 0, D); \
|
||||
LDRB_U12(i, wback, fixedaddress); \
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
@@ -243,7 +285,8 @@
|
||||
wb1 = 0; \
|
||||
ed = i; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, rex, 0, D); \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff, 0, rex, NULL, 0, D); \
|
||||
ADDx_REG(x3, wback, i); \
|
||||
if(wback!=x3) wback = x3; \
|
||||
LDRB_U12(i, wback, fixedaddress); \
|
||||
@@ -264,13 +307,34 @@
|
||||
wb1 = 0; \
|
||||
ed = i; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff, 0, rex, 0, D); \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff, 0, rex, NULL, 0, D); \
|
||||
LDRSBx_U12(i, wback, fixedaddress); \
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
}
|
||||
//GETEB will use i for ed, and can use r3 for wback.
|
||||
#define GETEB32(i, D) if(MODREG) { \
|
||||
if(rex.rex) { \
|
||||
wback = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
wb2 = 0; \
|
||||
} else { \
|
||||
wback = (nextop&7); \
|
||||
wb2 = (wback>>2)*8; \
|
||||
wback = xRAX+(wback&3); \
|
||||
} \
|
||||
UBFXx(i, wback, wb2, 8); \
|
||||
wb1 = 0; \
|
||||
ed = i; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted32(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff, 0, rex, NULL, 0, D); \
|
||||
LDRB_U12(i, wback, fixedaddress); \
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
}
|
||||
// Write eb (ed) back to original register / memory
|
||||
#define EBBACK if(wb1) {STRB_U12(ed, wback, fixedaddress);} else {BFIx(wback, ed, wb2, 8);}
|
||||
#define EBBACK if(wb1) {STRB_U12(ed, wback, fixedaddress); SMWRITE();} else {BFIx(wback, ed, wb2, 8);}
|
||||
//GETGB will use i for gd
|
||||
#define GETGB(i) if(rex.rex) { \
|
||||
gb1 = xRAX+((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
@@ -296,6 +360,84 @@
|
||||
// Write gb (gd) back to original register / memory
|
||||
#define GBBACK BFIx(gb1, gd, gb2, 8);
|
||||
|
||||
// Generic get GD, but reg value in gd (R_RAX is not added)
|
||||
#define GETG gd = ((nextop&0x38)>>3)+(rex.r<<3)
|
||||
|
||||
// Get GX as a quad (might use x1)
|
||||
#define GETGX(a, w) \
|
||||
gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg(dyn, ninst, x1, gd, w)
|
||||
|
||||
// Get an empty GX (use x1)
|
||||
#define GETGX_empty(a) \
|
||||
gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg_empty(dyn, ninst, x1, gd)
|
||||
|
||||
// Get EX as a quad, (x1 is used)
|
||||
#define GETEX(a, w, D) \
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), w); \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, D); \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
VLDR128_U12(a, ed, fixedaddress); \
|
||||
}
|
||||
|
||||
// Put Back EX if it was a memory and not an emm register
|
||||
#define PUTEX(a) \
|
||||
if(!MODREG) { \
|
||||
VSTR128_U12(a, ed, fixedaddress); \
|
||||
SMWRITE2(); \
|
||||
}
|
||||
|
||||
|
||||
// Get Ex as a double, not a quad (warning, x1 get used)
|
||||
#define GETEXSD(a, w, D) \
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), w); \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, D); \
|
||||
VLDR64_U12(a, ed, fixedaddress); \
|
||||
}
|
||||
|
||||
// Get Ex as a single, not a quad (warning, x1 get used)
|
||||
#define GETEXSS(a, w, D) \
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), w); \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, D); \
|
||||
VLDR32_U12(a, ed, fixedaddress); \
|
||||
}
|
||||
|
||||
// Get GM, might use x1, x2 and x3
|
||||
#define GETGM(a) \
|
||||
gd = ((nextop&0x38)>>3); \
|
||||
a = mmx_get_reg(dyn, ninst, x1, x2, x3, gd)
|
||||
|
||||
// Get EM, might use x1, x2 and x3
|
||||
#define GETEM(a, D) \
|
||||
if(MODREG) { \
|
||||
a = mmx_get_reg(dyn, ninst, x1, x2, x3, (nextop&7)); \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, D); \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
VLDR64_U12(a, ed, fixedaddress); \
|
||||
}
|
||||
|
||||
// Put Back EM if it was a memory and not an emm register
|
||||
#define PUTEM(a) \
|
||||
if(!MODREG) { \
|
||||
VSTR64_U12(a, ed, fixedaddress); \
|
||||
SMWRITE2(); \
|
||||
}
|
||||
|
||||
|
||||
// Get Direction with size Z and based of F_DF flag, on register r ready for LDR/STR fetching
|
||||
// F_DF is 1<<10, so 1 ROR 11*2 (so F_OF)
|
||||
#define GETDIR(r, A) \
|
||||
@@ -386,10 +528,18 @@
|
||||
#define CBNZx_MARK3(reg) \
|
||||
j64 = GETMARK3-(dyn->native_size); \
|
||||
CBNZx(reg, j64)
|
||||
// Branch to MARK3 if reg is not 0 (use j64)
|
||||
#define CBNZw_MARK3(reg) \
|
||||
j64 = GETMARK3-(dyn->native_size); \
|
||||
CBNZw(reg, j64)
|
||||
// Branch to MARK3 if reg is 0 (use j64)
|
||||
#define CBZx_MARK3(reg) \
|
||||
j64 = GETMARK3-(dyn->native_size); \
|
||||
CBZx(reg, j64)
|
||||
// Branch to MARK3 if reg is 0 (use j64)
|
||||
#define CBZw_MARK3(reg) \
|
||||
j64 = GETMARK3-(dyn->native_size); \
|
||||
CBZw(reg, j64)
|
||||
// Test bit N of A and branch to MARK3 if not set
|
||||
#define TBZ_MARK3(A, N) \
|
||||
j64 = GETMARK3-(dyn->native_size); \
|
||||
@@ -443,15 +593,19 @@
|
||||
j64 = GETMARKLOCK-(dyn->native_size); \
|
||||
Bcond(cond, j64)
|
||||
// Branch to MARKLOCK if reg is not 0 (use j64)
|
||||
#define CBNZw_MARKLOCK(reg) \
|
||||
j64 = GETMARKLOCK-(dyn->native_size); \
|
||||
CBNZw(reg, j64)
|
||||
// Branch to MARKLOCK if reg is not 0 (use j64)
|
||||
#define CBNZx_MARKLOCK(reg) \
|
||||
j64 = GETMARKLOCK-(dyn->native_size); \
|
||||
CBNZx(reg, j64)
|
||||
|
||||
#define IFX(A) if((dyn->insts[ninst].x64.need_flags&(A)))
|
||||
#define IFX_PENDOR0 if((dyn->insts[ninst].x64.need_flags&(X_PEND) || !dyn->insts[ninst].x64.need_flags))
|
||||
#define IFXX(A) if((dyn->insts[ninst].x64.need_flags==(A)))
|
||||
#define IFX2X(A, B) if((dyn->insts[ninst].x64.need_flags==(A) || dyn->insts[ninst].x64.need_flags==(B) || dyn->insts[ninst].x64.need_flags==((A)|(B))))
|
||||
#define IFXN(A, B) if((dyn->insts[ninst].x64.need_flags&(A) && !(dyn->insts[ninst].x64.need_flags&(B))))
|
||||
#define IFX(A) if((dyn->insts[ninst].x64.gen_flags&(A)))
|
||||
#define IFX_PENDOR0 if((dyn->insts[ninst].x64.gen_flags&(X_PEND) || !dyn->insts[ninst].x64.gen_flags))
|
||||
#define IFXX(A) if((dyn->insts[ninst].x64.gen_flags==(A)))
|
||||
#define IFX2X(A, B) if((dyn->insts[ninst].x64.gen_flags==(A) || dyn->insts[ninst].x64.gen_flags==(B) || dyn->insts[ninst].x64.gen_flags==((A)|(B))))
|
||||
#define IFXN(A, B) if((dyn->insts[ninst].x64.gen_flags&(A) && !(dyn->insts[ninst].x64.gen_flags&(B))))
|
||||
|
||||
// Generate FCOM with s1 and s2 scratch regs (the VCMP is already done)
|
||||
#define FCOM(s1, s2, s3) \
|
||||
@@ -469,9 +623,19 @@
|
||||
|
||||
// Generate FCOMI with s1 and s2 scratch regs (the VCMP is already done)
|
||||
#define FCOMI(s1, s2) \
|
||||
IFX(X_CF|X_PF|X_ZF|X_PEND) { \
|
||||
MOV32w(s2, 0b01000101); \
|
||||
IFX(X_OF|X_AF|X_SF|X_PEND) { \
|
||||
MOV32w(s2, 0b100011010101); \
|
||||
BICw_REG(xFlags, xFlags, s2); \
|
||||
IFX(X_CF|X_PF|X_ZF|X_PEND) { \
|
||||
MOV32w(s2, 0b01000101); \
|
||||
} \
|
||||
} else { \
|
||||
IFX(X_CF|X_PF|X_ZF|X_PEND) { \
|
||||
MOV32w(s2, 0b01000101); \
|
||||
BICw_REG(xFlags, xFlags, s2); \
|
||||
} \
|
||||
} \
|
||||
IFX(X_CF|X_PF|X_ZF|X_PEND) { \
|
||||
CSETw(s1, cMI); /* 1 if less than, 0 else */ \
|
||||
/*s2 already set */ /* unordered */ \
|
||||
CSELw(s1, s2, s1, cVS); \
|
||||
@@ -481,60 +645,43 @@
|
||||
ORRw_REG(xFlags, xFlags, s1); \
|
||||
} \
|
||||
SET_DFNONE(s1); \
|
||||
IFX(X_OF|X_PEND) { \
|
||||
BFCw(xFlags, F_OF, 1); \
|
||||
} \
|
||||
IFX(X_AF|X_PEND) { \
|
||||
BFCw(xFlags, F_AF, 1); \
|
||||
} \
|
||||
IFX(X_SF|X_PEND) { \
|
||||
BFCw(xFlags, F_SF, 1); \
|
||||
} \
|
||||
|
||||
|
||||
#define STORE_REG(A) STRx_U12(x##A, xEmu, offsetof(x64emu_t, regs[_##A]))
|
||||
#define STP_REGS(A, B) STPx_S7_offset(x##A, x##B, xEmu, offsetof(x64emu_t, regs[_##A]))
|
||||
#define LDP_REGS(A, B) LDPx_S7_offset(x##A, x##B, xEmu, offsetof(x64emu_t, regs[_##A]))
|
||||
#define STORE_XEMU_REGS(A) \
|
||||
STORE_REG(RAX); \
|
||||
STORE_REG(RCX); \
|
||||
STORE_REG(RDX); \
|
||||
STORE_REG(RBX); \
|
||||
STORE_REG(RSP); \
|
||||
STORE_REG(RBP); \
|
||||
STORE_REG(RSI); \
|
||||
STORE_REG(RDI); \
|
||||
STORE_REG(R8); \
|
||||
STORE_REG(R9); \
|
||||
STORE_REG(R10); \
|
||||
STORE_REG(R11); \
|
||||
STORE_REG(R12); \
|
||||
STORE_REG(R13); \
|
||||
STORE_REG(R14); \
|
||||
STORE_REG(R15); \
|
||||
STRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags)); \
|
||||
if(A) {STRx_U12(A, xEmu, offsetof(x64emu_t, ip));}
|
||||
STP_REGS(RAX, RCX); \
|
||||
STP_REGS(RDX, RBX); \
|
||||
STP_REGS(RSP, RBP); \
|
||||
STP_REGS(RSI, RDI); \
|
||||
STP_REGS(R8, R9); \
|
||||
STP_REGS(R10, R11); \
|
||||
STP_REGS(R12, R13); \
|
||||
STP_REGS(R14, R15); \
|
||||
if(A==xRIP) { \
|
||||
STPx_S7_offset(xFlags, xRIP, xEmu, offsetof(x64emu_t, eflags)); \
|
||||
} else { \
|
||||
STRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags)); \
|
||||
if(A) {STRx_U12(A, xEmu, offsetof(x64emu_t, ip));} \
|
||||
}
|
||||
|
||||
#define LOAD_REG(A) LDRx_U12(x##A, xEmu, offsetof(x64emu_t, regs[_##A]))
|
||||
#define LOAD_XEMU_REGS(A) \
|
||||
LOAD_REG(RAX); \
|
||||
LOAD_REG(RCX); \
|
||||
LOAD_REG(RDX); \
|
||||
LOAD_REG(RBX); \
|
||||
LOAD_REG(RSP); \
|
||||
LOAD_REG(RBP); \
|
||||
LOAD_REG(RSI); \
|
||||
LOAD_REG(RDI); \
|
||||
LOAD_REG(R8); \
|
||||
LOAD_REG(R9); \
|
||||
LOAD_REG(R10); \
|
||||
LOAD_REG(R11); \
|
||||
LOAD_REG(R12); \
|
||||
LOAD_REG(R13); \
|
||||
LOAD_REG(R14); \
|
||||
LOAD_REG(R15); \
|
||||
LDRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags)); \
|
||||
if(A) {LDRx_U12(A, xEmu, offsetof(x64emu_t, ip));}
|
||||
#define LOAD_XEMU_REGS(A) \
|
||||
LDP_REGS(RAX, RCX); \
|
||||
LDP_REGS(RDX, RBX); \
|
||||
LDP_REGS(RSP, RBP); \
|
||||
LDP_REGS(RSI, RDI); \
|
||||
LDP_REGS(R8, R9); \
|
||||
LDP_REGS(R10, R11); \
|
||||
LDP_REGS(R12, R13); \
|
||||
LDP_REGS(R14, R15); \
|
||||
if(A==xRIP) { \
|
||||
LDPx_S7_offset(xFlags, xRIP, xEmu, offsetof(x64emu_t, eflags)); \
|
||||
} else { \
|
||||
LDRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags)); \
|
||||
if(A) {LDRx_U12(A, xEmu, offsetof(x64emu_t, ip));} \
|
||||
}
|
||||
|
||||
#define STORE_XEMU_MINIMUM(A) \
|
||||
STORE_REG(RAX); \
|
||||
@@ -575,6 +722,10 @@
|
||||
#define SET_NODF() dyn->f.dfnone = 0
|
||||
#define SET_DFOK() dyn->f.dfnone = 1
|
||||
|
||||
#ifndef MAYSETFLAGS
|
||||
#define MAYSETFLAGS()
|
||||
#endif
|
||||
|
||||
#ifndef READFLAGS
|
||||
#define READFLAGS(A) \
|
||||
if(((A)!=X_PEND && dyn->f.pending!=SF_SET) \
|
||||
@@ -590,23 +741,21 @@
|
||||
SET_DFOK(); \
|
||||
}
|
||||
#endif
|
||||
// SF_MAYSET doesn't change the flags status cache
|
||||
// it also doesn't consume any needed flags
|
||||
|
||||
#ifndef SETFLAGS
|
||||
#define SETFLAGS(A, B) \
|
||||
if(dyn->f.pending!=SF_SET \
|
||||
&& (B==SF_SUBSET || B==SF_SUBSET_PENDING) \
|
||||
&& (dyn->insts[ninst].x64.need_flags&(~((A)|((B==SF_SUBSET_PENDING)?X_PEND:0))))) \
|
||||
READFLAGS(dyn->insts[ninst].x64.need_flags&(~(A)|X_PEND)); \
|
||||
if(dyn->insts[ninst].x64.need_flags) switch(B) { \
|
||||
&& ((B)&SF_SUB) \
|
||||
&& (dyn->insts[ninst].x64.gen_flags&(~(A)))) \
|
||||
READFLAGS(((dyn->insts[ninst].x64.gen_flags&X_PEND)?X_ALL:dyn->insts[ninst].x64.gen_flags)&(~(A)));\
|
||||
if(dyn->insts[ninst].x64.gen_flags) switch(B) { \
|
||||
case SF_SUBSET: \
|
||||
case SF_SET: dyn->f.pending = SF_SET; break; \
|
||||
case SF_PENDING: dyn->f.pending = SF_PENDING; break; \
|
||||
case SF_SUBSET_PENDING: \
|
||||
case SF_SET_PENDING: \
|
||||
dyn->f.pending = (dyn->insts[ninst].x64.need_flags&X_PEND)?SF_SET_PENDING:SF_SET; \
|
||||
dyn->f.pending = (dyn->insts[ninst].x64.gen_flags&X_PEND)?SF_SET_PENDING:SF_SET; \
|
||||
break; \
|
||||
case SF_MAYSET: break; \
|
||||
} else dyn->f.pending = SF_SET
|
||||
#endif
|
||||
#ifndef JUMP
|
||||
@@ -618,12 +767,12 @@
|
||||
#ifndef BARRIER_NEXT
|
||||
#define BARRIER_NEXT(A)
|
||||
#endif
|
||||
#define UFLAG_OP1(A) if(dyn->insts[ninst].x64.need_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, op1));}
|
||||
#define UFLAG_OP2(A) if(dyn->insts[ninst].x64.need_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, op2));}
|
||||
#define UFLAG_OP12(A1, A2) if(dyn->insts[ninst].x64.need_flags) {STRxw_U12(A1, xEmu, offsetof(x64emu_t, op1));STRxw_U12(A2, 0, offsetof(x64emu_t, op2));}
|
||||
#define UFLAG_RES(A) if(dyn->insts[ninst].x64.need_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, res));}
|
||||
#define UFLAG_DF(r, A) if(dyn->insts[ninst].x64.need_flags) {SET_DF(r, A)}
|
||||
#define UFLAG_IF if(dyn->insts[ninst].x64.need_flags)
|
||||
#define UFLAG_OP1(A) if(dyn->insts[ninst].x64.gen_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, op1));}
|
||||
#define UFLAG_OP2(A) if(dyn->insts[ninst].x64.gen_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, op2));}
|
||||
#define UFLAG_OP12(A1, A2) if(dyn->insts[ninst].x64.gen_flags) {STRxw_U12(A1, xEmu, offsetof(x64emu_t, op1));STRxw_U12(A2, 0, offsetof(x64emu_t, op2));}
|
||||
#define UFLAG_RES(A) if(dyn->insts[ninst].x64.gen_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, res));}
|
||||
#define UFLAG_DF(r, A) if(dyn->insts[ninst].x64.gen_flags) {SET_DF(r, A)}
|
||||
#define UFLAG_IF if(dyn->insts[ninst].x64.gen_flags)
|
||||
#ifndef DEFAULT
|
||||
#define DEFAULT *ok = -1; BARRIER(2)
|
||||
#endif
|
||||
@@ -707,6 +856,7 @@ void* arm64_next(x64emu_t* emu, uintptr_t addr);
|
||||
#define dynarec64_F0 STEPNAME(dynarec64_F0)
|
||||
#define dynarec64_660F STEPNAME(dynarec64_660F)
|
||||
#define dynarec64_6664 STEPNAME(dynarec64_6664)
|
||||
#define dynarec64_66F0 STEPNAME(dynarec64_66F0)
|
||||
#define dynarec64_F20F STEPNAME(dynarec64_F20F)
|
||||
#define dynarec64_F30F STEPNAME(dynarec64_F30F)
|
||||
|
||||
@@ -826,13 +976,13 @@ void* arm64_next(x64emu_t* emu, uintptr_t addr);
|
||||
#define fpu_reflectcache STEPNAME(fpu_reflectcache)
|
||||
#endif
|
||||
|
||||
#define fpuCacheTransform STEPNAME(fpuCacheTransform)
|
||||
#define CacheTransform STEPNAME(CacheTransform)
|
||||
|
||||
/* setup r2 to address pointed by */
|
||||
uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int absmax, uint32_t mask, rex_t rex, int s, int delta);
|
||||
uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int absmax, uint32_t mask, rex_t rex, int* l, int s, int delta);
|
||||
|
||||
/* setup r2 to address pointed by */
|
||||
uintptr_t geted32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int absmax, uint32_t mask, rex_t rex, int s, int delta);
|
||||
uintptr_t geted32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int absmax, uint32_t mask, rex_t rex, int* l, int s, int delta);
|
||||
|
||||
/* setup r2 to address pointed by */
|
||||
uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int absmax, uint32_t mask, int s);
|
||||
@@ -908,14 +1058,14 @@ void emit_neg32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4
|
||||
void emit_neg16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_neg8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_shl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
void emit_shl32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, int s3, int s4);
|
||||
void emit_shl32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_shr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
void emit_shr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, int s3, int s4);
|
||||
void emit_sar32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, int s3, int s4);
|
||||
void emit_rol32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, int s3, int s4);
|
||||
void emit_ror32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, int s3, int s4);
|
||||
void emit_shrd32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int32_t c, int s3, int s4);
|
||||
void emit_shld32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int32_t c, int s3, int s4);
|
||||
void emit_shr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_sar32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rol32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_ror32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_shrd32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4);
|
||||
void emit_shld32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4);
|
||||
|
||||
void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
|
||||
@@ -953,12 +1103,12 @@ void x87_restoreround(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
// Set rounding according to mxcsr flags, return reg to restore flags
|
||||
int sse_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
|
||||
void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd, int s1, int s2, int s3);
|
||||
|
||||
#if STEP < 2
|
||||
#define CHECK_CACHE() 0
|
||||
#else
|
||||
#define CHECK_CACHE() fpuCacheNeedsTransform(dyn, ninst)
|
||||
#define CHECK_CACHE() (cacheupd = CacheNeedsTransform(dyn, ninst))
|
||||
#endif
|
||||
|
||||
#define neoncache_st_coherency STEPNAME(neoncache_st_coherency)
|
||||
@@ -1028,11 +1178,12 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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);
|
||||
uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
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);
|
||||
//uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
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);
|
||||
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);
|
||||
uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
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);
|
||||
uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int seg, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog);
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "arm64_emitter.h"
|
||||
|
||||
#define EMIT(A) *block = (A); ++block
|
||||
void CreateJmpNext(void* addr, void* next)
|
||||
{
|
||||
uint32_t* block = (uint32_t*)addr;
|
||||
LDRx_literal(x2, (intptr_t)next - (intptr_t)addr);
|
||||
BR(x2);
|
||||
}
|
||||
@@ -6,16 +6,15 @@
|
||||
if(ninst) dyn->insts[ninst-1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst-1].x64.addr
|
||||
|
||||
#define MESSAGE(A, ...)
|
||||
#define MAYSETFLAGS() dyn->insts[ninst].x64.may_set = 1
|
||||
#define READFLAGS(A) \
|
||||
dyn->insts[ninst].x64.use_flags = A; dyn->f.dfnone = 1;\
|
||||
dyn->f.pending=SF_SET
|
||||
#define SETFLAGS(A,B) \
|
||||
dyn->insts[ninst].x64.set_flags = A; \
|
||||
if(B!=SF_MAYSET) { \
|
||||
dyn->insts[ninst].x64.state_flags = B; \
|
||||
dyn->f.pending=(B)&SF_SET_PENDING; \
|
||||
dyn->f.dfnone=((B)&SF_SET)?1:0; \
|
||||
}
|
||||
dyn->insts[ninst].x64.set_flags = A; \
|
||||
dyn->insts[ninst].x64.state_flags = B; \
|
||||
dyn->f.pending=(B)&SF_SET_PENDING; \
|
||||
dyn->f.dfnone=((B)&SF_SET)?1:0;
|
||||
#define EMIT(A)
|
||||
#define JUMP(A, C) add_next(dyn, (uintptr_t)A); dyn->insts[ninst].x64.jmp = A; dyn->insts[ninst].x64.jmp_cond = C
|
||||
#define BARRIER(A) if(A!=BARRIER_MAYBE) {fpu_purgecache(dyn, ninst, 0, x1, x2, x3); dyn->insts[ninst].x64.barrier = A;} else dyn->insts[ninst].barrier_maybe = 1
|
||||
@@ -23,7 +22,7 @@
|
||||
#define NEW_INST \
|
||||
++dyn->size; \
|
||||
if(dyn->size+3>=dyn->cap) { \
|
||||
dyn->insts = (instruction_native_t*)realloc(dyn->insts, sizeof(instruction_native_t)*dyn->cap*2); \
|
||||
dyn->insts = (instruction_native_t*)customRealloc(dyn->insts, sizeof(instruction_native_t)*dyn->cap*2);\
|
||||
memset(&dyn->insts[dyn->cap], 0, sizeof(instruction_native_t)*dyn->cap); \
|
||||
dyn->cap *= 2; \
|
||||
} \
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
#define INIT dyn->native_size = 0
|
||||
#define FINI if(ninst) {dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size);}
|
||||
#define FINI \
|
||||
if(ninst) { \
|
||||
dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size); \
|
||||
dyn->insts_size += 1+((dyn->insts[ninst].x64.size>dyn->insts[ninst].size)?dyn->insts[ninst].x64.size:dyn->insts[ninst].size)/15; \
|
||||
}
|
||||
|
||||
#define MESSAGE(A, ...)
|
||||
#define EMIT(A) dyn->insts[ninst].size+=4; dyn->native_size+=4
|
||||
#define NEW_INST \
|
||||
if(ninst) { \
|
||||
dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size); \
|
||||
if(ninst && isInstClean(dyn, ninst)) { \
|
||||
if(isInstClean(dyn, ninst) && dyn->last_ip!=ip) \
|
||||
dyn->last_ip = 0; \
|
||||
++dyn->sons_size; \
|
||||
} \
|
||||
dyn->insts_size += 1+((dyn->insts[ninst-1].x64.size>dyn->insts[ninst-1].size)?dyn->insts[ninst-1].x64.size:dyn->insts[ninst-1].size)/15; \
|
||||
}
|
||||
#define INST_EPILOG dyn->insts[ninst].epilog = dyn->native_size;
|
||||
#define INST_NAME(name)
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#define INIT
|
||||
#define FINI
|
||||
#define FINI \
|
||||
if(ninst) \
|
||||
addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst].x64.size, dyn->insts[ninst].size/4); \
|
||||
addInst(dyn->instsize, &dyn->insts_size, 0, 0);
|
||||
#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); \
|
||||
@@ -9,17 +12,15 @@
|
||||
#define MESSAGE(A, ...) if(box64_dynarec_dump) dynarec_log(LOG_NONE, __VA_ARGS__)
|
||||
#define NEW_INST \
|
||||
if(ninst && isInstClean(dyn, ninst)) { \
|
||||
dyn->last_ip = 0; \
|
||||
dyn->sons_x64[dyn->sons_size] = (uintptr_t)ip; \
|
||||
dyn->sons_native[dyn->sons_size] = dyn->block; \
|
||||
MESSAGE(LOG_DUMP, "----> potential Son here %p/%p\n", (void*)ip, dyn->block); \
|
||||
++dyn->sons_size; \
|
||||
}
|
||||
if(dyn->last_ip!=ip) dyn->last_ip = 0; \
|
||||
} \
|
||||
if(ninst) \
|
||||
addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst-1].x64.size, dyn->insts[ninst-1].size/4);
|
||||
#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, inst=%d, barrier=%d state=%d/%d(%d), set=%X, use=%X, need=%X", \
|
||||
dynarec_log(LOG_NONE, "%s%p: %d emited opcodes, inst=%d, barrier=%d state=%d/%d(%d), %s=%X/%X, use=%X, need=%X/%X, sm=%d/%d", \
|
||||
(box64_dynarec_dump>1)?"\e[32m":"", \
|
||||
(void*)(dyn->native_start+dyn->insts[ninst].address), \
|
||||
dyn->insts[ninst].size/4, \
|
||||
@@ -28,9 +29,13 @@
|
||||
dyn->insts[ninst].x64.state_flags, \
|
||||
dyn->f.pending, \
|
||||
dyn->f.dfnone, \
|
||||
dyn->insts[ninst].x64.may_set?"may":"set", \
|
||||
dyn->insts[ninst].x64.set_flags, \
|
||||
dyn->insts[ninst].x64.gen_flags, \
|
||||
dyn->insts[ninst].x64.use_flags, \
|
||||
dyn->insts[ninst].x64.need_flags); \
|
||||
dyn->insts[ninst].x64.need_before, \
|
||||
dyn->insts[ninst].x64.need_after, \
|
||||
dyn->smread, dyn->smwrite); \
|
||||
if(dyn->insts[ninst].pred_sz) { \
|
||||
dynarec_log(LOG_NONE, ", pred="); \
|
||||
for(int ii=0; ii<dyn->insts[ninst].pred_sz; ++ii)\
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
typedef struct x64emu_s x64emu_t;
|
||||
typedef struct dynablock_s dynablock_t;
|
||||
typedef struct instsize_s instsize_t;
|
||||
|
||||
#define BARRIER_MAYBE 8
|
||||
|
||||
@@ -18,15 +19,15 @@ typedef struct dynablock_s dynablock_t;
|
||||
typedef union neon_cache_s {
|
||||
int8_t v;
|
||||
struct {
|
||||
unsigned int t:4; // reg type
|
||||
unsigned int n:4; // reg number
|
||||
uint8_t t:4; // reg type
|
||||
uint8_t n:4; // reg number
|
||||
};
|
||||
} neon_cache_t;
|
||||
typedef union sse_cache_s {
|
||||
int8_t v;
|
||||
struct {
|
||||
unsigned int reg:7;
|
||||
unsigned int write:1;
|
||||
uint8_t reg:7;
|
||||
uint8_t write:1;
|
||||
};
|
||||
} sse_cache_t;
|
||||
typedef struct neoncache_s {
|
||||
@@ -81,7 +82,7 @@ typedef struct instruction_arm64_s {
|
||||
} instruction_arm64_t;
|
||||
|
||||
typedef struct dynarec_arm_s {
|
||||
instruction_arm64_t *insts;
|
||||
instruction_arm64_t*insts;
|
||||
int32_t size;
|
||||
int32_t cap;
|
||||
uintptr_t start; // start of the block
|
||||
@@ -90,7 +91,7 @@ typedef struct dynarec_arm_s {
|
||||
uintptr_t native_start; // start of the arm code
|
||||
size_t native_size; // size of emitted arm code
|
||||
uintptr_t last_ip; // last set IP in RIP (or NULL if unclean state) TODO: move to a cache something
|
||||
uint64_t *table64; // table of 64bits value
|
||||
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;
|
||||
@@ -99,11 +100,16 @@ typedef struct dynarec_arm_s {
|
||||
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_native; // the arm address of potential dynablock sons
|
||||
int sons_size; // number of potential dynablock sons
|
||||
int* predecessor;// single array of all predecessor
|
||||
dynablock_t* dynablock;
|
||||
instsize_t* instsize;
|
||||
size_t insts_size; // size of the instruction size array (calculated)
|
||||
uint8_t smread; // for strongmem model emulation
|
||||
uint8_t smwrite; // for strongmem model emulation
|
||||
uintptr_t forward; // address of the last end of code while testing forward
|
||||
uintptr_t forward_to; // address of the next jump to (to check if everything is ok)
|
||||
int32_t forward_size; // size at the forward point
|
||||
int forward_ninst; // ninst at the forward point
|
||||
} dynarec_arm_t;
|
||||
|
||||
void add_next(dynarec_arm_t *dyn, uintptr_t addr);
|
||||
@@ -113,6 +119,8 @@ 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
|
||||
|
||||
void CreateJmpNext(void* addr, void* next);
|
||||
|
||||
#define GO_TRACE() \
|
||||
GETIP_(ip); \
|
||||
MOVx_REG(x1, xRIP); \
|
||||
|
||||
+126
-408
@@ -3,6 +3,7 @@
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <setjmp.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
@@ -19,6 +20,7 @@
|
||||
#include "dynablock_private.h"
|
||||
#include "dynarec_private.h"
|
||||
#include "elfloader.h"
|
||||
#include "bridge.h"
|
||||
|
||||
#include "dynarec_native.h"
|
||||
#include "native_lock.h"
|
||||
@@ -26,8 +28,6 @@
|
||||
#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;
|
||||
@@ -37,261 +37,92 @@ uint32_t X31_hash_code(void* addr, int len)
|
||||
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;
|
||||
ret->minstart = text;
|
||||
ret->maxend = text+textsz-1;
|
||||
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, int need_lock)
|
||||
{
|
||||
if(db) {
|
||||
if(db->gone)
|
||||
return; // already in the process of deletion!
|
||||
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-1, db->parent, db->father, db->sons_size, db->gone);
|
||||
dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x64=%p:%p already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size-1, db->gone);
|
||||
if(need_lock)
|
||||
pthread_mutex_lock(&my_context->mutex_dyndump);
|
||||
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)
|
||||
native_lock_xchg(&db->parent->direct[addr-startdb], 0); // secured write
|
||||
}
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
// 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*)native_lock_xchg(&db->sons[i], 0);
|
||||
FreeDynablock(son, 0);
|
||||
}
|
||||
// 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);
|
||||
dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->actual_block, db->size);
|
||||
db->done = 0;
|
||||
db->gone = 1;
|
||||
FreeDynarecMap((uintptr_t)db->actual_block);
|
||||
customFree(db);
|
||||
if(need_lock)
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
}
|
||||
|
||||
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], 1);
|
||||
}
|
||||
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
|
||||
dynarec_log(LOG_DEBUG, "MarkDynablock %p with %d son(s) %p-%p\n", db, db->sons_size, db->x64_addr, db->x64_addr+db->x64_size-1);
|
||||
dynarec_log(LOG_DEBUG, "MarkDynablock %p %p-%p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1);
|
||||
db->need_test = 1;
|
||||
setJumpTableDefault64(db->x64_addr);
|
||||
for(int i=0; i<db->sons_size; ++i)
|
||||
setJumpTableDefault64(db->sons[i]->x64_addr);
|
||||
setJumpTableIfRef64(db->x64_addr, db->jmpnext, db->block);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
static 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)
|
||||
static int MarkedDynablock(dynablock_t* db)
|
||||
{
|
||||
// Mark will try to find *any* blocks that intersect the range to mark
|
||||
if(!dynablocks)
|
||||
return;
|
||||
if(!dynablocks->direct)
|
||||
return;
|
||||
uintptr_t startdb = dynablocks->text;
|
||||
uintptr_t sizedb = dynablocks->textsz;
|
||||
dynablock_t *db;
|
||||
dynarec_log(LOG_DEBUG, "MarkDirectDynablock %p-%p .. startdb=%p, sizedb=%p\n", (void*)addr, (void*)addr+size-1, (void*)startdb, (void*)sizedb);
|
||||
for(uintptr_t i = 0; i<sizedb; ++i)
|
||||
if((db=dynablocks->direct[i]))
|
||||
if(IntervalIntersects((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr+db->x64_size-1, addr, addr+size+1))
|
||||
MarkDynablock(db);
|
||||
if(db) {
|
||||
if(db->need_test)
|
||||
return 1; // already done
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
void MarkRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
// Mark will try to find *any* blocks that intersect the range to mark
|
||||
if(!db)
|
||||
return;
|
||||
dynarec_log(LOG_DEBUG, "MarkRangeDynablock %p-%p .. startdb=%p, sizedb=%p\n", (void*)addr, (void*)addr+size-1, (void*)db->x64_addr, (void*)db->x64_size);
|
||||
if(!MarkedDynablock(db))
|
||||
if(IntervalIntersects((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr+db->x64_size-1, addr, addr+size+1))
|
||||
MarkDynablock(db);
|
||||
}
|
||||
|
||||
int FreeRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!db)
|
||||
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*)native_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, 1);
|
||||
);
|
||||
kh_destroy(dynablocks, blocks);
|
||||
// check emptyness
|
||||
for(uintptr_t i=0; i<dynablocks->textsz; ++i)
|
||||
if(dynablocks->direct[i])
|
||||
return 0;
|
||||
return 1;
|
||||
int need_lock = my_context?1:0;
|
||||
if(IntervalIntersects((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr+db->x64_size-1, addr, addr+size+1)) {
|
||||
FreeDynablock(db, need_lock);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
dynarec_log(LOG_DEBUG, "MarkRangeDynablock %p-%p\n", (void*)addr, (void*)addr+size-1);
|
||||
if(dynablocks->direct) {
|
||||
uintptr_t new_addr = dynablocks->minstart;
|
||||
uintptr_t new_size = dynablocks->maxend - new_addr + 1;
|
||||
MarkDirectDynablock(dynablocks, addr, size);
|
||||
// the blocks check before
|
||||
for(unsigned idx=(new_addr)>>DYNAMAP_SHIFT; idx<(addr>>DYNAMAP_SHIFT); ++idx)
|
||||
MarkDirectDynablock(getDB(idx), addr, size);
|
||||
}
|
||||
}
|
||||
|
||||
dynablock_t* FindDynablockDynablocklist(void* addr, kh_dynablocks_t* dynablocks)
|
||||
dynablock_t *AddNewDynablock(uintptr_t addr)
|
||||
{
|
||||
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;
|
||||
dynablock_t* block;
|
||||
#if 0
|
||||
// check if memory as the correct flags
|
||||
int prot = getProtection(addr);
|
||||
if(!(prot&(PROT_EXEC|PROT_DYNAREC|PROT_DYNAREC_R))) {
|
||||
dynarec_log(LOG_VERBOSE, "Block asked on a memory with no execution flags 0x%02X\n", prot);
|
||||
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;
|
||||
|
||||
pthread_mutex_lock(&my_context->mutex_dyndump);
|
||||
if(!dynablocks->direct) {
|
||||
dynablock_t** p = (dynablock_t**)calloc(dynablocks->textsz, sizeof(dynablock_t*));
|
||||
if(native_lock_storeifnull(&dynablocks->direct, p)!=p)
|
||||
free(p); // someone already create the direct array, too late...
|
||||
}
|
||||
|
||||
#endif
|
||||
// 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*)native_lock_storeifnull(&dynablocks->direct[addr-dynablocks->text], block);
|
||||
if(tmp != block) {
|
||||
// a block appeard!
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
free(block);
|
||||
*created = 0;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
*created = 1;
|
||||
pthread_mutex_lock(&my_context->mutex_dyndump);
|
||||
block = (dynablock_t*)customCalloc(1, sizeof(dynablock_t));
|
||||
return block;
|
||||
}
|
||||
|
||||
@@ -307,217 +138,107 @@ void cancelFillBlock()
|
||||
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, int need_lock)
|
||||
static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, int need_lock)
|
||||
{
|
||||
// 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)
|
||||
if(hasAlternate((void*)addr))
|
||||
return NULL;
|
||||
dynablock_t* block = getDB(addr);
|
||||
if(block || !create)
|
||||
return block;
|
||||
|
||||
if(need_lock) {
|
||||
if(box64_dynarec_wait) {
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
} else {
|
||||
if(mutex_trylock(&my_context->mutex_dyndump)) // FillBlock not available for now
|
||||
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...
|
||||
|
||||
block = getDB(addr); // just in case
|
||||
if(block) {
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
return block;
|
||||
}
|
||||
|
||||
block = AddNewDynablock(addr);
|
||||
|
||||
// fill the block
|
||||
block->x64_addr = (void*)addr;
|
||||
if(need_lock)
|
||||
pthread_mutex_lock(&my_context->mutex_dyndump);
|
||||
if(sigsetjmp(&dynarec_jmpbuf, 1)) {
|
||||
printf_log(LOG_INFO, "FillBlock at %p triggered a segfault, cancelling\n", (void*)addr);
|
||||
if(need_lock)
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
return NULL;
|
||||
}
|
||||
void* ret = FillBlock64(block, filladdr);
|
||||
if(need_lock)
|
||||
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*)native_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);
|
||||
customFree(block);
|
||||
block = NULL;
|
||||
}
|
||||
// check size
|
||||
if(block && block->x64_size) {
|
||||
if(dynablocks->minstart>addr)
|
||||
dynablocks->minstart = addr;
|
||||
if(block && (block->x64_size || (!block->x64_size && !block->done))) {
|
||||
int blocksz = block->x64_size;
|
||||
if(dynablocks->maxend<addr+blocksz) {
|
||||
dynablocks->maxend = addr+blocksz;
|
||||
for(unsigned idx=(addr>>DYNAMAP_SHIFT)+1; idx<=((addr+blocksz-1)>>DYNAMAP_SHIFT); ++idx) {
|
||||
dynablocklist_t* dblist;
|
||||
if((dblist = getDB(idx)))
|
||||
if(dblist->minstart>addr)
|
||||
dblist->minstart = addr;
|
||||
}
|
||||
}
|
||||
if(blocksz>my_context->max_db_size)
|
||||
my_context->max_db_size = blocksz;
|
||||
// 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;
|
||||
if(!addJumpTableIfDefault64(block->x64_addr, block->block)) {
|
||||
FreeDynablock(block, 0);
|
||||
block = getDB(addr);
|
||||
} else {
|
||||
if(block->x64_size)
|
||||
block->done = 1; // don't validate the block if the size is null, but keep the block
|
||||
}
|
||||
block->done = 1;
|
||||
}
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
|
||||
dynarec_log(LOG_DEBUG, "%04d| --- DynaRec Block %s @%p:%p (%p, 0x%x bytes, with %d son(s))\n", GetTID(), created?"created":"recycled", (void*)addr, (void*)(addr+((block)?block->x64_size:1)-1), (block)?block->block:0, (block)?block->size:0, (block)?block->sons_size:0);
|
||||
dynarec_log(LOG_DEBUG, "%04d| --- DynaRec Block created @%p:%p (%p, 0x%x bytes)\n", GetTID(), (void*)addr, (void*)(addr+((block)?block->x64_size:1)-1), (block)?block->block:0, (block)?block->size:0);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
#define MAX_HOTPAGE 64
|
||||
#define HOTPAGE_STEP 64
|
||||
static int volatile hotpage_count[MAX_HOTPAGE] = {0};
|
||||
static uintptr_t volatile hotpage[MAX_HOTPAGE] = {0};
|
||||
static uintptr_t volatile hotpage_size[MAX_HOTPAGE] = {0};
|
||||
static volatile int hotpages = 0;
|
||||
|
||||
int IsInHotPage(uintptr_t addr) {
|
||||
if(!hotpages)
|
||||
return 0;
|
||||
for(int i=0; i<MAX_HOTPAGE; ++i) {
|
||||
if((hotpage_count[i]>0) && (addr>=hotpage[i]) && (addr<hotpage[i]+0x1000*(hotpage_size[i]+1))) {
|
||||
--hotpage_count[i];
|
||||
if(!hotpage_count[i]) {
|
||||
--hotpages;
|
||||
hotpage_size[i] = 0;
|
||||
dynarec_log(LOG_DEBUG, "End of Hotpage %p\n", (void*)hotpage[i]);
|
||||
}
|
||||
__sync_synchronize();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AreaInHotPage(uintptr_t start, uintptr_t end) {
|
||||
if(!hotpages)
|
||||
return 0;
|
||||
for(int i=0; i<MAX_HOTPAGE; ++i) {
|
||||
if(hotpage_count[i]>0)
|
||||
if(IntervalIntersects(start, end, hotpage[i], hotpage[i]+0x1000*(hotpage_size[i]+1)-1)) {
|
||||
--hotpage_count[i];
|
||||
if(!hotpage_count[i]) {
|
||||
--hotpages;
|
||||
hotpage_size[i] = 0;
|
||||
dynarec_log(LOG_DEBUG, "End of Hotpage %p\n", (void*)hotpage[i]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AddHotPage(uintptr_t addr) {
|
||||
addr&=~0xfff;
|
||||
// look for same address
|
||||
for(int i=0; i<MAX_HOTPAGE; ++i) {
|
||||
if(addr>=hotpage[i] && addr<hotpage[i]+0x1000*(hotpage_size[i]+1)) {
|
||||
if(!hotpage_count[i])
|
||||
++hotpages;
|
||||
hotpage_count[i] = HOTPAGE_STEP;
|
||||
__sync_synchronize();
|
||||
return;
|
||||
}
|
||||
if(addr==hotpage[i]+0x1000*(hotpage_size[i]+1)) {
|
||||
++hotpage_size[i];
|
||||
hotpage_count[i] = HOTPAGE_STEP;
|
||||
__sync_synchronize();
|
||||
return;
|
||||
}
|
||||
if(addr+0x1000==hotpage[i]) {
|
||||
++hotpage_size[i];
|
||||
hotpage[i] = addr;
|
||||
hotpage_count[i] = HOTPAGE_STEP;
|
||||
__sync_synchronize();
|
||||
return;
|
||||
}
|
||||
}
|
||||
// look for empty spot / minium
|
||||
int mincnt = hotpage_count[0];
|
||||
int minidx = 0;
|
||||
for(int i=1; i<MAX_HOTPAGE; ++i)
|
||||
if(hotpage_count[i]<mincnt) {
|
||||
mincnt = hotpage_count[i];
|
||||
minidx = i;
|
||||
}
|
||||
if(hotpage_count[minidx]) {
|
||||
static int cnt = 0;
|
||||
if(cnt<50) {
|
||||
dynarec_log(LOG_NONE, "Warning, not enough Hotpage, replacing %p(%p/%d) with %p\n", (void*)hotpage[minidx], (void*)(0x1000*(hotpage_size[minidx]+1)), hotpage_count[minidx], (void*)addr);
|
||||
++cnt;
|
||||
if(cnt==50) // stop spamming console with message...
|
||||
dynarec_log(LOG_NONE, " will stop warning about not enough Hotpage now\n");
|
||||
}
|
||||
hotpage_size[minidx] = 0;
|
||||
} else
|
||||
++hotpages;
|
||||
hotpage[minidx] = addr;
|
||||
hotpage_count[minidx] = HOTPAGE_STEP;
|
||||
__sync_synchronize();
|
||||
}
|
||||
|
||||
dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, dynablock_t** current)
|
||||
dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create)
|
||||
{
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, *current, 1);
|
||||
dynablock_t *father = (db && db->father)?db->father:db;
|
||||
if(father && father->done && db->block && father->need_test) {
|
||||
if(pthread_mutex_trylock(&my_context->mutex_dyndump)) {
|
||||
dynarec_log(LOG_DEBUG, "mutex_dyndump not available when trying to validate block %p from %p:%p (hash:%X) with %d son(s) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, db->hash, db->sons_size, (void*)addr);
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, 1);
|
||||
if(db && db->done && db->block && db->need_test) {
|
||||
if(AreaInHotPage((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr + db->x64_size - 1)) {
|
||||
if(box64_dynarec_fastpage) {
|
||||
uint32_t hash = X31_hash_code(db->x64_addr, db->x64_size);
|
||||
if(hash==db->hash) // seems ok, run it without reprotecting it
|
||||
return db;
|
||||
db->done = 0; // invalidating the block, it's already not good
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, hash, db->hash, (void*)addr);
|
||||
// Free db, it's now invalid!
|
||||
FreeDynablock(db, 1);
|
||||
return NULL; // not building a new one, it's still a hotpage
|
||||
} else {
|
||||
dynarec_log(LOG_INFO, "Not running block %p from %p:%p with for %p because it's in a hotpage\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
uint32_t hash = X31_hash_code(db->x64_addr, db->x64_size);
|
||||
if(mutex_trylock(&my_context->mutex_dyndump)) {
|
||||
dynarec_log(LOG_DEBUG, "mutex_dyndump not available when trying to validate block %p from %p:%p (hash:%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, db->hash, (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
if(AreaInHotPage((uintptr_t)father->x64_addr, (uintptr_t)father->x64_addr + father->x64_size - 1)) {
|
||||
dynarec_log(LOG_DEBUG, "Not running block %p from %p:%p with %d son(s) for %p because it's in a hotpage\n", father, father->x64_addr, father->x64_addr+father->x64_size-1, father->sons_size, (void*)addr);
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
return NULL;
|
||||
}
|
||||
uint32_t hash = X31_hash_code(father->x64_addr, father->x64_size);
|
||||
if(hash!=father->hash) {
|
||||
father->done = 0; // invalidating the block
|
||||
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-1, hash, father->hash, father->sons_size, (void*)addr);
|
||||
// no more current if it gets invalidated too
|
||||
if(*current && IntervalIntersects(
|
||||
(uintptr_t)father->x64_addr,
|
||||
(uintptr_t)father->x64_addr+father->x64_size-1,
|
||||
(uintptr_t)(*current)->x64_addr,
|
||||
(uintptr_t)(*current)->x64_addr+(*current)->x64_size-1))
|
||||
*current = NULL;
|
||||
// Free father, it's now invalid!
|
||||
FreeDynablock(father, 0);
|
||||
if(hash!=db->hash) {
|
||||
db->done = 0; // invalidating the block
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, hash, db->hash, (void*)addr);
|
||||
// Free db, it's now invalid!
|
||||
FreeDynablock(db, 0);
|
||||
// start again... (will create a new block)
|
||||
db = internalDBGetBlock(emu, addr, addr, create, *current, 0);
|
||||
db = internalDBGetBlock(emu, addr, addr, create, 0);
|
||||
} else {
|
||||
father->need_test = 0;
|
||||
dynarec_log(LOG_DEBUG, "Validating block %p from %p:%p (hash:%X) with %d son(s) for %p\n", father, father->x64_addr, father->x64_addr+father->x64_size-1, father->hash, father->sons_size, (void*)addr);
|
||||
protectDB((uintptr_t)father->x64_addr, father->x64_size);
|
||||
db->need_test = 0;
|
||||
dynarec_log(LOG_DEBUG, "Validating block %p from %p:%p (hash:%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, db->hash, (void*)addr);
|
||||
protectDB((uintptr_t)db->x64_addr, db->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);
|
||||
setJumpTableIfRef64(db->x64_addr, db->block, db->jmpnext);
|
||||
}
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
return db;
|
||||
}
|
||||
@@ -526,28 +247,25 @@ 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, 1);
|
||||
dynablock_t *father = (db && db->father)?db->father:db;
|
||||
if(father && father->done && db->block && father->need_test) {
|
||||
if(pthread_mutex_trylock(&my_context->mutex_dyndump))
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, 1);
|
||||
if(db && db->done && db->block && db->need_test) {
|
||||
if(mutex_trylock(&my_context->mutex_dyndump))
|
||||
return NULL;
|
||||
uint32_t hash = X31_hash_code(father->x64_addr, father->x64_size);
|
||||
if(hash!=father->hash) {
|
||||
father->done = 0; // invalidating the block
|
||||
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, 0);
|
||||
uint32_t hash = X31_hash_code(db->x64_addr, db->x64_size);
|
||||
if(hash!=db->hash) {
|
||||
db->done = 0; // invalidating the block
|
||||
dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size, hash, db->hash, (void*)addr);
|
||||
// Free db, it's now invalid!
|
||||
FreeDynablock(db, 0);
|
||||
// start again... (will create a new block)
|
||||
db = internalDBGetBlock(emu, addr, filladdr, create, NULL, 0);
|
||||
db = internalDBGetBlock(emu, addr, filladdr, create, 0);
|
||||
} else {
|
||||
father->need_test = 0;
|
||||
protectDB((uintptr_t)father->x64_addr, father->x64_size);
|
||||
db->need_test = 0;
|
||||
protectDB((uintptr_t)db->x64_addr, db->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);
|
||||
addJumpTableIfDefault64(db->x64_addr, db->block);
|
||||
}
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
return db;
|
||||
}
|
||||
@@ -1,16 +1,14 @@
|
||||
#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;
|
||||
unsigned char x64:4;
|
||||
unsigned char nat:4;
|
||||
} instsize_t;
|
||||
|
||||
typedef struct dynablock_s {
|
||||
dynablocklist_t* parent;
|
||||
void* block;
|
||||
void* block; // block-sizeof(void*) == self
|
||||
void* actual_block; // the actual start of the block (so block-sizeof(void*))
|
||||
int size;
|
||||
void* x64_addr;
|
||||
uintptr_t x64_size;
|
||||
@@ -20,18 +18,8 @@ typedef struct dynablock_s {
|
||||
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;
|
||||
void* jmpnext; // a branch jmpnext code when block is marked
|
||||
} dynablock_t;
|
||||
|
||||
typedef struct dynablocklist_s {
|
||||
uintptr_t text;
|
||||
int textsz;
|
||||
uintptr_t maxend; // max address end for anyblock on this blocklist
|
||||
uintptr_t minstart; // min start address for block overlapping this blocklist
|
||||
dynablock_t** direct; // direct mapping (waste of space, so the array is created at first write)
|
||||
} dynablocklist_t;
|
||||
|
||||
#endif //__DYNABLOCK_PRIVATE_H_
|
||||
+13
-34
@@ -20,22 +20,10 @@
|
||||
#include "dynablock.h"
|
||||
#include "dynablock_private.h"
|
||||
#include "bridge.h"
|
||||
#include "dynarec_next.h"
|
||||
#endif
|
||||
|
||||
#ifdef DYNAREC
|
||||
#ifdef ARM64
|
||||
void arm64_prolog(x64emu_t* emu, void* addr) EXPORTDYN;
|
||||
void arm64_epilog() EXPORTDYN;
|
||||
#define native_prolog arm64_prolog
|
||||
#define native_epilog arm64_epilog
|
||||
#elif defined(LA464)
|
||||
void la464_prolog(x64emu_t* emu, void* addr) EXPORTDYN;
|
||||
void la464_epilog() EXPORTDYN;
|
||||
#define native_prolog la464_prolog
|
||||
#define native_epilog la464_epilog
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
#ifdef HAVE_TRACE
|
||||
#include "elfloader.h"
|
||||
#endif
|
||||
|
||||
#ifdef DYNAREC
|
||||
@@ -46,26 +34,27 @@ void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3)
|
||||
#ifdef HAVE_TRACE
|
||||
if(!addr) {
|
||||
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);
|
||||
printf_log(LOG_NONE, "Warning, jumping to NULL address from %p (db=%p, x64addr=%p/%s)\n", x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
|
||||
}
|
||||
#endif
|
||||
dynablock_t* current = NULL;
|
||||
void * jblock;
|
||||
dynablock_t* block = DBGetBlock(emu, addr, 1, ¤t);
|
||||
dynablock_t* block = DBGetBlock(emu, addr, 1);
|
||||
if(!block) {
|
||||
// no block, let link table as is...
|
||||
if(hasAlternate((void*)addr)) {
|
||||
printf_log(LOG_DEBUG, "Jmp address has alternate: %p", (void*)addr);
|
||||
if(box64_log<LOG_DEBUG) dynarec_log(LOG_INFO, "Jmp address has alternate: %p", (void*)addr);
|
||||
addr = (uintptr_t)getAlternate((void*)addr); // set new address
|
||||
R_RIP = addr; // but also new RIP!
|
||||
*x3 = addr; // and the RIP in x27 register
|
||||
printf_log(LOG_DEBUG, " -> %p\n", (void*)addr);
|
||||
block = DBGetBlock(emu, addr, 1, ¤t);
|
||||
block = DBGetBlock(emu, addr, 1);
|
||||
}
|
||||
if(!block) {
|
||||
#ifdef HAVE_TRACE
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
|
||||
dynarec_log(LOG_INFO, "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);
|
||||
elfheader_t* h = FindElfAddress(my_context, (uintptr_t)x2-4);
|
||||
dynarec_log(LOG_INFO, "Warning, jumping to a no-block address %p from %p (db=%p, x64addr=%p(elf=%s))\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, h?ElfName(h):"(none)");
|
||||
#endif
|
||||
//tableupdate(native_epilog, addr, table);
|
||||
return native_epilog;
|
||||
@@ -121,23 +110,18 @@ void DynaCall(x64emu_t* emu, uintptr_t addr)
|
||||
PushExit(emu);
|
||||
R_RIP = addr;
|
||||
emu->df = d_none;
|
||||
dynablock_t* current = NULL;
|
||||
dynablock_t* block = DBGetBlock(emu, R_RIP, 1, ¤t);
|
||||
current = block;
|
||||
while(!emu->quit) {
|
||||
dynablock_t* block = DBGetBlock(emu, R_RIP, 1);
|
||||
if(!block || !block->block || !block->done) {
|
||||
// no block, of block doesn't have DynaRec content (yet, temp is not null)
|
||||
// Use interpreter (should use single instruction step...)
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling Interpretor @%p, emu=%p\n", GetTID(), (void*)R_RIP, emu);
|
||||
Run(emu, 1);
|
||||
block = DBGetBlock(emu, R_RIP, 1, ¤t);
|
||||
current = block;
|
||||
} else {
|
||||
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);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling DynaRec Block @%p (%p) of %d x64 instructions emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize ,emu);
|
||||
CHECK_FLAGS(emu);
|
||||
// block is here, let's run it!
|
||||
native_prolog(emu, block->block);
|
||||
block = NULL;
|
||||
}
|
||||
if(emu->fork) {
|
||||
int forktype = emu->fork;
|
||||
@@ -201,22 +185,17 @@ int DynaRun(x64emu_t* emu)
|
||||
return Run(emu, 0);
|
||||
#ifdef DYNAREC
|
||||
else {
|
||||
dynablock_t* current = NULL;
|
||||
dynablock_t* block = DBGetBlock(emu, R_RIP, 1, ¤t);;
|
||||
current = block;
|
||||
while(!emu->quit) {
|
||||
dynablock_t* block = DBGetBlock(emu, R_RIP, 1);
|
||||
if(!block || !block->block || !block->done) {
|
||||
// no block, of block doesn't have DynaRec content (yet, temp is not null)
|
||||
// Use interpreter (should use single instruction step...)
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running Interpretor @%p, emu=%p\n", GetTID(), (void*)R_RIP, emu);
|
||||
Run(emu, 1);
|
||||
block = DBGetBlock(emu, R_RIP, 1, ¤t);
|
||||
current = block;
|
||||
} else {
|
||||
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);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x64 insts emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize, emu);
|
||||
// block is here, let's run it!
|
||||
native_prolog(emu, block->block);
|
||||
block = NULL;
|
||||
}
|
||||
if(emu->fork) {
|
||||
int forktype = emu->fork;
|
||||
|
||||
+186
-225
@@ -23,21 +23,22 @@
|
||||
|
||||
#include "dynarec_native.h"
|
||||
#include "dynarec_arch.h"
|
||||
#include "dynarec_next.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":"");
|
||||
dynarec_log(LOG_NONE, "%s%p: Exit x64emu%s\n", (box64_dynarec_dump>1)?"\e[01;33m":"", (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":"");
|
||||
dynarec_log(LOG_NONE, "%s%p: Native call to %p%s\n", (box64_dynarec_dump>1)?"\e[01;33m":"", (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));
|
||||
dynarec_log(LOG_NONE, "%s%p: %s", (box64_dynarec_dump>1)?"\e[01;33m":"", ip, DecodeX64Trace(dec, inst->addr));
|
||||
} else {
|
||||
dynarec_log(LOG_NONE, "%s%p: ", (box64_dynarec_dump>1)?"\e[1m":"", ip);
|
||||
dynarec_log(LOG_NONE, "%s%p: ", (box64_dynarec_dump>1)?"\e[01;33m":"", ip);
|
||||
for(int i=0; i<inst->size; ++i) {
|
||||
dynarec_log(LOG_NONE, "%02X ", ip[i]);
|
||||
}
|
||||
@@ -61,12 +62,20 @@ void printf_x64_instruction(zydis_dec_t* dec, instruction_x64_t* inst, const cha
|
||||
void add_next(dynarec_native_t *dyn, uintptr_t addr) {
|
||||
if(!box64_dynarec_bigblock)
|
||||
return;
|
||||
// exist?
|
||||
for(int i=0; i<dyn->next_sz; ++i)
|
||||
if(dyn->next[i]==addr)
|
||||
return;
|
||||
// put in a free slot
|
||||
for(int i=0; i<dyn->next_sz; ++i)
|
||||
if(!dyn->next[i]) {
|
||||
dyn->next[i] = addr;
|
||||
return;
|
||||
}
|
||||
// add slots
|
||||
if(dyn->next_sz == dyn->next_cap) {
|
||||
dyn->next_cap += 16;
|
||||
dyn->next = (uintptr_t*)realloc(dyn->next, dyn->next_cap*sizeof(uintptr_t));
|
||||
dyn->next_cap += 64;
|
||||
dyn->next = (uintptr_t*)customRealloc(dyn->next, dyn->next_cap*sizeof(uintptr_t));
|
||||
}
|
||||
dyn->next[dyn->next_sz++] = addr;
|
||||
}
|
||||
@@ -76,13 +85,12 @@ uintptr_t get_closest_next(dynarec_native_t *dyn, uintptr_t addr) {
|
||||
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;
|
||||
dyn->next[i] = 0;
|
||||
} else {
|
||||
if((dyn->next[i]<best) || !best)
|
||||
best = dyn->next[i];
|
||||
++i;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return best;
|
||||
}
|
||||
@@ -232,7 +240,7 @@ int is_instructions(dynarec_native_t *dyn, uintptr_t addr, int n)
|
||||
return (i==n)?1:0;
|
||||
}
|
||||
|
||||
instsize_t* addInst(instsize_t* insts, size_t* size, size_t* cap, int x64_size, int native_size)
|
||||
void addInst(instsize_t* insts, size_t* size, int x64_size, int native_size)
|
||||
{
|
||||
// x64 instruction is <16 bytes
|
||||
int toadd;
|
||||
@@ -240,10 +248,6 @@ instsize_t* addInst(instsize_t* insts, size_t* size, size_t* cap, int x64_size,
|
||||
toadd = 1 + x64_size/15;
|
||||
else
|
||||
toadd = 1 + native_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;
|
||||
@@ -258,7 +262,6 @@ instsize_t* addInst(instsize_t* insts, size_t* size, size_t* cap, int x64_size,
|
||||
++(*size);
|
||||
--toadd;
|
||||
}
|
||||
return insts;
|
||||
}
|
||||
|
||||
// add a value to table64 (if needed) and gives back the imm19 to use in LDR_literal
|
||||
@@ -272,8 +275,8 @@ int Table64(dynarec_native_t *dyn, uint64_t val)
|
||||
// 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));
|
||||
dyn->table64cap+=16;
|
||||
dyn->table64 = (uint64_t*)customRealloc(dyn->table64, dyn->table64cap * sizeof(uint64_t));
|
||||
}
|
||||
idx = dyn->table64size++;
|
||||
dyn->table64[idx] = val;
|
||||
@@ -285,23 +288,23 @@ int Table64(dynarec_native_t *dyn, uint64_t val)
|
||||
|
||||
static void fillPredecessors(dynarec_native_t* dyn)
|
||||
{
|
||||
int pred_sz = 0;
|
||||
int pred_sz = 1; // to be safe
|
||||
// compute total size of predecessor to alocate the array
|
||||
// first compute the jumps
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
if(dyn->insts[i].x64.jmp && dyn->insts[i].x64.jmp_insts!=-1) {
|
||||
++pred_sz;
|
||||
++dyn->insts[dyn->insts[i].x64.jmp_insts].pred_sz;
|
||||
if(dyn->insts[i].x64.jmp && (dyn->insts[i].x64.jmp_insts!=-1)) {
|
||||
pred_sz++;
|
||||
dyn->insts[dyn->insts[i].x64.jmp_insts].pred_sz++;
|
||||
}
|
||||
}
|
||||
// second the "has_next"
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
if(i!=dyn->size-1 && dyn->insts[i].x64.has_next && (!i || dyn->insts[i].pred_sz)) {
|
||||
++pred_sz;
|
||||
++dyn->insts[i+1].pred_sz;
|
||||
for(int i=0; i<dyn->size-1; ++i) {
|
||||
if(dyn->insts[i].x64.has_next) {
|
||||
pred_sz++;
|
||||
dyn->insts[i+1].pred_sz++;
|
||||
}
|
||||
}
|
||||
dyn->predecessor = (int*)malloc(pred_sz*sizeof(int));
|
||||
dyn->predecessor = (int*)customMalloc(pred_sz*sizeof(int));
|
||||
// fill pred pointer
|
||||
int* p = dyn->predecessor;
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
@@ -309,87 +312,88 @@ static void fillPredecessors(dynarec_native_t* dyn)
|
||||
p += dyn->insts[i].pred_sz;
|
||||
dyn->insts[i].pred_sz=0; // reset size, it's reused to actually fill pred[]
|
||||
}
|
||||
assert(p==dyn->predecessor+pred_sz);
|
||||
// fill pred
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
if(i!=dyn->size-1 && dyn->insts[i].x64.has_next && (!i || dyn->insts[i].pred_sz))
|
||||
if((i!=dyn->size-1) && dyn->insts[i].x64.has_next)
|
||||
dyn->insts[i+1].pred[dyn->insts[i+1].pred_sz++] = i;
|
||||
if(dyn->insts[i].x64.jmp && dyn->insts[i].x64.jmp_insts!=-1)
|
||||
dyn->insts[dyn->insts[i].x64.jmp_insts].pred[dyn->insts[dyn->insts[i].x64.jmp_insts].pred_sz++] = i;
|
||||
if(dyn->insts[i].x64.jmp && (dyn->insts[i].x64.jmp_insts!=-1)) {
|
||||
int j = dyn->insts[i].x64.jmp_insts;
|
||||
dyn->insts[j].pred[dyn->insts[j].pred_sz++] = i;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void updateNeed(dynarec_native_t* dyn, int ninst, uint32_t need) {
|
||||
uint32_t old_need = dyn->insts[ninst].x64.need_flags;
|
||||
uint32_t new_need = old_need | need;
|
||||
uint32_t new_use = dyn->insts[ninst].x64.use_flags;
|
||||
uint32_t old_use = dyn->insts[ninst].x64.old_use;
|
||||
|
||||
if((new_need&X_PEND) && dyn->insts[ninst].x64.state_flags==SF_SUBSET) {
|
||||
new_need &=~X_PEND;
|
||||
new_need |= X_ALL;
|
||||
// updateNeed goes backward, from last intruction to top
|
||||
static int updateNeed(dynarec_arm_t* dyn, int ninst, uint8_t need) {
|
||||
while (ninst>=0) {
|
||||
// need pending but instruction is only a subset: remove pend and use an X_ALL instead
|
||||
need |= dyn->insts[ninst].x64.need_after;
|
||||
if((need&X_PEND) && (dyn->insts[ninst].x64.state_flags==SF_SUBSET)) {
|
||||
need &=~X_PEND;
|
||||
need |= X_ALL;
|
||||
}
|
||||
if((need&X_PEND) && (dyn->insts[ninst].x64.state_flags==SF_SET)) {
|
||||
need &=~X_PEND;
|
||||
need |= dyn->insts[ninst].x64.set_flags; // SF_SET will compute all flags, it's not SUBSET!
|
||||
}
|
||||
if((need&X_PEND) && dyn->insts[ninst].x64.state_flags==SF_SUBSET_PENDING) {
|
||||
need |= X_ALL&~(dyn->insts[ninst].x64.set_flags);
|
||||
}
|
||||
dyn->insts[ninst].x64.gen_flags = need&dyn->insts[ninst].x64.set_flags;
|
||||
if((need&X_PEND) && (dyn->insts[ninst].x64.state_flags&SF_PENDING))
|
||||
dyn->insts[ninst].x64.gen_flags |= X_PEND;
|
||||
dyn->insts[ninst].x64.need_after = need;
|
||||
need = dyn->insts[ninst].x64.need_after&~dyn->insts[ninst].x64.gen_flags;
|
||||
if(dyn->insts[ninst].x64.may_set)
|
||||
need |= dyn->insts[ninst].x64.gen_flags; // forward the flags
|
||||
// Consume X_PEND if relevant
|
||||
if((need&X_PEND) && (dyn->insts[ninst].x64.set_flags&SF_PENDING))
|
||||
need &=~X_PEND;
|
||||
need |= dyn->insts[ninst].x64.use_flags;
|
||||
if(dyn->insts[ninst].x64.need_before == need)
|
||||
return ninst - 1;
|
||||
dyn->insts[ninst].x64.need_before = need;
|
||||
if(dyn->insts[ninst].x64.barrier&BARRIER_FLAGS) {
|
||||
need = need?X_PEND:0;
|
||||
}
|
||||
int ok = 0;
|
||||
for(int i=0; i<dyn->insts[ninst].pred_sz; ++i) {
|
||||
if(dyn->insts[ninst].pred[i] == ninst-1)
|
||||
ok = 1;
|
||||
else
|
||||
updateNeed(dyn, dyn->insts[ninst].pred[i], need);
|
||||
}
|
||||
if(!ok)
|
||||
return ninst - 1;
|
||||
--ninst;
|
||||
}
|
||||
|
||||
uint32_t new_set = 0;
|
||||
if(dyn->insts[ninst].x64.state_flags & SF_SET)
|
||||
new_set = dyn->insts[ninst].x64.set_flags;
|
||||
if(dyn->insts[ninst].x64.state_flags & SF_PENDING)
|
||||
new_set |= X_PEND;
|
||||
if((new_need&X_PEND) && (
|
||||
dyn->insts[ninst].x64.state_flags==SF_SET || dyn->insts[ninst].x64.state_flags==SF_SUBSET)) {
|
||||
new_need &=~X_PEND;
|
||||
new_need |=X_ALL;
|
||||
}
|
||||
|
||||
dyn->insts[ninst].x64.need_flags = new_need;
|
||||
dyn->insts[ninst].x64.old_use = new_use;
|
||||
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1)
|
||||
new_need |= X_PEND;
|
||||
|
||||
// a Flag Barrier will change all need to "Pending", as it clear all flags optimisation
|
||||
if(new_need && dyn->insts[ninst].x64.barrier&BARRIER_FLAGS)
|
||||
new_need = X_PEND;
|
||||
|
||||
if((new_need == old_need) && (new_use == old_use)) // no changes, bye
|
||||
return;
|
||||
|
||||
if(!(new_need && dyn->insts[ninst].x64.barrier&BARRIER_FLAGS)) {
|
||||
new_need &=~new_set; // clean needed flag that were suplied
|
||||
new_need |= new_use; // new need
|
||||
}
|
||||
|
||||
if((new_need == (X_ALL|X_PEND)) && (dyn->insts[ninst].x64.state_flags & SF_SET))
|
||||
new_need = X_ALL;
|
||||
|
||||
//update need to new need on predecessor
|
||||
for(int i=0; i<dyn->insts[ninst].pred_sz; ++i)
|
||||
updateNeed(dyn, dyn->insts[ninst].pred[i], new_need);
|
||||
return ninst;
|
||||
}
|
||||
|
||||
static void resetNeed(dynarec_native_t* dyn) {
|
||||
for(int i = dyn->size; i-- > 0;) {
|
||||
dyn->insts[i].x64.old_use = 0;
|
||||
dyn->insts[i].x64.need_flags = dyn->insts[i].x64.default_need;
|
||||
}
|
||||
}
|
||||
void* current_helper = NULL;
|
||||
|
||||
__thread void* current_helper = NULL;
|
||||
|
||||
void CancelBlock64()
|
||||
void CancelBlock64(int need_lock)
|
||||
{
|
||||
if(need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
dynarec_native_t* helper = (dynarec_native_t*)current_helper;
|
||||
current_helper = NULL;
|
||||
if(!helper)
|
||||
if(!helper) {
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
return;
|
||||
free(helper->next);
|
||||
free(helper->insts);
|
||||
free(helper->table64);
|
||||
free(helper->sons_x64);
|
||||
free(helper->sons_native);
|
||||
if(helper->dynablock && helper->dynablock->block)
|
||||
FreeDynarecMap(helper->dynablock, (uintptr_t)helper->dynablock->block, helper->dynablock->size);
|
||||
}
|
||||
customFree(helper->next);
|
||||
customFree(helper->insts);
|
||||
customFree(helper->predecessor);
|
||||
customFree(helper->table64);
|
||||
if(helper->dynablock && helper->dynablock->actual_block)
|
||||
FreeDynarecMap((uintptr_t)helper->dynablock->actual_block);
|
||||
else if(helper->dynablock && helper->block)
|
||||
FreeDynarecMap((uintptr_t)helper->block-sizeof(void*));
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
|
||||
uintptr_t native_pass0(dynarec_native_t* dyn, uintptr_t addr);
|
||||
@@ -397,14 +401,55 @@ uintptr_t native_pass1(dynarec_native_t* dyn, uintptr_t addr);
|
||||
uintptr_t native_pass2(dynarec_native_t* dyn, uintptr_t addr);
|
||||
uintptr_t native_pass3(dynarec_native_t* dyn, uintptr_t addr);
|
||||
|
||||
void* CreateEmptyBlock(dynablock_t* block, uintptr_t addr) {
|
||||
block->isize = 0;
|
||||
block->done = 0;
|
||||
size_t sz = 4*sizeof(void*);
|
||||
void* actual_p = (void*)AllocDynarecMap(sz);
|
||||
void* p = actual_p + sizeof(void*);
|
||||
if(actual_p==NULL) {
|
||||
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, cancelling block\n", block, sz);
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
block->size = sz;
|
||||
block->actual_block = actual_p;
|
||||
block->block = p;
|
||||
block->jmpnext = p;
|
||||
*(dynablock_t**)actual_p = block;
|
||||
*(void**)(p+2*sizeof(void*)) = native_epilog;
|
||||
CreateJmpNext(block->jmpnext, p+2*sizeof(void*));
|
||||
block->need_test = 0;
|
||||
// all done...
|
||||
__clear_cache(actual_p, actual_p+sz); // need to clear the cache before execution...
|
||||
return block;
|
||||
}
|
||||
|
||||
void* FillBlock64(dynablock_t* block, uintptr_t addr) {
|
||||
/*
|
||||
A Block must have this layout:
|
||||
|
||||
0x0000..0x0007 : dynablock_t* : self
|
||||
0x0008..8+4*n : actual Native instructions, (n is the total number)
|
||||
A .. A+8*n : Table64: n 64bits values
|
||||
B .. B+7 : dynablock_t* : self (as part of JmpNext, that simulate another block)
|
||||
B+8 .. B+15 : 2 Native code for jmpnext (or jmp epilog in case of empty block)
|
||||
B+16 .. B+23 : jmpnext (or jmp_epilog) address
|
||||
B+24 .. B+31 : empty (in case an architecture needs more than 2 opcodes)
|
||||
B+32 .. B+32+sz : instsize (compressed array with each instruction lenght on x64 and native side)
|
||||
|
||||
*/
|
||||
if(IsInHotPage(addr)) {
|
||||
dynarec_log(LOG_DEBUG, "Cancelling dynarec FillBlock on hotpage for %p\n", (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
if(addr>=box64_nodynarec_start && addr<box64_nodynarec_end) {
|
||||
block->done = 1;
|
||||
return (void*)block;
|
||||
dynarec_log(LOG_INFO, "Create empty block in no-dynarec zone\n");
|
||||
return CreateEmptyBlock(block, addr);
|
||||
}
|
||||
if(current_helper) {
|
||||
dynarec_log(LOG_DEBUG, "Cancelling dynarec FillBlock at %p as anothor one is going on\n", (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
// protect the 1st page
|
||||
protectDB(addr, 1);
|
||||
@@ -414,41 +459,38 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
|
||||
helper.dynablock = block;
|
||||
helper.start = addr;
|
||||
uintptr_t start = addr;
|
||||
helper.cap = 64; // needs epilog handling
|
||||
helper.insts = (instruction_native_t*)calloc(helper.cap, sizeof(instruction_native_t));
|
||||
helper.cap = 128;
|
||||
helper.insts = (instruction_native_t*)customCalloc(helper.cap, sizeof(instruction_native_t));
|
||||
// pass 0, addresses, x64 jump addresses, overall size of the block
|
||||
uintptr_t end = native_pass0(&helper, addr);
|
||||
// no need for next anymore
|
||||
free(helper.next);
|
||||
customFree(helper.next);
|
||||
helper.next_sz = helper.next_cap = 0;
|
||||
helper.next = NULL;
|
||||
// basic checks
|
||||
if(!helper.size) {
|
||||
dynarec_log(LOG_INFO, "Warning, null-sized dynarec block (%p)\n", (void*)addr);
|
||||
CancelBlock64();
|
||||
return (void*)block;
|
||||
CancelBlock64(0);
|
||||
return CreateEmptyBlock(block, addr);;
|
||||
}
|
||||
if(!isprotectedDB(addr, 1)) {
|
||||
dynarec_log(LOG_INFO, "Warning, write on current page on pass0, aborting dynablock creation (%p)\n", (void*)addr);
|
||||
CancelBlock64();
|
||||
AddHotPage(addr);
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
// protect the block of it goes over the 1st page
|
||||
if((addr&~0xfff)!=(end&~0xfff)) // need to protect some other pages too
|
||||
if((addr&~box64_pagesize)!=(end&~box64_pagesize)) // need to protect some other pages too
|
||||
protectDB(addr, end-addr); //end is 1byte after actual end
|
||||
// compute hash signature
|
||||
uint32_t hash = X31_hash_code((void*)addr, end-addr);
|
||||
// Compute flag_need, without with current barriers
|
||||
resetNeed(&helper);
|
||||
for(int i = helper.size; i-- > 0;)
|
||||
updateNeed(&helper, i, 0);
|
||||
// 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) {
|
||||
if(j<start || j>=end || j==helper.insts[i].x64.addr) {
|
||||
helper.insts[i].x64.jmp_insts = -1;
|
||||
helper.insts[i].x64.use_flags |= X_PEND;
|
||||
helper.insts[i].x64.need_after |= X_PEND;
|
||||
} else {
|
||||
// find jump address instruction
|
||||
int k=-1;
|
||||
@@ -463,86 +505,37 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
|
||||
}
|
||||
// fill predecessors with the jump address
|
||||
fillPredecessors(&helper);
|
||||
// check for the optionnal barriers now
|
||||
for(int i=helper.size-1; i>=0; --i) {
|
||||
if(helper.insts[i].barrier_maybe) {
|
||||
// out-of-block jump
|
||||
if(helper.insts[i].x64.jmp_insts == -1) {
|
||||
// nothing for now
|
||||
} else {
|
||||
// inside block jump
|
||||
int k = helper.insts[i].x64.jmp_insts;
|
||||
if(k>i) {
|
||||
// jump in the future
|
||||
if(helper.insts[k].pred_sz>1) {
|
||||
// with multiple flow, put a barrier
|
||||
helper.insts[k].x64.barrier|=BARRIER_FLAGS;
|
||||
}
|
||||
} else {
|
||||
// jump back
|
||||
helper.insts[k].x64.barrier|=BARRIER_FLAGS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// check to remove useless barrier, in case of jump when destination doesn't needs flags
|
||||
/*for(int i=helper.size-1; i>=0; --i) {
|
||||
int k;
|
||||
if(helper.insts[i].x64.jmp
|
||||
&& ((k=helper.insts[i].x64.jmp_insts)>=0)
|
||||
&& helper.insts[k].x64.barrier&BARRIER_FLAGS) {
|
||||
//TODO: optimize FPU barrier too
|
||||
if((!helper.insts[k].x64.need_flags)
|
||||
||(helper.insts[k].x64.set_flags==X_ALL
|
||||
&& helper.insts[k].x64.state_flags==SF_SET)
|
||||
||(helper.insts[k].x64.state_flags==SF_SET_PENDING)) {
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "Removed barrier for inst %d\n", k);
|
||||
helper.insts[k].x64.barrier &= ~BARRIER_FLAGS; // remove flag barrier
|
||||
}
|
||||
}
|
||||
}*/
|
||||
// reset need_flags and compute again, now taking barrier into account (because barrier change use_flags)
|
||||
for(int i = helper.size; i-- > 0;) {
|
||||
int k;
|
||||
if(helper.insts[i].x64.jmp
|
||||
&& ((k=helper.insts[i].x64.jmp_insts)>=0)
|
||||
) {
|
||||
if(helper.insts[k].x64.barrier&BARRIER_FLAGS)
|
||||
// jumpto barrier
|
||||
helper.insts[i].x64.use_flags |= X_PEND;
|
||||
if(helper.insts[i].x64.barrier&BARRIER_FLAGS && (helper.insts[k].x64.need_flags | helper.insts[k].x64.use_flags))
|
||||
helper.insts[k].x64.barrier|=BARRIER_FLAGS;
|
||||
else
|
||||
helper.insts[i].x64.use_flags |= (helper.insts[k].x64.need_flags | helper.insts[k].x64.use_flags);
|
||||
}
|
||||
if(helper.insts[i].x64.barrier&BARRIER_FLAGS)
|
||||
// immediate barrier
|
||||
helper.insts[i].x64.use_flags |= X_PEND;
|
||||
}
|
||||
resetNeed(&helper);
|
||||
for(int i = helper.size; i-- > 0;)
|
||||
updateNeed(&helper, i, 0);
|
||||
|
||||
int pos = helper.size;
|
||||
while (pos>=0)
|
||||
pos = updateNeed(&helper, pos, 0);
|
||||
|
||||
// pass 1, float optimisations, first pass for flags
|
||||
native_pass1(&helper, addr);
|
||||
|
||||
// pass 2, instruction size
|
||||
native_pass2(&helper, addr);
|
||||
// keep size of instructions for signal handling
|
||||
size_t insts_rsize = (helper.insts_size+2)*sizeof(instsize_t);
|
||||
insts_rsize = (insts_rsize+7)&~7; // round the size...
|
||||
// ok, now allocate mapped memory, with executable flag on
|
||||
size_t sz = helper.native_size + helper.table64size*sizeof(uint64_t);
|
||||
void* p = (void*)AllocDynarecMap(block, sz);
|
||||
if(p==NULL) {
|
||||
size_t sz = sizeof(void*) + helper.native_size + helper.table64size*sizeof(uint64_t) + 4*sizeof(void*) + insts_rsize;
|
||||
// dynablock_t* block (arm insts) table64 jmpnext code instsize
|
||||
void* actual_p = (void*)AllocDynarecMap(sz);
|
||||
void* p = actual_p + sizeof(void*);
|
||||
void* next = p + helper.native_size + helper.table64size*sizeof(uint64_t);
|
||||
void* instsize = next + 4*sizeof(void*);
|
||||
if(actual_p==NULL) {
|
||||
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, cancelling block\n", block, sz);
|
||||
CancelBlock64();
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
helper.block = p;
|
||||
helper.native_start = (uintptr_t)p;
|
||||
helper.tablestart = helper.native_start + helper.native_size;
|
||||
if(helper.sons_size) {
|
||||
helper.sons_x64 = (uintptr_t*)calloc(helper.sons_size, sizeof(uintptr_t));
|
||||
helper.sons_native = (void**)calloc(helper.sons_size, sizeof(void*));
|
||||
}
|
||||
helper.insts_size = 0; // reset
|
||||
helper.instsize = (instsize_t*)instsize;
|
||||
*(dynablock_t**)actual_p = block;
|
||||
// pass 3, emit (log emit native 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.native_size, helper.isize);
|
||||
@@ -572,75 +565,43 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
|
||||
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
|
||||
}
|
||||
block->instsize = instsize;
|
||||
// ok, free the helper now
|
||||
free(helper.insts);
|
||||
customFree(helper.insts);
|
||||
helper.insts = NULL;
|
||||
free(helper.table64);
|
||||
customFree(helper.table64);
|
||||
helper.table64 = NULL;
|
||||
helper.instsize = NULL;
|
||||
customFree(helper.predecessor);
|
||||
helper.predecessor = NULL;
|
||||
block->size = sz;
|
||||
block->isize = helper.size;
|
||||
block->actual_block = actual_p;
|
||||
block->block = p;
|
||||
block->jmpnext = next+sizeof(void*);
|
||||
*(dynablock_t**)next = block;
|
||||
*(void**)(next+2*sizeof(void*)) = native_next;
|
||||
CreateJmpNext(block->jmpnext, next+2*sizeof(void*));
|
||||
block->need_test = 0;
|
||||
//block->x64_addr = (void*)start;
|
||||
block->x64_size = end-start;
|
||||
// all done...
|
||||
__clear_cache(actual_p, actual_p+sz); // need to clear the cache before execution...
|
||||
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);
|
||||
CancelBlock64();
|
||||
dynarec_log(LOG_DEBUG, "Warning, a block changed while beeing processed hash(%p:%ld)=%x/%x\n", block->x64_addr, block->x64_size, block->hash, hash);
|
||||
AddHotPage(addr);
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
if(!isprotectedDB(addr, end-addr)) {
|
||||
dynarec_log(LOG_INFO, "Warning, block unprotected while beeing processed %p:%ld, cancelling\n", block->x64_addr, block->x64_size);
|
||||
CancelBlock64();
|
||||
return NULL;
|
||||
dynarec_log(LOG_DEBUG, "Warning, block unprotected while beeing processed %p:%ld, cancelling\n", block->x64_addr, block->x64_size);
|
||||
AddHotPage(addr);
|
||||
block->need_test = 1;
|
||||
//protectDB(addr, end-addr);
|
||||
}
|
||||
// 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_native[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 / Native=%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);
|
||||
helper.sons_x64 = NULL;
|
||||
free(helper.sons_native);
|
||||
helper.sons_native = NULL;
|
||||
current_helper = NULL;
|
||||
//block->done = 1;
|
||||
return (void*)block;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "dynablock.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "custommem.h"
|
||||
#include "elfloader.h"
|
||||
|
||||
#include "dynarec_arch.h"
|
||||
#include "dynarec_helper.h"
|
||||
@@ -30,18 +31,23 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr)
|
||||
{
|
||||
int ok = 1;
|
||||
int ninst = 0;
|
||||
int j64;
|
||||
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->f.pending = 0;
|
||||
dyn->f.dfnone = 0;
|
||||
dyn->forward = 0;
|
||||
dyn->forward_to = 0;
|
||||
dyn->forward_size = 0;
|
||||
dyn->forward_ninst = 0;
|
||||
fpu_reset(dyn);
|
||||
int reset_n = -1;
|
||||
dyn->last_ip = (dyn->insts && dyn->insts[0].pred_sz)?0:ip; // RIP is always set at start of block unless there is a predecessor!
|
||||
int stopblock = 2+(FindElfAddress(my_context, addr)?0:1); // if block is in elf_memory, it can be extended with bligblocks==2, else it needs 3
|
||||
// ok, go now
|
||||
INIT;
|
||||
while(ok) {
|
||||
@@ -104,7 +110,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr)
|
||||
}
|
||||
}
|
||||
reset_n = -1;
|
||||
} else if(dyn->insts[ninst].pred_sz!=1)
|
||||
} else if(ninst && (dyn->insts[ninst].pred_sz!=1 || dyn->insts[ninst].pred[0]!=ninst-1))
|
||||
dyn->last_ip = 0; // reset IP if some jump are comming here
|
||||
// propagate ST stack state, especial stack pop that are defered
|
||||
if(dyn->n.stack_pop) {
|
||||
@@ -122,7 +128,11 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr)
|
||||
dyn->n.stack_push = 0;
|
||||
dyn->n.swapped = 0;
|
||||
NEW_INST;
|
||||
if(dyn->insts[ninst].pred_sz>1) {SMSTART();}
|
||||
fpu_reset_scratch(dyn);
|
||||
if((dyn->insts[ninst].x64.need_before&~X_PEND) && !dyn->insts[ninst].pred_sz) {
|
||||
READFLAGS(dyn->insts[ninst].x64.need_before&~X_PEND);
|
||||
}
|
||||
#ifdef HAVE_TRACE
|
||||
if(my_context->dec && box64_dynarec_trace) {
|
||||
if((trace_end == 0)
|
||||
@@ -142,7 +152,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr)
|
||||
++addr;
|
||||
pk = PK(0);
|
||||
}
|
||||
while(pk==0x3E) { //Branch Taken Hint ignored
|
||||
while(pk==0x3E || pk==0x26) { //Branch Taken Hint ignored, same for ES: prefix
|
||||
++addr;
|
||||
pk = PK(0);
|
||||
}
|
||||
@@ -171,6 +181,9 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr)
|
||||
dyn->last_ip = 0;
|
||||
}
|
||||
}
|
||||
#ifndef PROT_READ
|
||||
#define PROT_READ 1
|
||||
#endif
|
||||
#if STEP != 0
|
||||
if(!ok && !need_epilog && (addr < (dyn->start+dyn->isize))) {
|
||||
ok = 1;
|
||||
@@ -189,7 +202,29 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr)
|
||||
}
|
||||
}
|
||||
#else
|
||||
if(!ok && !need_epilog && box64_dynarec_bigblock && getProtection(addr+3)&~PROT_CUSTOM)
|
||||
if(dyn->forward) {
|
||||
if(dyn->forward_to == addr && !need_epilog) {
|
||||
// we made it!
|
||||
if(box64_dynarec_dump) dynarec_log(LOG_NONE, "Forward extend block for %d bytes %p -> %p\n", dyn->forward_to-dyn->forward, (void*)dyn->forward, (void*)dyn->forward_to);
|
||||
dyn->forward = 0;
|
||||
dyn->forward_to = 0;
|
||||
dyn->forward_size = 0;
|
||||
dyn->forward_ninst = 0;
|
||||
ok = 1; // in case it was 0
|
||||
} else if ((dyn->forward_to < addr) || !ok) {
|
||||
// something when wrong! rollback
|
||||
if(box64_dynarec_dump) dynarec_log(LOG_NONE, "Could not forward extend block for %d bytes %p -> %p\n", dyn->forward_to-dyn->forward, (void*)dyn->forward, (void*)dyn->forward_to);
|
||||
ok = 0;
|
||||
dyn->size = dyn->forward_size;
|
||||
ninst = dyn->forward_ninst;
|
||||
addr = dyn->forward;
|
||||
dyn->forward = 0;
|
||||
dyn->forward_to = 0;
|
||||
dyn->forward_size = 0;
|
||||
dyn->forward_ninst = 0;
|
||||
}
|
||||
// else just continue
|
||||
} else if(!ok && !need_epilog && box64_dynarec_bigblock && (getProtection(addr+3)&~PROT_READ))
|
||||
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 && (
|
||||
@@ -205,31 +240,36 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr)
|
||||
ii=ninst;
|
||||
}
|
||||
if(box64_dynarec_dump) dynarec_log(LOG_NONE, "Extend block %p, %p -> %p (ninst=%d, jump from %d)\n", dyn, (void*)addr, (void*)next, ninst, reset_n);
|
||||
} else if(next && (next-addr)<30) {
|
||||
if(box64_dynarec_dump) dynarec_log(LOG_NONE, "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));
|
||||
} else if(next && (next-addr)<box64_dynarec_forward && (getProtection(next)&PROT_READ)/*box64_dynarec_bigblock>=stopblock*/) {
|
||||
dyn->forward = addr;
|
||||
dyn->forward_to = next;
|
||||
dyn->forward_size = dyn->size;
|
||||
dyn->forward_ninst = ninst;
|
||||
reset_n = -2;
|
||||
ok = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(ok<0) {ok = 0; need_epilog=1;}
|
||||
++ninst;
|
||||
#if STEP == 0
|
||||
if(ok && !isJumpTableDefault64((void*)addr) && (box64_dynarec_bigblock<2))
|
||||
if(ok && (((box64_dynarec_bigblock<stopblock) && !isJumpTableDefault64((void*)addr))
|
||||
|| (addr>=box64_nodynarec_start && addr<box64_nodynarec_end)))
|
||||
#else
|
||||
if(ok && (ninst==dyn->size))
|
||||
#endif
|
||||
{
|
||||
int j32;
|
||||
MAYUSE(j32);
|
||||
MESSAGE(LOG_DEBUG, "Stopping block %p (%d / %d)\n",(void*)init_addr, ninst, dyn->size);
|
||||
MESSAGE(LOG_DEBUG, "Stopping block %p (%d / %d)\n",(void*)init_addr, ninst, dyn->size);
|
||||
if(!box64_dynarec_dump && addr>=box64_nodynarec_start && addr<box64_nodynarec_end)
|
||||
dynarec_log(LOG_INFO, "Stopping block in no-dynarec zone\n");
|
||||
--ninst;
|
||||
if(!dyn->insts[ninst].x64.barrier) {
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
}
|
||||
#if STEP == 0
|
||||
if(dyn->insts[ninst].x64.set_flags)
|
||||
dyn->insts[ninst].x64.default_need |= X_PEND;
|
||||
else
|
||||
dyn->insts[ninst].x64.use_flags |= X_PEND;
|
||||
dyn->insts[ninst].x64.need_after |= X_PEND;
|
||||
#endif
|
||||
++ninst;
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
@@ -242,6 +282,6 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr)
|
||||
jump_to_epilog(dyn, ip, 0, ninst); // no linker here, it's an unknow instruction
|
||||
}
|
||||
FINI;
|
||||
MESSAGE(LOG_DUMP, "---- END OF BLOCK ---- (%d, %d sons)\n", dyn->size, dyn->sons_size);
|
||||
MESSAGE(LOG_DUMP, "---- END OF BLOCK ---- (%d)\n", dyn->size);
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef __DYNAREC_NEXT_H__
|
||||
#define __DYNAREC_NEXT_H__
|
||||
|
||||
#ifdef ARM64
|
||||
void arm64_next(void) EXPORTDYN;
|
||||
void arm64_prolog(x64emu_t* emu, void* addr) EXPORTDYN;
|
||||
void arm64_epilog() EXPORTDYN;
|
||||
#define native_next arm64_next
|
||||
#define native_prolog arm64_prolog
|
||||
#define native_epilog arm64_epilog
|
||||
#elif defined(LA464)
|
||||
void la464_next(void) EXPORTDYN;
|
||||
void la464_prolog(x64emu_t* emu, void* addr) EXPORTDYN;
|
||||
void la464_epilog() EXPORTDYN;
|
||||
#define native_next la464_next
|
||||
#define native_prolog la464_prolog
|
||||
#define native_epilog la464_epilog
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
|
||||
#endif //__DYNAREC_NEXT_H__
|
||||
@@ -24,7 +24,6 @@
|
||||
#define SF_SUB 4
|
||||
#define SF_SUBSET (SF_SUB|SF_SET)
|
||||
#define SF_SUBSET_PENDING (SF_SUBSET|SF_PENDING)
|
||||
#define SF_MAYSET 8
|
||||
|
||||
typedef struct instruction_x64_s {
|
||||
uintptr_t addr; //address of the instruction
|
||||
@@ -37,9 +36,10 @@ typedef struct instruction_x64_s {
|
||||
uint8_t state_flags;// One of SF_XXX state
|
||||
uint8_t use_flags; // 0 or combination of X_?F
|
||||
uint8_t set_flags; // 0 or combination of X_?F
|
||||
uint8_t default_need;// 0 or X_PEND basically
|
||||
uint8_t need_flags; // calculated
|
||||
uint8_t old_use; // calculated
|
||||
uint8_t may_set; // 1 if the flags may not be set
|
||||
uint8_t gen_flags; // calculated
|
||||
uint8_t need_before;// calculated
|
||||
uint8_t need_after; // calculated
|
||||
} instruction_x64_t;
|
||||
|
||||
void printf_x64_instruction(zydis_dec_t* dec, instruction_x64_t* inst, const char* name);
|
||||
|
||||
@@ -15,8 +15,17 @@
|
||||
#define native_lock_read_dq(A, B, C) arm64_lock_read_dq(A, B, C)
|
||||
#define native_lock_write_dq(A, B, C) arm64_lock_write_dq(A, B, C)
|
||||
#define native_lock_xchg(A, B) arm64_lock_xchg(A, B)
|
||||
#define native_lock_xchg_d(A, B) arm64_lock_xchg_d(A, B)
|
||||
#define native_lock_storeifref(A, B, C) arm64_lock_storeifref(A, B, C)
|
||||
#define native_lock_storeifref_d(A, B, C) arm64_lock_storeifref_d(A, B, C)
|
||||
#define native_lock_storeifref2_d(A, B, C) arm64_lock_storeifref2_d(A, B, C)
|
||||
#define native_lock_storeifnull(A, B) arm64_lock_storeifnull(A, B)
|
||||
#define native_lock_storeifnull_d(A, B) arm64_lock_storeifnull_d(A, B)
|
||||
#define native_lock_decifnot0b(A) arm64_lock_decifnot0b(A)
|
||||
#define native_lock_storeb(A, B) arm64_lock_storeb(A, B)
|
||||
#define native_lock_incif0(A) arm64_lock_incif0(A)
|
||||
#define native_lock_decifnot0(A) arm64_lock_decifnot0(A)
|
||||
#define native_lock_store(A, B) arm64_lock_store(A, B)
|
||||
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
|
||||
+38
-34
@@ -108,6 +108,10 @@ uintptr_t get_parent_registers(dwarf_unwind_t *unwind, const elfheader_t *ehdr,
|
||||
*success = 0;
|
||||
return 0;
|
||||
}
|
||||
if(!IsAddressInElfSpace(ehdr, ehdr->ehframehdr)) {
|
||||
*success = 0;
|
||||
return 0;
|
||||
}
|
||||
unsigned char ehfh_version = *(unsigned char*)ehdr->ehframehdr;
|
||||
if (ehfh_version != 1) {
|
||||
*success = 0;
|
||||
@@ -389,17 +393,17 @@ uintptr_t get_parent_registers(dwarf_unwind_t *unwind, const elfheader_t *ehdr,
|
||||
++unwind_constr.reg_count;
|
||||
size_t tablelen = unwind_constr.reg_count * sizeof(uint64_t);
|
||||
size_t statuseslen = ((unwind_constr.reg_count+1) >> 1) * sizeof(uint8_t);
|
||||
unwind_constr.table = (uint64_t*)malloc(tablelen);
|
||||
unwind_constr.statuses = (uint8_t*)calloc((unwind_constr.reg_count+1) >> 1, sizeof(uint8_t));
|
||||
unwind_constr.table = (uint64_t*)box_malloc(tablelen);
|
||||
unwind_constr.statuses = (uint8_t*)box_calloc((unwind_constr.reg_count+1) >> 1, sizeof(uint8_t));
|
||||
// ~~undefined is 0: no initialization needed~~ still initialize the first 17 to same_val
|
||||
for (int i = 0; (i < 17) && (i <= unwind_constr.reg_count); ++i) {
|
||||
SET_STATUS(unwind_constr, i, REGSTATUS_same_val);
|
||||
}
|
||||
|
||||
curstacksize = 0;
|
||||
uint64_t **table_stack = (uint64_t**)malloc(maxstacksize * sizeof(uint64_t*));
|
||||
uint64_t **table_stack = (uint64_t**)box_malloc(maxstacksize * sizeof(uint64_t*));
|
||||
for (uint64_t i = 0; i < maxstacksize; ++i) {
|
||||
table_stack[i] = (uint64_t*)malloc(tablelen);
|
||||
table_stack[i] = (uint64_t*)box_malloc(tablelen);
|
||||
}
|
||||
cur_inst = initCIEinstr;
|
||||
uintptr_t cur_pointed_addr = pc_begin;
|
||||
@@ -537,10 +541,10 @@ uintptr_t get_parent_registers(dwarf_unwind_t *unwind, const elfheader_t *ehdr,
|
||||
printf_log(LOG_DEBUG, "Trying to restore register 0x%02lX while in the intial CFIs\n", (uint64_t)reg); \
|
||||
FAILED
|
||||
#define FAILED \
|
||||
free(unwind_constr.statuses); \
|
||||
free(unwind_constr.table); \
|
||||
for (uint64_t i = 0; i < maxstacksize; ++i) free(table_stack[i]); \
|
||||
free(table_stack); \
|
||||
box_free(unwind_constr.statuses); \
|
||||
box_free(unwind_constr.table); \
|
||||
for (uint64_t i = 0; i < maxstacksize; ++i) box_free(table_stack[i]); \
|
||||
box_free(table_stack); \
|
||||
*success = 0; return 0;
|
||||
while (cur_inst < endCIEinstr) {
|
||||
unsigned char inst; READ_U1(inst, cur_inst);
|
||||
@@ -549,21 +553,21 @@ uintptr_t get_parent_registers(dwarf_unwind_t *unwind, const elfheader_t *ehdr,
|
||||
}
|
||||
#undef FAILED
|
||||
#undef RESTORE_REG
|
||||
uint64_t *init_table = (uint64_t*)malloc(tablelen);
|
||||
uint64_t *init_table = (uint64_t*)box_malloc(tablelen);
|
||||
memcpy(init_table, unwind_constr.table, tablelen);
|
||||
uint8_t *init_statuses = (uint8_t*)malloc(statuseslen);
|
||||
uint8_t *init_statuses = (uint8_t*)box_malloc(statuseslen);
|
||||
memcpy(init_statuses, unwind_constr.statuses, statuseslen);
|
||||
cur_inst = cur_addr;
|
||||
#define RESTORE_REG(reg) \
|
||||
unwind_constr.table[reg] = init_table[reg]; \
|
||||
SET_STATUS(unwind_constr, (reg), ((init_statuses[(reg) >> 1] >> (((reg) & 1) << 2)) & 0xF));
|
||||
#define FAILED \
|
||||
free(init_statuses); \
|
||||
free(init_table); \
|
||||
free(unwind_constr.statuses); \
|
||||
free(unwind_constr.table); \
|
||||
for (uint64_t i = 0; i < maxstacksize; ++i) free(table_stack[i]); \
|
||||
free(table_stack); \
|
||||
box_free(init_statuses); \
|
||||
box_free(init_table); \
|
||||
box_free(unwind_constr.statuses); \
|
||||
box_free(unwind_constr.table); \
|
||||
for (uint64_t i = 0; i < maxstacksize; ++i) box_free(table_stack[i]); \
|
||||
box_free(table_stack); \
|
||||
*success = 0; return 0;
|
||||
while ((cur_inst < next_addr) && (cur_pointed_addr <= addr)) {
|
||||
unsigned char inst; READ_U1(inst, cur_inst);
|
||||
@@ -573,16 +577,16 @@ uintptr_t get_parent_registers(dwarf_unwind_t *unwind, const elfheader_t *ehdr,
|
||||
#undef FAILED
|
||||
#undef RESTORE_REG
|
||||
#undef PARSE_INST
|
||||
free(init_statuses);
|
||||
free(init_table);
|
||||
box_free(init_statuses);
|
||||
box_free(init_table);
|
||||
for (int i = 0; i < maxstacksize; ++i) {
|
||||
free(table_stack[i]);
|
||||
box_free(table_stack[i]);
|
||||
}
|
||||
free(table_stack);
|
||||
box_free(table_stack);
|
||||
|
||||
dwarf_unwind_t new_unwind;
|
||||
new_unwind.reg_count = unwind_constr.reg_count;
|
||||
new_unwind.regs = calloc(unwind_constr.reg_count, sizeof(uint64_t));
|
||||
new_unwind.regs = box_calloc(unwind_constr.reg_count, sizeof(uint64_t));
|
||||
uintptr_t cfa = unwind->regs[cfa_reg];
|
||||
if (cfa_signed) cfa += cfa_offset.soff;
|
||||
else cfa += cfa_offset.uoff;
|
||||
@@ -596,9 +600,9 @@ uintptr_t get_parent_registers(dwarf_unwind_t *unwind, const elfheader_t *ehdr,
|
||||
case REGSTATUS_same_val:
|
||||
if (i >= unwind->reg_count) {
|
||||
printf_log(LOG_DEBUG, "Invalid register status (value copied from register 0x%02lX)\n", i);
|
||||
free(unwind_constr.statuses);
|
||||
free(unwind_constr.table);
|
||||
free(new_unwind.regs);
|
||||
box_free(unwind_constr.statuses);
|
||||
box_free(unwind_constr.table);
|
||||
box_free(new_unwind.regs);
|
||||
*success = 0;
|
||||
return 0;
|
||||
}
|
||||
@@ -616,9 +620,9 @@ uintptr_t get_parent_registers(dwarf_unwind_t *unwind, const elfheader_t *ehdr,
|
||||
case REGSTATUS_register:
|
||||
if (unwind_constr.table[i] >= unwind->reg_count) {
|
||||
printf_log(LOG_DEBUG, "Invalid register status (value copied from register 0x%02lX)\n", unwind_constr.table[i]);
|
||||
free(unwind_constr.statuses);
|
||||
free(unwind_constr.table);
|
||||
free(new_unwind.regs);
|
||||
box_free(unwind_constr.statuses);
|
||||
box_free(unwind_constr.table);
|
||||
box_free(new_unwind.regs);
|
||||
*success = 0;
|
||||
return 0;
|
||||
}
|
||||
@@ -628,10 +632,10 @@ uintptr_t get_parent_registers(dwarf_unwind_t *unwind, const elfheader_t *ehdr,
|
||||
}
|
||||
}
|
||||
*success = (GET_STATUS(unwind_constr, return_addr_reg) == REGSTATUS_undefined) ? 0 : ((aug_fields & AUG_SIGHDLER) ? 2 : 1);
|
||||
free(unwind_constr.statuses);
|
||||
free(unwind_constr.table);
|
||||
box_free(unwind_constr.statuses);
|
||||
box_free(unwind_constr.table);
|
||||
|
||||
free(unwind->regs);
|
||||
box_free(unwind->regs);
|
||||
unwind->reg_count = new_unwind.reg_count;
|
||||
unwind->regs = new_unwind.regs;
|
||||
|
||||
@@ -654,9 +658,9 @@ uintptr_t get_parent_registers(dwarf_unwind_t *unwind, const elfheader_t *ehdr,
|
||||
}
|
||||
|
||||
dwarf_unwind_t *init_dwarf_unwind_registers(x64emu_t *emu) {
|
||||
dwarf_unwind_t *unwind_struct = (dwarf_unwind_t*)malloc(sizeof(dwarf_unwind_t));
|
||||
dwarf_unwind_t *unwind_struct = (dwarf_unwind_t*)box_malloc(sizeof(dwarf_unwind_t));
|
||||
unwind_struct->reg_count = 17;
|
||||
unwind_struct->regs = (uint64_t*)malloc(17*sizeof(uint64_t));
|
||||
unwind_struct->regs = (uint64_t*)box_malloc(17*sizeof(uint64_t));
|
||||
/* x86_64-abi-0.99.pdf
|
||||
* Register Name | Number | Abbreviation
|
||||
* General Purpose Register RAX | 0 | %rax
|
||||
@@ -711,7 +715,7 @@ dwarf_unwind_t *init_dwarf_unwind_registers(x64emu_t *emu) {
|
||||
}
|
||||
|
||||
void free_dwarf_unwind_registers(dwarf_unwind_t **unwind_struct) {
|
||||
free((*unwind_struct)->regs);
|
||||
free(*unwind_struct);
|
||||
box_free((*unwind_struct)->regs);
|
||||
box_free(*unwind_struct);
|
||||
*unwind_struct = NULL;
|
||||
}
|
||||
+295
-183
@@ -10,7 +10,11 @@
|
||||
#include <link.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#ifndef _DLFCN_H
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#include "custommem.h"
|
||||
#include "box64version.h"
|
||||
#include "elfloader.h"
|
||||
#include "debug.h"
|
||||
@@ -26,7 +30,6 @@
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "box64stack.h"
|
||||
#include "custommem.h"
|
||||
#include "wine_tools.h"
|
||||
#include "dictionnary.h"
|
||||
#include "symbols.h"
|
||||
@@ -54,10 +57,16 @@ elfheader_t* LoadAndCheckElfHeader(FILE* f, const char* name, int exec)
|
||||
if(!h)
|
||||
return NULL;
|
||||
|
||||
if ((h->path = realpath(name, NULL)) == NULL) {
|
||||
h->path = (char*)malloc(1);
|
||||
if ((h->path = box_realpath(name, NULL)) == NULL) {
|
||||
h->path = (char*)box_malloc(1);
|
||||
h->path[0] = '\0';
|
||||
}
|
||||
|
||||
h->mapsymbols = NewMapSymbols();
|
||||
h->weaksymbols = NewMapSymbols();
|
||||
h->localsymbols = NewMapSymbols();
|
||||
h->refcnt = 1;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
@@ -72,19 +81,23 @@ void FreeElfHeader(elfheader_t** head)
|
||||
cleanDBFromAddressRange(my_context, h->text, h->textsz, 1);
|
||||
}*/ // will be free at the end, no need to free it now
|
||||
#endif
|
||||
free(h->name);
|
||||
free(h->path);
|
||||
free(h->PHEntries);
|
||||
free(h->SHEntries);
|
||||
free(h->SHStrTab);
|
||||
free(h->StrTab);
|
||||
free(h->Dynamic);
|
||||
free(h->DynStr);
|
||||
free(h->SymTab);
|
||||
free(h->DynSym);
|
||||
box_free(h->name);
|
||||
box_free(h->path);
|
||||
box_free(h->PHEntries);
|
||||
box_free(h->SHEntries);
|
||||
box_free(h->SHStrTab);
|
||||
box_free(h->StrTab);
|
||||
box_free(h->Dynamic);
|
||||
box_free(h->DynStr);
|
||||
box_free(h->SymTab);
|
||||
box_free(h->DynSym);
|
||||
|
||||
FreeMapSymbols(&h->mapsymbols);
|
||||
FreeMapSymbols(&h->weaksymbols);
|
||||
FreeMapSymbols(&h->localsymbols);
|
||||
|
||||
FreeElfMemory(h);
|
||||
free(h);
|
||||
box_free(h);
|
||||
|
||||
*head = NULL;
|
||||
}
|
||||
@@ -144,7 +157,7 @@ int CalcLoadAddr(elfheader_t* head)
|
||||
const char* ElfName(elfheader_t* head)
|
||||
{
|
||||
if(!head)
|
||||
return "(noelf)";
|
||||
return "box64";
|
||||
return head->name;
|
||||
}
|
||||
const char* ElfPath(elfheader_t* head)
|
||||
@@ -156,12 +169,12 @@ const char* ElfPath(elfheader_t* head)
|
||||
int AllocElfMemory(box64context_t* context, elfheader_t* head, int mainbin)
|
||||
{
|
||||
uintptr_t offs = 0;
|
||||
if(mainbin && head->vaddr==0) {
|
||||
char* load_addr = getenv("BOX64_LOAD_ADDR");
|
||||
if(load_addr)
|
||||
if(sscanf(load_addr, "0x%zx", &offs)!=1)
|
||||
offs = 0;
|
||||
if(!head->vaddr && box64_load_addr) {
|
||||
offs = box64_load_addr;
|
||||
box64_load_addr += head->memsz;
|
||||
box64_load_addr = (box64_load_addr+0x10ffffffLL)&~0xffffffLL;
|
||||
}
|
||||
int log_level = box64_load_addr?LOG_INFO:LOG_DEBUG;
|
||||
if(!offs)
|
||||
offs = head->vaddr;
|
||||
if(head->vaddr) {
|
||||
@@ -169,9 +182,9 @@ int AllocElfMemory(box64context_t* context, elfheader_t* head, int mainbin)
|
||||
for (size_t i=0; i<head->numPHEntries; ++i)
|
||||
if(head->PHEntries[i].p_type == PT_LOAD && head->PHEntries[i].p_flags)
|
||||
++head->multiblock_n;
|
||||
head->multiblock_size = (uint64_t*)calloc(head->multiblock_n, sizeof(uint64_t));
|
||||
head->multiblock_offs = (uintptr_t*)calloc(head->multiblock_n, sizeof(uintptr_t));
|
||||
head->multiblock = (void**)calloc(head->multiblock_n, sizeof(void*));
|
||||
head->multiblock_size = (uint64_t*)box_calloc(head->multiblock_n, sizeof(uint64_t));
|
||||
head->multiblock_offs = (uintptr_t*)box_calloc(head->multiblock_n, sizeof(uintptr_t));
|
||||
head->multiblock = (void**)box_calloc(head->multiblock_n, sizeof(void*));
|
||||
// and now, create all individual blocks
|
||||
head->memory = (char*)0xffffffffffffffff;
|
||||
int n = 0;
|
||||
@@ -209,8 +222,7 @@ int AllocElfMemory(box64context_t* context, elfheader_t* head, int mainbin)
|
||||
}
|
||||
head->multiblock_n = n; // might be less in fact
|
||||
for (int i=0; i<head->multiblock_n; ++i) {
|
||||
|
||||
printf_log(LOG_DEBUG, "Allocating 0x%lx memory @%p for Elf \"%s\"\n", head->multiblock_size[i], (void*)head->multiblock_offs[i], head->name);
|
||||
printf_log(log_level, "Allocating 0x%lx memory @%p for Elf \"%s\"\n", head->multiblock_size[i], (void*)head->multiblock_offs[i], head->name);
|
||||
void* p = mmap((void*)head->multiblock_offs[i], head->multiblock_size[i]
|
||||
, PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
, MAP_PRIVATE | MAP_ANONYMOUS /*| ((wine_preloaded)?MAP_FIXED:0)*/
|
||||
@@ -245,7 +257,7 @@ int AllocElfMemory(box64context_t* context, elfheader_t* head, int mainbin)
|
||||
// vaddr is 0, load everything has a One block
|
||||
if(!offs && box64_wine)
|
||||
offs = (uintptr_t)find47bitBlock(head->memsz); // limit to 47bits...
|
||||
printf_log(LOG_DEBUG, "Allocating 0x%zx memory @%p for Elf \"%s\"\n", head->memsz, (void*)offs, head->name);
|
||||
printf_log(log_level, "Allocating 0x%zx memory @%p for Elf \"%s\"\n", head->memsz, (void*)offs, head->name);
|
||||
void* p = mmap((void*)offs, head->memsz
|
||||
, PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
, MAP_PRIVATE | MAP_ANONYMOUS /*| (((offs&&wine_preloaded)?MAP_FIXED:0))*/
|
||||
@@ -262,12 +274,12 @@ int AllocElfMemory(box64context_t* context, elfheader_t* head, int mainbin)
|
||||
head->memory = p;
|
||||
memset(p, 0, head->memsz);
|
||||
head->delta = (intptr_t)p - (intptr_t)head->vaddr;
|
||||
printf_log(LOG_DEBUG, "Got %p (delta=%p)\n", p, (void*)head->delta);
|
||||
printf_log(log_level, "Got %p (delta=%p)\n", p, (void*)head->delta);
|
||||
|
||||
head->multiblock_n = 1;
|
||||
head->multiblock_size = (uint64_t*)calloc(head->multiblock_n, sizeof(uint64_t));
|
||||
head->multiblock_offs = (uintptr_t*)calloc(head->multiblock_n, sizeof(uintptr_t));
|
||||
head->multiblock = (void**)calloc(head->multiblock_n, sizeof(void*));
|
||||
head->multiblock_size = (uint64_t*)box_calloc(head->multiblock_n, sizeof(uint64_t));
|
||||
head->multiblock_offs = (uintptr_t*)box_calloc(head->multiblock_n, sizeof(uintptr_t));
|
||||
head->multiblock = (void**)box_calloc(head->multiblock_n, sizeof(void*));
|
||||
head->multiblock_size[0] = head->memsz;
|
||||
head->multiblock_offs[0] = (uintptr_t)p;
|
||||
head->multiblock[0] = p;
|
||||
@@ -283,9 +295,9 @@ void FreeElfMemory(elfheader_t* head)
|
||||
if(head->multiblock_n) {
|
||||
for(int i=0; i<head->multiblock_n; ++i)
|
||||
munmap(head->multiblock[i], head->multiblock_size[i]);
|
||||
free(head->multiblock);
|
||||
free(head->multiblock_size);
|
||||
free(head->multiblock_offs);
|
||||
box_free(head->multiblock);
|
||||
box_free(head->multiblock_size);
|
||||
box_free(head->multiblock_offs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,9 +309,9 @@ int LoadElfMemory(FILE* f, box64context_t* context, elfheader_t* head)
|
||||
char* dest = (char*)e->p_paddr + head->delta;
|
||||
printf_log(LOG_DEBUG, "MMap block #%zu @%p offset=%p (0x%zx/0x%zx)\n", i, dest, (void*)e->p_offset, e->p_filesz, e->p_memsz);
|
||||
void* p = (void*)-1;
|
||||
if(e->p_memsz==e->p_filesz && !(e->p_align&0xfff)) {
|
||||
if(e->p_memsz==e->p_filesz && !(e->p_align&(box64_pagesize-1))) {
|
||||
printf_log(LOG_DEBUG, "MMap block #%zu @%p offset=%p (0x%zx/0x%zx, flags:0x%x)\n", i, dest, (void*)e->p_offset, e->p_filesz, e->p_memsz, e->p_flags);
|
||||
mmap(dest, e->p_filesz, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fileno(f), e->p_offset);
|
||||
p = mmap(dest, e->p_filesz, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fileno(f), e->p_offset);
|
||||
}
|
||||
if(p!=dest) {
|
||||
printf_log(LOG_DEBUG, "Loading block #%zu %p (0x%zx/0x%zx)\n",i, dest, e->p_filesz, e->p_memsz);
|
||||
@@ -355,8 +367,9 @@ int ReloadElfMemory(FILE* f, box64context_t* context, elfheader_t* head)
|
||||
#ifdef DYNAREC
|
||||
cleanDBFromAddressRange((uintptr_t)dest, e->p_memsz, 0);
|
||||
#endif
|
||||
mprotect(dest, e->p_memsz, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
setProtection((uintptr_t)dest, e->p_memsz, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
uint32_t page_offset = (uintptr_t)dest & (box64_pagesize - 1);
|
||||
mprotect(dest - page_offset, e->p_memsz + page_offset, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
setProtection((uintptr_t)dest - page_offset, e->p_memsz + page_offset, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
if(e->p_filesz) {
|
||||
ssize_t r = -1;
|
||||
if((r=fread(dest, e->p_filesz, 1, f))!=1) {
|
||||
@@ -373,7 +386,7 @@ int ReloadElfMemory(FILE* f, box64context_t* context, elfheader_t* head)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FindR64COPYRel(elfheader_t* h, const char* name, uintptr_t *offs, uint64_t** p, int version, const char* vername)
|
||||
int FindR64COPYRel(elfheader_t* h, const char* name, uintptr_t *offs, uint64_t** p, size_t size, int version, const char* vername)
|
||||
{
|
||||
if(!h)
|
||||
return 0;
|
||||
@@ -385,7 +398,7 @@ int FindR64COPYRel(elfheader_t* h, const char* name, uintptr_t *offs, uint64_t**
|
||||
int t = ELF64_R_TYPE(rela[i].r_info);
|
||||
Elf64_Sym *sym = &h->DynSym[ELF64_R_SYM(rela[i].r_info)];
|
||||
const char* symname = SymName(h, sym);
|
||||
if(t==R_X86_64_COPY && symname && !strcmp(symname, name)) {
|
||||
if(t==R_X86_64_COPY && symname && !strcmp(symname, name) && sym->st_size==size) {
|
||||
int version2 = h->VerSym?((Elf64_Half*)((uintptr_t)h->VerSym+h->delta))[ELF64_R_SYM(rela[i].r_info)]:-1;
|
||||
if(version2!=-1) version2 &= 0x7fff;
|
||||
if(version && !version2) version2=-1; // match a versionned symbol against a global "local" symbol
|
||||
@@ -412,13 +425,22 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t*
|
||||
uint64_t *p = (uint64_t*)(rel[i].r_offset + head->delta);
|
||||
uintptr_t offs = 0;
|
||||
uintptr_t end = 0;
|
||||
size_t size = sym->st_size;
|
||||
//uintptr_t tmp = 0;
|
||||
int version = head->VerSym?((Elf64_Half*)((uintptr_t)head->VerSym+head->delta))[ELF64_R_SYM(rel[i].r_info)]:-1;
|
||||
if(version!=-1) version &=0x7fff;
|
||||
const char* vername = GetSymbolVersion(head, version);
|
||||
const char* defver = GetDefaultVersion((bind==STB_WEAK)?my_context->weakdefver:my_context->globaldefver, symname);
|
||||
if(bind==STB_LOCAL) {
|
||||
offs = sym->st_value + head->delta;
|
||||
end = offs + sym->st_size;
|
||||
if(!symname || !symname[0]) {
|
||||
offs = sym->st_value + head->delta;
|
||||
end = offs + sym->st_size;
|
||||
} else {
|
||||
if(!offs && !end && local_maplib)
|
||||
GetLocalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername);
|
||||
if(!offs && !end)
|
||||
GetLocalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername);
|
||||
}
|
||||
} else {
|
||||
// this is probably very very wrong. A proprer way to get reloc need to be writen, but this hack seems ok for now
|
||||
// at least it work for half-life, unreal, ut99, zsnes, Undertale, ColinMcRae Remake, FTL, ShovelKnight...
|
||||
@@ -452,14 +474,14 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t*
|
||||
*p += offs;
|
||||
break;
|
||||
case R_X86_64_GLOB_DAT:
|
||||
if(head!=my_context->elfs[0] && !IsGlobalNoWeakSymbolInNative(maplib, symname, version, vername) && FindR64COPYRel(my_context->elfs[0], symname, &globoffs, &globp, version, vername)) {
|
||||
if(head!=my_context->elfs[0] && !IsGlobalNoWeakSymbolInNative(maplib, symname, version, vername) && FindR64COPYRel(my_context->elfs[0], symname, &globoffs, &globp, size, version, vername)) {
|
||||
// set global offs / size for the symbol
|
||||
offs = sym->st_value;
|
||||
end = offs + sym->st_size;
|
||||
if(sym->st_size && offs) {
|
||||
printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT with R_X86_64_COPY @%p/%p (%p/%p -> %p/%p) size=%ld on sym=%s \n", (bind==STB_LOCAL)?"Local":"Global", p, globp, (void*)(p?(*p):0), (void*)(globp?(*globp):0), (void*)(offs + head->delta), (void*)globoffs, sym->st_size, symname);
|
||||
memmove((void*)globoffs, (void*)offs, sym->st_size); // preapply to copy part from lib to main elf
|
||||
AddWeakSymbol(GetGlobalData(maplib), symname, offs + head->delta, sym->st_size, version, vername);
|
||||
AddUniqueSymbol(GetGlobalData(maplib), symname, offs + head->delta, sym->st_size, version, vername);
|
||||
} else {
|
||||
printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT with R_X86_64_COPY @%p/%p (%p/%p -> %p/%p) null sized on sym=%s \n", (bind==STB_LOCAL)?"Local":"Global", p, globp, (void*)(p?(*p):0), (void*)(globp?(*globp):0), (void*)offs, (void*)globoffs, symname);
|
||||
}
|
||||
@@ -471,8 +493,8 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t*
|
||||
end = globend;
|
||||
}
|
||||
if (!offs) {
|
||||
if(strcmp(symname, "__gmon_start__") && strcmp(symname, "data_start") && strcmp(symname, "__data_start"))
|
||||
printf_log(LOG_NONE, "%s: Global Symbol %s not found, cannot apply R_X86_64_GLOB_DAT @%p (%p) in %s\n", (bind==STB_WEAK)?"Warning":"Error", symname, p, *(void**)p, head->name);
|
||||
if(strcmp(symname, "__gmon_start__") && strcmp(symname, "data_start") && strcmp(symname, "__data_start") && strcmp(symname, "collector_func_load"))
|
||||
printf_log(LOG_NONE, "%s: Global Symbol %s (ver=%d/%s) not found, cannot apply R_X86_64_GLOB_DAT @%p (%p) in %s\n", (bind==STB_WEAK)?"Warning":"Error", symname, version, vername?vername:"(none)", p, *(void**)p, head->name);
|
||||
} else {
|
||||
printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT @%p (%p -> %p) on sym=%s (ver=%d/%s)\n", (bind==STB_LOCAL)?"Local":"Global", p, (void*)(p?(*p):0), (void*)offs, symname, version, vername?vername:"(none)");
|
||||
*p = offs;
|
||||
@@ -484,11 +506,11 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t*
|
||||
uintptr_t old_offs = offs;
|
||||
uintptr_t old_end = end;
|
||||
offs = 0;
|
||||
GetSymbolStartEnd(GetGlobalData(maplib), symname, &offs, &end, version, vername, 1); // try globaldata symbols first
|
||||
GetSizedSymbolStartEnd(GetGlobalData(maplib), symname, &offs, &end, size, version, vername, 1, defver); // try globaldata symbols first
|
||||
if(offs==0) {
|
||||
GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername); // get original copy if any
|
||||
GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head, size, version, vername); // get original copy if any
|
||||
if(!offs && local_maplib)
|
||||
GetNoSelfSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername);
|
||||
GetNoSelfSymbolStartEnd(local_maplib, symname, &offs, &end, head, size, version, vername);
|
||||
}
|
||||
if(!offs) {
|
||||
offs = old_offs;
|
||||
@@ -566,7 +588,6 @@ uintptr_t tlsdescUndefweak = 0;
|
||||
uintptr_t GetSegmentBaseEmu(x64emu_t* emu, int seg);
|
||||
EXPORT uintptr_t _dl_tlsdesc_undefweak(x64emu_t* emu)
|
||||
{
|
||||
printf_log(LOG_DEBUG, "_dl_tlsdesc_undefweak, rax=%p\n", (void*)R_RAX);
|
||||
struct tlsdesc *td = (struct tlsdesc *)R_RAX;
|
||||
return td->arg;
|
||||
}
|
||||
@@ -584,13 +605,22 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t
|
||||
uint64_t *p = (uint64_t*)(rela[i].r_offset + head->delta);
|
||||
uintptr_t offs = 0;
|
||||
uintptr_t end = 0;
|
||||
size_t size = sym->st_size;
|
||||
elfheader_t* h_tls = NULL;//head;
|
||||
int version = head->VerSym?((Elf64_Half*)((uintptr_t)head->VerSym+head->delta))[ELF64_R_SYM(rela[i].r_info)]:-1;
|
||||
if(version!=-1) version &=0x7fff;
|
||||
const char* vername = GetSymbolVersion(head, version);
|
||||
const char* defver = GetDefaultVersion((bind==STB_WEAK)?my_context->weakdefver:my_context->globaldefver, symname);
|
||||
if(bind==STB_LOCAL) {
|
||||
offs = sym->st_value + head->delta;
|
||||
end = offs + sym->st_size;
|
||||
if(!symname || !symname[0]) {
|
||||
offs = sym->st_value + head->delta;
|
||||
end = offs + sym->st_size;
|
||||
} else {
|
||||
if(!offs && !end && local_maplib)
|
||||
GetLocalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername);
|
||||
if(!offs && !end)
|
||||
GetLocalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername);
|
||||
}
|
||||
} else {
|
||||
// this is probably very very wrong. A proprer way to get reloc need to be writen, but this hack seems ok for now
|
||||
// at least it work for half-life, unreal, ut99, zsnes, Undertale, ColinMcRae Remake, FTL, ShovelKnight...
|
||||
@@ -621,15 +651,23 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t
|
||||
printf_dump(LOG_NEVER, "Apply %s R_X86_64_RELATIVE @%p (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", p, *(void**)p, (void*)(head->delta+ rela[i].r_addend));
|
||||
*p = head->delta+ rela[i].r_addend;
|
||||
break;
|
||||
case R_X86_64_IRELATIVE:
|
||||
{
|
||||
x64emu_t* emu = thread_get_emu();
|
||||
EmuCall(emu, head->delta+rela[i].r_addend);
|
||||
printf_dump(LOG_NEVER, "Apply %s R_X86_64_IRELATIVE @%p (%p -> %p()=%p)\n", (bind==STB_LOCAL)?"Local":"Global", p, *(void**)p, (void*)(head->delta+ rela[i].r_addend), (void*)(R_RAX));
|
||||
*p = R_RAX;
|
||||
}
|
||||
break;
|
||||
case R_X86_64_COPY:
|
||||
globoffs = offs;
|
||||
globend = end;
|
||||
offs = end = 0;
|
||||
GetSymbolStartEnd(GetGlobalData(maplib), symname, &offs, &end, version, vername, 1); // try globaldata symbols first
|
||||
GetSizedSymbolStartEnd(GetGlobalData(maplib), symname, &offs, &end, size, version, vername, 1, defver); // try globaldata symbols first
|
||||
if(!offs && local_maplib)
|
||||
GetNoSelfSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername);
|
||||
GetNoSelfSymbolStartEnd(local_maplib, symname, &offs, &end, head, size, version, vername);
|
||||
if(!offs)
|
||||
GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername);
|
||||
GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head, size, version, vername);
|
||||
if(!offs) {offs = globoffs; end = globend;}
|
||||
if(offs) {
|
||||
// add r_addend to p?
|
||||
@@ -641,7 +679,7 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t
|
||||
}
|
||||
break;
|
||||
case R_X86_64_GLOB_DAT:
|
||||
if(head!=my_context->elfs[0] && !IsGlobalNoWeakSymbolInNative(maplib, symname, version, vername) && FindR64COPYRel(my_context->elfs[0], symname, &globoffs, &globp, version, vername)) {
|
||||
if(head!=my_context->elfs[0] && !IsGlobalNoWeakSymbolInNative(maplib, symname, version, vername) && FindR64COPYRel(my_context->elfs[0], symname, &globoffs, &globp, size, version, vername)) {
|
||||
// set global offs / size for the symbol
|
||||
offs = sym->st_value + head->delta;
|
||||
end = offs + sym->st_size;
|
||||
@@ -650,7 +688,7 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t
|
||||
(bind==STB_LOCAL)?"Local":"Global", p, globp, (void*)(p?(*p):0),
|
||||
(void*)(globp?(*globp):0), (void*)offs, (void*)globoffs, sym->st_size, symname, version, vername?vername:"(none)");
|
||||
//memmove((void*)globoffs, (void*)offs, sym->st_size); // preapply to copy part from lib to main elf
|
||||
AddWeakSymbol(GetGlobalData(maplib), symname, offs, sym->st_size, version, vername);
|
||||
AddUniqueSymbol(GetGlobalData(maplib), symname, offs, sym->st_size, version, vername);
|
||||
} else {
|
||||
printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT with R_X86_64_COPY @%p/%p (%p/%p -> %p/%p) null sized on sym=%s (ver=%d/%s)\n",
|
||||
(bind==STB_LOCAL)?"Local":"Global", p, globp, (void*)(p?(*p):0),
|
||||
@@ -664,8 +702,8 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t
|
||||
end = globend;
|
||||
}
|
||||
if (!offs) {
|
||||
if(strcmp(symname, "__gmon_start__") && strcmp(symname, "data_start") && strcmp(symname, "__data_start"))
|
||||
printf_log(LOG_NONE, "%s: Global Symbol %s not found, cannot apply R_X86_64_GLOB_DAT @%p (%p) in %s\n", (bind==STB_WEAK)?"Warning":"Error", symname, p, *(void**)p, head->name);
|
||||
if(strcmp(symname, "__gmon_start__") && strcmp(symname, "data_start") && strcmp(symname, "__data_start") && strcmp(symname, "collector_func_load"))
|
||||
printf_log((bind==STB_WEAK)?LOG_INFO:LOG_NONE, "%s: Global Symbol %s not found, cannot apply R_X86_64_GLOB_DAT @%p (%p) in %s\n", (bind==STB_WEAK)?"Warning":"Error", symname, p, *(void**)p, head->name);
|
||||
} else {
|
||||
printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT @%p (%p -> %p) on sym=%s (ver=%d/%s)\n", (bind==STB_LOCAL)?"Local":"Global", p, (void*)(p?(*p):0), (void*)offs, symname, version, vername?vername:"(none)");
|
||||
*p = offs/* + rela[i].r_addend*/; // not addend it seems
|
||||
@@ -697,7 +735,7 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t
|
||||
(bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)(offs+rela[i].r_addend));
|
||||
*p = offs + rela[i].r_addend;
|
||||
} else {
|
||||
printf_log(LOG_NONE, "Warning, Symbol %s found, but Jump Slot Offset is NULL \n", symname);
|
||||
printf_log(LOG_INFO, "Warning, Symbol %s found, but Jump Slot Offset is NULL \n", symname);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -709,9 +747,13 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t
|
||||
break;
|
||||
case R_X86_64_64:
|
||||
if (!offs) {
|
||||
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_X86_64_64 @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
|
||||
ret_ok = 1;
|
||||
// return -1;
|
||||
if(symname && !strcmp(symname, "__gxx_personality_v0")) {
|
||||
printf_dump(LOG_NEVER, "Warning: Symbol %s not found, cannot apply R_X86_64_64 @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
|
||||
} else {
|
||||
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_X86_64_64 @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
|
||||
ret_ok = 1;
|
||||
// return -1;
|
||||
}
|
||||
} else {
|
||||
printf_dump(LOG_NEVER, "Apply %s R_X86_64_64 @%p with sym=%s (ver=%d/%s) addend=0x%lx (%p -> %p)\n",
|
||||
(bind==STB_LOCAL)?"Local":"Global", p, symname, version, vername?vername:"(none)", rela[i].r_addend, *(void**)p, (void*)(offs+rela[i].r_addend/*+*(uint64_t*)p*/));
|
||||
@@ -770,7 +812,7 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t
|
||||
}
|
||||
// return -1;
|
||||
} else {
|
||||
if(!symname || symname[0]=='\0' || bind==STB_LOCAL)
|
||||
if(!symname || symname[0]=='\0')
|
||||
offs = sym->st_value;
|
||||
if(p) {
|
||||
int64_t tlsoffset = offs; // it's not an offset in elf memory
|
||||
@@ -799,6 +841,7 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t
|
||||
}
|
||||
return bindnow?ret_ok:0;
|
||||
}
|
||||
void checkHookedSymbols(lib_t *maplib, elfheader_t* h); // in mallochook.c
|
||||
int RelocateElf(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t* head)
|
||||
{
|
||||
if(head->rel) {
|
||||
@@ -815,7 +858,7 @@ int RelocateElf(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t* he
|
||||
if(RelocateElfRELA(maplib, local_maplib, bindnow, head, cnt, (Elf64_Rela *)(head->rela + head->delta), NULL))
|
||||
return -1;
|
||||
}
|
||||
|
||||
checkHookedSymbols(maplib, head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -923,22 +966,6 @@ uintptr_t GetLastByte(elfheader_t* h)
|
||||
void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* weaksymbols, kh_mapsymbols_t* localsymbols, elfheader_t* h)
|
||||
{
|
||||
if(box64_dump && h->DynSym) DumpDynSym(h);
|
||||
int libcef = (strstr(h->name, "libcef.so"))?1:0;
|
||||
//libcef.so is linked with tcmalloc staticaly, but this cannot be easily supported in box64, so hacking some "unlink" here
|
||||
const char* avoid_libcef[] = {"malloc", "realloc", "free", "calloc", "cfree",
|
||||
"__libc_calloc", "__libc_cfree", "__libc_memallign", "__liv_pvalloc",
|
||||
"__libcrealloc", "__libc_valloc", "__posix_memalign",
|
||||
"valloc", "pvalloc", "posix_memalign", "malloc_stats", "malloc_usable_size",
|
||||
/*"mallopt",*/ "localtime_r",
|
||||
//c++ symbol from libstdc++ too
|
||||
//"_ZnwmRKSt9nothrow_t", "_ZdaPv", // operator new(unsigned long, std::nothrow_t const&), operator delete[](void*)
|
||||
//"_Znwm", "_ZdlPv", "_Znam", // operator new(unsigned long), operator delete(void*), operator new[](unsigned long)
|
||||
//"_ZnwmSt11align_val_t", "_ZnwmSt11align_val_tRKSt9nothrow_t", // operator new(unsigned long, std::align_val_t)
|
||||
//"_ZnamSt11align_val_t", "_ZnamSt11align_val_tRKSt9nothrow_t", // operator new[](unsigned long, std::align_val_t)
|
||||
//"_ZdlPvRKSt9nothrow_t", "_ZdaPvSt11align_val_tRKSt9nothrow_t", // more delete operators
|
||||
//"_ZdlPvmSt11align_val_t", "_ZdaPvRKSt9nothrow_t",
|
||||
//"_ZdaPvSt11align_val_t", "_ZdlPvSt11align_val_t",
|
||||
};
|
||||
printf_dump(LOG_NEVER, "Will look for Symbol to add in SymTable(%zu)\n", h->numSymTab);
|
||||
for (size_t i=0; i<h->numSymTab; ++i) {
|
||||
const char * symname = h->StrTab+h->SymTab[i].st_name;
|
||||
@@ -947,7 +974,7 @@ void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* wea
|
||||
int vis = h->SymTab[i].st_other&0x3;
|
||||
size_t sz = h->SymTab[i].st_size;
|
||||
if((type==STT_OBJECT || type==STT_FUNC || type==STT_COMMON || type==STT_TLS || type==STT_NOTYPE)
|
||||
&& (vis==STV_DEFAULT || vis==STV_PROTECTED) && (h->SymTab[i].st_shndx!=0)) {
|
||||
&& (vis==STV_DEFAULT || vis==STV_PROTECTED || (vis==STV_HIDDEN && bind==STB_LOCAL)) && (h->SymTab[i].st_shndx!=0)) {
|
||||
if(sz && strstr(symname, "@@")) {
|
||||
char symnameversionned[strlen(symname)+1];
|
||||
strcpy(symnameversionned, symname);
|
||||
@@ -957,6 +984,7 @@ void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* wea
|
||||
p+=2;
|
||||
symname = AddDictionnary(my_context->versym, symnameversionned);
|
||||
const char* vername = AddDictionnary(my_context->versym, p);
|
||||
AddDefaultVersion((bind==STB_WEAK)?my_context->weakdefver:my_context->globaldefver, symname, vername);
|
||||
if((bind==STB_GNU_UNIQUE /*|| (bind==STB_GLOBAL && type==STT_FUNC)*/) && FindGlobalSymbol(maplib, symname, 2, p))
|
||||
continue;
|
||||
uintptr_t offs = (type==STT_TLS)?h->SymTab[i].st_value:(h->SymTab[i].st_value + h->delta);
|
||||
@@ -971,13 +999,6 @@ void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* wea
|
||||
}
|
||||
} else {
|
||||
int to_add = 1;
|
||||
if(libcef) {
|
||||
if(strstr(symname, "_Zn")==symname || strstr(symname, "_Zd")==symname)
|
||||
to_add = 0;
|
||||
for(int j=0; j<sizeof(avoid_libcef)/sizeof(avoid_libcef[0]) && to_add; ++j)
|
||||
if(!strcmp(symname, avoid_libcef[j]))
|
||||
to_add = 0;
|
||||
}
|
||||
if(!to_add || (bind==STB_GNU_UNIQUE && FindGlobalSymbol(maplib, symname, -1, NULL)))
|
||||
continue;
|
||||
uintptr_t offs = (type==STT_TLS)?h->SymTab[i].st_value:(h->SymTab[i].st_value + h->delta);
|
||||
@@ -1001,20 +1022,18 @@ void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* wea
|
||||
int type = ELF64_ST_TYPE(h->DynSym[i].st_info);
|
||||
int vis = h->DynSym[i].st_other&0x3;
|
||||
if((type==STT_OBJECT || type==STT_FUNC || type==STT_COMMON || type==STT_TLS || type==STT_NOTYPE)
|
||||
&& (vis==STV_DEFAULT || vis==STV_PROTECTED) && (h->DynSym[i].st_shndx!=0 && h->DynSym[i].st_shndx<=65521)) {
|
||||
&& (vis==STV_DEFAULT || vis==STV_PROTECTED || (vis==STV_HIDDEN && bind==STB_LOCAL)) && (h->DynSym[i].st_shndx!=0 && h->DynSym[i].st_shndx<=65521)) {
|
||||
uintptr_t offs = (type==STT_TLS)?h->DynSym[i].st_value:(h->DynSym[i].st_value + h->delta);
|
||||
size_t sz = h->DynSym[i].st_size;
|
||||
int version = h->VerSym?((Elf64_Half*)((uintptr_t)h->VerSym+h->delta))[i]:-1;
|
||||
int add_default = (version!=-1 && (version&0x7fff)>1 && !(version&0x8000) && !GetDefaultVersion((bind==STB_WEAK)?my_context->weakdefver:my_context->globaldefver, symname))?1:0;
|
||||
if(version!=-1) version &= 0x7fff;
|
||||
const char* vername = GetSymbolVersion(h, version);
|
||||
int to_add = 1;
|
||||
if(libcef) {
|
||||
if(strstr(symname, "_Zn")==symname || strstr(symname, "_Zd")==symname)
|
||||
to_add = 0;
|
||||
for(int j=0; j<sizeof(avoid_libcef)/sizeof(avoid_libcef[0]) && to_add; ++j)
|
||||
if(!strcmp(symname, avoid_libcef[j]))
|
||||
to_add = 0;
|
||||
if(add_default) {
|
||||
AddDefaultVersion((bind==STB_WEAK)?my_context->weakdefver:my_context->globaldefver, symname, vername);
|
||||
printf_dump(LOG_NEVER, "Adding Default Version \"%s\" for Symbol\"%s\"\n", vername, symname);
|
||||
}
|
||||
int to_add = 1;
|
||||
if(!to_add || (bind==STB_GNU_UNIQUE && FindGlobalSymbol(maplib, symname, version, vername)))
|
||||
continue;
|
||||
printf_dump(LOG_NEVER, "Adding Versionned Symbol(bind=%s) \"%s\" (ver=%d/%s) with offset=%p sz=%zu\n", (bind==STB_LOCAL)?"LOCAL":((bind==STB_WEAK)?"WEAK":"GLOBAL"), symname, version, vername?vername:"(none)", (void*)offs, sz);
|
||||
@@ -1024,11 +1043,10 @@ void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* wea
|
||||
if(bind==STB_WEAK) {
|
||||
AddSymbol(weaksymbols, symname, offs, sz, version, vername);
|
||||
} else {
|
||||
AddWeakSymbol(mapsymbols, symname, offs, sz, version?version:1, vername);
|
||||
AddSymbol(mapsymbols, symname, offs, sz, version?version:1, vername);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1045,8 +1063,10 @@ $PLATFORM – Expands to the processor type of the current machine (see the
|
||||
uname(1) man page description of the -i option). For more details of this token
|
||||
expansion, see “System Specific Shared Objects”
|
||||
*/
|
||||
int LoadNeededLibs(elfheader_t* h, lib_t *maplib, needed_libs_t* neededlibs, library_t *deplib, int local, int bindnow, box64context_t *box64, x64emu_t* emu)
|
||||
int LoadNeededLibs(elfheader_t* h, lib_t *maplib, int local, int bindnow, box64context_t *box64, x64emu_t* emu)
|
||||
{
|
||||
if(h->needed) // already done
|
||||
return 0;
|
||||
DumpDynamicRPath(h);
|
||||
// update RPATH first
|
||||
for (size_t i=0; i<h->numDynamic; ++i)
|
||||
@@ -1054,46 +1074,46 @@ int LoadNeededLibs(elfheader_t* h, lib_t *maplib, needed_libs_t* neededlibs, lib
|
||||
char *rpathref = h->DynStrTab+h->delta+h->Dynamic[i].d_un.d_val;
|
||||
char* rpath = rpathref;
|
||||
while(strstr(rpath, "$ORIGIN")) {
|
||||
char* origin = strdup(h->path);
|
||||
char* origin = box_strdup(h->path);
|
||||
char* p = strrchr(origin, '/');
|
||||
if(p) *p = '\0'; // remove file name to have only full path, without last '/'
|
||||
char* tmp = (char*)calloc(1, strlen(rpath)-strlen("$ORIGIN")+strlen(origin)+1);
|
||||
char* tmp = (char*)box_calloc(1, strlen(rpath)-strlen("$ORIGIN")+strlen(origin)+1);
|
||||
p = strstr(rpath, "$ORIGIN");
|
||||
memcpy(tmp, rpath, p-rpath);
|
||||
strcat(tmp, origin);
|
||||
strcat(tmp, p+strlen("$ORIGIN"));
|
||||
if(rpath!=rpathref)
|
||||
free(rpath);
|
||||
box_free(rpath);
|
||||
rpath = tmp;
|
||||
free(origin);
|
||||
box_free(origin);
|
||||
}
|
||||
while(strstr(rpath, "${ORIGIN}")) {
|
||||
char* origin = strdup(h->path);
|
||||
char* origin = box_strdup(h->path);
|
||||
char* p = strrchr(origin, '/');
|
||||
if(p) *p = '\0'; // remove file name to have only full path, without last '/'
|
||||
char* tmp = (char*)calloc(1, strlen(rpath)-strlen("${ORIGIN}")+strlen(origin)+1);
|
||||
char* tmp = (char*)box_calloc(1, strlen(rpath)-strlen("${ORIGIN}")+strlen(origin)+1);
|
||||
p = strstr(rpath, "${ORIGIN}");
|
||||
memcpy(tmp, rpath, p-rpath);
|
||||
strcat(tmp, origin);
|
||||
strcat(tmp, p+strlen("${ORIGIN}"));
|
||||
if(rpath!=rpathref)
|
||||
free(rpath);
|
||||
box_free(rpath);
|
||||
rpath = tmp;
|
||||
free(origin);
|
||||
box_free(origin);
|
||||
}
|
||||
while(strstr(rpath, "${PLATFORM}")) {
|
||||
char* platform = strdup("x86_64");
|
||||
char* platform = box_strdup("x86_64");
|
||||
char* p = strrchr(platform, '/');
|
||||
if(p) *p = '\0'; // remove file name to have only full path, without last '/'
|
||||
char* tmp = (char*)calloc(1, strlen(rpath)-strlen("${PLATFORM}")+strlen(platform)+1);
|
||||
char* tmp = (char*)box_calloc(1, strlen(rpath)-strlen("${PLATFORM}")+strlen(platform)+1);
|
||||
p = strstr(rpath, "${PLATFORM}");
|
||||
memcpy(tmp, rpath, p-rpath);
|
||||
strcat(tmp, platform);
|
||||
strcat(tmp, p+strlen("${PLATFORM}"));
|
||||
if(rpath!=rpathref)
|
||||
free(rpath);
|
||||
box_free(rpath);
|
||||
rpath = tmp;
|
||||
free(platform);
|
||||
box_free(platform);
|
||||
}
|
||||
if(strchr(rpath, '$')) {
|
||||
printf_log(LOG_INFO, "BOX64: Warning, RPATH with $ variable not supported yet (%s)\n", rpath);
|
||||
@@ -1102,25 +1122,24 @@ int LoadNeededLibs(elfheader_t* h, lib_t *maplib, needed_libs_t* neededlibs, lib
|
||||
PrependList(&box64->box64_ld_lib, rpath, 1);
|
||||
}
|
||||
if(rpath!=rpathref)
|
||||
free(rpath);
|
||||
box_free(rpath);
|
||||
}
|
||||
|
||||
if(!h->neededlibs && neededlibs)
|
||||
h->neededlibs = neededlibs;
|
||||
|
||||
DumpDynamicNeeded(h);
|
||||
int cnt = 0;
|
||||
for (int i=0; i<h->numDynamic; ++i)
|
||||
if(h->Dynamic[i].d_tag==DT_NEEDED)
|
||||
++cnt;
|
||||
const char* nlibs[cnt];
|
||||
h->needed = new_neededlib(cnt);
|
||||
if(h == my_context->elfs[0])
|
||||
my_context->neededlibs = h->needed;
|
||||
int j=0;
|
||||
for (int i=0; i<h->numDynamic; ++i)
|
||||
if(h->Dynamic[i].d_tag==DT_NEEDED)
|
||||
nlibs[j++] = h->DynStrTab+h->delta+h->Dynamic[i].d_un.d_val;
|
||||
h->needed->names[j++] = h->DynStrTab+h->delta+h->Dynamic[i].d_un.d_val;
|
||||
|
||||
// TODO: Add LD_LIBRARY_PATH and RPATH handling
|
||||
if(AddNeededLib(maplib, neededlibs, deplib, local, bindnow, nlibs, cnt, box64, emu)) {
|
||||
if(AddNeededLib(maplib, local, bindnow, h->needed, box64, emu)) {
|
||||
printf_log(LOG_INFO, "Error loading one of needed lib\n");
|
||||
if(!allow_missing_libs)
|
||||
return 1; //error...
|
||||
@@ -1145,6 +1164,56 @@ int ElfCheckIfUseTCMallocMinimal(elfheader_t* h)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RefreshElfTLS(elfheader_t* h)
|
||||
{
|
||||
if(h->tlsfilesize) {
|
||||
char* dest = (char*)(my_context->tlsdata+my_context->tlssize+h->tlsbase);
|
||||
printf_dump(LOG_DEBUG, "Refreshing main TLS block @%p from %p:0x%lx\n", dest, (void*)h->tlsaddr, h->tlsfilesize);
|
||||
memcpy(dest, (void*)(h->tlsaddr+h->delta), h->tlsfilesize);
|
||||
tlsdatasize_t* ptr;
|
||||
if ((ptr = (tlsdatasize_t*)pthread_getspecific(my_context->tlskey)) != NULL) {
|
||||
// refresh in tlsdata too
|
||||
dest = (char*)(ptr->data+h->tlsbase);
|
||||
printf_dump(LOG_DEBUG, "Refreshing active TLS block @%p from %p:0x%lx\n", dest, (void*)h->tlsaddr, h->tlssize-h->tlsfilesize);
|
||||
memcpy(dest, (void*)(h->tlsaddr+h->delta), h->tlsfilesize);
|
||||
}
|
||||
}
|
||||
}
|
||||
void MarkElfInitDone(elfheader_t* h)
|
||||
{
|
||||
if(h)
|
||||
h->init_done = 1;
|
||||
}
|
||||
void RunElfInitPltResolver(elfheader_t* h, x64emu_t *emu)
|
||||
{
|
||||
if(!h || h->init_done)
|
||||
return;
|
||||
uintptr_t p = h->initentry + h->delta;
|
||||
h->init_done = 1;
|
||||
for(int i=0; i<h->needed->size; ++i) {
|
||||
library_t *lib = h->needed->libs[i];
|
||||
elfheader_t *lib_elf = GetElf(lib);
|
||||
if(lib_elf)
|
||||
RunElfInitPltResolver(lib_elf, emu);
|
||||
}
|
||||
printf_dump(LOG_DEBUG, "Calling Init for %s @%p\n", ElfName(h), (void*)p);
|
||||
if(h->initentry)
|
||||
RunSafeFunction(my_context, p, 3, my_context->argc, my_context->argv, my_context->envv);
|
||||
printf_dump(LOG_DEBUG, "Done Init for %s\n", ElfName(h));
|
||||
// and check init array now
|
||||
Elf64_Addr *addr = (Elf64_Addr*)(h->initarray + h->delta);
|
||||
for (size_t i=0; i<h->initarray_sz; ++i) {
|
||||
if(addr[i]) {
|
||||
printf_dump(LOG_DEBUG, "Calling Init[%zu] for %s @%p\n", i, ElfName(h), (void*)addr[i]);
|
||||
RunSafeFunction(my_context, (uintptr_t)addr[i], 3, my_context->argc, my_context->argv, my_context->envv);
|
||||
}
|
||||
}
|
||||
|
||||
h->fini_done = 0; // can be fini'd now (in case it was re-inited)
|
||||
printf_dump(LOG_DEBUG, "All Init Done for %s\n", ElfName(h));
|
||||
return;
|
||||
}
|
||||
|
||||
void RunElfInit(elfheader_t* h, x64emu_t *emu)
|
||||
{
|
||||
if(!h || h->init_done)
|
||||
@@ -1153,44 +1222,39 @@ void RunElfInit(elfheader_t* h, x64emu_t *emu)
|
||||
memset(emu->segs_serial, 0, sizeof(emu->segs_serial));
|
||||
uintptr_t p = h->initentry + h->delta;
|
||||
box64context_t* context = GetEmuContext(emu);
|
||||
// Refresh no-file part of TLS in case default value changed
|
||||
RefreshElfTLS(h);
|
||||
// check if in deferedInit
|
||||
if(context->deferedInit) {
|
||||
if(context->deferedInitSz==context->deferedInitCap) {
|
||||
context->deferedInitCap += 4;
|
||||
context->deferedInitList = (elfheader_t**)realloc(context->deferedInitList, context->deferedInitCap*sizeof(elfheader_t*));
|
||||
context->deferedInitList = (elfheader_t**)box_realloc(context->deferedInitList, context->deferedInitCap*sizeof(elfheader_t*));
|
||||
}
|
||||
context->deferedInitList[context->deferedInitSz++] = h;
|
||||
return;
|
||||
}
|
||||
// Refresh no-file part of TLS in case default value changed
|
||||
if(h->tlsfilesize) {
|
||||
char* dest = (char*)(my_context->tlsdata+my_context->tlssize+h->tlsbase);
|
||||
printf_dump(LOG_DEBUG, "Refreshing main TLS block @%p from %p:0x%lx\n", dest, (void*)h->tlsaddr, h->tlsfilesize);
|
||||
memcpy(dest, (void*)(h->tlsaddr+h->delta), h->tlsfilesize);
|
||||
tlsdatasize_t* ptr;
|
||||
if ((ptr = (tlsdatasize_t*)pthread_getspecific(my_context->tlskey)) != NULL)
|
||||
if(ptr->tlssize==my_context->tlssize) {
|
||||
// refresh in tlsdata too
|
||||
dest = (char*)(ptr->tlsdata+ptr->tlssize+h->tlsbase);
|
||||
printf_dump(LOG_DEBUG, "Refreshing active TLS block @%p from %p:0x%lx\n", dest, (void*)h->tlsaddr, h->tlssize-h->tlsfilesize);
|
||||
memcpy(dest, (void*)(h->tlsaddr+h->delta), h->tlsfilesize);
|
||||
}
|
||||
h->init_done = 1;
|
||||
for(int i=0; i<h->needed->size; ++i) {
|
||||
library_t *lib = h->needed->libs[i];
|
||||
elfheader_t *lib_elf = GetElf(lib);
|
||||
if(lib_elf)
|
||||
RunElfInit(lib_elf, emu);
|
||||
}
|
||||
printf_log(LOG_DEBUG, "Calling Init for %s @%p\n", ElfName(h), (void*)p);
|
||||
printf_dump(LOG_DEBUG, "Calling Init for %s @%p\n", ElfName(h), (void*)p);
|
||||
if(h->initentry)
|
||||
RunFunctionWithEmu(emu, 0, p, 3, context->argc, context->argv, context->envv);
|
||||
printf_log(LOG_DEBUG, "Done Init for %s\n", ElfName(h));
|
||||
printf_dump(LOG_DEBUG, "Done Init for %s\n", ElfName(h));
|
||||
// and check init array now
|
||||
Elf64_Addr *addr = (Elf64_Addr*)(h->initarray + h->delta);
|
||||
for (size_t i=0; i<h->initarray_sz; ++i) {
|
||||
if(addr[i]) {
|
||||
printf_log(LOG_DEBUG, "Calling Init[%zu] for %s @%p\n", i, ElfName(h), (void*)addr[i]);
|
||||
printf_dump(LOG_DEBUG, "Calling Init[%zu] for %s @%p\n", i, ElfName(h), (void*)addr[i]);
|
||||
RunFunctionWithEmu(emu, 0, (uintptr_t)addr[i], 3, context->argc, context->argv, context->envv);
|
||||
}
|
||||
}
|
||||
|
||||
h->init_done = 1;
|
||||
h->fini_done = 0; // can be fini'd now (in case it was re-inited)
|
||||
printf_log(LOG_DEBUG, "All Init Done for %s\n", ElfName(h));
|
||||
printf_dump(LOG_DEBUG, "All Init Done for %s\n", ElfName(h));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1209,7 +1273,7 @@ void RunDeferedElfInit(x64emu_t *emu)
|
||||
context->deferedInitCap = context->deferedInitSz = 0;
|
||||
for (int i=0; i<Sz; ++i)
|
||||
RunElfInit(List[i], emu);
|
||||
free(List);
|
||||
box_free(List);
|
||||
}
|
||||
|
||||
void RunElfFini(elfheader_t* h, x64emu_t *emu)
|
||||
@@ -1220,16 +1284,18 @@ void RunElfFini(elfheader_t* h, x64emu_t *emu)
|
||||
// first check fini array
|
||||
Elf64_Addr *addr = (Elf64_Addr*)(h->finiarray + h->delta);
|
||||
for (int i=h->finiarray_sz-1; i>=0; --i) {
|
||||
printf_log(LOG_DEBUG, "Calling Fini[%d] for %s @%p\n", i, ElfName(h), (void*)addr[i]);
|
||||
printf_dump(LOG_DEBUG, "Calling Fini[%d] for %s @%p\n", i, ElfName(h), (void*)addr[i]);
|
||||
RunFunctionWithEmu(emu, 0, (uintptr_t)addr[i], 0);
|
||||
}
|
||||
// then the "old-style" fini
|
||||
if(h->finientry) {
|
||||
uintptr_t p = h->finientry + h->delta;
|
||||
printf_log(LOG_DEBUG, "Calling Fini for %s @%p\n", ElfName(h), (void*)p);
|
||||
printf_dump(LOG_DEBUG, "Calling Fini for %s @%p\n", ElfName(h), (void*)p);
|
||||
RunFunctionWithEmu(emu, 0, p, 0);
|
||||
}
|
||||
h->init_done = 0; // can be re-inited again...
|
||||
for(int i=0; i<h->needed->size; ++i)
|
||||
FiniLibrary(h->needed->libs[i], emu);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1257,7 +1323,7 @@ uint32_t GetBaseSize(elfheader_t* h)
|
||||
return h->memsz;
|
||||
}
|
||||
|
||||
int IsAddressInElfSpace(elfheader_t* h, uintptr_t addr)
|
||||
int IsAddressInElfSpace(const elfheader_t* h, uintptr_t addr)
|
||||
{
|
||||
if(!h)
|
||||
return 0;
|
||||
@@ -1287,6 +1353,22 @@ const char* FindNearestSymbolName(elfheader_t* h, void* p, uintptr_t* start, uin
|
||||
const char* ret = NULL;
|
||||
uintptr_t s = 0;
|
||||
uint64_t size = 0;
|
||||
#ifdef HAVE_TRACE
|
||||
if(!h) {
|
||||
if(getProtection((uintptr_t)p)&(PROT_READ)) {
|
||||
if(*(uint8_t*)(p)==0xCC && *(uint8_t*)(p+1)=='S' && *(uint8_t*)(p+2)=='C') {
|
||||
ret = getBridgeName(*(void**)(p+3+8));
|
||||
if(ret) {
|
||||
if(start)
|
||||
*start = (uintptr_t)p;
|
||||
if(sz)
|
||||
*sz = 32;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
if(!h || h->fini_done)
|
||||
return ret;
|
||||
|
||||
@@ -1387,7 +1469,7 @@ void* GetTLSPointer(box64context_t* context, elfheader_t* h)
|
||||
}
|
||||
if(ptr->tlssize != context->tlssize)
|
||||
ptr = (tlsdatasize_t*)resizeTLSData(context, ptr);
|
||||
return ptr->tlsdata+(ptr->tlssize+h->tlsbase);
|
||||
return ptr->data+h->tlsbase;
|
||||
}
|
||||
|
||||
void* GetDynamicSection(elfheader_t* h)
|
||||
@@ -1398,7 +1480,7 @@ void* GetDynamicSection(elfheader_t* h)
|
||||
}
|
||||
|
||||
#ifdef DYNAREC
|
||||
dynablocklist_t* GetDynablocksFromAddress(box64context_t *context, uintptr_t addr)
|
||||
dynablock_t* GetDynablocksFromAddress(box64context_t *context, uintptr_t addr)
|
||||
{
|
||||
(void)context;
|
||||
// if we are here, the there is not block in standard "space"
|
||||
@@ -1408,7 +1490,7 @@ dynablocklist_t* GetDynablocksFromAddress(box64context_t *context, uintptr_t add
|
||||
}*/
|
||||
if(box64_dynarec_forced) {
|
||||
addDBFromAddressRange(addr, 1);
|
||||
return getDB(addr>>DYNAMAP_SHIFT);
|
||||
return getDB(addr);
|
||||
}
|
||||
//check if address is in an elf... if yes, grant a block (should I warn)
|
||||
Dl_info info;
|
||||
@@ -1443,14 +1525,14 @@ GO(4)
|
||||
|
||||
// dl_iterate_phdr ...
|
||||
#define GO(A) \
|
||||
static uintptr_t my_dl_iterate_phdr_fct_##A = 0; \
|
||||
static int my_dl_iterate_phdr_##A(struct dl_phdr_info* a, size_t b, void* c)\
|
||||
{ \
|
||||
if(!a->dlpi_name) \
|
||||
return 0; \
|
||||
if(!a->dlpi_name[0]) /*don't send informations about box64 itself*/ \
|
||||
return 0; \
|
||||
return RunFunction(my_context, my_dl_iterate_phdr_fct_##A, 3, a, b, c); \
|
||||
static uintptr_t my_dl_iterate_phdr_fct_##A = 0; \
|
||||
static int my_dl_iterate_phdr_##A(struct dl_phdr_info* a, size_t b, void* c) \
|
||||
{ \
|
||||
if(!a->dlpi_name) \
|
||||
return 0; \
|
||||
if(!a->dlpi_name[0]) /*don't send informations about box64 itself*/ \
|
||||
return 0; \
|
||||
return (int)RunFunction(my_context, my_dl_iterate_phdr_fct_##A, 3, a, b, c); \
|
||||
}
|
||||
SUPER()
|
||||
#undef GO
|
||||
@@ -1533,39 +1615,44 @@ void ResetSpecialCaseMainElf(elfheader_t* h)
|
||||
|
||||
void CreateMemorymapFile(box64context_t* context, int fd)
|
||||
{
|
||||
// this will tranform current memory map
|
||||
// by anotating anonymous entry that belong to emulated elf
|
||||
// also anonymising current stack
|
||||
// and setting emulated stack as the current one
|
||||
|
||||
char* line = NULL;
|
||||
size_t len = 0;
|
||||
char buff[1024];
|
||||
struct stat st;
|
||||
int dummy;
|
||||
FILE* f = fopen("/proc/self/maps", "r");
|
||||
if(!f)
|
||||
return;
|
||||
while(getline(&line, &len, f)>0) {
|
||||
// line is like
|
||||
// aaaadd750000-aaaadd759000 r-xp 00000000 103:02 13386730 /usr/bin/cat
|
||||
uintptr_t start, end;
|
||||
if (sscanf(line, "%zx-%zx", &start, &end)==2) {
|
||||
elfheader_t* h = FindElfAddress(my_context, start);
|
||||
int l = strlen(line);
|
||||
if(h && l<73) {
|
||||
sprintf(buff, "%s%*s\n", line, 74-l, h->name);
|
||||
dummy = write(fd, buff, strlen(buff));
|
||||
} else if(start==(uintptr_t)my_context->stack) {
|
||||
sprintf(buff, "%s%*s\n", line, 74-l, "[stack]");
|
||||
dummy = write(fd, buff, strlen(buff));
|
||||
} else if (strstr(line, "[stack]")) {
|
||||
char* p = strstr(line, "[stack]")-1;
|
||||
while (*p==' ' || *p=='\t') --p;
|
||||
p[1]='\0';
|
||||
strcat(line, "\n");
|
||||
dummy = write(fd, line, strlen(line));
|
||||
} else {
|
||||
dummy = write(fd, line, strlen(line));
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
(void)dummy;
|
||||
|
||||
elfheader_t *h = context->elfs[0];
|
||||
|
||||
if (stat(h->path, &st)) {
|
||||
printf_log(LOG_INFO, "Failed to stat file %s (creating memory maps \"file\")!", h->path);
|
||||
// Some constants, to have "valid" values
|
||||
st.st_dev = makedev(0x03, 0x00);
|
||||
st.st_ino = 0;
|
||||
}
|
||||
|
||||
// TODO: create heap entry?
|
||||
|
||||
for (size_t i=0; i<h->numPHEntries; ++i) {
|
||||
if (h->PHEntries[i].p_memsz == 0) continue;
|
||||
|
||||
sprintf(buff, "%016lx-%016lx %c%c%c%c %016lx %02x:%02x %ld %s\n", (uintptr_t)h->PHEntries[i].p_vaddr + h->delta,
|
||||
(uintptr_t)h->PHEntries[i].p_vaddr + h->PHEntries[i].p_memsz + h->delta,
|
||||
(h->PHEntries[i].p_type & (PF_R|PF_X) ? 'r':'-'), (h->PHEntries[i].p_type & PF_W ? 'w':'-'),
|
||||
(h->PHEntries[i].p_type & PF_X ? 'x':'-'), 'p', // p for private or s for shared
|
||||
(uintptr_t)h->PHEntries[i].p_offset,
|
||||
major(st.st_dev), minor(st.st_dev), st.st_ino, h->path);
|
||||
|
||||
dummy = write(fd, buff, strlen(buff));
|
||||
}
|
||||
// create stack entry
|
||||
sprintf(buff, "%16lx-%16lx %c%c%c%c %16lx %02x:%02x %ld %s\n",
|
||||
(uintptr_t)context->stack, (uintptr_t)context->stack+context->stacksz,
|
||||
'r','w','-','p', 0L, 0, 0, 0L, "[stack]");
|
||||
dummy = write(fd, buff, strlen(buff));
|
||||
}
|
||||
|
||||
void ElfAttachLib(elfheader_t* head, library_t* lib)
|
||||
@@ -1575,6 +1662,25 @@ void ElfAttachLib(elfheader_t* head, library_t* lib)
|
||||
head->lib = lib;
|
||||
}
|
||||
|
||||
kh_mapsymbols_t* GetMapSymbols(elfheader_t* h)
|
||||
{
|
||||
if(!h)
|
||||
return NULL;
|
||||
return h->mapsymbols;
|
||||
}
|
||||
kh_mapsymbols_t* GetWeakSymbols(elfheader_t* h)
|
||||
{
|
||||
if(!h)
|
||||
return NULL;
|
||||
return h->weaksymbols;
|
||||
}
|
||||
kh_mapsymbols_t* GetLocalSymbols(elfheader_t* h)
|
||||
{
|
||||
if(!h)
|
||||
return NULL;
|
||||
return h->localsymbols;
|
||||
}
|
||||
|
||||
typedef struct search_symbol_s{
|
||||
const char* name;
|
||||
void* addr;
|
||||
@@ -1680,8 +1786,14 @@ EXPORT void PltResolver(x64emu_t* emu)
|
||||
emu->quit = 1;
|
||||
return;
|
||||
} else {
|
||||
elfheader_t* sym_elf = FindElfAddress(my_context, offs);
|
||||
if(sym_elf && sym_elf!=my_context->elfs[0] && !sym_elf->init_done) {
|
||||
printf_dump(LOG_DEBUG, "symbol %s from %s but elf not initialized yet, run Init now (from %s)\n", symname, ElfName(sym_elf), ElfName(h));
|
||||
RunElfInitPltResolver(sym_elf, emu);
|
||||
}
|
||||
|
||||
if(p) {
|
||||
printf_dump(LOG_DEBUG, " Apply %s R_X86_64_JUMP_SLOT %p with sym=%s(ver %d: %s%s%s) (%p -> %p / %s)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, version, symname, vername?"@":"", vername?vername:"",*(void**)p, (void*)offs, ElfName(FindElfAddress(my_context, offs)));
|
||||
printf_dump(LOG_DEBUG, " Apply %s R_X86_64_JUMP_SLOT %p with sym=%s(ver %d: %s%s%s) (%p -> %p / %s)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, version, symname, vername?"@":"", vername?vername:"",*(void**)p, (void*)offs, ElfName(sym_elf));
|
||||
*p = offs;
|
||||
} else {
|
||||
printf_log(LOG_NONE, "PltResolver: Warning, Symbol %s(ver %d: %s%s%s) found, but Jump Slot Offset is NULL \n", symname, version, symname, vername?"@":"", vername?vername:"");
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
#ifndef __ELFLOADER_PRIVATE_H_
|
||||
#define __ELFLOADER_PRIVATE_H_
|
||||
|
||||
#ifdef DYNAREC
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
#endif
|
||||
|
||||
typedef struct library_s library_t;
|
||||
typedef struct needed_libs_s needed_libs_t;
|
||||
typedef struct kh_mapsymbols_s kh_mapsymbols_t;
|
||||
|
||||
#include <elf.h>
|
||||
#include "elfloader.h"
|
||||
@@ -86,15 +83,20 @@ struct elfheader_s {
|
||||
|
||||
int init_done;
|
||||
int fini_done;
|
||||
int refcnt; // ref count for the elf
|
||||
|
||||
char* memory; // char* and not void* to allow math on memory pointer
|
||||
char* memory; // char* and not void* to allow math on memory pointer
|
||||
void** multiblock;
|
||||
uintptr_t* multiblock_offs;
|
||||
uint64_t* multiblock_size;
|
||||
int multiblock_n;
|
||||
|
||||
library_t *lib;
|
||||
needed_libs_t *neededlibs;
|
||||
library_t *lib; // attached lib (exept on main elf)
|
||||
needed_libs_t* needed;
|
||||
|
||||
kh_mapsymbols_t *mapsymbols;
|
||||
kh_mapsymbols_t *weaksymbols;
|
||||
kh_mapsymbols_t *localsymbols;
|
||||
};
|
||||
|
||||
#define R_X86_64_NONE 0 /* No reloc */
|
||||
|
||||
+73
-43
@@ -23,7 +23,7 @@ int LoadSH(FILE *f, Elf64_Shdr *s, void** SH, const char* name, uint32_t type)
|
||||
if (type==SHT_SYMTAB && s->sh_size%sizeof(Elf64_Sym)) {
|
||||
printf_log(LOG_INFO, "Section Header \"%s\" (off=%ld, size=%ld) has size (not multiple of %ld)\n", name, s->sh_offset, s->sh_size, sizeof(Elf64_Sym));
|
||||
}
|
||||
*SH = calloc(1, s->sh_size);
|
||||
*SH = box_calloc(1, s->sh_size);
|
||||
fseeko64(f, s->sh_offset ,SEEK_SET);
|
||||
if(fread(*SH, s->sh_size, 1, f)!=1) {
|
||||
printf_log(LOG_INFO, "Cannot read Section Header \"%s\" (off=%ld, size=%ld)\n", name, s->sh_offset, s->sh_size);
|
||||
@@ -46,7 +46,7 @@ int FindSection(Elf64_Shdr *s, int n, char* SHStrTab, const char* name)
|
||||
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);
|
||||
printf_dump(LOG_DEBUG, "Loading %s (idx = %d)\n", clearname, n);
|
||||
if(n)
|
||||
LoadSH(f, s+n, what, name, type);
|
||||
if(type==SHT_SYMTAB || type==SHT_DYNSYM) {
|
||||
@@ -73,7 +73,7 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
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]);
|
||||
printf_dump(LOG_DEBUG, "Not a 64bits ELF (%d)\n", header.e_ident[EI_CLASS]);
|
||||
return NULL;
|
||||
}
|
||||
if(header.e_ident[EI_CLASS]==ELFCLASS32) {
|
||||
@@ -119,8 +119,8 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
elfheader_t *h = calloc(1, sizeof(elfheader_t));
|
||||
h->name = strdup(name);
|
||||
elfheader_t *h = box_calloc(1, sizeof(elfheader_t));
|
||||
h->name = box_strdup(name);
|
||||
h->entrypoint = header.e_entry;
|
||||
h->numPHEntries = header.e_phnum;
|
||||
h->numSHEntries = header.e_shnum;
|
||||
@@ -129,20 +129,20 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
if(header.e_shentsize && header.e_shnum) {
|
||||
// special cases for nums
|
||||
if(h->numSHEntries == 0) {
|
||||
printf_log(LOG_DEBUG, "Read number of Sections in 1st Section\n");
|
||||
printf_dump(LOG_DEBUG, "Read number of Sections in 1st Section\n");
|
||||
// read 1st section header and grab actual number from here
|
||||
fseeko64(f, header.e_shoff, SEEK_SET);
|
||||
Elf64_Shdr section;
|
||||
if(fread(§ion, sizeof(Elf64_Shdr), 1, f)!=1) {
|
||||
free(h);
|
||||
box_free(h);
|
||||
printf_log(LOG_INFO, "Cannot read Initial Section Header\n");
|
||||
return NULL;
|
||||
}
|
||||
h->numSHEntries = section.sh_size;
|
||||
}
|
||||
// now read all section headers
|
||||
printf_log(LOG_DEBUG, "Read %zu Section header\n", h->numSHEntries);
|
||||
h->SHEntries = (Elf64_Shdr*)calloc(h->numSHEntries, sizeof(Elf64_Shdr));
|
||||
printf_dump(LOG_DEBUG, "Read %zu Section header\n", h->numSHEntries);
|
||||
h->SHEntries = (Elf64_Shdr*)box_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) {
|
||||
FreeElfHeader(&h);
|
||||
@@ -151,14 +151,14 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
}
|
||||
|
||||
if(h->numPHEntries == PN_XNUM) {
|
||||
printf_log(LOG_DEBUG, "Read number of Program Header in 1st Section\n");
|
||||
printf_dump(LOG_DEBUG, "Read number of Program Header in 1st Section\n");
|
||||
// read 1st section header and grab actual number from here
|
||||
h->numPHEntries = h->SHEntries[0].sh_info;
|
||||
}
|
||||
}
|
||||
|
||||
printf_log(LOG_DEBUG, "Read %zu Program header\n", h->numPHEntries);
|
||||
h->PHEntries = (Elf64_Phdr*)calloc(h->numPHEntries, sizeof(Elf64_Phdr));
|
||||
printf_dump(LOG_DEBUG, "Read %zu Program header\n", h->numPHEntries);
|
||||
h->PHEntries = (Elf64_Phdr*)box_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) {
|
||||
FreeElfHeader(&h);
|
||||
@@ -168,7 +168,7 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
|
||||
if(header.e_shentsize && header.e_shnum) {
|
||||
if(h->SHIdx == SHN_XINDEX) {
|
||||
printf_log(LOG_DEBUG, "Read number of String Table in 1st Section\n");
|
||||
printf_dump(LOG_DEBUG, "Read number of String Table in 1st Section\n");
|
||||
h->SHIdx = h->SHEntries[0].sh_link;
|
||||
}
|
||||
if(h->SHIdx > h->numSHEntries) {
|
||||
@@ -177,7 +177,7 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
return NULL;
|
||||
}
|
||||
// load Section table
|
||||
printf_log(LOG_DEBUG, "Loading Sections Table String (idx = %zu)\n", h->SHIdx);
|
||||
printf_dump(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;
|
||||
@@ -236,15 +236,15 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
break;
|
||||
case DT_INIT: // Entry point
|
||||
h->initentry = ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_INIT is at address %p\n", (void*)h->initentry);
|
||||
printf_dump(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);
|
||||
printf_dump(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);
|
||||
printf_dump(LOG_DEBUG, "The DT_INIT_ARRAYSZ is %zu\n", h->initarray_sz);
|
||||
break;
|
||||
case DT_PREINIT_ARRAYSZ:
|
||||
if(val)
|
||||
@@ -252,31 +252,31 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
break;
|
||||
case DT_FINI: // Exit hook
|
||||
h->finientry = ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_FINI is at address %p\n", (void*)h->finientry);
|
||||
printf_dump(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);
|
||||
printf_dump(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);
|
||||
printf_dump(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);
|
||||
printf_dump(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);
|
||||
printf_dump(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);
|
||||
printf_dump(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);
|
||||
printf_dump(LOG_DEBUG, "The DT_VERDEF is at address %p\n", h->VerDef);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -286,7 +286,7 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
}
|
||||
printf_log(LOG_DEBUG, "Rel Table @%p (0x%zx/0x%x)\n", (void*)h->rel, h->relsz, h->relent);
|
||||
printf_dump(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)) {
|
||||
@@ -294,7 +294,7 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
}
|
||||
printf_log(LOG_DEBUG, "RelA Table @%p (0x%zx/0x%x)\n", (void*)h->rela, h->relasz, h->relaent);
|
||||
printf_dump(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) {
|
||||
@@ -311,7 +311,7 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
}
|
||||
printf_log(LOG_DEBUG, "PLT Table @%p (type=%ld 0x%zx/0x%0x)\n", (void*)h->jmprel, h->pltrel, h->pltsz, h->pltent);
|
||||
printf_dump(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
|
||||
@@ -322,43 +322,43 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
if(ii) {
|
||||
h->gotplt = h->SHEntries[ii].sh_addr;
|
||||
h->gotplt_end = h->gotplt + h->SHEntries[ii].sh_size;
|
||||
printf_log(LOG_DEBUG, "The GOT.PLT Table is at address %p\n", (void*)h->gotplt);
|
||||
printf_dump(LOG_DEBUG, "The GOT.PLT Table is at address %p\n", (void*)h->gotplt);
|
||||
}
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".got");
|
||||
if(ii) {
|
||||
h->got = h->SHEntries[ii].sh_addr;
|
||||
h->got_end = h->got + h->SHEntries[ii].sh_size;
|
||||
printf_log(LOG_DEBUG, "The GOT Table is at address %p..%p\n", (void*)h->got, (void*)h->got_end);
|
||||
printf_dump(LOG_DEBUG, "The GOT Table is at address %p..%p\n", (void*)h->got, (void*)h->got_end);
|
||||
}
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".plt");
|
||||
if(ii) {
|
||||
h->plt = h->SHEntries[ii].sh_addr;
|
||||
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);
|
||||
printf_dump(LOG_DEBUG, "The PLT Table is at address %p..%p\n", (void*)h->plt, (void*)h->plt_end);
|
||||
}
|
||||
// grab version of symbols
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".gnu.version");
|
||||
if(ii) {
|
||||
h->VerSym = (Elf64_Half*)(h->SHEntries[ii].sh_addr);
|
||||
printf_log(LOG_DEBUG, "The .gnu.version is at address %p\n", h->VerSym);
|
||||
printf_dump(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 %zu big\n", (void*)h->text, h->textsz);
|
||||
printf_dump(LOG_DEBUG, "The .text is at address %p, and is %zu big\n", (void*)h->text, h->textsz);
|
||||
}
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".eh_frame");
|
||||
if(ii) {
|
||||
h->ehframe = (uintptr_t)(h->SHEntries[ii].sh_addr);
|
||||
h->ehframe_end = h->ehframe + h->SHEntries[ii].sh_size;
|
||||
printf_log(LOG_DEBUG, "The .eh_frame section is at address %p..%p\n", (void*)h->ehframe, (void*)h->ehframe_end);
|
||||
printf_dump(LOG_DEBUG, "The .eh_frame section is at address %p..%p\n", (void*)h->ehframe, (void*)h->ehframe_end);
|
||||
}
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".eh_frame_hdr");
|
||||
if(ii) {
|
||||
h->ehframehdr = (uintptr_t)(h->SHEntries[ii].sh_addr);
|
||||
printf_log(LOG_DEBUG, "The .eh_frame_hdr section is at address %p\n", (void*)h->ehframehdr);
|
||||
printf_dump(LOG_DEBUG, "The .eh_frame_hdr section is at address %p\n", (void*)h->ehframehdr);
|
||||
}
|
||||
|
||||
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynstr", "DynSym Strings", SHT_STRTAB, (void**)&h->DynStr, NULL);
|
||||
@@ -370,19 +370,21 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
|
||||
const char* GetSymbolVersion(elfheader_t* h, int version)
|
||||
{
|
||||
if(!h->VerNeed || (version<2))
|
||||
if(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);
|
||||
if(h->VerNeed) {
|
||||
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;
|
||||
}
|
||||
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
|
||||
}
|
||||
@@ -405,3 +407,31 @@ const char* GetParentSymbolVersion(elfheader_t* h, int index)
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int GetVersionIndice(elfheader_t* h, const char* vername)
|
||||
{
|
||||
if(!vername)
|
||||
return 0;
|
||||
if(h->VerNeed) {
|
||||
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(!strcmp(h->DynStr+aux->vna_name, vername))
|
||||
return aux->vna_other;
|
||||
aux = (Elf64_Vernaux*)((uintptr_t)aux + aux->vna_next);
|
||||
}
|
||||
ver = ver->vn_next?((Elf64_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL;
|
||||
}
|
||||
}
|
||||
if(h->VerDef) {
|
||||
Elf64_Verdef *def = (Elf64_Verdef*)((uintptr_t)h->VerDef + h->delta);
|
||||
while(def) {
|
||||
Elf64_Verdaux *aux = (Elf64_Verdaux*)((uintptr_t)def + def->vd_aux);
|
||||
if(!strcmp(h->DynStr+aux->vda_name, vername))
|
||||
return def->vd_ndx;
|
||||
def = def->vd_next?((Elf64_Verdef*)((uintptr_t)def + def->vd_next)):NULL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
+49
-29
@@ -1,38 +1,42 @@
|
||||
#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 F8 *(uint8_t*)(addr++)
|
||||
#define F8S *(int8_t*)(addr++)
|
||||
#define F16 *(uint16_t*)(addr+=2, addr-2)
|
||||
#define F16S *(int16_t*)(addr+=2, addr-2)
|
||||
#define F32 *(uint32_t*)(addr+=4, addr-4)
|
||||
#define F32S *(int32_t*)(addr+=4, addr-4)
|
||||
#define F32S64 (uint64_t)(int64_t)F32S
|
||||
#define F64 *(uint64_t*)(R_RIP+=8, R_RIP-8)
|
||||
#define F64S *(int64_t*)(R_RIP+=8, R_RIP-8)
|
||||
#define PK(a) *(uint8_t*)(R_RIP+a)
|
||||
#define F64 *(uint64_t*)(addr+=8, addr-8)
|
||||
#define F64S *(int64_t*)(addr+=8, addr-8)
|
||||
#define PK(a) *(uint8_t*)(addr+a)
|
||||
#ifdef DYNAREC
|
||||
#define STEP if(step) return 0;
|
||||
#define STEP2 if(step) {R_RIP = addr; return 0;}
|
||||
#define STEP3 if(*step) (*step)++;
|
||||
#else
|
||||
#define STEP
|
||||
#define STEP2
|
||||
#define STEP3
|
||||
#endif
|
||||
|
||||
#define GETED(D) oped=GetEd(emu, rex, nextop, D)
|
||||
#define GETED32(D) oped=GetEd32O(emu, rex, nextop, D, 0)
|
||||
#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 GETEM32(D) opem=GetEm32O(emu, rex, nextop, D, 0)
|
||||
#define GETGM opgm=GetGm(emu, rex, nextop)
|
||||
#define GETED(D) oped=GetEd(emu, &addr, rex, nextop, D)
|
||||
#define GETED32(D) oped=GetEd32O(emu, &addr, rex, nextop, D, 0)
|
||||
#define GETED_OFFS(D, O) oped=GetEdO(emu, &addr, rex, nextop, D, O)
|
||||
#define GETGD opgd=GetGd(emu, &addr, rex, nextop)
|
||||
#define GETEB(D) oped=GetEb(emu, &addr, rex, nextop, D)
|
||||
#define GETEB32(D) oped=GetEb32O(emu, &addr, rex, nextop, D, 0)
|
||||
#define GETEB_OFFS(D, O) oped=GetEbO(emu, &addr, rex, nextop, D, O)
|
||||
#define GETGB opgd=GetGb(emu, &addr, rex, nextop)
|
||||
#define GETEW(D) oped=GetEw(emu, &addr, rex, nextop, D)
|
||||
#define GETEW32(D) oped=GetEw32O(emu, &addr, rex, nextop, D, 0)
|
||||
#define GETEW_OFFS(D, O) oped=GetEdO(emu, &addr, rex, nextop, D, O)
|
||||
#define GETGW opgd=GetGw(emu, &addr, rex, nextop)
|
||||
#define GETEX(D) opex=GetEx(emu, &addr, rex, nextop, D)
|
||||
#define GETEX32(D) opex=GetEx32O(emu, &addr, rex, nextop, D, 0)
|
||||
#define GETEX_OFFS(D, O) opex=GetExO(emu, &addr, rex, nextop, D, O)
|
||||
#define GETGX opgx=GetGx(emu, &addr, rex, nextop)
|
||||
#define GETEM(D) opem=GetEm(emu, &addr, rex, nextop, D)
|
||||
#define GETEM32(D) opem=GetEm32O(emu, &addr, rex, nextop, D, 0)
|
||||
#define GETGM opgm=GetGm(emu, &addr, rex, nextop)
|
||||
#define ED oped
|
||||
#define GD opgd
|
||||
#define EB oped
|
||||
@@ -46,7 +50,7 @@
|
||||
|
||||
#define MODREG ((nextop&0xC0)==0xC0)
|
||||
|
||||
#define GOCOND(BASE, PREFIX, COND, NOTCOND) \
|
||||
#define GOCOND(BASE, PREFIX, COND, NOTCOND, POST)\
|
||||
case BASE+0x0: \
|
||||
PREFIX \
|
||||
if(ACCESS_FLAG(F_OF)) { \
|
||||
@@ -54,6 +58,7 @@
|
||||
} else { \
|
||||
NOTCOND \
|
||||
} \
|
||||
POST \
|
||||
break; \
|
||||
case BASE+0x1: \
|
||||
PREFIX \
|
||||
@@ -62,6 +67,7 @@
|
||||
} else { \
|
||||
NOTCOND \
|
||||
} \
|
||||
POST \
|
||||
break; \
|
||||
case BASE+0x2: \
|
||||
PREFIX \
|
||||
@@ -70,6 +76,7 @@
|
||||
} else { \
|
||||
NOTCOND \
|
||||
} \
|
||||
POST \
|
||||
break; \
|
||||
case BASE+0x3: \
|
||||
PREFIX \
|
||||
@@ -78,6 +85,7 @@
|
||||
} else { \
|
||||
NOTCOND \
|
||||
} \
|
||||
POST \
|
||||
break; \
|
||||
case BASE+0x4: \
|
||||
PREFIX \
|
||||
@@ -86,6 +94,7 @@
|
||||
} else { \
|
||||
NOTCOND \
|
||||
} \
|
||||
POST \
|
||||
break; \
|
||||
case BASE+0x5: \
|
||||
PREFIX \
|
||||
@@ -94,6 +103,7 @@
|
||||
} else { \
|
||||
NOTCOND \
|
||||
} \
|
||||
POST \
|
||||
break; \
|
||||
case BASE+0x6: \
|
||||
PREFIX \
|
||||
@@ -102,6 +112,7 @@
|
||||
} else { \
|
||||
NOTCOND \
|
||||
} \
|
||||
POST \
|
||||
break; \
|
||||
case BASE+0x7: \
|
||||
PREFIX \
|
||||
@@ -110,6 +121,7 @@
|
||||
} else { \
|
||||
NOTCOND \
|
||||
} \
|
||||
POST \
|
||||
break; \
|
||||
case BASE+0x8: \
|
||||
PREFIX \
|
||||
@@ -118,6 +130,7 @@
|
||||
} else { \
|
||||
NOTCOND \
|
||||
} \
|
||||
POST \
|
||||
break; \
|
||||
case BASE+0x9: \
|
||||
PREFIX \
|
||||
@@ -126,6 +139,7 @@
|
||||
} else { \
|
||||
NOTCOND \
|
||||
} \
|
||||
POST \
|
||||
break; \
|
||||
case BASE+0xA: \
|
||||
PREFIX \
|
||||
@@ -134,6 +148,7 @@
|
||||
} else { \
|
||||
NOTCOND \
|
||||
} \
|
||||
POST \
|
||||
break; \
|
||||
case BASE+0xB: \
|
||||
PREFIX \
|
||||
@@ -142,6 +157,7 @@
|
||||
} else { \
|
||||
NOTCOND \
|
||||
} \
|
||||
POST \
|
||||
break; \
|
||||
case BASE+0xC: \
|
||||
PREFIX \
|
||||
@@ -150,6 +166,7 @@
|
||||
} else { \
|
||||
NOTCOND \
|
||||
} \
|
||||
POST \
|
||||
break; \
|
||||
case BASE+0xD: \
|
||||
PREFIX \
|
||||
@@ -158,6 +175,7 @@
|
||||
} else { \
|
||||
NOTCOND \
|
||||
} \
|
||||
POST \
|
||||
break; \
|
||||
case BASE+0xE: \
|
||||
PREFIX \
|
||||
@@ -166,6 +184,7 @@
|
||||
} else { \
|
||||
NOTCOND \
|
||||
} \
|
||||
POST \
|
||||
break; \
|
||||
case BASE+0xF: \
|
||||
PREFIX \
|
||||
@@ -174,4 +193,5 @@
|
||||
} else { \
|
||||
NOTCOND \
|
||||
} \
|
||||
POST \
|
||||
break;
|
||||
+44
-12
@@ -23,6 +23,16 @@
|
||||
#ifdef DYNAREC
|
||||
#include "custommem.h"
|
||||
#endif
|
||||
// for the applyFlushTo0
|
||||
#ifdef __x86_64__
|
||||
#include <immintrin.h>
|
||||
#elif defined(__aarch64__)
|
||||
#else
|
||||
#warning Architecture cannot follow SSE Flush to 0 flag
|
||||
#endif
|
||||
|
||||
// from src/wrapped/wrappedlibc.c
|
||||
int my_munmap(x64emu_t* emu, void* addr, unsigned long length);
|
||||
|
||||
typedef struct cleanup_s {
|
||||
void* f;
|
||||
@@ -81,7 +91,7 @@ static void internalX64Setup(x64emu_t* emu, box64context_t *context, uintptr_t s
|
||||
emu->segs[_GS] = default_gs;
|
||||
// setup fpu regs
|
||||
reset_fpu(emu);
|
||||
emu->mxcsr = 0x1f80;
|
||||
emu->mxcsr.x32 = 0x1f80;
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
@@ -89,7 +99,7 @@ x64emu_t *NewX64Emu(box64context_t *context, uintptr_t start, uintptr_t stack, i
|
||||
{
|
||||
printf_log(LOG_DEBUG, "Allocate a new X86_64 Emu, with EIP=%p and Stack=%p/0x%X\n", (void*)start, (void*)stack, stacksize);
|
||||
|
||||
x64emu_t *emu = (x64emu_t*)calloc(1, sizeof(x64emu_t));
|
||||
x64emu_t *emu = (x64emu_t*)box_calloc(1, sizeof(x64emu_t));
|
||||
|
||||
internalX64Setup(emu, context, start, stack, stacksize, ownstack);
|
||||
|
||||
@@ -135,7 +145,7 @@ void AddCleanup(x64emu_t *emu, void *p)
|
||||
|
||||
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);
|
||||
my_context->cleanups = (cleanup_t*)box_realloc(my_context->cleanups, sizeof(cleanup_t)*my_context->clean_cap);
|
||||
}
|
||||
my_context->cleanups[my_context->clean_sz].arg = 0;
|
||||
my_context->cleanups[my_context->clean_sz].a = NULL;
|
||||
@@ -148,7 +158,7 @@ void AddCleanup1Arg(x64emu_t *emu, void *p, void* a)
|
||||
|
||||
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);
|
||||
my_context->cleanups = (cleanup_t*)box_realloc(my_context->cleanups, sizeof(cleanup_t)*my_context->clean_cap);
|
||||
}
|
||||
my_context->cleanups[my_context->clean_sz].arg = 1;
|
||||
my_context->cleanups[my_context->clean_sz].a = a;
|
||||
@@ -175,17 +185,17 @@ void CallAllCleanup(x64emu_t *emu)
|
||||
printf_log(LOG_DEBUG, "Calling atexit registered functions\n");
|
||||
for(int i=my_context->clean_sz-1; i>=0; --i) {
|
||||
printf_log(LOG_DEBUG, "Call cleanup #%d\n", i);
|
||||
--my_context->clean_sz;
|
||||
RunFunctionWithEmu(emu, 0, (uintptr_t)(my_context->cleanups[i].f), my_context->cleanups[i].arg, my_context->cleanups[i].a );
|
||||
}
|
||||
my_context->clean_sz = 0;
|
||||
free(my_context->cleanups);
|
||||
box_free(my_context->cleanups);
|
||||
my_context->cleanups = NULL;
|
||||
}
|
||||
|
||||
static void internalFreeX64(x64emu_t* emu)
|
||||
{
|
||||
if(emu && emu->stack2free)
|
||||
munmap(emu->stack2free, emu->size_stack);
|
||||
my_munmap(NULL, emu->stack2free, emu->size_stack);
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
@@ -197,7 +207,7 @@ void FreeX64Emu(x64emu_t **emu)
|
||||
|
||||
internalFreeX64(*emu);
|
||||
|
||||
free(*emu);
|
||||
box_free(*emu);
|
||||
*emu = NULL;
|
||||
}
|
||||
|
||||
@@ -224,10 +234,9 @@ void CloneEmu(x64emu_t *newemu, const x64emu_t* emu)
|
||||
memcpy(newemu->fpu_ll, emu->fpu_ll, sizeof(emu->fpu_ll));
|
||||
memcpy(newemu->p_regs, emu->p_regs, sizeof(emu->p_regs));
|
||||
newemu->cw = emu->cw;
|
||||
memcpy(&newemu->sw, &emu->sw, sizeof(emu->sw));
|
||||
newemu->sw = emu->sw;
|
||||
newemu->top = emu->top;
|
||||
newemu->fpu_stack = emu->fpu_stack;
|
||||
memcpy(&newemu->round, &emu->round, sizeof(emu->round));
|
||||
memcpy(newemu->xmm, emu->xmm, sizeof(emu->xmm));
|
||||
newemu->mxcsr = emu->mxcsr;
|
||||
newemu->quit = emu->quit;
|
||||
@@ -441,8 +450,9 @@ void UnimpOpcode(x64emu_t* emu)
|
||||
R_RIP = emu->old_ip;
|
||||
|
||||
int tid = syscall(SYS_gettid);
|
||||
printf_log(LOG_NONE, "%04d|%p: Unimplemented Opcode (%02X) %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n",
|
||||
tid, (void*)emu->old_ip, Peek(emu, -1),
|
||||
printf_log(LOG_NONE, "%04d|%p: Unimplemented Opcode (%02X %02X %02X %02X) %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n",
|
||||
tid, (void*)emu->old_ip,
|
||||
Peek(emu, -4), Peek(emu, -3), Peek(emu, -2), Peek(emu, -1),
|
||||
Peek(emu, 0), Peek(emu, 1), Peek(emu, 2), Peek(emu, 3),
|
||||
Peek(emu, 4), Peek(emu, 5), Peek(emu, 6), Peek(emu, 7),
|
||||
Peek(emu, 8), Peek(emu, 9), Peek(emu,10), Peek(emu,11),
|
||||
@@ -505,3 +515,25 @@ void ResetSegmentsCache(x64emu_t *emu)
|
||||
return;
|
||||
memset(emu->segs_serial, 0, sizeof(emu->segs_serial));
|
||||
}
|
||||
|
||||
void applyFlushTo0(x64emu_t* emu)
|
||||
{
|
||||
#ifdef __x86_64__
|
||||
_mm_setcsr(_mm_getcsr() | (emu->mxcsr.x32&0x8040));
|
||||
#elif defined(__aarch64__)
|
||||
#ifdef __ANDROID__
|
||||
uint64_t fpcr;
|
||||
__asm__ __volatile__ ("mrs %0, fpcr":"=r"(fpcr));
|
||||
#else
|
||||
uint64_t fpcr = __builtin_aarch64_get_fpcr();
|
||||
#endif
|
||||
fpcr &= ~((1<<24) | (1<<1)); // clear bit FZ (24) and AH (1)
|
||||
fpcr |= (emu->mxcsr.f.MXCSR_FZ)<<24; // set FZ as mxcsr FZ
|
||||
fpcr |= ((emu->mxcsr.f.MXCSR_DAZ)^(emu->mxcsr.f.MXCSR_FZ))<<1; // set AH if DAZ different from FZ
|
||||
#ifdef __ANDROID__
|
||||
__asm__ __volatile__ ("msr fpcr, %0"::"r"(fpcr));
|
||||
#else
|
||||
__builtin_aarch64_set_fpcr(fpcr);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
@@ -35,12 +35,11 @@ typedef struct x64emu_s {
|
||||
// fpu / mmx
|
||||
mmx87_regs_t x87[8];
|
||||
mmx87_regs_t mmx[8];
|
||||
uint16_t cw;
|
||||
x87control_t cw;
|
||||
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;
|
||||
mmxcontrol_t mxcsr;
|
||||
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];
|
||||
@@ -52,6 +51,9 @@ typedef struct x64emu_s {
|
||||
multiuint_t op1;
|
||||
multiuint_t op2;
|
||||
multiuint_t res;
|
||||
multiuint_t op1_sav; // for dec/inc defered flags, to be able to compute CF
|
||||
multiuint_t res_sav;
|
||||
defered_flags_t df_sav;
|
||||
uint32_t *x64emu_parity_tab; // helper
|
||||
#ifdef HAVE_TRACE
|
||||
reg64_t oldregs[16];
|
||||
@@ -73,6 +75,7 @@ typedef struct x64emu_s {
|
||||
forkpty_t* forkpty_info;
|
||||
int exit;
|
||||
int quitonlongjmp; // quit if longjmp is called
|
||||
int quitonexit; // quit if exit/_exit is called
|
||||
int longjmp; // if quit because of longjmp
|
||||
// scratch stack, used for alignement of double and 64bits ints on arm. 200 elements should be enough
|
||||
uint64_t scratch[200];
|
||||
@@ -94,4 +97,6 @@ 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
|
||||
|
||||
void applyFlushTo0(x64emu_t* emu);
|
||||
|
||||
#endif //__X86EMU_PRIVATE_H_
|
||||
+129
-63
@@ -11,6 +11,7 @@
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <poll.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64stack.h"
|
||||
@@ -54,8 +55,13 @@ x64emu_t* x64emu_fork(x64emu_t* emu, int forktype)
|
||||
for (int i=0; i<my_context->atfork_sz; --i)
|
||||
if(my_context->atforks[i].parent)
|
||||
EmuCall(emu, my_context->atforks[i].parent);
|
||||
if(forktype==3) {
|
||||
// vfork, the parent wait the end or execve of the son
|
||||
waitpid(v, NULL, WEXITED);
|
||||
}
|
||||
|
||||
} else if(v==0) {
|
||||
ResetSegmentsCache(emu);
|
||||
// execute atforks child functions
|
||||
for (int i=0; i<my_context->atfork_sz; --i)
|
||||
if(my_context->atforks[i].child)
|
||||
@@ -65,181 +71,228 @@ x64emu_t* x64emu_fork(x64emu_t* emu, int forktype)
|
||||
return emu;
|
||||
}
|
||||
|
||||
extern int errno;
|
||||
void x64Int3(x64emu_t* emu)
|
||||
static uint64_t F64(uintptr_t* addr) {
|
||||
uint64_t ret = *(uint64_t*)*addr;
|
||||
*addr+=8;
|
||||
return ret;
|
||||
}
|
||||
static uint8_t Peek8(uintptr_t addr, uintptr_t offset)
|
||||
{
|
||||
if(Peek(emu, 0)=='S' && Peek(emu, 1)=='C') // Signature for "Out of x86 door"
|
||||
return *(uint8_t*)(addr+offset);
|
||||
}
|
||||
|
||||
void x64Int3(x64emu_t* emu, uintptr_t* addr)
|
||||
{
|
||||
if(Peek8(*addr, 0)=='S' && Peek8(*addr, 1)=='C') // Signature for "Out of x86 door"
|
||||
{
|
||||
R_RIP += 2;
|
||||
uintptr_t addr = Fetch64(emu);
|
||||
if(addr==0) {
|
||||
*addr += 2;
|
||||
uintptr_t a = F64(addr);
|
||||
if(a==0) {
|
||||
R_RIP = *addr;
|
||||
//printf_log(LOG_INFO, "%p:Exit x86 emu (emu=%p)\n", *(void**)(R_ESP), emu);
|
||||
emu->quit=1; // normal quit
|
||||
} else {
|
||||
RESET_FLAGS(emu);
|
||||
wrapper_t w = (wrapper_t)addr;
|
||||
addr = Fetch64(emu);
|
||||
wrapper_t w = (wrapper_t)a;
|
||||
a = F64(addr);
|
||||
R_RIP = *addr;
|
||||
/* This party can be used to trace only 1 specific lib (but it is quite slow)
|
||||
elfheader_t *h = FindElfAddress(my_context, *(uintptr_t*)(R_ESP));
|
||||
int have_trace = 0;
|
||||
if(h && strstr(ElfName(h), "libMiles")) have_trace = 1;*/
|
||||
if(box64_log>=LOG_DEBUG /*|| have_trace*/) {
|
||||
pthread_mutex_lock(&emu->context->mutex_trace);
|
||||
if(box64_log>=LOG_DEBUG || cycle_log) {
|
||||
int tid = GetTID();
|
||||
char buff[256] = "\0";
|
||||
char t_buff[256] = "\0";
|
||||
char buff2[64] = "\0";
|
||||
char buff3[64] = "\0";
|
||||
int cycle_line = my_context->current_line;
|
||||
if(cycle_log) {
|
||||
my_context->current_line = (my_context->current_line+1)%cycle_log;
|
||||
}
|
||||
char* buff = cycle_log?my_context->log_call[cycle_line]:t_buff;
|
||||
char* buffret = cycle_log?my_context->log_ret[cycle_line]:NULL;
|
||||
if(buffret) buffret[0] = '\0';
|
||||
char *tmp;
|
||||
int post = 0;
|
||||
int perr = 0;
|
||||
uint64_t *pu64 = NULL;
|
||||
uint32_t *pu32 = NULL;
|
||||
const char *s = NULL;
|
||||
s = GetNativeName((void*)addr);
|
||||
if(addr==(uintptr_t)PltResolver) {
|
||||
snprintf(buff, 256, "%s", " ... ");
|
||||
s = GetNativeName((void*)a);
|
||||
if(a==(uintptr_t)PltResolver) {
|
||||
snprintf(buff, 256, "%s", cycle_log?"PltResolver ":" ... ");
|
||||
} else if (!strcmp(s, "__open") || !strcmp(s, "open") || !strcmp(s, "open ") || !strcmp(s, "open64")) {
|
||||
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));
|
||||
snprintf(buff, 256, "%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 (!strcmp(s, "shm_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));
|
||||
snprintf(buff, 256, "%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 (!strcmp(s, "fopen") || !strcmp(s, "fopen64")) {
|
||||
tmp = (char*)(R_RDI);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\")", tid, *(void**)(R_RSP), s, (tmp)?tmp:"(nil)", (char*)(R_RSI));
|
||||
snprintf(buff, 256, "%04d|%p: Calling %s(\"%s\", \"%s\")", tid, *(void**)(R_RSP), s, (tmp)?tmp:"(nil)", (char*)(R_RSI));
|
||||
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));
|
||||
snprintf(buff, 256, "%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 (!strcmp(s, "readlink")) {
|
||||
tmp = (char*)(R_RDI);
|
||||
snprintf(buff, 256, "%04d|%p: Calling %s(\"%s\", %p, %zd)", tid, *(void**)(R_RSP), s, (tmp)?tmp:"(nil)", (void*)(R_RSI), (size_t)R_RDX);
|
||||
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));
|
||||
snprintf(buff, 256, "%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)");
|
||||
snprintf(buff, 256, "%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);
|
||||
snprintf(buff, 256, "%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);
|
||||
if(R_EDI==2 || R_EDI==3)
|
||||
snprintf(buff, 256, "%04d|%p: Calling %s(%d, %p\"%s\", %zu)", tid, *(void**)(R_RSP), s, R_EDI, (void*)R_RSI, (char*)R_RSI, R_RDX);
|
||||
else
|
||||
snprintf(buff, 256, "%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);
|
||||
snprintf(buff, 256, "%04d|%p: Calling %s(\"%s\", 0x%x)", tid, *(void**)(R_RSP), s, (tmp)?tmp:"(nil)", R_ESI);
|
||||
perr = 1;
|
||||
} else if (strstr(s, "waitpid")==s) {
|
||||
pu32 = (uint32_t*)R_RSI;
|
||||
snprintf(buff, 256, "%04d|%p: Calling %s(%d, %p, %d)", tid, *(void**)(R_RSP), s, R_EDI, pu32, R_EDX);
|
||||
perr = 1;
|
||||
post = 6;
|
||||
} else if (!strcmp(s, "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);
|
||||
snprintf(buff, 256, "%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")) {
|
||||
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);
|
||||
snprintf(buff, 256, "%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, "recvmsg")) {
|
||||
snprintf(buff, 256, "%04d|%p: Calling %s(%d, %p, 0x%x)", tid, *(void**)(R_RSP), s, R_EDI, (void*)R_RSI, 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)");
|
||||
snprintf(buff, 256, "%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)");
|
||||
snprintf(buff, 256, "%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);
|
||||
snprintf(buff, 256, "%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)");
|
||||
post = 2;
|
||||
snprintf(buff, 256, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)(R_RSP), s, (tmp)?tmp:"(nil)");
|
||||
} else if (strstr(s, "setenv")==s) {
|
||||
snprintf(buff, 256, "%04d|%p: Calling %s(\"%s\", \"%s\", %d)", tid, *(void**)(R_RSP), s, (char*)R_RDI, (char*)R_RSI, R_EDX);
|
||||
} 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);
|
||||
snprintf(buff, 256, "%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, "__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));
|
||||
snprintf(buff, 256, "%04d|%p: Calling %s(%d, \"%s\" (,%p))", tid, *(void**)(R_RSP), s, R_EDI, (tmp)?tmp:"(nil)", (void*)(R_RDX));
|
||||
} else if (strstr(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));
|
||||
snprintf(buff, 256, "%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 (!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));
|
||||
snprintf(buff, 256, "%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);
|
||||
snprintf(buff, 256, "%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);
|
||||
snprintf(buff, 256, "%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)");
|
||||
snprintf(buff, 256, "%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)");
|
||||
snprintf(buff, 256, "%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);
|
||||
snprintf(buff, 256, "%04d|%p: Calling %s(0x%x, %d)", tid, *(void**)(R_RSP), s, R_EDI, R_ESI);
|
||||
} else if (!strcmp(s, "_dl_tlsdesc_undefweak")) {
|
||||
snprintf(buff, 256, "%04d|%p: Calling %s(RAX=%p)", tid, *(void**)(R_RSP), s, (void*)R_RAX);
|
||||
} 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);
|
||||
snprintf(buff, 256, "%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));
|
||||
snprintf(buff, 256, "%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));
|
||||
snprintf(buff, 256, "%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);
|
||||
snprintf(buff, 256, "%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);
|
||||
snprintf(buff, 256, "%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]);
|
||||
snprintf(buff, 256, "%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,
|
||||
snprintf(buff, 256, "%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));
|
||||
snprintf(buff, 256, "%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,
|
||||
snprintf(buff, 256, "%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);
|
||||
snprintf(buff, 256, "%04d|%p: Calling %s(0x%lX, 0x%lX, 0x%lX, ...)", tid, *(void**)(R_RSP), s, R_RDI, R_RSI, R_RDX);
|
||||
}
|
||||
printf_log(LOG_NONE, "%s =>", buff);
|
||||
pthread_mutex_unlock(&emu->context->mutex_trace);
|
||||
w(emu, addr); // some function never come back, so unlock the mutex first!
|
||||
pthread_mutex_lock(&emu->context->mutex_trace);
|
||||
if(!cycle_log) {
|
||||
mutex_lock(&emu->context->mutex_trace);
|
||||
printf_log(LOG_NONE, "%s =>", buff);
|
||||
mutex_unlock(&emu->context->mutex_trace);
|
||||
}
|
||||
w(emu, a); // some function never come back, so unlock the mutex first!
|
||||
if(post)
|
||||
switch(post) { // Only ever 2 for now...
|
||||
case 1: snprintf(buff2, 63, " [%llu sec %llu nsec]", pu64?pu64[0]:~0ull, pu64?pu64[1]:~0ull);
|
||||
case 1: snprintf(buff2, 64, " [%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");
|
||||
case 2: snprintf(buff2, 64, "(%s)", R_RAX?((char*)R_RAX):"nil");
|
||||
break;
|
||||
case 3: snprintf(buff2, 63, "(%s)", pu64?((char*)pu64):"nil");
|
||||
case 3: snprintf(buff2, 64, "(%s)", pu64?((char*)pu64):"nil");
|
||||
break;
|
||||
case 4: snprintf(buff2, 63, " (%f)", ST0.d);
|
||||
case 4: snprintf(buff2, 64, " (%f)", ST0.d);
|
||||
break;
|
||||
case 5: {
|
||||
uint32_t* p = (uint32_t*)R_RAX; // uint64_t? (case never used)
|
||||
if(p)
|
||||
snprintf(buff2, 63, " size=%ux%u, pitch=%u, pixels=%p", p[2], p[3], p[4], p+5);
|
||||
snprintf(buff2, 64, " size=%ux%u, pitch=%u, pixels=%p", p[2], p[3], p[4], p+5);
|
||||
else
|
||||
snprintf(buff2, 63, "NULL Surface");
|
||||
snprintf(buff2, 64, "NULL Surface");
|
||||
}
|
||||
break;
|
||||
case 6: if(pu32) snprintf(buff2, 64, " [0x%x] ", pu32[0]);
|
||||
break;
|
||||
}
|
||||
if(perr==1 && ((int)R_EAX)<0)
|
||||
snprintf(buff3, 63, " (errno=%d:\"%s\")", errno, strerror(errno));
|
||||
snprintf(buff3, 64, " (errno=%d:\"%s\")", errno, strerror(errno));
|
||||
else if(perr==2 && R_EAX==0)
|
||||
snprintf(buff3, 63, " (errno=%d:\"%s\")", errno, strerror(errno));
|
||||
printf_log(LOG_NONE, " return 0x%lX%s%s\n", R_RAX, buff2, buff3);
|
||||
pthread_mutex_unlock(&emu->context->mutex_trace);
|
||||
snprintf(buff3, 64, " (errno=%d:\"%s\")", errno, strerror(errno));
|
||||
if(cycle_log)
|
||||
snprintf(buffret, 128, "0x%lX%s%s", R_RAX, buff2, buff3);
|
||||
else {
|
||||
mutex_lock(&emu->context->mutex_trace);
|
||||
printf_log(LOG_NONE, " return 0x%lX%s%s\n", R_RAX, buff2, buff3);
|
||||
mutex_unlock(&emu->context->mutex_trace);
|
||||
}
|
||||
} else
|
||||
w(emu, addr);
|
||||
w(emu, a);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -254,3 +307,16 @@ int GetTID()
|
||||
{
|
||||
return syscall(SYS_gettid);
|
||||
}
|
||||
|
||||
void print_cycle_log(int loglevel) {
|
||||
if(cycle_log) {
|
||||
printf_log(LOG_INFO, "Last calls\n");
|
||||
int j = (my_context->current_line+1)%cycle_log;
|
||||
for (int i=0; i<cycle_log; ++i) {
|
||||
int k = (i+j)%cycle_log;
|
||||
if(my_context->log_call[k][0]) {
|
||||
printf_log(loglevel, "%s => return %s\n", my_context->log_call[k], my_context->log_ret[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-3
@@ -1189,8 +1189,9 @@ uint16_t sbb16(x64emu_t *emu, uint16_t d, uint16_t s)
|
||||
|
||||
if (ACCESS_FLAG(F_CF))
|
||||
res = d - s - 1;
|
||||
else
|
||||
else {
|
||||
res = d - s;
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
|
||||
CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
||||
@@ -1211,8 +1212,9 @@ uint32_t sbb32(x64emu_t *emu, uint32_t d, uint32_t s)
|
||||
|
||||
if (ACCESS_FLAG(F_CF))
|
||||
res = d - s - 1;
|
||||
else
|
||||
else {
|
||||
res = d - s;
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
|
||||
CONDITIONAL_SET_FLAG(!res, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
||||
@@ -1233,8 +1235,9 @@ uint64_t sbb64(x64emu_t *emu, uint64_t d, uint64_t s)
|
||||
|
||||
if (ACCESS_FLAG(F_CF))
|
||||
res = d - s - 1;
|
||||
else
|
||||
else {
|
||||
res = d - s;
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(res & 0x8000000000000000LL, F_SF);
|
||||
CONDITIONAL_SET_FLAG(!res, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
||||
|
||||
+30
-12
@@ -89,88 +89,106 @@ uint64_t cmp64 (x64emu_t *emu, uint64_t d, uint64_t s);
|
||||
uint8_t daa8 (x64emu_t *emu, uint8_t d);
|
||||
uint8_t das8 (x64emu_t *emu, uint8_t d);
|
||||
|
||||
#define CF_SAV() \
|
||||
if(emu->df>=d_dec8 && emu->df<=d_inc64) { \
|
||||
emu->df_sav = d_none; \
|
||||
} else if(emu->df<d_dec8i || emu->df>d_inc64i) {\
|
||||
emu->df_sav = emu->df; \
|
||||
emu->op1_sav = emu->op1; \
|
||||
emu->res_sav = emu->res; \
|
||||
}
|
||||
|
||||
static inline uint8_t dec8(x64emu_t *emu, uint8_t d)
|
||||
{
|
||||
CF_SAV();
|
||||
emu->res.u8 = d - 1;
|
||||
emu->op1.u8 = d;
|
||||
emu->df = d_dec8;
|
||||
emu->df = d_dec8i;
|
||||
return emu->res.u8;
|
||||
}
|
||||
|
||||
static inline uint16_t dec16(x64emu_t *emu, uint16_t d)
|
||||
{
|
||||
CF_SAV();
|
||||
emu->res.u16 = d - 1;
|
||||
emu->op1.u16 = d;
|
||||
emu->df = d_dec16;
|
||||
emu->df = d_dec16i;
|
||||
return emu->res.u16;
|
||||
|
||||
}
|
||||
|
||||
static inline uint32_t dec32(x64emu_t *emu, uint32_t d)
|
||||
{
|
||||
CF_SAV();
|
||||
emu->res.u32 = d - 1;
|
||||
emu->op1.u32 = d;
|
||||
emu->df = d_dec32;
|
||||
emu->df = d_dec32i;
|
||||
|
||||
return emu->res.u32;
|
||||
}
|
||||
|
||||
static inline uint64_t dec64(x64emu_t *emu, uint64_t d)
|
||||
{
|
||||
CF_SAV();
|
||||
emu->res.u64 = d - 1;
|
||||
emu->op1.u64 = d;
|
||||
emu->df = d_dec64;
|
||||
emu->df = d_dec64i;
|
||||
|
||||
return emu->res.u64;
|
||||
}
|
||||
|
||||
static inline uint8_t inc8(x64emu_t *emu, uint8_t d)
|
||||
{
|
||||
CF_SAV();
|
||||
emu->res.u8 = d + 1;
|
||||
emu->op1.u8 = d;
|
||||
emu->df = d_inc8;
|
||||
emu->df = d_inc8i;
|
||||
return emu->res.u8;
|
||||
}
|
||||
|
||||
static inline uint16_t inc16(x64emu_t *emu, uint16_t d)
|
||||
{
|
||||
CF_SAV();
|
||||
emu->res.u16 = d + 1;
|
||||
emu->op1.u16 = d;
|
||||
emu->df = d_inc16;
|
||||
emu->df = d_inc16i;
|
||||
return emu->res.u16;
|
||||
}
|
||||
|
||||
static inline uint32_t inc32(x64emu_t *emu, uint32_t d)
|
||||
{
|
||||
if(emu->df == d_shr32) {
|
||||
/*if(emu->df == d_shr32) {
|
||||
// workaround for some wine trickery
|
||||
uint32_t cnt = emu->op2.u32;
|
||||
if (cnt > 0) {
|
||||
uint32_t cc = emu->op1.u32 & (1 << (cnt - 1));
|
||||
CONDITIONAL_SET_FLAG(cc, F_CF);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
CF_SAV();
|
||||
emu->res.u32 = d + 1;
|
||||
emu->op1.u32 = d;
|
||||
emu->df = d_inc32;
|
||||
emu->df = d_inc32i;
|
||||
return emu->res.u32;
|
||||
}
|
||||
|
||||
static inline uint64_t inc64(x64emu_t *emu, uint64_t d)
|
||||
{
|
||||
if(emu->df == d_shr64) {
|
||||
/*if(emu->df == d_shr64) {
|
||||
// workaround for some wine trickery
|
||||
uint64_t cnt = emu->op2.u64;
|
||||
if (cnt > 0) {
|
||||
uint64_t cc = emu->op1.u64 & (1LL << (cnt - 1));
|
||||
CONDITIONAL_SET_FLAG(cc, F_CF);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
CF_SAV();
|
||||
emu->res.u64 = d + 1;
|
||||
emu->op1.u64 = d;
|
||||
emu->df = d_inc64;
|
||||
emu->df = d_inc64i;
|
||||
return emu->res.u64;
|
||||
}
|
||||
#undef CF_SAV
|
||||
|
||||
static inline uint8_t or8(x64emu_t *emu, uint8_t d, uint8_t s)
|
||||
{
|
||||
|
||||
+109
-82
@@ -40,33 +40,34 @@ int Run(x64emu_t *emu, int step)
|
||||
uint32_t tmp32u, tmp32u2;
|
||||
int64_t tmp64s;
|
||||
uint64_t tmp64u, tmp64u2, tmp64u3;
|
||||
uintptr_t addr = R_RIP;
|
||||
rex_t rex;
|
||||
int rep; // 0 none, 1=F2 prefix, 2=F3 prefix
|
||||
int unimp = 0;
|
||||
|
||||
if(emu->quit)
|
||||
return 0;
|
||||
if(R_RIP==0) {
|
||||
if(addr==0) {
|
||||
emu->quit = 1;
|
||||
printf_log(LOG_INFO, "Ask to run at NULL, quit silently\n");
|
||||
printf_log(LOG_INFO, "%04d|Ask to run at NULL, quit silently\n", GetTID());
|
||||
print_cycle_log(LOG_INFO);
|
||||
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, (void*)R_RSP);
|
||||
printf_log(LOG_DEBUG, "Run X86 (%p), RIP=%p, Stack=%p\n", emu, (void*)addr, (void*)R_RSP);
|
||||
|
||||
x64emurun:
|
||||
|
||||
while(1) {
|
||||
#ifdef HAVE_TRACE
|
||||
__builtin_prefetch((void*)R_RIP, 0, 0);
|
||||
__builtin_prefetch((void*)addr, 0, 0);
|
||||
emu->prev2_ip = emu->old_ip;
|
||||
if(my_context->dec && (
|
||||
(trace_end == 0)
|
||||
|| ((R_RIP >= trace_start) && (R_RIP < trace_end))) )
|
||||
PrintTrace(emu, R_RIP, 0);
|
||||
|| ((addr >= trace_start) && (addr < trace_end))) )
|
||||
PrintTrace(emu, addr, 0);
|
||||
#endif
|
||||
emu->old_ip = R_RIP;
|
||||
emu->old_ip = addr;
|
||||
|
||||
opcode = F8;
|
||||
|
||||
@@ -135,26 +136,30 @@ x64emurun:
|
||||
case 0x0F: /* More instructions */
|
||||
switch(rep) {
|
||||
case 1:
|
||||
if(RunF20F(emu, rex)) {
|
||||
if(!(addr = RunF20F(emu, rex, addr, &step))) {
|
||||
unimp = 1;
|
||||
goto fini;
|
||||
}
|
||||
if(step==2) STEP2;
|
||||
break;
|
||||
case 2:
|
||||
if(RunF30F(emu, rex)) {
|
||||
if(!(addr = RunF30F(emu, rex, addr))) {
|
||||
unimp = 1;
|
||||
goto fini;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if(Run0F(emu, rex)) {
|
||||
if(!(addr = Run0F(emu, rex, addr, &step))) {
|
||||
unimp = 1;
|
||||
goto fini;
|
||||
}
|
||||
if(step==2) STEP2;
|
||||
break;
|
||||
}
|
||||
if(emu->quit)
|
||||
if(emu->quit) {
|
||||
R_RIP = addr;
|
||||
goto fini;
|
||||
}
|
||||
break;
|
||||
GO(0x10, adc) /* ADC 0x10 -> 0x15 */
|
||||
GO(0x18, sbb) /* SBB 0x18 -> 0x1D */
|
||||
@@ -163,7 +168,7 @@ x64emurun:
|
||||
GO(0x30, xor) /* XOR 0x30 -> 0x35 */
|
||||
#undef GO
|
||||
|
||||
case 0x2E: /* segments are ignored */
|
||||
case 0x2E: /* segments are ignored */
|
||||
case 0x36: /* SS: (ignored) */
|
||||
break;
|
||||
|
||||
@@ -250,36 +255,44 @@ x64emurun:
|
||||
GD->sdword[0] = ED->sdword[0]; // meh?
|
||||
break;
|
||||
case 0x64: /* FS: prefix */
|
||||
if(Run64(emu, rex, _FS)) {
|
||||
if(!(addr = Run64(emu, rex, _FS, addr))) {
|
||||
unimp = 1;
|
||||
goto fini;
|
||||
}
|
||||
if(emu->quit)
|
||||
if(emu->quit) {
|
||||
R_RIP = addr;
|
||||
goto fini;
|
||||
}
|
||||
break;
|
||||
case 0x65: /* GS: prefix */
|
||||
if(Run64(emu, rex, _GS)) {
|
||||
if(!(addr = Run64(emu, rex, _GS, addr))) {
|
||||
unimp = 1;
|
||||
goto fini;
|
||||
}
|
||||
if(emu->quit)
|
||||
if(emu->quit) {
|
||||
R_RIP = addr;
|
||||
goto fini;
|
||||
}
|
||||
break;
|
||||
case 0x66: /* 16bits prefix */
|
||||
if(Run66(emu, rex, rep)) {
|
||||
if(!(addr = Run66(emu, rex, rep, addr))) {
|
||||
unimp = 1;
|
||||
goto fini;
|
||||
}
|
||||
if(emu->quit)
|
||||
if(emu->quit) {
|
||||
R_RIP = addr;
|
||||
goto fini;
|
||||
}
|
||||
break;
|
||||
case 0x67: /* reduce EASize prefix */
|
||||
if(Run67(emu, rex, rep)) {
|
||||
if(!(addr = Run67(emu, rex, rep, addr))) {
|
||||
unimp = 1;
|
||||
goto fini;
|
||||
}
|
||||
if(emu->quit)
|
||||
if(emu->quit) {
|
||||
R_RIP = addr;
|
||||
goto fini;
|
||||
}
|
||||
break;
|
||||
case 0x68: /* Push Id */
|
||||
Push(emu, F32S64);
|
||||
@@ -313,15 +326,14 @@ x64emurun:
|
||||
case 0x6E: /* OUTSB DX */
|
||||
case 0x6F: /* OUTSL DX */
|
||||
// this is a privilege opcode...
|
||||
--R_RIP;
|
||||
emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
|
||||
STEP;
|
||||
break;
|
||||
|
||||
GOCOND(0x70
|
||||
, tmp8s = F8S; CHECK_FLAGS(emu);
|
||||
, R_RIP += tmp8s;
|
||||
,
|
||||
, addr += tmp8s;
|
||||
,,STEP2
|
||||
) /* Jxx Ib */
|
||||
|
||||
case 0x80: /* GRP Eb,Ib */
|
||||
@@ -1027,13 +1039,13 @@ x64emurun:
|
||||
break;
|
||||
case 0xC2: /* RETN Iw */
|
||||
tmp16u = F16;
|
||||
R_RIP = Pop(emu);
|
||||
addr = Pop(emu);
|
||||
R_RSP += tmp16u;
|
||||
STEP
|
||||
STEP2
|
||||
break;
|
||||
case 0xC3: /* RET */
|
||||
R_RIP = Pop(emu);
|
||||
STEP
|
||||
addr = Pop(emu);
|
||||
STEP2
|
||||
break;
|
||||
|
||||
case 0xC6: /* MOV Eb,Ib */
|
||||
@@ -1073,19 +1085,19 @@ x64emurun:
|
||||
break;
|
||||
|
||||
case 0xCC: /* INT 3 */
|
||||
x64Int3(emu);
|
||||
if(emu->quit) goto fini;
|
||||
x64Int3(emu, &addr);
|
||||
if(emu->quit) goto fini; // R_RIP is up to date when returning from x64Int3
|
||||
addr = R_RIP;
|
||||
break;
|
||||
case 0xCD: /* INT n */
|
||||
// this is a privilege opcode...
|
||||
--R_RIP;
|
||||
emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
|
||||
STEP;
|
||||
break;
|
||||
|
||||
|
||||
case 0xCF: /* IRET */
|
||||
R_RIP = Pop(emu);
|
||||
addr = Pop(emu);
|
||||
emu->segs[_CS] = Pop(emu)&0xffff;
|
||||
emu->segs_serial[_CS] = 0;
|
||||
emu->eflags.x64 = ((Pop(emu) & 0x3F7FD7)/* & (0xffff-40)*/ ) | 0x2; // mask off res2 and res3 and on res1
|
||||
@@ -1094,6 +1106,7 @@ x64emurun:
|
||||
emu->segs_serial[_SS] = 0;
|
||||
R_RSP= tmp64u;
|
||||
RESET_FLAGS(emu);
|
||||
R_RIP = addr;
|
||||
goto fini; // exit, to recompute CS if needed
|
||||
break;
|
||||
case 0xD0: /* GRP2 Eb,1 */
|
||||
@@ -1158,145 +1171,160 @@ x64emurun:
|
||||
R_AL = *(uint8_t*)(R_RBX + R_AL);
|
||||
break;
|
||||
case 0xD8: /* x87 opcodes */
|
||||
if(RunD8(emu, rex)) {
|
||||
if(!(addr = RunD8(emu, rex, addr))) {
|
||||
unimp = 1;
|
||||
goto fini;
|
||||
}
|
||||
if(emu->quit)
|
||||
if(emu->quit) {
|
||||
R_RIP = addr;
|
||||
goto fini;
|
||||
}
|
||||
break;
|
||||
case 0xD9: /* x87 opcodes */
|
||||
if(RunD9(emu, rex)) {
|
||||
if(!(addr = RunD9(emu, rex, addr))) {
|
||||
unimp = 1;
|
||||
goto fini;
|
||||
}
|
||||
if(emu->quit)
|
||||
if(emu->quit) {
|
||||
R_RIP = addr;
|
||||
goto fini;
|
||||
}
|
||||
break;
|
||||
case 0xDA: /* x87 opcodes */
|
||||
if(RunDA(emu, rex)) {
|
||||
if(!(addr = RunDA(emu, rex, addr))) {
|
||||
unimp = 1;
|
||||
goto fini;
|
||||
}
|
||||
if(emu->quit)
|
||||
if(emu->quit) {
|
||||
R_RIP = addr;
|
||||
goto fini;
|
||||
}
|
||||
break;
|
||||
case 0xDB: /* x87 opcodes */
|
||||
if(RunDB(emu, rex)) {
|
||||
if(!(addr = RunDB(emu, rex, addr))) {
|
||||
unimp = 1;
|
||||
goto fini;
|
||||
}
|
||||
if(emu->quit)
|
||||
if(emu->quit) {
|
||||
R_RIP = addr;
|
||||
goto fini;
|
||||
}
|
||||
break;
|
||||
case 0xDC: /* x87 opcodes */
|
||||
if(RunDC(emu, rex)) {
|
||||
if(!(addr = RunDC(emu, rex, addr))) {
|
||||
unimp = 1;
|
||||
goto fini;
|
||||
}
|
||||
if(emu->quit)
|
||||
if(emu->quit) {
|
||||
R_RIP = addr;
|
||||
goto fini;
|
||||
}
|
||||
break;
|
||||
case 0xDD: /* x87 opcodes */
|
||||
if(RunDD(emu, rex)) {
|
||||
if(!(addr = RunDD(emu, rex, addr))) {
|
||||
unimp = 1;
|
||||
goto fini;
|
||||
}
|
||||
if(emu->quit)
|
||||
if(emu->quit) {
|
||||
R_RIP = addr;
|
||||
goto fini;
|
||||
}
|
||||
break;
|
||||
case 0xDE: /* x87 opcodes */
|
||||
if(RunDE(emu, rex)) {
|
||||
if(!(addr = RunDE(emu, rex, addr))) {
|
||||
unimp = 1;
|
||||
goto fini;
|
||||
}
|
||||
if(emu->quit)
|
||||
if(emu->quit) {
|
||||
R_RIP = addr;
|
||||
goto fini;
|
||||
}
|
||||
break;
|
||||
case 0xDF: /* x87 opcodes */
|
||||
if(RunDF(emu, rex)) {
|
||||
if(!(addr = RunDF(emu, rex, addr))) {
|
||||
unimp = 1;
|
||||
goto fini;
|
||||
}
|
||||
if(emu->quit)
|
||||
if(emu->quit) {
|
||||
R_RIP = addr;
|
||||
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
|
||||
addr += tmp8s;
|
||||
STEP2
|
||||
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
|
||||
addr += tmp8s;
|
||||
STEP2
|
||||
break;
|
||||
case 0xE2: /* LOOP */
|
||||
tmp8s = F8S;
|
||||
--R_RCX; // don't update flags
|
||||
if(R_RCX)
|
||||
R_RIP += tmp8s;
|
||||
STEP
|
||||
addr += tmp8s;
|
||||
STEP2
|
||||
break;
|
||||
case 0xE3: /* JECXZ */
|
||||
case 0xE3: /* JRCXZ */
|
||||
tmp8s = F8S;
|
||||
if(!R_RCX)
|
||||
R_RIP += tmp8s;
|
||||
STEP
|
||||
addr += tmp8s;
|
||||
STEP2
|
||||
break;
|
||||
case 0xE4: /* IN AL, XX */
|
||||
case 0xE5: /* IN EAX, XX */
|
||||
case 0xE6: /* OUT XX, AL */
|
||||
case 0xE7: /* OUT XX, EAX */
|
||||
// this is a privilege opcode...
|
||||
--R_RIP;
|
||||
emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
|
||||
STEP;
|
||||
break;
|
||||
case 0xE8: /* CALL Id */
|
||||
tmp32s = F32S; // call is relative
|
||||
Push(emu, R_RIP);
|
||||
R_RIP += tmp32s;
|
||||
STEP
|
||||
Push(emu, addr);
|
||||
addr += tmp32s;
|
||||
STEP2
|
||||
break;
|
||||
case 0xE9: /* JMP Id */
|
||||
tmp32s = F32S; // jmp is relative
|
||||
R_RIP += tmp32s;
|
||||
STEP
|
||||
addr += tmp32s;
|
||||
STEP2
|
||||
break;
|
||||
|
||||
case 0xEB: /* JMP Ib */
|
||||
tmp32s = F8S; // jump is relative
|
||||
R_RIP += tmp32s;
|
||||
STEP
|
||||
addr += tmp32s;
|
||||
STEP2
|
||||
break;
|
||||
case 0xEC: /* IN AL, DX */
|
||||
case 0xED: /* IN EAX, DX */
|
||||
case 0xEE: /* OUT DX, AL */
|
||||
case 0xEF: /* OUT DX, EAX */
|
||||
// this is a privilege opcode...
|
||||
--R_RIP;
|
||||
emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
|
||||
STEP;
|
||||
break;
|
||||
case 0xF0: /* LOCK prefix */
|
||||
if(RunF0(emu, rex)) {
|
||||
if(!(addr = RunF0(emu, rex, addr))) {
|
||||
unimp = 1;
|
||||
goto fini;
|
||||
}
|
||||
if(emu->quit)
|
||||
if(emu->quit) {
|
||||
R_RIP = addr;
|
||||
goto fini;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF4: /* HLT */
|
||||
// this is a privilege opcode...
|
||||
--R_RIP;
|
||||
emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
|
||||
STEP;
|
||||
break;
|
||||
@@ -1386,10 +1414,12 @@ x64emurun:
|
||||
case 4: /* MUL EAX,Ed */
|
||||
mul32_eax(emu, ED->dword[0]);
|
||||
emu->regs[_AX].dword[1] = 0;
|
||||
emu->regs[_DX].dword[1] = 0;
|
||||
break;
|
||||
case 5: /* IMUL EAX,Ed */
|
||||
imul32_eax(emu, ED->dword[0]);
|
||||
emu->regs[_AX].dword[1] = 0;
|
||||
emu->regs[_DX].dword[1] = 0;
|
||||
break;
|
||||
case 6: /* DIV Ed */
|
||||
div32(emu, ED->dword[0]);
|
||||
@@ -1414,13 +1444,11 @@ x64emurun:
|
||||
break;
|
||||
case 0xFA: /* CLI */
|
||||
// this is a privilege opcode...
|
||||
--R_RIP;
|
||||
emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
|
||||
STEP;
|
||||
break;
|
||||
case 0xFB: /* STI */
|
||||
// this is a privilege opcode...
|
||||
--R_RIP;
|
||||
emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
|
||||
STEP;
|
||||
break;
|
||||
@@ -1471,32 +1499,30 @@ x64emurun:
|
||||
break;
|
||||
case 2: /* CALL NEAR Ed */
|
||||
tmp64u = (uintptr_t)getAlternate((void*)ED->q[0]);
|
||||
Push(emu, R_RIP);
|
||||
R_RIP = tmp64u;
|
||||
STEP
|
||||
Push(emu, addr);
|
||||
addr = tmp64u;
|
||||
STEP2
|
||||
break;
|
||||
case 3: /* CALL FAR Ed */
|
||||
if(MODREG) {
|
||||
R_RIP = emu->old_ip;
|
||||
printf_log(LOG_NONE, "Illegal Opcode %p: %02X %02X %02X %02X\n", (void*)R_RIP, opcode, nextop, PK(2), PK(3));
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_ILLEGAL;
|
||||
goto fini;
|
||||
} else {
|
||||
Push(emu, R_CS);
|
||||
Push(emu, R_RIP);
|
||||
R_RIP = (uintptr_t)getAlternate((void*)ED->q[0]); // check CS?
|
||||
Push(emu, addr);
|
||||
R_RIP = addr = (uintptr_t)getAlternate((void*)ED->q[0]); // check CS?
|
||||
R_CS = (ED+1)->word[0];
|
||||
goto fini; // exit loop to recompute new CS...
|
||||
}
|
||||
break;
|
||||
case 4: /* JMP NEAR Ed */
|
||||
R_RIP = (uintptr_t)getAlternate((void*)ED->q[0]);
|
||||
STEP
|
||||
addr = (uintptr_t)getAlternate((void*)ED->q[0]);
|
||||
STEP2
|
||||
break;
|
||||
case 5: /* JMP FAR Ed */
|
||||
if(MODREG) {
|
||||
R_RIP = emu->old_ip;
|
||||
printf_log(LOG_NONE, "Illegal Opcode %p: 0x%02X 0x%02X %02X %02X\n", (void*)R_RIP, opcode, nextop, PK(2), PK(3));
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_ILLEGAL;
|
||||
@@ -1512,7 +1538,6 @@ x64emurun:
|
||||
Push(emu, tmp64u); // avoid potential issue with push [esp+...]
|
||||
break;
|
||||
default:
|
||||
R_RIP = emu->old_ip;
|
||||
printf_log(LOG_NONE, "Illegal Opcode %p: %02X %02X %02X %02X %02X %02X\n",(void*)R_RIP, opcode, nextop, PK(2), PK(3), PK(4), PK(5));
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_ILLEGAL;
|
||||
@@ -1523,18 +1548,19 @@ x64emurun:
|
||||
unimp = 1;
|
||||
goto fini;
|
||||
}
|
||||
R_RIP = addr;
|
||||
}
|
||||
|
||||
|
||||
fini:
|
||||
printf_log(LOG_DEBUG, "End of X86 run (%p), RIP=%p, Stack=%p, unimp=%d, emu->fork=%d, emu->uc_link=%p, emu->quit=%d\n", emu, (void*)R_RIP, (void*)R_RSP, unimp, emu->fork, emu->uc_link, emu->quit);
|
||||
if(unimp) {
|
||||
R_RIP = emu->old_ip;
|
||||
emu->quit = 1;
|
||||
UnimpOpcode(emu);
|
||||
}
|
||||
// fork handling
|
||||
if(emu->fork) {
|
||||
addr = R_RIP;
|
||||
if(step)
|
||||
return 0;
|
||||
int forktype = emu->fork;
|
||||
@@ -1547,6 +1573,7 @@ fini:
|
||||
else if(emu->uc_link) {
|
||||
emu->quit = 0;
|
||||
my_setcontext(emu, emu->uc_link);
|
||||
addr = R_RIP;
|
||||
goto x64emurun;
|
||||
}
|
||||
return 0;
|
||||
|
||||
+92
-61
@@ -28,7 +28,7 @@
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
int Run0F(x64emu_t *emu, rex_t rex)
|
||||
uintptr_t Run0F(x64emu_t *emu, rex_t rex, uintptr_t addr, int *step)
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t nextop;
|
||||
@@ -37,6 +37,7 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
int32_t tmp32s, tmp32s2;
|
||||
uint32_t tmp32u, tmp32u2;
|
||||
uint64_t tmp64u, tmp64u2;
|
||||
int64_t tmp64s;
|
||||
reg64_t *oped, *opgd;
|
||||
sse_regs_t *opex, *opgx, eax1;
|
||||
mmx87_regs_t *opem, *opgm, eam1;
|
||||
@@ -46,18 +47,17 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
switch(opcode) {
|
||||
|
||||
case 0x05: /* SYSCALL */
|
||||
R_RIP = addr;
|
||||
x64Syscall(emu);
|
||||
break;
|
||||
case 0x06: /* CLTS */
|
||||
// this is a privilege opcode...
|
||||
R_RIP-=2;
|
||||
emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
|
||||
break;
|
||||
|
||||
case 0x08: /* INVD */
|
||||
case 0x09: /* WBINVD */
|
||||
// this is a privilege opcode...
|
||||
R_RIP-=2;
|
||||
emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
|
||||
break;
|
||||
|
||||
@@ -73,7 +73,7 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
__builtin_prefetch((void*)ED, 1, 0);
|
||||
break;
|
||||
default: //???
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -159,7 +159,6 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
case 0x22: /* MOV cxR, REG */
|
||||
case 0x23: /* MOV drX, REG */
|
||||
// this is a privilege opcode...
|
||||
R_RIP-=2;
|
||||
emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
|
||||
break;
|
||||
|
||||
@@ -195,32 +194,38 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGM;
|
||||
GM->sd[1] = EX->f[1];
|
||||
GM->sd[0] = EX->f[0];
|
||||
if(isnanf(EX->f[1]) || isinff(EX->f[1]) || EX->f[1]>0x7fffffff)
|
||||
GM->sd[1] = 0x80000000;
|
||||
else
|
||||
GM->sd[1] = EX->f[1];
|
||||
if(isnanf(EX->f[0]) || isinff(EX->f[0]) || EX->f[0]>0x7fffffff)
|
||||
GM->sd[0] = 0x80000000;
|
||||
else
|
||||
GM->sd[0] = EX->f[0];
|
||||
break;
|
||||
case 0x2D: /* CVTPS2PI Gm, Ex */
|
||||
// rounding should be done; and indefinite integer should also be assigned if overflow or NaN/Inf
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGM;
|
||||
switch((emu->mxcsr>>13)&3) {
|
||||
case ROUND_Nearest:
|
||||
GM->sd[1] = floorf(EX->f[1]+0.5f);
|
||||
GM->sd[0] = floorf(EX->f[0]+0.5f);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
GM->sd[1] = floorf(EX->f[1]);
|
||||
GM->sd[0] = floorf(EX->f[0]);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
GM->sd[1] = ceilf(EX->f[1]);
|
||||
GM->sd[0] = ceilf(EX->f[0]);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
GM->sd[1] = EX->f[1];
|
||||
GM->sd[0] = EX->f[0];
|
||||
break;
|
||||
}
|
||||
for(int i=1; i>=0; --i)
|
||||
if(isnanf(EX->f[i]) || isinff(EX->f[i]) || EX->f[i]>0x7fffffff)
|
||||
GM->sd[i] = 0x80000000;
|
||||
else
|
||||
switch(emu->mxcsr.f.MXCSR_RC) {
|
||||
case ROUND_Nearest:
|
||||
GM->sd[i] = nearbyintf(EX->f[i]);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
GM->sd[i] = floorf(EX->f[i]);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
GM->sd[i] = ceilf(EX->f[i]);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
GM->sd[i] = EX->f[i];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x2E: /* UCOMISS Gx, Ex */
|
||||
// same for now
|
||||
@@ -306,8 +311,27 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF0: /* MOVBE Gd, Ed*/
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
if(rex.w)
|
||||
GD->q[0] = __builtin_bswap64(ED->q[0]);
|
||||
else
|
||||
GD->q[0] = __builtin_bswap32(ED->dword[0]);
|
||||
break;
|
||||
case 0xF1: /* MOVBE Ed, Gd*/
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
if(rex.w)
|
||||
ED->q[0] = __builtin_bswap64(GD->q[0]);
|
||||
else
|
||||
ED->q[0] = __builtin_bswap32(GD->dword[0]);
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -333,7 +357,7 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -345,6 +369,7 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
CHECK_FLAGS(emu);
|
||||
, if(rex.w) {GD->q[0] = ED->q[0]; } else {GD->q[0] = ED->dword[0];}
|
||||
, if(!rex.w) GD->dword[1] = 0;
|
||||
,
|
||||
) /* 0x40 -> 0x4F CMOVxx Gd,Ed */ // conditional move, no sign
|
||||
|
||||
case 0x50: /* MOVMSKPS Gd, Ex */
|
||||
@@ -648,7 +673,7 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
for (int i=0; i<4; ++i) EM->uw[i] <<= tmp8u;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 0x72: /* GRP */
|
||||
@@ -674,7 +699,7 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
for (int i=0; i<2; ++i) EM->ud[i] <<= tmp8u;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 0x73: /* GRP */
|
||||
@@ -696,7 +721,7 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
{EM->q <<= tmp8u;}
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 0x74: /* PCMPEQB Gm,Em */
|
||||
@@ -750,14 +775,15 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
break;
|
||||
GOCOND(0x80
|
||||
, tmp32s = F32S; CHECK_FLAGS(emu);
|
||||
, R_RIP += tmp32s;
|
||||
,
|
||||
, addr += tmp32s;
|
||||
,,STEP3
|
||||
) /* 0x80 -> 0x8F Jxx */
|
||||
GOCOND(0x90
|
||||
, nextop = F8; CHECK_FLAGS(emu);
|
||||
GETEB(0);
|
||||
, EB->byte[0]=1;
|
||||
, EB->byte[0]=0;
|
||||
,
|
||||
) /* 0x90 -> 0x9F SETxx Eb */
|
||||
|
||||
case 0xA2: /* CPUID */
|
||||
@@ -812,12 +838,12 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
tmp32s = GD->sdword[0];
|
||||
tmp8u=tmp32s&(rex.w?63:31);
|
||||
tmp32s >>= (rex.w?6:5);
|
||||
tmp64s = rex.w?GD->sq[0]:GD->sdword[0];
|
||||
tmp8u=tmp64s&(rex.w?63:31);
|
||||
tmp64s >>= (rex.w?6:5);
|
||||
if(!MODREG)
|
||||
{
|
||||
ED=(reg64_t*)(((uintptr_t)(ED))+(tmp32s<<(rex.w?3:2)));
|
||||
ED=(reg64_t*)(((uintptr_t)(ED))+(tmp64s<<(rex.w?3:2)));
|
||||
}
|
||||
if(rex.w) {
|
||||
if(ED->q[0] & (1LL<<tmp8u))
|
||||
@@ -855,13 +881,13 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
case 0xAE: /* Grp Ed (SSE) */
|
||||
nextop = F8;
|
||||
if((nextop&0xF8)==0xE8) {
|
||||
return 0; /* LFENCE */
|
||||
return addr; /* LFENCE */
|
||||
}
|
||||
if((nextop&0xF8)==0xF0) {
|
||||
return 0; /* MFENCE */
|
||||
return addr; /* MFENCE */
|
||||
}
|
||||
if((nextop&0xF8)==0xF8) {
|
||||
return 0; /* SFENCE */
|
||||
return addr; /* SFENCE */
|
||||
}
|
||||
GETED(0);
|
||||
switch((nextop>>3)&7) {
|
||||
@@ -878,18 +904,21 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
fpu_fxrstor32(emu, ED);
|
||||
break;
|
||||
case 2: /* LDMXCSR Md */
|
||||
emu->mxcsr = ED->dword[0];
|
||||
emu->mxcsr.x32 = ED->dword[0];
|
||||
if(box64_sse_flushto0)
|
||||
applyFlushTo0(emu);
|
||||
break;
|
||||
case 3: /* STMXCSR Md */
|
||||
ED->dword[0] = emu->mxcsr;
|
||||
ED->dword[0] = emu->mxcsr.x32;
|
||||
break;
|
||||
case 7: /* CLFLUSH Ed */
|
||||
#ifdef DYNAREC
|
||||
cleanDBFromAddressRange((uintptr_t)ED, 8, 0);
|
||||
if(box64_dynarec)
|
||||
cleanDBFromAddressRange((uintptr_t)ED, 8, 0);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 0xAF: /* IMUL Gd,Ed */
|
||||
@@ -925,12 +954,14 @@ 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];
|
||||
R_RAX = R_EAX; // to erase upper part of RAX
|
||||
} else {
|
||||
R_RAX = ED->dword[0];
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -939,12 +970,12 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
tmp32s = GD->sdword[0];
|
||||
tmp8u=tmp32s&(rex.w?63:31);
|
||||
tmp32s >>= (rex.w?6:5);
|
||||
tmp64s = rex.w?GD->sq[0]:GD->sdword[0];
|
||||
tmp8u=tmp64s&(rex.w?63:31);
|
||||
tmp64s >>= (rex.w?6:5);
|
||||
if(!MODREG)
|
||||
{
|
||||
ED=(reg64_t*)(((uintptr_t)(ED))+(tmp32s<<(rex.w?3:2)));
|
||||
ED=(reg64_t*)(((uintptr_t)(ED))+(tmp64s<<(rex.w?3:2)));
|
||||
}
|
||||
if(rex.w) {
|
||||
if(ED->q[0] & (1LL<<tmp8u)) {
|
||||
@@ -1061,7 +1092,7 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 0xBB: /* BTC Ed,Gd */
|
||||
@@ -1069,12 +1100,12 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
tmp32s = GD->sdword[0];
|
||||
tmp8u=tmp32s&(rex.w?63:31);
|
||||
tmp32s >>= (rex.w?6:5);
|
||||
tmp64s = rex.w?GD->sq[0]:GD->sdword[0];
|
||||
tmp8u=tmp64s&(rex.w?63:31);
|
||||
tmp64s >>= (rex.w?6:5);
|
||||
if(!MODREG)
|
||||
{
|
||||
ED=(reg64_t*)(((uintptr_t)(ED))+(tmp32s<<(rex.w?3:2)));
|
||||
ED=(reg64_t*)(((uintptr_t)(ED))+(tmp64s<<(rex.w?3:2)));
|
||||
}
|
||||
if(rex.w) {
|
||||
if(ED->q[0] & (1LL<<tmp8u))
|
||||
@@ -1228,14 +1259,14 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
break;
|
||||
case 0xC4: /* PINSRW Gm,Ew,Ib */
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETED(1);
|
||||
GETGM;
|
||||
tmp8u = F8;
|
||||
GM->uw[tmp8u&3] = ED->word[0]; // only low 16bits
|
||||
break;
|
||||
case 0xC5: /* PEXTRW Gw,Em,Ib */
|
||||
nextop = F8;
|
||||
GETEM(0);
|
||||
GETEM(1);
|
||||
GETGD;
|
||||
tmp8u = F8;
|
||||
GD->q[0] = EM->uw[tmp8u&3]; // 16bits extract, 0 extended
|
||||
@@ -1287,7 +1318,7 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 0xC8:
|
||||
@@ -1350,7 +1381,7 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
nextop = F8;
|
||||
GETEM(0);
|
||||
GETGD;
|
||||
GD->dword[0] = 0;
|
||||
GD->q[0] = 0;
|
||||
for (int i=0; i<8; ++i)
|
||||
if(EM->ub[i]&0x80)
|
||||
GD->dword[0] |= (1<<i);
|
||||
@@ -1429,7 +1460,7 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
GETEM(0);
|
||||
GETGM;
|
||||
if(EM->q>15)
|
||||
tmp8u = 16;
|
||||
tmp8u = 15;
|
||||
else
|
||||
tmp8u = EM->ub[0];
|
||||
for(int i=0; i<4; ++i)
|
||||
@@ -1476,7 +1507,7 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
case 0xE7: /* MOVNTQ Em,Gm */
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0)
|
||||
return 1;
|
||||
return 0;
|
||||
GETEM(0);
|
||||
GETGM;
|
||||
EM->q = GM->q;
|
||||
@@ -1629,7 +1660,7 @@ int Run0F(x64emu_t *emu, rex_t rex)
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
return addr;
|
||||
}
|
||||
+72
-46
@@ -22,7 +22,7 @@
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
int Run64(x64emu_t *emu, rex_t rex, int seg)
|
||||
uintptr_t Run64(x64emu_t *emu, rex_t rex, int seg, uintptr_t addr)
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t nextop;
|
||||
@@ -49,6 +49,10 @@ int Run64(x64emu_t *emu, rex_t rex, int seg)
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
while(opcode>=0x40 && opcode<=0x4f) {
|
||||
rex.rex = opcode;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
switch(opcode) {
|
||||
#define GO(B, OP) \
|
||||
@@ -115,7 +119,7 @@ int Run64(x64emu_t *emu, rex_t rex, int seg)
|
||||
GETEX_OFFS(0, tlsdata);
|
||||
GETGX;
|
||||
GX->q[0] = EX->q[0];
|
||||
if((nextop&0xC0)!=0xC0) {
|
||||
if(!MODREG) {
|
||||
// EX is not a register
|
||||
GX->q[1] = 0;
|
||||
}
|
||||
@@ -125,13 +129,13 @@ int Run64(x64emu_t *emu, rex_t rex, int seg)
|
||||
GETEX_OFFS(0, tlsdata);
|
||||
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;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
@@ -155,11 +159,11 @@ int Run64(x64emu_t *emu, rex_t rex, int seg)
|
||||
EX->ud[0] = GX->ud[0];
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x29: /* MOVAPS Ex,Gx */
|
||||
case 0x29: /* MOVAPS FS:Ex,Gx */
|
||||
switch(rep) {
|
||||
case 0:
|
||||
nextop = F8;
|
||||
@@ -169,13 +173,13 @@ int Run64(x64emu_t *emu, rex_t rex, int seg)
|
||||
EX->q[1] = GX->q[1];
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 0x59:
|
||||
switch(rep) {
|
||||
case 2: /* MULSS Gx, Ex */
|
||||
case 2: /* MULSS Gx, FS:Ex */
|
||||
nextop = F8;
|
||||
GETEX_OFFS(0, tlsdata);
|
||||
GETGX;
|
||||
@@ -183,13 +187,26 @@ int Run64(x64emu_t *emu, rex_t rex, int seg)
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 0x5A:
|
||||
switch(rep) {
|
||||
case 2: /* CVTSS2SD Gx, FS:Ex */
|
||||
nextop = F8;
|
||||
GETEX_OFFS(0, tlsdata);
|
||||
GETGX;
|
||||
GX->d[0] = EX->f[0];
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x6F:
|
||||
switch(rep) {
|
||||
case 2: /* MOVDQU Gx, Ex */
|
||||
case 2: /* MOVDQU Gx, FS:Ex */
|
||||
nextop = F8;
|
||||
GETEX_OFFS(0, tlsdata);
|
||||
GETGX;
|
||||
@@ -197,29 +214,41 @@ int Run64(x64emu_t *emu, rex_t rex, int seg)
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xAF: /* IMUL Gd,Ed */
|
||||
nextop = F8;
|
||||
GETED_OFFS(0, tlsdata);
|
||||
GETGD;
|
||||
if(rex.w)
|
||||
GD->q[0] = imul64(emu, GD->q[0], ED->q[0]);
|
||||
else
|
||||
GD->q[0] = imul32(emu, GD->dword[0], ED->dword[0]);
|
||||
case 0xAF:
|
||||
switch(rep) {
|
||||
case 0: /* IMUL Gd, FS:Ed */
|
||||
nextop = F8;
|
||||
GETED_OFFS(0, tlsdata);
|
||||
GETGD;
|
||||
if(rex.w)
|
||||
GD->q[0] = imul64(emu, GD->q[0], ED->q[0]);
|
||||
else
|
||||
GD->q[0] = imul32(emu, GD->dword[0], ED->dword[0]);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xB6: /* MOVZX Gd,Eb */
|
||||
nextop = F8;
|
||||
GETEB_OFFS(0, tlsdata);
|
||||
GETGD;
|
||||
GD->q[0] = EB->byte[0];
|
||||
case 0xB6:
|
||||
switch(rep) {
|
||||
case 0: /* MOVZX Gd, FS:Eb */
|
||||
nextop = F8;
|
||||
GETEB_OFFS(0, tlsdata);
|
||||
GETGD;
|
||||
GD->q[0] = EB->byte[0];
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -250,7 +279,7 @@ int Run64(x64emu_t *emu, rex_t rex, int seg)
|
||||
break;
|
||||
|
||||
|
||||
case 0x63: /* MOVSXD Gd,Ed */
|
||||
case 0x63: /* MOVSXD Gd, FS:Ed */
|
||||
nextop = F8;
|
||||
GETED_OFFS(0, tlsdata);
|
||||
GETGD;
|
||||
@@ -264,7 +293,7 @@ int Run64(x64emu_t *emu, rex_t rex, int seg)
|
||||
break;
|
||||
|
||||
case 0x66:
|
||||
return Run6664(emu, rex);
|
||||
return Run6664(emu, rex, seg, addr);
|
||||
|
||||
case 0x80: /* GRP Eb,Ib */
|
||||
nextop = F8;
|
||||
@@ -291,7 +320,7 @@ int Run64(x64emu_t *emu, rex_t rex, int seg)
|
||||
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;
|
||||
@@ -329,13 +358,13 @@ int Run64(x64emu_t *emu, rex_t rex, int seg)
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x88: /* MOV Eb,Gb */
|
||||
case 0x88: /* MOV FS:Eb,Gb */
|
||||
nextop = F8;
|
||||
GETEB_OFFS(0, tlsdata);
|
||||
GETGB;
|
||||
EB->byte[0] = GB;
|
||||
break;
|
||||
case 0x89: /* MOV Ed,Gd */
|
||||
case 0x89: /* MOV FS:Ed,Gd */
|
||||
nextop = F8;
|
||||
GETED_OFFS(0, tlsdata);
|
||||
GETGD;
|
||||
@@ -349,13 +378,13 @@ int Run64(x64emu_t *emu, rex_t rex, int seg)
|
||||
ED->dword[0] = GD->dword[0];
|
||||
}
|
||||
break;
|
||||
case 0x8A: /* MOV Gb,Eb */
|
||||
case 0x8A: /* MOV Gb, FS:Eb */
|
||||
nextop = F8;
|
||||
GETEB_OFFS(0, tlsdata);
|
||||
GETGB;
|
||||
GB = EB->byte[0];
|
||||
break;
|
||||
case 0x8B: /* MOV Gd,Ed */
|
||||
case 0x8B: /* MOV Gd, FS:Ed */
|
||||
nextop = F8;
|
||||
GETED_OFFS(0, tlsdata);
|
||||
GETGD;
|
||||
@@ -365,12 +394,12 @@ int Run64(x64emu_t *emu, rex_t rex, int seg)
|
||||
GD->q[0] = ED->dword[0];
|
||||
break;
|
||||
|
||||
case 0xC6: /* MOV Eb,Ib */
|
||||
case 0xC6: /* MOV FS:Eb, Ib */
|
||||
nextop = F8;
|
||||
GETEB_OFFS(1, tlsdata);
|
||||
EB->byte[0] = F8;
|
||||
break;
|
||||
case 0xC7: /* MOV Ed,Id */
|
||||
case 0xC7: /* MOV FS:Ed, Id */
|
||||
nextop = F8;
|
||||
GETED_OFFS(4, tlsdata);
|
||||
if(rex.w)
|
||||
@@ -521,36 +550,34 @@ int Run64(x64emu_t *emu, rex_t rex, int seg)
|
||||
break;
|
||||
case 2: /* CALL NEAR Ed */
|
||||
tmp64u = (uintptr_t)getAlternate((void*)ED->q[0]);
|
||||
Push(emu, R_RIP);
|
||||
R_RIP = tmp64u;
|
||||
Push(emu, addr);
|
||||
addr = tmp64u;
|
||||
break;
|
||||
case 3: /* CALL FAR Ed */
|
||||
if(nextop>0xC0) {
|
||||
R_RIP = emu->old_ip;
|
||||
printf_log(LOG_NONE, "Illegal Opcode %p: %02X %02X %02X %02X\n", (void*)R_RIP, opcode, nextop, PK(2), PK(3));
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_ILLEGAL;
|
||||
return 0;
|
||||
} else {
|
||||
Push16(emu, R_CS);
|
||||
Push(emu, R_RIP);
|
||||
R_RIP = ED->dword[0];
|
||||
Push(emu, addr);
|
||||
R_RIP = addr = ED->dword[0];
|
||||
R_CS = (ED+1)->word[0];
|
||||
return 0; // exit loop to recompute new CS...
|
||||
}
|
||||
break;
|
||||
case 4: /* JMP NEAR Ed */
|
||||
R_RIP = (uintptr_t)getAlternate((void*)ED->q[0]);
|
||||
addr = (uintptr_t)getAlternate((void*)ED->q[0]);
|
||||
break;
|
||||
case 5: /* JMP FAR Ed */
|
||||
if(nextop>0xc0) {
|
||||
R_RIP = emu->old_ip;
|
||||
printf_log(LOG_NONE, "Illegal Opcode %p: 0x%02X 0x%02X %02X %02X\n", (void*)R_RIP, opcode, nextop, PK(2), PK(3));
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_ILLEGAL;
|
||||
return 0;
|
||||
} else {
|
||||
R_RIP = ED->q[0];
|
||||
R_RIP = addr = ED->q[0];
|
||||
R_CS = (ED+1)->word[0];
|
||||
return 0; // exit loop to recompute CS...
|
||||
}
|
||||
@@ -560,7 +587,6 @@ int Run64(x64emu_t *emu, rex_t rex, int seg)
|
||||
Push(emu, tmp64u); // avoid potential issue with push [esp+...]
|
||||
break;
|
||||
default:
|
||||
R_RIP = emu->old_ip;
|
||||
printf_log(LOG_NONE, "Illegal Opcode %p: %02X %02X %02X %02X %02X %02X\n",(void*)R_RIP, opcode, nextop, PK(2), PK(3), PK(4), PK(5));
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_ILLEGAL;
|
||||
@@ -568,7 +594,7 @@ int Run64(x64emu_t *emu, rex_t rex, int seg)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
return addr;
|
||||
}
|
||||
+20
-14
@@ -25,7 +25,7 @@
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
int Run66(x64emu_t *emu, rex_t rex, int rep)
|
||||
uintptr_t Run66(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr)
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t nextop;
|
||||
@@ -105,7 +105,7 @@ int Run66(x64emu_t *emu, rex_t rex, int rep)
|
||||
GO(0x30, xor) /* XOR 0x31 ~> 0x35 */
|
||||
|
||||
case 0x0F: /* more opcdes */
|
||||
return Run660F(emu, rex);
|
||||
return Run660F(emu, rex, addr);
|
||||
|
||||
case 0x39:
|
||||
nextop = F8;
|
||||
@@ -133,7 +133,9 @@ int Run66(x64emu_t *emu, rex_t rex, int rep)
|
||||
break;
|
||||
|
||||
case 0x64: /* FS: */
|
||||
return Run6664(emu, rex);
|
||||
return Run6664(emu, rex, _FS, addr);
|
||||
case 0x65: /* GS: */
|
||||
return Run6664(emu, rex, _GS, addr);
|
||||
|
||||
case 0x69: /* IMUL Gw,Ew,Iw */
|
||||
nextop = F8;
|
||||
@@ -178,8 +180,8 @@ int Run66(x64emu_t *emu, rex_t rex, int rep)
|
||||
case 0x7e:
|
||||
case 0x7f:
|
||||
// just ignore the 66 (and maybe other) prefix and use regular conditional jump
|
||||
R_RIP--;
|
||||
return 0;
|
||||
addr--;
|
||||
return addr;
|
||||
|
||||
case 0x81: /* GRP3 Ew,Iw */
|
||||
case 0x83: /* GRP3 Ew,Ib */
|
||||
@@ -607,19 +609,19 @@ int Run66(x64emu_t *emu, rex_t rex, int rep)
|
||||
break;
|
||||
|
||||
case 0xD9: /* x87 opcdes */
|
||||
return Run66D9(emu, rex);
|
||||
return Run66D9(emu, rex, addr);
|
||||
|
||||
case 0xDD: /* x87 opcdes */
|
||||
return Run66DD(emu, rex);
|
||||
return Run66DD(emu, rex, addr);
|
||||
|
||||
case 0xE8: /* CALL Id */
|
||||
tmp32s = F32S; // call is relative
|
||||
Push(emu, R_RIP);
|
||||
R_RIP += tmp32s;
|
||||
Push(emu, addr);
|
||||
addr += tmp32s;
|
||||
break;
|
||||
|
||||
case 0xF0: /* LOCK: */
|
||||
return Run66F0(emu, rex);
|
||||
return Run66F0(emu, rex, addr);
|
||||
|
||||
case 0xF7: /* GRP3 Ew(,Iw) */
|
||||
nextop = F8;
|
||||
@@ -697,11 +699,15 @@ int Run66(x64emu_t *emu, rex_t rex, int rep)
|
||||
case 1: /* DEC Ed */
|
||||
EW->word[0] = dec16(emu, EW->word[0]);
|
||||
break;
|
||||
/*case 6:
|
||||
case 2: /* CALL NEAR Ed */
|
||||
tmp64u = (uintptr_t)getAlternate((void*)ED->q[0]);
|
||||
Push(emu, addr);
|
||||
addr = tmp64u;
|
||||
break;
|
||||
/*case 6:
|
||||
Push16(emu, EW->word[0]);
|
||||
break;*/
|
||||
default:
|
||||
R_RIP = emu->old_ip;
|
||||
printf_log(LOG_NONE, "Illegal Opcode %p: 66 %02X %02X %02X %02X %02X %02X\n",(void*)R_RIP, opcode, nextop, PK(2), PK(3), PK(4), PK(5));
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_ILLEGAL;
|
||||
@@ -710,7 +716,7 @@ int Run66(x64emu_t *emu, rex_t rex, int rep)
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
return addr;
|
||||
}
|
||||
+179
-83
@@ -43,7 +43,7 @@ static uint8_t ff_mult(uint8_t a, uint8_t b)
|
||||
return retval;
|
||||
}
|
||||
|
||||
int Run660F(x64emu_t *emu, rex_t rex)
|
||||
uintptr_t Run660F(x64emu_t *emu, rex_t rex, uintptr_t addr)
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t nextop;
|
||||
@@ -54,6 +54,7 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
int32_t tmp32s;
|
||||
uint32_t tmp32u;
|
||||
uint64_t tmp64u;
|
||||
int64_t tmp64s;
|
||||
float tmpf;
|
||||
#ifndef NOALIGN
|
||||
int is_nan;
|
||||
@@ -197,10 +198,10 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGM;
|
||||
switch((emu->mxcsr>>13)&3) {
|
||||
switch(emu->mxcsr.f.MXCSR_RC) {
|
||||
case ROUND_Nearest:
|
||||
GM->sd[0] = floor(EX->d[0]+0.5);
|
||||
GM->sd[1] = floor(EX->d[1]+0.5);
|
||||
GM->sd[0] = nearbyint(EX->d[0]);
|
||||
GM->sd[1] = nearbyint(EX->d[1]);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
GM->sd[0] = floor(EX->d[0]);
|
||||
@@ -347,6 +348,16 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x10: /* PBLENDVB Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
for (int i=0; i<16; ++i) {
|
||||
if(emu->xmm[0].ub[i]&0x80)
|
||||
GX->ub[i] = EX->ub[i];
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x14: /* BLENDVPS Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
@@ -477,6 +488,14 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
GX->q[i] = EX->ud[i];
|
||||
break;
|
||||
|
||||
case 0x38: /* PMINSB Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
for(int i=0; i<16; ++i)
|
||||
if(GX->sb[i]>EX->sb[i])
|
||||
GX->sb[i] = EX->sb[i];
|
||||
break;
|
||||
case 0x39: /* PMINSD Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
@@ -490,10 +509,25 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
for(int i=0; i<8; ++i)
|
||||
if(GX->uw[i]<EX->uw[i])
|
||||
if(GX->uw[i]>EX->uw[i])
|
||||
GX->uw[i] = EX->uw[i];
|
||||
break;
|
||||
|
||||
case 0x3B: /* PMINUD Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
for(int i=0; i<4; ++i)
|
||||
if(GX->ud[i]>EX->ud[i])
|
||||
GX->ud[i] = EX->ud[i];
|
||||
break;
|
||||
case 0x3C: /* PMAXSB Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
for(int i=0; i<16; ++i)
|
||||
if(GX->sb[i]<EX->sb[i])
|
||||
GX->sb[i] = EX->sb[i];
|
||||
break;
|
||||
case 0x3D: /* PMAXSD Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
@@ -502,6 +536,22 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
if(GX->sd[i]<EX->sd[i])
|
||||
GX->sd[i] = EX->sd[i];
|
||||
break;
|
||||
case 0x3E: /* PMAXUW Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
for(int i=0; i<8; ++i)
|
||||
if(GX->uw[i]<EX->uw[i])
|
||||
GX->uw[i] = EX->uw[i];
|
||||
break;
|
||||
case 0x3F: /* PMAXUD Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
for(int i=0; i<4; ++i)
|
||||
if(GX->ud[i]<EX->ud[i])
|
||||
GX->ud[i] = EX->ud[i];
|
||||
break;
|
||||
|
||||
case 0xDB: /* AESIMC Gx, Ex */
|
||||
nextop = F8;
|
||||
@@ -606,7 +656,7 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -619,18 +669,18 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
GETGX;
|
||||
tmp8u = F8; // ignoring bit 3 interupt thingy
|
||||
if(tmp8u&4)
|
||||
tmp8u = (emu->mxcsr>>13)&3;
|
||||
tmp8u = emu->mxcsr.f.MXCSR_RC;
|
||||
else
|
||||
tmp8u &= 3;
|
||||
switch(tmp8u) {
|
||||
case ROUND_Nearest:
|
||||
GX->f[0] = floor(EX->f[0]+0.5);
|
||||
GX->f[0] = nearbyintf(EX->f[0]);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
GX->f[0] = floor(EX->f[0]);
|
||||
GX->f[0] = floorf(EX->f[0]);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
GX->f[0] = ceil(EX->f[0]);
|
||||
GX->f[0] = ceilf(EX->f[0]);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
GX->f[0] = EX->f[0];
|
||||
@@ -643,12 +693,12 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
GETGX;
|
||||
tmp8u = F8; // ignoring bit 3 interupt thingy
|
||||
if(tmp8u&4)
|
||||
tmp8u = (emu->mxcsr>>13)&3;
|
||||
tmp8u = emu->mxcsr.f.MXCSR_RC;
|
||||
else
|
||||
tmp8u &= 3;
|
||||
switch(tmp8u) {
|
||||
case ROUND_Nearest:
|
||||
GX->d[0] = floor(EX->d[0]+0.5);
|
||||
GX->d[0] = nearbyint(EX->d[0]);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
GX->d[0] = floor(EX->d[0]);
|
||||
@@ -713,12 +763,12 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
GETGX;
|
||||
tmp8u = F8;
|
||||
ED->dword[0] = GX->ud[tmp8u&3];
|
||||
if(MODREG && rex.w) ED->dword[1] = 0;
|
||||
if(MODREG) ED->dword[1] = 0;
|
||||
break;
|
||||
|
||||
case 0x20: // PINSRB GX, ED, u8
|
||||
nextop = F8;
|
||||
GETED(1);
|
||||
GETED(1); // It's ED, and not EB
|
||||
GETGX;
|
||||
tmp8u = F8;
|
||||
GX->ub[tmp8u&0xf] = ED->byte[0];
|
||||
@@ -758,6 +808,25 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
GX->f[i] = (tmp8u&(1<<i))?tmpf:0.0f;
|
||||
break;
|
||||
|
||||
case 0x44: /* PCLMULQDQ Gx, Ex, Ib */
|
||||
nextop = F8;
|
||||
GETEX(1);
|
||||
GETGX;
|
||||
tmp8u = F8;
|
||||
{
|
||||
int g = (tmp8u&1)?1:0;
|
||||
int e = (tmp8u&0b10000)?1:0;
|
||||
__int128 result = 0;
|
||||
__int128 op2 = EX->q[e];
|
||||
for (int i=0; i<64; ++i)
|
||||
if(GX->q[g]&(1LL<<i))
|
||||
result ^= (op2<<i);
|
||||
|
||||
GX->q[0] = result&0xffffffffffffffffLL;
|
||||
GX->q[1] = (result>>64)&0xffffffffffffffffLL;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xDF: // AESKEYGENASSIST Gx, Ex, u8
|
||||
nextop = F8;
|
||||
GETEX(1);
|
||||
@@ -780,7 +849,7 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -790,14 +859,14 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
GETEW(0);
|
||||
GETGW;
|
||||
, if(rex.w) GW->q[0] = EW->q[0]; else GW->word[0] = EW->word[0];
|
||||
,
|
||||
,,
|
||||
) /* 0x40 -> 0x4F CMOVxx Gw,Ew */ // conditional move, no sign
|
||||
|
||||
case 0x50: /* MOVMSKPD Gd, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGD;
|
||||
GD->dword[0] = 0;
|
||||
GD->q[0] = 0;
|
||||
for(int i=0; i<2; ++i)
|
||||
GD->dword[0] |= ((EX->q[i]>>63)&1)<<i;
|
||||
break;
|
||||
@@ -883,32 +952,24 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
switch((emu->mxcsr>>13)&3) {
|
||||
case ROUND_Nearest:
|
||||
GX->sd[0] = floorf(EX->f[0]+0.5f);
|
||||
GX->sd[1] = floorf(EX->f[1]+0.5f);
|
||||
GX->sd[2] = floorf(EX->f[2]+0.5f);
|
||||
GX->sd[3] = floorf(EX->f[3]+0.5f);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
GX->sd[0] = floorf(EX->f[0]);
|
||||
GX->sd[1] = floorf(EX->f[1]);
|
||||
GX->sd[2] = floorf(EX->f[2]);
|
||||
GX->sd[3] = floorf(EX->f[3]);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
GX->sd[0] = ceilf(EX->f[0]);
|
||||
GX->sd[1] = ceilf(EX->f[1]);
|
||||
GX->sd[2] = ceilf(EX->f[2]);
|
||||
GX->sd[3] = ceilf(EX->f[3]);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
GX->sd[0] = EX->f[0];
|
||||
GX->sd[1] = EX->f[1];
|
||||
GX->sd[2] = EX->f[2];
|
||||
GX->sd[3] = EX->f[3];
|
||||
break;
|
||||
}
|
||||
for(int i=0; i<4; ++i)
|
||||
if(isnanf(EX->f[i]) || isinff(EX->f[i]) || EX->f[i]>0x7fffffff || EX->f[i]<-0x80000000)
|
||||
GX->sd[i] = 0x80000000;
|
||||
else
|
||||
switch(emu->mxcsr.f.MXCSR_RC) {
|
||||
case ROUND_Nearest:
|
||||
GX->sd[i] = nearbyintf(EX->f[i]);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
GX->sd[i] = floorf(EX->f[i]);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
GX->sd[i] = ceilf(EX->f[i]);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
GX->sd[i] = EX->f[i];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x5C: /* SUBPD Gx, Ex */
|
||||
nextop = F8;
|
||||
@@ -1146,6 +1207,7 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
break;
|
||||
case 4: /* PSRAW Ex, Ib */
|
||||
tmp8u = F8;
|
||||
if(tmp8u>15) tmp8u=15;
|
||||
for (int i=0; i<8; ++i) EX->sw[i] >>= tmp8u;
|
||||
break;
|
||||
case 6: /* PSLLW Ex, Ib */
|
||||
@@ -1156,7 +1218,7 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
for (int i=0; i<8; ++i) EX->uw[i] <<= tmp8u;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 0x72: /* GRP */
|
||||
@@ -1172,10 +1234,8 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
break;
|
||||
case 4: /* PSRAD Ex, Ib */
|
||||
tmp8u = F8;
|
||||
if(tmp8u>31) {
|
||||
for (int i=0; i<4; ++i) EX->sd[i] = (EX->sd[i]<0)?-1:0;
|
||||
} else
|
||||
for (int i=0; i<4; ++i) EX->sd[i] >>= tmp8u;
|
||||
if(tmp8u>31) tmp8u=31;
|
||||
for (int i=0; i<4; ++i) EX->sd[i] >>= tmp8u;
|
||||
break;
|
||||
case 6: /* PSLLD Ex, Ib */
|
||||
tmp8u = F8;
|
||||
@@ -1185,7 +1245,7 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
for (int i=0; i<4; ++i) EX->ud[i] <<= tmp8u;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 0x73: /* GRP */
|
||||
@@ -1237,7 +1297,7 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 0x74: /* PCMPEQB Gx,Ex */
|
||||
@@ -1287,7 +1347,31 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7D: /* HSUBPD Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
#ifndef NOALIGN
|
||||
is_nan = isnan(GX->d[0]) || isnan(GX->d[1]);
|
||||
#endif
|
||||
GX->d[0] -= GX->d[1];
|
||||
#ifndef NOALIGN
|
||||
if(!is_nan && isnan(GX->d[0]))
|
||||
GX->d[0] = -NAN;
|
||||
#endif
|
||||
if(EX==GX) {
|
||||
GX->d[1] = GX->d[0];
|
||||
} else {
|
||||
#ifndef NOALIGN
|
||||
is_nan = isnan(EX->d[0]) || isnan(EX->d[1]);
|
||||
#endif
|
||||
GX->d[1] = EX->d[0] - EX->d[1];
|
||||
#ifndef NOALIGN
|
||||
if(!is_nan && isnan(GX->d[1]))
|
||||
GX->d[1] = -NAN;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case 0x7E: /* MOVD Ed, Gx */
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
@@ -1453,13 +1537,19 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
nextop = F8;
|
||||
GETEB(0);
|
||||
GETGW;
|
||||
GW->word[0] = EB->byte[0];
|
||||
if(rex.w)
|
||||
GW->q[0] = EB->byte[0];
|
||||
else
|
||||
GW->word[0] = EB->byte[0];
|
||||
break;
|
||||
case 0xB7: /* MOVZX Gw,Ew */
|
||||
nextop = F8;
|
||||
GETEW(0);
|
||||
GETGW;
|
||||
GW->word[0] = EW->word[0];
|
||||
if(rex.w)
|
||||
GW->q[0] = EW->word[0];
|
||||
else
|
||||
GW->word[0] = EW->word[0];
|
||||
break;
|
||||
|
||||
case 0xBA:
|
||||
@@ -1467,7 +1557,7 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
switch((nextop>>3)&7) {
|
||||
case 4: /* BT Ew,Ib */
|
||||
CHECK_FLAGS(emu);
|
||||
GETEW(0);
|
||||
GETEW(1);
|
||||
GETGW;
|
||||
tmp8u = F8;
|
||||
if(rex.w) {
|
||||
@@ -1486,7 +1576,7 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
break;
|
||||
case 5: /* BTS Ew, Ib */
|
||||
CHECK_FLAGS(emu);
|
||||
GETEW(0);
|
||||
GETEW(1);
|
||||
GETGW;
|
||||
tmp8u = F8;
|
||||
if(rex.w) {
|
||||
@@ -1509,7 +1599,7 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
break;
|
||||
case 6: /* BTR Ew, Ib */
|
||||
CHECK_FLAGS(emu);
|
||||
GETEW(0);
|
||||
GETEW(1);
|
||||
GETGW;
|
||||
tmp8u = F8;
|
||||
if(rex.w) {
|
||||
@@ -1530,7 +1620,7 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
break;
|
||||
case 7: /* BTC Ew, Ib */
|
||||
CHECK_FLAGS(emu);
|
||||
GETEW(0);
|
||||
GETEW(1);
|
||||
GETGW;
|
||||
tmp8u = F8;
|
||||
if(rex.w) {
|
||||
@@ -1550,7 +1640,7 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 0xBB: /* BTC Ew,Gw */
|
||||
@@ -1558,12 +1648,12 @@ 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);
|
||||
tmp64s = rex.w?GW->sq[0]:GW->sword[0];
|
||||
tmp8u=tmp64s&(rex.w?63:15);
|
||||
tmp64s >>= (rex.w?6:4);
|
||||
if(!MODREG)
|
||||
{
|
||||
EW=(reg64_t*)(((uintptr_t)(EW))+(tmp32s<<(rex.w?3:1)));
|
||||
EW=(reg64_t*)(((uintptr_t)(EW))+(tmp64s<<(rex.w?3:1)));
|
||||
}
|
||||
if(rex.w) {
|
||||
if(EW->q[0] & (1LL<<tmp8u))
|
||||
@@ -1690,7 +1780,7 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
GETEX(1);
|
||||
GETGD;
|
||||
tmp8u = F8;
|
||||
GD->dword[0] = EX->uw[tmp8u&7]; // 16bits extract, 0 extended
|
||||
GD->q[0] = EX->uw[tmp8u&7]; // 16bits extract, 0 extended
|
||||
break;
|
||||
case 0xC6: /* SHUFPD Gx, Ex, Ib */
|
||||
nextop = F8;
|
||||
@@ -1718,7 +1808,13 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
emu->regs[tmp8u].word[0] = __builtin_bswap16(emu->regs[tmp8u].word[0]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xD0: /* ADDSUBPD Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
GX->d[0] -= EX->d[0];
|
||||
GX->d[1] += EX->d[1];
|
||||
break;
|
||||
case 0xD1: /* PSRLW Gx, Ex */
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
@@ -1780,7 +1876,7 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
if(EX->ub[i]&0x80)
|
||||
GD->dword[0] |= (1<<i);
|
||||
} else
|
||||
return 1;
|
||||
return 0;
|
||||
break;
|
||||
case 0xD8: /* PSUBUSB Gx,Ex */
|
||||
nextop = F8;
|
||||
@@ -1857,7 +1953,7 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
tmp8u=(EX->q[0]>15)?16:EX->ub[0];
|
||||
tmp8u=(EX->q[0]>15)?15:EX->ub[0];
|
||||
for (int i=0; i<8; ++i)
|
||||
GX->sw[i] >>= tmp8u;
|
||||
break;
|
||||
@@ -1865,13 +1961,9 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
tmp8u=(EX->q[0]>31)?32:EX->ub[0];
|
||||
if(tmp8u>31)
|
||||
for (int i=0; i<4; ++i)
|
||||
GX->sd[i] = (GX->sd[i]<0)?-1:0;
|
||||
else
|
||||
for (int i=0; i<4; ++i)
|
||||
GX->sd[i] >>= tmp8u;
|
||||
tmp8u=(EX->q[0]>31)?31:EX->ub[0];
|
||||
for (int i=0; i<4; ++i)
|
||||
GX->sd[i] >>= tmp8u;
|
||||
break;
|
||||
case 0xE3: /* PAVGW Gx, Ex */
|
||||
nextop = F8;
|
||||
@@ -1902,8 +1994,14 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
GX->sd[0] = EX->d[0];
|
||||
GX->sd[1] = EX->d[1];
|
||||
if(isnan(EX->d[0]) || isinf(EX->d[0]) || EX->d[0]>0x7fffffff)
|
||||
GX->sd[0] = 0x80000000;
|
||||
else
|
||||
GX->sd[0] = EX->d[0];
|
||||
if(isnan(EX->d[1]) || isinf(EX->d[1]) || EX->d[1]>0x7fffffff)
|
||||
GX->sd[1] = 0x80000000;
|
||||
else
|
||||
GX->sd[1] = EX->d[1];
|
||||
GX->q[1] = 0;
|
||||
break;
|
||||
case 0xE7: /* MOVNTDQ Ex, Gx */
|
||||
@@ -1942,10 +2040,8 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
nextop = F8;
|
||||
GETEX(0);
|
||||
GETGX;
|
||||
GX->ud[0] |= EX->ud[0];
|
||||
GX->ud[1] |= EX->ud[1];
|
||||
GX->ud[2] |= EX->ud[2];
|
||||
GX->ud[3] |= EX->ud[3];
|
||||
GX->q[0] |= EX->q[0];
|
||||
GX->q[1] |= EX->q[1];
|
||||
break;
|
||||
case 0xEC: /* PADDSB Gx,Ex */
|
||||
nextop = F8;
|
||||
@@ -2005,7 +2101,7 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
if(EX->q[0]>63)
|
||||
{GX->q[0] = GX->q[1] = 0;}
|
||||
else
|
||||
{tmp8u=EX->q[0]; for (int i=0; i<2; ++i) GX->q[i] <<= tmp8u;}
|
||||
{tmp8u=EX->ub[0]; for (int i=0; i<2; ++i) GX->q[i] <<= tmp8u;}
|
||||
break;
|
||||
case 0xF4: /* PMULUDQ Gx,Ex */
|
||||
nextop = F8;
|
||||
@@ -2099,7 +2195,7 @@ int Run660F(x64emu_t *emu, rex_t rex)
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
return addr;
|
||||
}
|
||||
+32
-5
@@ -22,13 +22,13 @@
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
int Run6664(x64emu_t *emu, rex_t rex)
|
||||
uintptr_t Run6664(x64emu_t *emu, rex_t rex, int seg, uintptr_t addr)
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t nextop;
|
||||
reg64_t *oped, *opgd;
|
||||
sse_regs_t *opex, *opgx;
|
||||
uintptr_t tlsdata = GetFSBaseEmu(emu);
|
||||
uintptr_t tlsdata = GetSegmentBaseEmu(emu, seg);
|
||||
|
||||
opcode = F8;
|
||||
// REX prefix before the F0 are ignored
|
||||
@@ -43,6 +43,33 @@ int Run6664(x64emu_t *emu, rex_t rex)
|
||||
case 0x0F:
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
|
||||
case 0x11: /* MOVUPD Ex, Gx */
|
||||
nextop = F8;
|
||||
GETEX_OFFS(0, tlsdata);
|
||||
GETGX;
|
||||
memcpy(EX, GX, 16); // unaligned...
|
||||
break;
|
||||
|
||||
case 0x2E: /* UCOMISD Gx, Ex */
|
||||
// no special check...
|
||||
case 0x2F: /* COMISD Gx, Ex */
|
||||
RESET_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GETEX_OFFS(0, tlsdata);
|
||||
GETGX;
|
||||
if(isnan(GX->d[0]) || isnan(EX->d[0])) {
|
||||
SET_FLAG(F_ZF); SET_FLAG(F_PF); SET_FLAG(F_CF);
|
||||
} else if(isgreater(GX->d[0], EX->d[0])) {
|
||||
CLEAR_FLAG(F_ZF); CLEAR_FLAG(F_PF); CLEAR_FLAG(F_CF);
|
||||
} else if(isless(GX->d[0], EX->d[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;
|
||||
|
||||
case 0xD6: /* MOVQ Ex,Gx */
|
||||
nextop = F8;
|
||||
GETEX_OFFS(0, tlsdata);
|
||||
@@ -53,7 +80,7 @@ int Run6664(x64emu_t *emu, rex_t rex)
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -78,7 +105,7 @@ int Run6664(x64emu_t *emu, rex_t rex)
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
return addr;
|
||||
}
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
int Run66D9(x64emu_t *emu, rex_t rex)
|
||||
uintptr_t Run66D9(x64emu_t *emu, rex_t rex, uintptr_t addr)
|
||||
{
|
||||
uint8_t nextop;
|
||||
reg64_t *oped;
|
||||
@@ -73,7 +73,7 @@ int Run66D9(x64emu_t *emu, rex_t rex)
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
return 1;
|
||||
return 0;
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 4: /* FLDENV m */
|
||||
@@ -87,8 +87,8 @@ int Run66D9(x64emu_t *emu, rex_t rex)
|
||||
fpu_savenv(emu, (char*)ED, 1);
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return addr;
|
||||
}
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
int Run66DD(x64emu_t *emu, rex_t rex)
|
||||
uintptr_t Run66DD(x64emu_t *emu, rex_t rex, uintptr_t addr)
|
||||
{
|
||||
uint8_t nextop;
|
||||
reg64_t *oped;
|
||||
@@ -73,7 +73,7 @@ int Run66DD(x64emu_t *emu, rex_t rex)
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
return 1;
|
||||
return 0;
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 4: /* FRSTOR m94byte */
|
||||
@@ -105,8 +105,8 @@ int Run66DD(x64emu_t *emu, rex_t rex)
|
||||
reset_fpu(emu);
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return addr;
|
||||
}
|
||||
+53
-16
@@ -25,7 +25,7 @@
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
int Run66F0(x64emu_t *emu, rex_t rex)
|
||||
uintptr_t Run66F0(x64emu_t *emu, rex_t rex, uintptr_t addr)
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t nextop;
|
||||
@@ -43,7 +43,7 @@ int Run66F0(x64emu_t *emu, rex_t rex)
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
if(rex.w) return RunF0(emu, rex);
|
||||
if(rex.w) return RunF0(emu, rex, addr);
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
@@ -78,8 +78,50 @@ int Run66F0(x64emu_t *emu, rex_t rex)
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0xC1: /* XADD Gw,Ew */
|
||||
nextop = F8;
|
||||
GETEW(0);
|
||||
GETGW;
|
||||
#ifdef DYNAREC
|
||||
if(rex.w) {
|
||||
do {
|
||||
tmp64u = native_lock_read_dd(ED);
|
||||
tmp64u2 = add64(emu, tmp64u, GD->q[0]);
|
||||
} while(native_lock_write_dd(ED, tmp64u2));
|
||||
GD->q[0] = tmp64u;
|
||||
} else {
|
||||
if(((uintptr_t)ED)&1) {
|
||||
do {
|
||||
tmp16u = ED->word[0] & ~0xff;
|
||||
tmp16u |= native_lock_read_h(ED);
|
||||
tmp16u2 = add16(emu, tmp16u, GD->word[0]);
|
||||
} while(native_lock_write_h(ED, tmp16u2&0xff));
|
||||
ED->word[0] = tmp16u2;
|
||||
} else {
|
||||
do {
|
||||
tmp16u = native_lock_read_h(ED);
|
||||
tmp16u2 = add16(emu, tmp16u, GD->word[0]);
|
||||
} while(native_lock_write_h(ED, tmp16u2));
|
||||
}
|
||||
GD->word[0] = tmp16u;
|
||||
}
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
if(rex.w) {
|
||||
tmp64u = add64(emu, ED->q[0], GD->q[0]);
|
||||
GD->q[0] = ED->q[0];
|
||||
ED->q[0] = tmp64u;
|
||||
} else {
|
||||
tmp16u = add16(emu, ED->word[0], GD->word[0]);
|
||||
GD->word[0] = ED->word[0];
|
||||
ED->word[0] = tmp16u;
|
||||
}
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -91,16 +133,14 @@ int Run66F0(x64emu_t *emu, rex_t rex)
|
||||
GETGW; \
|
||||
if(rex.w) { \
|
||||
do { \
|
||||
tmp64u = native_lock_read_dd(ED); \
|
||||
tmp64u = native_lock_read_dd(ED); \
|
||||
tmp64u = OP##64(emu, tmp64u, GD->q[0]); \
|
||||
} while (native_lock_write_dd(ED, tmp64u)); \
|
||||
} while (native_lock_write_dd(ED, tmp64u)); \
|
||||
} else { \
|
||||
do { \
|
||||
tmp16u = native_lock_read_h(ED); \
|
||||
tmp16u = native_lock_read_h(ED); \
|
||||
tmp16u = OP##16(emu, tmp16u, GW->word[0]); \
|
||||
} while (native_lock_write_d(ED, tmp16u)); \
|
||||
if(MODREG) \
|
||||
EW->word[1] = 0; \
|
||||
} while (native_lock_write_h(ED, tmp16u)); \
|
||||
} \
|
||||
break; \
|
||||
case B+3: \
|
||||
@@ -128,10 +168,7 @@ int Run66F0(x64emu_t *emu, rex_t rex)
|
||||
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 \
|
||||
EW->word[0] = OP##16(emu, EW->word[0], GW->word[0]); \
|
||||
EW->word[0] = OP##16(emu, EW->word[0], GW->word[0]);\
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock); \
|
||||
break; \
|
||||
case B+3: \
|
||||
@@ -236,7 +273,7 @@ int Run66F0(x64emu_t *emu, rex_t rex)
|
||||
tmp16u &=~0xff;
|
||||
tmp16u |= native_lock_read_b(ED);
|
||||
tmp16u = inc16(emu, tmp16u);
|
||||
} while(native_lock_write_b(ED, tmp16u&0xff));
|
||||
} while(native_lock_write_b(ED, tmp16u&0xff));
|
||||
ED->word[0] = tmp16u;
|
||||
} else {
|
||||
do {
|
||||
@@ -293,7 +330,7 @@ int Run66F0(x64emu_t *emu, rex_t rex)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
return addr;
|
||||
}
|
||||
+115
-15
@@ -22,7 +22,7 @@
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
int Run67(x64emu_t *emu, rex_t rex, int rep)
|
||||
uintptr_t Run67(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr)
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t nextop;
|
||||
@@ -98,16 +98,55 @@ int Run67(x64emu_t *emu, rex_t rex, int rep)
|
||||
GO(0x00, add) /* ADD 0x00 -> 0x05 */
|
||||
GO(0x08, or) /* OR 0x08 -> 0x0D */
|
||||
case 0x0F:
|
||||
return Run670F(emu, rex, rep);
|
||||
return Run670F(emu, rex, rep, addr);
|
||||
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 0x38:
|
||||
nextop = F8;
|
||||
GETEB32(0);
|
||||
GETGB;
|
||||
cmp8(emu, EB->byte[0], GB);
|
||||
break;
|
||||
case 0x39:
|
||||
nextop = F8;
|
||||
GETED32(0);
|
||||
GETGD;
|
||||
if(rex.w)
|
||||
cmp64(emu, ED->q[0], GD->q[0]);
|
||||
else
|
||||
cmp32(emu, ED->dword[0], GD->dword[0]);
|
||||
break;
|
||||
case 0x3A:
|
||||
nextop = F8;
|
||||
GETEB32(0);
|
||||
GETGB;
|
||||
cmp8(emu, GB, EB->byte[0]);
|
||||
break;
|
||||
case 0x3B:
|
||||
nextop = F8;
|
||||
GETED32(0);
|
||||
GETGD;
|
||||
if(rex.w)
|
||||
cmp64(emu, GD->q[0], ED->q[0]);
|
||||
else
|
||||
cmp32(emu, GD->dword[0], ED->dword[0]);
|
||||
break;
|
||||
case 0x3C:
|
||||
R_AL = cmp8(emu, R_AL, F8);
|
||||
break;
|
||||
case 0x3D:
|
||||
if(rex.w)
|
||||
cmp64(emu, R_RAX, F32S64);
|
||||
else
|
||||
cmp32(emu, R_EAX, F32);
|
||||
break;
|
||||
|
||||
case 0x66:
|
||||
return Run6766(emu, rex, rep);
|
||||
return Run6766(emu, rex, rep, addr);
|
||||
|
||||
case 0x80: /* GRP Eb,Ib */
|
||||
nextop = F8;
|
||||
@@ -124,6 +163,53 @@ int Run67(x64emu_t *emu, rex_t rex, int rep)
|
||||
case 7: cmp8(emu, EB->byte[0], tmp8u); break;
|
||||
}
|
||||
break;
|
||||
case 0x81: /* GRP Ed,Id */
|
||||
case 0x83: /* GRP Ed,Ib */
|
||||
nextop = F8;
|
||||
GETED32((opcode==0x81)?4:1);
|
||||
if(opcode==0x81) {
|
||||
tmp32s = F32S;
|
||||
} else {
|
||||
tmp32s = F8S;
|
||||
}
|
||||
if(rex.w) {
|
||||
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;
|
||||
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 {
|
||||
tmp32u = (uint32_t)tmp32s;
|
||||
if(MODREG)
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: ED->q[0] = add32(emu, ED->dword[0], tmp32u); break;
|
||||
case 1: ED->q[0] = or32(emu, ED->dword[0], tmp32u); break;
|
||||
case 2: ED->q[0] = adc32(emu, ED->dword[0], tmp32u); break;
|
||||
case 3: ED->q[0] = sbb32(emu, ED->dword[0], tmp32u); break;
|
||||
case 4: ED->q[0] = and32(emu, ED->dword[0], tmp32u); break;
|
||||
case 5: ED->q[0] = sub32(emu, ED->dword[0], tmp32u); break;
|
||||
case 6: ED->q[0] = xor32(emu, ED->dword[0], tmp32u); break;
|
||||
case 7: cmp32(emu, ED->dword[0], tmp32u); break;
|
||||
}
|
||||
else
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: ED->dword[0] = add32(emu, ED->dword[0], tmp32u); break;
|
||||
case 1: ED->dword[0] = or32(emu, ED->dword[0], tmp32u); break;
|
||||
case 2: ED->dword[0] = adc32(emu, ED->dword[0], tmp32u); break;
|
||||
case 3: ED->dword[0] = sbb32(emu, ED->dword[0], tmp32u); break;
|
||||
case 4: ED->dword[0] = and32(emu, ED->dword[0], tmp32u); break;
|
||||
case 5: ED->dword[0] = sub32(emu, ED->dword[0], tmp32u); break;
|
||||
case 6: ED->dword[0] = xor32(emu, ED->dword[0], tmp32u); break;
|
||||
case 7: cmp32(emu, ED->dword[0], tmp32u); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x88: /* MOV Eb,Gb */
|
||||
nextop = F8;
|
||||
@@ -212,36 +298,48 @@ int Run67(x64emu_t *emu, rex_t rex, int rep)
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC7: /* MOV Ed,Id */
|
||||
nextop = F8;
|
||||
GETED32(4);
|
||||
if(rex.w)
|
||||
ED->q[0] = F32S64;
|
||||
else
|
||||
if(MODREG)
|
||||
ED->q[0] = F32;
|
||||
else
|
||||
ED->dword[0] = F32;
|
||||
break;
|
||||
|
||||
case 0xE0: /* LOOPNZ */
|
||||
CHECK_FLAGS(emu);
|
||||
tmp8s = F8S;
|
||||
--R_ECX; // don't update flags
|
||||
if(R_ECX && !ACCESS_FLAG(F_ZF))
|
||||
R_RIP += tmp8s;
|
||||
addr += tmp8s;
|
||||
break;
|
||||
case 0xE1: /* LOOPZ */
|
||||
CHECK_FLAGS(emu);
|
||||
tmp8s = F8S;
|
||||
--R_ECX; // don't update flags
|
||||
if(R_ECX && ACCESS_FLAG(F_ZF))
|
||||
R_RIP += tmp8s;
|
||||
addr += tmp8s;
|
||||
break;
|
||||
case 0xE2: /* LOOP */
|
||||
tmp8s = F8S;
|
||||
--R_ECX; // don't update flags
|
||||
if(R_ECX)
|
||||
R_RIP += tmp8s;
|
||||
addr += tmp8s;
|
||||
break;
|
||||
case 0xE3: /* JECXZ Ib */
|
||||
tmp8s = F8S;
|
||||
if(!R_ECX)
|
||||
R_RIP += tmp8s;
|
||||
addr += tmp8s;
|
||||
break;
|
||||
|
||||
case 0xE8: /* CALL Id */
|
||||
tmp32s = F32S; // call is relative
|
||||
Push(emu, R_RIP);
|
||||
R_RIP += tmp32s;
|
||||
Push(emu, addr);
|
||||
addr += tmp32s;
|
||||
break;
|
||||
|
||||
case 0xF7: /* GRP3 Ed(,Id) */
|
||||
@@ -296,27 +394,29 @@ int Run67(x64emu_t *emu, rex_t rex, int rep)
|
||||
case 4: /* MUL EAX,Ed */
|
||||
mul32_eax(emu, ED->dword[0]);
|
||||
emu->regs[_AX].dword[1] = 0;
|
||||
emu->regs[_DX].dword[1] = 0;
|
||||
break;
|
||||
case 5: /* IMUL EAX,Ed */
|
||||
imul32_eax(emu, ED->dword[0]);
|
||||
emu->regs[_AX].dword[1] = 0;
|
||||
emu->regs[_DX].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;
|
||||
//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;
|
||||
//emu->regs[_AX].dword[1] = 0;
|
||||
//emu->regs[_DX].dword[1] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
return addr;
|
||||
}
|
||||
+59
-31
@@ -19,13 +19,14 @@
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
#include "bridge.h"
|
||||
#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/native_lock.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
int Run670F(x64emu_t *emu, rex_t rex, int rep)
|
||||
uintptr_t Run670F(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr)
|
||||
{
|
||||
(void)rep;
|
||||
uint8_t opcode;
|
||||
@@ -43,44 +44,71 @@ int Run670F(x64emu_t *emu, rex_t rex, int rep)
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x2E: /* UCOMISS Gx, Ex */
|
||||
case 0x2E:
|
||||
// same for now
|
||||
case 0x2F: /* COMISS Gx, Ex */
|
||||
if(rep) {
|
||||
return 1;
|
||||
case 0x2F:
|
||||
switch(rep) {
|
||||
case 0: /* (U)COMISS Gx, Ex */
|
||||
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 0;
|
||||
}
|
||||
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;
|
||||
|
||||
case 0x6F: /* MOVQ Gm, Em */
|
||||
nextop = F8;
|
||||
GETEM32(0);
|
||||
GETGM;
|
||||
GM->q = EM->q;
|
||||
case 0x6F:
|
||||
switch(rep) {
|
||||
case 0: /* MOVQ Gm, Em */
|
||||
nextop = F8;
|
||||
GETEM32(0);
|
||||
GETGM;
|
||||
GM->q = EM->q;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7F: /* MOVQ Em, Gm */
|
||||
nextop = F8;
|
||||
GETEM32(0);
|
||||
GETGM;
|
||||
EM->q = GM->q;
|
||||
case 0x7F:
|
||||
switch(rep) {
|
||||
case 0: /* MOVQ Em, Gm */
|
||||
nextop = F8;
|
||||
GETEM32(0);
|
||||
GETGM;
|
||||
EM->q = GM->q;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xB9:
|
||||
switch(rep) {
|
||||
case 0: /* UD1 Ed */
|
||||
nextop = F8;
|
||||
GETED32(0);
|
||||
emit_signal(emu, SIGILL, (void*)R_RIP, 0);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
return addr;
|
||||
}
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
int Run6766(x64emu_t *emu, rex_t rex, int rep)
|
||||
uintptr_t Run6766(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr)
|
||||
{
|
||||
// Hmmmm....
|
||||
(void)rep;
|
||||
@@ -59,10 +59,10 @@ int Run6766(x64emu_t *emu, rex_t rex, int rep)
|
||||
switch(opcode) {
|
||||
|
||||
case 0x0F: /* more opcodes */
|
||||
return Run67660F(emu, rex);
|
||||
return Run67660F(emu, rex, addr);
|
||||
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
return addr;
|
||||
}
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
int Run67660F(x64emu_t *emu, rex_t rex)
|
||||
uintptr_t Run67660F(x64emu_t *emu, rex_t rex, uintptr_t addr)
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t nextop;
|
||||
@@ -58,7 +58,7 @@ int Run67660F(x64emu_t *emu, rex_t rex)
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
return addr;
|
||||
}
|
||||
+141
-63
@@ -48,7 +48,10 @@ int32_t EXPORT my___libc_start_main(x64emu_t* emu, int *(main) (int, char * *, c
|
||||
SetRSP(emu, GetRBP(emu)); // restore RSP
|
||||
SetRBP(emu, Pop64(emu)); // restore RBP
|
||||
emu->quit = 0;
|
||||
} else {
|
||||
RunElfInit(my_context->elfs[0], emu);
|
||||
}
|
||||
MarkElfInitDone(my_context->elfs[0]);
|
||||
printf_log(LOG_DEBUG, "Transfert to main(%d, %p, %p)=>%p from __libc_start_main\n", my_context->argc, my_context->argv, my_context->envv, main);
|
||||
// call main and finish
|
||||
Push64(emu, GetRBP(emu)); // set frame pointer
|
||||
@@ -67,7 +70,7 @@ int32_t EXPORT my___libc_start_main(x64emu_t* emu, int *(main) (int, char * *, c
|
||||
SetRBP(emu, Pop64(emu)); // restore RBP
|
||||
emu->quit = 1; // finished!
|
||||
}
|
||||
return 0;
|
||||
return (int)GetEAX(emu);
|
||||
}
|
||||
|
||||
const char* GetNativeName(void* p)
|
||||
@@ -152,7 +155,7 @@ void UpdateFlags(x64emu_t *emu)
|
||||
case d_add64:
|
||||
lo = (emu->op2.u64 & 0xFFFFFFFF) + (emu->op1.u64 & 0xFFFFFFFF);
|
||||
hi = (lo >> 32) + (emu->op2.u64 >> 32) + (emu->op1.u64 >> 32);
|
||||
CONDITIONAL_SET_FLAG(hi & 0x100000000, F_CF);
|
||||
CONDITIONAL_SET_FLAG(hi & 0x100000000L, F_CF);
|
||||
CONDITIONAL_SET_FLAG(!emu->res.u64, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(emu->res.u64 & 0x8000000000000000LL, F_SF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res.u64 & 0xff), F_PF);
|
||||
@@ -834,7 +837,7 @@ void UpdateFlags(x64emu_t *emu)
|
||||
lo = 1 + (emu->op1.u64 & 0xFFFFFFFF) + (emu->op2.u64 & 0xFFFFFFFF);
|
||||
}
|
||||
hi = (lo >> 32) + (emu->op1.u64 >> 32) + (emu->op2.u64 >> 32);
|
||||
CONDITIONAL_SET_FLAG(hi & 0x1000000000000L, F_CF);
|
||||
CONDITIONAL_SET_FLAG(hi & 0x100000000L, F_CF);
|
||||
CONDITIONAL_SET_FLAG(!emu->res.u64, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(emu->res.u64 & 0x8000000000000000LL, F_SF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res.u64 & 0xff), F_PF);
|
||||
@@ -938,6 +941,33 @@ void UpdateFlags(x64emu_t *emu)
|
||||
case d_unknown:
|
||||
printf_log(LOG_NONE, "Box64: %p trying to evaluate Unknown defered Flags\n", (void*)R_RIP);
|
||||
break;
|
||||
|
||||
case d_dec8i:
|
||||
case d_dec16i:
|
||||
case d_dec32i:
|
||||
case d_dec64i:
|
||||
case d_inc8i:
|
||||
case d_inc16i:
|
||||
case d_inc32i:
|
||||
case d_inc64i:
|
||||
{
|
||||
defered_flags_t df = emu->df - (d_dec8i - d_dec8);
|
||||
if(emu->df_sav!=d_none) {
|
||||
// compute CF
|
||||
multiuint_t op1 = emu->op1;
|
||||
multiuint_t res = emu->res;
|
||||
emu->df = emu->df_sav;
|
||||
emu->op1 = emu->op1_sav;
|
||||
emu->res = emu->res_sav;
|
||||
emu->df_sav = d_none;
|
||||
UpdateFlags(emu);
|
||||
emu->op1 = op1;
|
||||
emu->res = res;
|
||||
}
|
||||
emu->df = df;
|
||||
}
|
||||
UpdateFlags(emu);
|
||||
break;
|
||||
}
|
||||
RESET_FLAGS(emu);
|
||||
}
|
||||
@@ -959,9 +989,10 @@ const char* getAddrFunctionName(uintptr_t addr)
|
||||
uintptr_t start = 0;
|
||||
elfheader_t* elf = FindElfAddress(my_context, addr);
|
||||
const char* symbname = FindNearestSymbolName(elf, (void*)addr, &start, &sz);
|
||||
if(!sz) sz=0x100; // arbitrary value...
|
||||
if(symbname && addr>=start && (addr<(start+sz) || !sz)) {
|
||||
if(symbname[0]=='\0')
|
||||
sprintf(ret, "%s + 0x%lx", ElfName(elf), addr - (uintptr_t)GetBaseAddress(elf));
|
||||
sprintf(ret, "%s + 0x%lx + 0x%lx", ElfName(elf), start - (uintptr_t)GetBaseAddress(elf), addr - start);
|
||||
else if(addr==start)
|
||||
sprintf(ret, "%s/%s", ElfName(elf), symbname);
|
||||
else
|
||||
@@ -980,6 +1011,7 @@ void printFunctionAddr(uintptr_t nextaddr, const char* text)
|
||||
uint64_t sz = 0;
|
||||
uintptr_t start = 0;
|
||||
const char* symbname = FindNearestSymbolName(FindElfAddress(my_context, nextaddr), (void*)nextaddr, &start, &sz);
|
||||
if(!sz) sz=0x100; // arbitrary value...
|
||||
if(symbname && nextaddr>=start && (nextaddr<(start+sz) || !sz)) {
|
||||
if(nextaddr==start)
|
||||
printf_log(LOG_NONE, " (%s%s:%s)", text, ElfName(FindElfAddress(my_context, nextaddr)), symbname);
|
||||
@@ -1001,7 +1033,7 @@ void PrintTrace(x64emu_t* emu, uintptr_t ip, int dynarec)
|
||||
(trace_end == 0)
|
||||
|| ((ip >= trace_start) && (ip < trace_end))) ) {
|
||||
int tid = syscall(SYS_gettid);
|
||||
pthread_mutex_lock(&my_context->mutex_trace);
|
||||
mutex_lock(&my_context->mutex_trace);
|
||||
#ifdef DYNAREC
|
||||
if((my_context->trace_tid != tid) || (my_context->trace_dynarec!=dynarec)) {
|
||||
printf_log(LOG_NONE, "Thread %04d| (%s) |\n", tid, dynarec?"dyn":"int");
|
||||
@@ -1018,7 +1050,7 @@ void PrintTrace(x64emu_t* emu, uintptr_t ip, int dynarec)
|
||||
printf_log(LOG_NONE, "%s", DumpCPURegs(emu, ip));
|
||||
if(R_RIP==0) {
|
||||
printf_log(LOG_NONE, "Running at NULL address\n");
|
||||
pthread_mutex_unlock(&my_context->mutex_trace);
|
||||
mutex_unlock(&my_context->mutex_trace);
|
||||
return;
|
||||
}
|
||||
if(PK(0)==0xcc && PK(1)=='S' && PK(2)=='C') {
|
||||
@@ -1031,12 +1063,22 @@ void PrintTrace(x64emu_t* emu, uintptr_t ip, int dynarec)
|
||||
} else {
|
||||
printf_log(LOG_NONE, "%s", DecodeX64Trace(my_context->dec, ip));
|
||||
uint8_t peek = PK(0);
|
||||
rex_t rex = {0};
|
||||
if(peek>=0x40 && peek<=0x4f) {
|
||||
rex.rex = peek;
|
||||
ip++;
|
||||
peek = PK(0);
|
||||
}
|
||||
if(peek==0xC3 || peek==0xC2 || (peek==0xF3 && PK(1)==0xC3)) {
|
||||
printf_log(LOG_NONE, " => %p", *(void**)(R_RSP));
|
||||
printFunctionAddr(*(uintptr_t*)(R_RSP), "=> ");
|
||||
} else if(peek==0x55 || peek==0x53) {
|
||||
} else if(peek==0x57 && rex.b) {
|
||||
printf_log(LOG_NONE, " => STACK_TOP: %p", *(void**)(R_RSP));
|
||||
printFunctionAddr(ip, "here: ");
|
||||
} else if(peek==0x55 || peek==0x53) {
|
||||
printFunctionAddr(*(uintptr_t*)(R_RSP), " STACK_TOP: ");
|
||||
} else if(peek==0xF3 && PK(1)==0x0F && PK(2)==0x1E && PK(3)==0xFA) {
|
||||
printFunctionAddr(*(uintptr_t*)(R_RSP), " STACK_TOP: ");
|
||||
} else if(peek==0xE8) { // Call
|
||||
uintptr_t nextaddr = ip + 5 + PK64(1);
|
||||
printFunctionAddr(nextaddr, "=> ");
|
||||
@@ -1048,92 +1090,128 @@ void PrintTrace(x64emu_t* emu, uintptr_t ip, int dynarec)
|
||||
}
|
||||
printf_log(LOG_NONE, "\n");
|
||||
}
|
||||
pthread_mutex_unlock(&my_context->mutex_trace);
|
||||
mutex_unlock(&my_context->mutex_trace);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
reg64_t* GetECommon(x64emu_t* emu, rex_t rex, uint8_t m, uint8_t delta)
|
||||
static uint8_t F8(uintptr_t* addr) {
|
||||
uint8_t ret = *(uint8_t*)*addr;
|
||||
*addr+=1;
|
||||
return ret;
|
||||
}
|
||||
static int8_t F8S(uintptr_t* addr) {
|
||||
int8_t ret = *(int8_t*)*addr;
|
||||
*addr+=1;
|
||||
return ret;
|
||||
}
|
||||
static uint16_t F16(uintptr_t* addr) {
|
||||
uint16_t ret = *(uint16_t*)*addr;
|
||||
*addr+=2;
|
||||
return ret;
|
||||
}
|
||||
static int16_t F16S(uintptr_t* addr) {
|
||||
int16_t ret = *(int16_t*)*addr;
|
||||
*addr+=2;
|
||||
return ret;
|
||||
}
|
||||
static uint32_t F32(uintptr_t* addr) {
|
||||
uint32_t ret = *(uint32_t*)*addr;
|
||||
*addr+=4;
|
||||
return ret;
|
||||
}
|
||||
static int32_t F32S(uintptr_t* addr) {
|
||||
int32_t ret = *(int32_t*)*addr;
|
||||
*addr+=4;
|
||||
return ret;
|
||||
}
|
||||
static uint64_t F64(uintptr_t* addr) {
|
||||
uint64_t ret = *(uint64_t*)*addr;
|
||||
*addr+=8;
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg64_t* GetECommon(x64emu_t* emu, uintptr_t* addr, rex_t rex, uint8_t m, uint8_t delta)
|
||||
{
|
||||
if (m<=7) {
|
||||
if(m==0x4) {
|
||||
uint8_t sib = Fetch8(emu);
|
||||
uintptr_t base = ((sib&0x7)==5)?((uint64_t)(int64_t)Fetch32s(emu)):(emu->regs[(sib&0x7)+(rex.b<<3)].q[0]); // base
|
||||
uint8_t sib = F8(addr);
|
||||
uintptr_t base = ((sib&0x7)==5)?((uint64_t)(int64_t)F32S(addr)):(emu->regs[(sib&0x7)+(rex.b<<3)].q[0]); // base
|
||||
base += (emu->sbiidx[((sib>>3)&7)+(rex.x<<3)]->sq[0] << (sib>>6));
|
||||
return (reg64_t*)base;
|
||||
} else if (m==0x5) { //disp32
|
||||
int32_t base = Fetch32s(emu);
|
||||
return (reg64_t*)(base+R_RIP+delta);
|
||||
int32_t base = F32S(addr);
|
||||
return (reg64_t*)(base+*addr+delta);
|
||||
}
|
||||
return (reg64_t*)(emu->regs[m+(rex.b<<3)].q[0]);
|
||||
} else {
|
||||
uintptr_t base;
|
||||
if((m&7)==4) {
|
||||
uint8_t sib = Fetch8(emu);
|
||||
uint8_t sib = F8(addr);
|
||||
base = emu->regs[(sib&0x7)+(rex.b<<3)].q[0]; // base
|
||||
base += (emu->sbiidx[((sib>>3)&7)+(rex.x<<3)]->sq[0] << (sib>>6));
|
||||
} else {
|
||||
base = emu->regs[(m&0x7)+(rex.b<<3)].q[0];
|
||||
}
|
||||
base+=(m&0x80)?Fetch32s(emu):Fetch8s(emu);
|
||||
base+=(m&0x80)?F32S(addr):F8S(addr);
|
||||
return (reg64_t*)base;
|
||||
}
|
||||
}
|
||||
|
||||
reg64_t* GetECommonO(x64emu_t* emu, rex_t rex, uint8_t m, uint8_t delta, uintptr_t base)
|
||||
reg64_t* GetECommonO(x64emu_t* emu, uintptr_t* addr, rex_t rex, uint8_t m, uint8_t delta, uintptr_t base)
|
||||
{
|
||||
if (m<=7) {
|
||||
if(m==0x4) {
|
||||
uint8_t sib = Fetch8(emu);
|
||||
base += ((sib&0x7)==5)?((uint64_t)(int64_t)Fetch32s(emu)):(emu->regs[(sib&0x7)+(rex.b<<3)].q[0]); // base
|
||||
uint8_t sib = F8(addr);
|
||||
base += ((sib&0x7)==5)?((uint64_t)(int64_t)F32S(addr)):(emu->regs[(sib&0x7)+(rex.b<<3)].q[0]); // base
|
||||
base += (emu->sbiidx[((sib>>3)&7)+(rex.x<<3)]->sq[0] << (sib>>6));
|
||||
return (reg64_t*)base;
|
||||
} else if (m==0x5) { //disp32
|
||||
base += Fetch32s(emu);
|
||||
return (reg64_t*)(base+R_RIP+delta);
|
||||
base += F32S(addr);
|
||||
return (reg64_t*)(base+*addr+delta);
|
||||
}
|
||||
return (reg64_t*)(base + emu->regs[m+(rex.b<<3)].q[0]);
|
||||
} else {
|
||||
if((m&7)==4) {
|
||||
uint8_t sib = Fetch8(emu);
|
||||
uint8_t sib = F8(addr);
|
||||
base += emu->regs[(sib&0x7)+(rex.b<<3)].q[0]; // base
|
||||
base += (emu->sbiidx[((sib>>3)&7)+(rex.x<<3)]->sq[0] << (sib>>6));
|
||||
} else {
|
||||
base += emu->regs[(m&0x7)+(rex.b<<3)].q[0];
|
||||
}
|
||||
base+=(m&0x80)?Fetch32s(emu):Fetch8s(emu);
|
||||
base+=(m&0x80)?F32S(addr):F8S(addr);
|
||||
return (reg64_t*)base;
|
||||
}
|
||||
}
|
||||
|
||||
reg64_t* GetECommon32O(x64emu_t* emu, rex_t rex, uint8_t m, uint8_t delta, uintptr_t base)
|
||||
reg64_t* GetECommon32O(x64emu_t* emu, uintptr_t* addr, rex_t rex, uint8_t m, uint8_t delta, uintptr_t base)
|
||||
{
|
||||
if (m<=7) {
|
||||
if(m==0x4) {
|
||||
uint8_t sib = Fetch8(emu);
|
||||
base += ((sib&0x7)==5)?((uint64_t)(int64_t)Fetch32s(emu)):(emu->regs[(sib&0x7)+(rex.b<<3)].dword[0]); // base
|
||||
uint8_t sib = F8(addr);
|
||||
base += ((sib&0x7)==5)?((uint64_t)(int64_t)F32S(addr)):(emu->regs[(sib&0x7)+(rex.b<<3)].dword[0]); // base
|
||||
base += (emu->sbiidx[((sib>>3)&7)+(rex.x<<3)]->sdword[0] << (sib>>6));
|
||||
return (reg64_t*)base;
|
||||
} else if (m==0x5) { //disp32
|
||||
base += Fetch32s(emu);
|
||||
return (reg64_t*)(base+R_RIP+delta);
|
||||
base += F32S(addr);
|
||||
return (reg64_t*)(base+(*addr)+delta);
|
||||
}
|
||||
return (reg64_t*)(uintptr_t)(base + emu->regs[m+(rex.b<<3)].dword[0]);
|
||||
} else {
|
||||
if((m&7)==4) {
|
||||
uint8_t sib = Fetch8(emu);
|
||||
uint8_t sib = F8(addr);
|
||||
base += emu->regs[(sib&0x7)+(rex.b<<3)].dword[0]; // base
|
||||
base += (emu->sbiidx[((sib>>3)&7)+(rex.x<<3)]->sdword[0] << (sib>>6));
|
||||
} else {
|
||||
base += emu->regs[(m&0x7)+(rex.b<<3)].dword[0];
|
||||
}
|
||||
base+=(m&0x80)?Fetch32s(emu):Fetch8s(emu);
|
||||
base+=(m&0x80)?F32S(addr):F8S(addr);
|
||||
return (reg64_t*)base;
|
||||
}
|
||||
}
|
||||
|
||||
reg64_t* GetEb(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta)
|
||||
reg64_t* GetEb(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta)
|
||||
{
|
||||
// rex ignored here
|
||||
uint8_t m = v&0xC7; // filter Eb
|
||||
@@ -1144,10 +1222,10 @@ reg64_t* GetEb(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta)
|
||||
int lowhigh = (m&4)>>2;
|
||||
return (reg64_t *)(((char*)(&emu->regs[(m&0x03)]))+lowhigh); //?
|
||||
}
|
||||
} else return GetECommon(emu, rex, m, delta);
|
||||
} else return GetECommon(emu, addr, rex, m, delta);
|
||||
}
|
||||
|
||||
reg64_t* GetEbO(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
|
||||
reg64_t* GetEbO(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
|
||||
{
|
||||
// rex ignored here
|
||||
uint8_t m = v&0xC7; // filter Eb
|
||||
@@ -1158,34 +1236,34 @@ reg64_t* GetEbO(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta, uintptr_t of
|
||||
int lowhigh = (m&4)>>2;
|
||||
return (reg64_t *)(((char*)(&emu->regs[(m&0x03)]))+lowhigh); //?
|
||||
}
|
||||
} else return GetECommonO(emu, rex, m, delta, offset);
|
||||
} else return GetECommonO(emu, addr, rex, m, delta, offset);
|
||||
}
|
||||
|
||||
reg64_t* GetEd(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta)
|
||||
reg64_t* GetEd(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta)
|
||||
{
|
||||
uint8_t m = v&0xC7; // filter Ed
|
||||
if(m>=0xC0) {
|
||||
return &emu->regs[(m&0x07)+(rex.b<<3)];
|
||||
} else return GetECommon(emu, rex, m, delta);
|
||||
} else return GetECommon(emu, addr, rex, m, delta);
|
||||
}
|
||||
|
||||
reg64_t* GetEdO(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
|
||||
reg64_t* GetEdO(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
|
||||
{
|
||||
uint8_t m = v&0xC7; // filter Ed
|
||||
if(m>=0xC0) {
|
||||
return &emu->regs[(m&0x07)+(rex.b<<3)];
|
||||
} else return GetECommonO(emu, rex, m, delta, offset);
|
||||
} else return GetECommonO(emu, addr, rex, m, delta, offset);
|
||||
}
|
||||
|
||||
reg64_t* GetEd32O(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
|
||||
reg64_t* GetEd32O(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
|
||||
{
|
||||
uint8_t m = v&0xC7; // filter Ed
|
||||
if(m>=0xC0) {
|
||||
return &emu->regs[(m&0x07)+(rex.b<<3)];
|
||||
} else return GetECommon32O(emu, rex, m, delta, offset);
|
||||
} else return GetECommon32O(emu, addr, rex, m, delta, offset);
|
||||
}
|
||||
|
||||
reg64_t* GetEb32O(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
|
||||
reg64_t* GetEb32O(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
|
||||
{
|
||||
uint8_t m = v&0xC7; // filter Eb
|
||||
if(m>=0xC0) {
|
||||
@@ -1195,12 +1273,12 @@ reg64_t* GetEb32O(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta, uintptr_t
|
||||
int lowhigh = (m&4)>>2;
|
||||
return (reg64_t *)(((char*)(&emu->regs[(m&0x03)]))+lowhigh); //?
|
||||
}
|
||||
} else return GetECommon32O(emu, rex, m, delta, offset);
|
||||
} else return GetECommon32O(emu, addr, rex, m, delta, offset);
|
||||
}
|
||||
|
||||
#define GetEw GetEd
|
||||
|
||||
reg64_t* GetEw16(x64emu_t *emu, rex_t rex, uint8_t v)
|
||||
reg64_t* GetEw16(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v)
|
||||
{
|
||||
(void)rex;
|
||||
|
||||
@@ -1220,16 +1298,16 @@ reg64_t* GetEw16(x64emu_t *emu, rex_t rex, uint8_t v)
|
||||
case 7: base = R_BX; break;
|
||||
}
|
||||
switch((m>>6)&3) {
|
||||
case 0: if(m==6) base = Fetch16(emu); break;
|
||||
case 1: base += Fetch8s(emu); break;
|
||||
case 2: base += Fetch16s(emu); break;
|
||||
case 0: if(m==6) base = F16(addr); break;
|
||||
case 1: base += F8S(addr); break;
|
||||
case 2: base += F16S(addr); break;
|
||||
// case 3 is C0..C7, already dealt with
|
||||
}
|
||||
return (reg64_t*)base;
|
||||
}
|
||||
}
|
||||
|
||||
reg64_t* GetEw16off(x64emu_t *emu, rex_t rex, uint8_t v, uintptr_t offset)
|
||||
reg64_t* GetEw16off(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uintptr_t offset)
|
||||
{
|
||||
(void)rex;
|
||||
|
||||
@@ -1249,62 +1327,62 @@ reg64_t* GetEw16off(x64emu_t *emu, rex_t rex, uint8_t v, uintptr_t offset)
|
||||
case 7: base = R_BX; break;
|
||||
}
|
||||
switch((m>>6)&3) {
|
||||
case 0: if(m==6) base = Fetch16(emu); break;
|
||||
case 1: base += Fetch8s(emu); break;
|
||||
case 2: base += Fetch16s(emu); break;
|
||||
case 0: if(m==6) base = F16(addr); break;
|
||||
case 1: base += F8S(addr); break;
|
||||
case 2: base += F16S(addr); break;
|
||||
// case 3 is C0..C7, already dealt with
|
||||
}
|
||||
return (reg64_t*)(base+offset);
|
||||
}
|
||||
}
|
||||
|
||||
mmx87_regs_t* GetEm(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta)
|
||||
mmx87_regs_t* GetEm(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta)
|
||||
{
|
||||
uint8_t m = v&0xC7; // filter Ed
|
||||
if(m>=0xC0) {
|
||||
return &emu->mmx[m&0x07];
|
||||
} else return (mmx87_regs_t*)GetECommon(emu, rex, m, delta);
|
||||
} else return (mmx87_regs_t*)GetECommon(emu, addr, rex, m, delta);
|
||||
}
|
||||
|
||||
sse_regs_t* GetEx(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta)
|
||||
sse_regs_t* GetEx(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta)
|
||||
{
|
||||
uint8_t m = v&0xC7; // filter Ed
|
||||
if(m>=0xC0) {
|
||||
return &emu->xmm[(m&0x07)+(rex.b<<3)];
|
||||
} else return (sse_regs_t*)GetECommon(emu, rex, m, delta);
|
||||
} else return (sse_regs_t*)GetECommon(emu, addr, rex, m, delta);
|
||||
}
|
||||
|
||||
sse_regs_t* GetExO(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
|
||||
sse_regs_t* GetExO(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
|
||||
{
|
||||
uint8_t m = v&0xC7; // filter Ed
|
||||
if(m>=0xC0) {
|
||||
return &emu->xmm[(m&0x07)+(rex.b<<3)];
|
||||
} else return (sse_regs_t*)GetECommonO(emu, rex, m, delta, offset);
|
||||
} else return (sse_regs_t*)GetECommonO(emu, addr, rex, m, delta, offset);
|
||||
}
|
||||
|
||||
sse_regs_t* GetEx32O(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
|
||||
sse_regs_t* GetEx32O(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
|
||||
{
|
||||
uint8_t m = v&0xC7; // filter Ed
|
||||
if(m>=0xC0) {
|
||||
return &emu->xmm[(m&0x07)+(rex.b<<3)];
|
||||
} else return (sse_regs_t*)GetECommon32O(emu, rex, m, delta, offset);
|
||||
} else return (sse_regs_t*)GetECommon32O(emu, addr, rex, m, delta, offset);
|
||||
}
|
||||
|
||||
mmx87_regs_t* GetEm32O(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
|
||||
mmx87_regs_t* GetEm32O(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
|
||||
{
|
||||
uint8_t m = v&0xC7; // filter Ed
|
||||
if(m>=0xC0) {
|
||||
return &emu->mmx[(m&0x07)];
|
||||
} else return (mmx87_regs_t*)GetECommon32O(emu, rex, m, delta, offset);
|
||||
} else return (mmx87_regs_t*)GetECommon32O(emu, addr, rex, m, delta, offset);
|
||||
}
|
||||
|
||||
|
||||
reg64_t* GetGd(x64emu_t *emu, rex_t rex, uint8_t v)
|
||||
reg64_t* GetGd(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v)
|
||||
{
|
||||
return &emu->regs[((v&0x38)>>3)+(rex.r<<3)];
|
||||
}
|
||||
|
||||
reg64_t* GetGb(x64emu_t *emu, rex_t rex, uint8_t v)
|
||||
reg64_t* GetGb(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v)
|
||||
{
|
||||
uint8_t m = (v&0x38)>>3;
|
||||
if(rex.rex)
|
||||
@@ -1313,7 +1391,7 @@ reg64_t* GetGb(x64emu_t *emu, rex_t rex, uint8_t v)
|
||||
return (reg64_t*)&emu->regs[m&3].byte[m>>2];
|
||||
}
|
||||
|
||||
mmx87_regs_t* GetGm(x64emu_t *emu, rex_t rex, uint8_t v)
|
||||
mmx87_regs_t* GetGm(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v)
|
||||
{
|
||||
(void)rex;
|
||||
|
||||
@@ -1321,7 +1399,7 @@ mmx87_regs_t* GetGm(x64emu_t *emu, rex_t rex, uint8_t v)
|
||||
return &emu->mmx[m&7];
|
||||
}
|
||||
|
||||
sse_regs_t* GetGx(x64emu_t *emu, rex_t rex, uint8_t v)
|
||||
sse_regs_t* GetGx(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v)
|
||||
{
|
||||
uint8_t m = (v&0x38)>>3;
|
||||
return &emu->xmm[(m&7)+(rex.r<<3)];
|
||||
|
||||
+44
-82
@@ -17,44 +17,6 @@ typedef union rex_s {
|
||||
};
|
||||
} rex_t;
|
||||
|
||||
static inline uint8_t Fetch8(x64emu_t *emu) {return *(uint8_t*)(R_RIP++);}
|
||||
static inline int8_t Fetch8s(x64emu_t *emu) {return *(int8_t*)(R_RIP++);}
|
||||
static inline uint16_t Fetch16(x64emu_t *emu)
|
||||
{
|
||||
uint16_t val = *(uint16_t*)R_RIP;
|
||||
R_RIP+=2;
|
||||
return val;
|
||||
}
|
||||
static inline int16_t Fetch16s(x64emu_t *emu)
|
||||
{
|
||||
int16_t val = *(int16_t*)R_RIP;
|
||||
R_RIP+=2;
|
||||
return val;
|
||||
}
|
||||
static inline uint32_t Fetch32(x64emu_t *emu)
|
||||
{
|
||||
uint32_t val = *(uint32_t*)R_RIP;
|
||||
R_RIP+=4;
|
||||
return val;
|
||||
}
|
||||
static inline int32_t Fetch32s(x64emu_t *emu)
|
||||
{
|
||||
int32_t val = *(int32_t*)R_RIP;
|
||||
R_RIP+=4;
|
||||
return val;
|
||||
}
|
||||
static inline uint64_t Fetch64(x64emu_t *emu)
|
||||
{
|
||||
uint64_t val = *(uint64_t*)R_RIP;
|
||||
R_RIP+=8;
|
||||
return val;
|
||||
}
|
||||
static inline int64_t Fetch64s(x64emu_t *emu)
|
||||
{
|
||||
int64_t val = *(int64_t*)R_RIP;
|
||||
R_RIP+=8;
|
||||
return val;
|
||||
}
|
||||
static inline uint8_t Peek(x64emu_t *emu, int offset){return *(uint8_t*)(R_RIP + offset);}
|
||||
|
||||
static inline uint64_t Pop(x64emu_t *emu)
|
||||
@@ -73,61 +35,61 @@ static inline void Push(x64emu_t *emu, uint64_t v)
|
||||
|
||||
// the op code definition can be found here: http://ref.x86asm.net/geek32.html
|
||||
|
||||
reg64_t* GetECommon(x64emu_t* emu, rex_t rex, uint8_t m, uint8_t delta);
|
||||
reg64_t* GetECommonO(x64emu_t* emu, rex_t rex, uint8_t m, uint8_t delta, uintptr_t offset);
|
||||
reg64_t* GetECommon32O(x64emu_t* emu, rex_t rex, uint8_t m, uint8_t delta, uintptr_t offset);
|
||||
reg64_t* GetEb(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta);
|
||||
reg64_t* GetEbO(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
|
||||
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);
|
||||
reg64_t* GetECommon(x64emu_t* emu, uintptr_t* addr, rex_t rex, uint8_t m, uint8_t delta);
|
||||
reg64_t* GetECommonO(x64emu_t* emu, uintptr_t* addr, rex_t rex, uint8_t m, uint8_t delta, uintptr_t offset);
|
||||
reg64_t* GetECommon32O(x64emu_t* emu, uintptr_t* addr, rex_t rex, uint8_t m, uint8_t delta, uintptr_t offset);
|
||||
reg64_t* GetEb(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta);
|
||||
reg64_t* GetEbO(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
|
||||
reg64_t* GetEd(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta);
|
||||
reg64_t* GetEdO(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
|
||||
reg64_t* GetEd32O(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
|
||||
reg64_t* GetEb32O(x64emu_t *emu, uintptr_t* addr, 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);
|
||||
reg64_t* GetEw16(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v);
|
||||
reg64_t* GetEw16off(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uintptr_t offset);
|
||||
mmx87_regs_t* GetEm(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta);
|
||||
sse_regs_t* GetEx(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta);
|
||||
sse_regs_t* GetExO(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
|
||||
sse_regs_t* GetEx32O(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
|
||||
reg64_t* GetGd(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v);
|
||||
#define GetGw GetGd
|
||||
reg64_t* GetGb(x64emu_t *emu, rex_t rex, uint8_t v);
|
||||
mmx87_regs_t* GetGm(x64emu_t *emu, rex_t rex, uint8_t v);
|
||||
mmx87_regs_t* GetEm32O(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
|
||||
sse_regs_t* GetGx(x64emu_t *emu, rex_t rex, uint8_t v);
|
||||
reg64_t* GetGb(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v);
|
||||
mmx87_regs_t* GetGm(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v);
|
||||
mmx87_regs_t* GetEm32O(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
|
||||
sse_regs_t* GetGx(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v);
|
||||
|
||||
void UpdateFlags(x64emu_t *emu);
|
||||
|
||||
#define CHECK_FLAGS(emu) if(emu->df) UpdateFlags(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 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 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);
|
||||
uintptr_t Run0F(x64emu_t *emu, rex_t rex, uintptr_t addr, int *step);
|
||||
uintptr_t Run64(x64emu_t *emu, rex_t rex, int seg, uintptr_t addr);
|
||||
uintptr_t Run66(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr);
|
||||
uintptr_t Run660F(x64emu_t *emu, rex_t rex, uintptr_t addr);
|
||||
uintptr_t Run6664(x64emu_t *emu, rex_t rex, int seg, uintptr_t addr);
|
||||
uintptr_t Run66D9(x64emu_t *emu, rex_t rex, uintptr_t addr);
|
||||
uintptr_t Run66DD(x64emu_t *emu, rex_t rex, uintptr_t addr);
|
||||
uintptr_t Run66F0(x64emu_t *emu, rex_t rex, uintptr_t addr);
|
||||
uintptr_t Run67(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr);
|
||||
uintptr_t Run670F(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr);
|
||||
uintptr_t Run6766(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr);
|
||||
uintptr_t Run67660F(x64emu_t *emu, rex_t rex, uintptr_t addr);
|
||||
uintptr_t RunD8(x64emu_t *emu, rex_t rex, uintptr_t addr);
|
||||
uintptr_t RunD9(x64emu_t *emu, rex_t rex, uintptr_t addr);
|
||||
uintptr_t RunDA(x64emu_t *emu, rex_t rex, uintptr_t addr);
|
||||
uintptr_t RunDB(x64emu_t *emu, rex_t rex, uintptr_t addr);
|
||||
uintptr_t RunDC(x64emu_t *emu, rex_t rex, uintptr_t addr);
|
||||
uintptr_t RunDD(x64emu_t *emu, rex_t rex, uintptr_t addr);
|
||||
uintptr_t RunDE(x64emu_t *emu, rex_t rex, uintptr_t addr);
|
||||
uintptr_t RunDF(x64emu_t *emu, rex_t rex, uintptr_t addr);
|
||||
uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr);
|
||||
uintptr_t RunF20F(x64emu_t *emu, rex_t rex, uintptr_t addr, int *step);
|
||||
uintptr_t RunF30F(x64emu_t *emu, rex_t rex, uintptr_t addr);
|
||||
|
||||
void x64Syscall(x64emu_t *emu);
|
||||
void x64Int3(x64emu_t* emu);
|
||||
void x64Int3(x64emu_t* emu, uintptr_t* addr);
|
||||
x64emu_t* x64emu_fork(x64emu_t* e, int forktype);
|
||||
|
||||
uintptr_t GetSegmentBaseEmu(x64emu_t* emu, int seg);
|
||||
|
||||
+11
-51
@@ -22,7 +22,7 @@
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
int RunD8(x64emu_t *emu, rex_t rex)
|
||||
uintptr_t RunD8(x64emu_t *emu, rex_t rex, uintptr_t addr)
|
||||
{
|
||||
uint8_t nextop;
|
||||
float f;
|
||||
@@ -116,80 +116,40 @@ int RunD8(x64emu_t *emu, rex_t rex)
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* FADD ST0, float */
|
||||
GETED(0);
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
ST0.d += *(float*)ED;
|
||||
else {
|
||||
memcpy(&f, ED, sizeof(float));
|
||||
ST0.d += f;
|
||||
}
|
||||
ST0.d += *(float*)ED;
|
||||
break;
|
||||
case 1: /* FMUL ST0, float */
|
||||
GETED(0);
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
ST0.d *= *(float*)ED;
|
||||
else {
|
||||
memcpy(&f, ED, sizeof(float));
|
||||
ST0.d *= f;
|
||||
}
|
||||
ST0.d *= *(float*)ED;
|
||||
break;
|
||||
case 2: /* FCOM ST0, float */
|
||||
GETED(0);
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
fpu_fcom(emu, *(float*)ED);
|
||||
else {
|
||||
memcpy(&f, ED, sizeof(float));
|
||||
fpu_fcom(emu, f);
|
||||
}
|
||||
fpu_fcom(emu, *(float*)ED);
|
||||
break;
|
||||
case 3: /* FCOMP */
|
||||
GETED(0);
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
fpu_fcom(emu, *(float*)ED);
|
||||
else {
|
||||
memcpy(&f, ED, sizeof(float));
|
||||
fpu_fcom(emu, f);
|
||||
}
|
||||
fpu_fcom(emu, *(float*)ED);
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 4: /* FSUB ST0, float */
|
||||
GETED(0);
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
ST0.d -= *(float*)ED;
|
||||
else {
|
||||
memcpy(&f, ED, sizeof(float));
|
||||
ST0.d -= f;
|
||||
}
|
||||
ST0.d -= *(float*)ED;
|
||||
break;
|
||||
case 5: /* FSUBR ST0, float */
|
||||
GETED(0);
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
ST0.d = *(float*)ED - ST0.d;
|
||||
else {
|
||||
memcpy(&f, ED, sizeof(float));
|
||||
ST0.d = f - ST0.d;
|
||||
}
|
||||
ST0.d = *(float*)ED - ST0.d;
|
||||
break;
|
||||
case 6: /* FDIV ST0, float */
|
||||
GETED(0);
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
ST0.d /= *(float*)ED;
|
||||
else {
|
||||
memcpy(&f, ED, sizeof(float));
|
||||
ST0.d /= f;
|
||||
}
|
||||
ST0.d /= *(float*)ED;
|
||||
break;
|
||||
case 7: /* FDIVR ST0, float */
|
||||
GETED(0);
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
ST0.d = *(float*)ED / ST0.d;
|
||||
else {
|
||||
memcpy(&f, ED, sizeof(float));
|
||||
ST0.d = f / ST0.d;
|
||||
}
|
||||
ST0.d = *(float*)ED / ST0.d;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return addr;
|
||||
}
|
||||
+20
-33
@@ -22,7 +22,7 @@
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
int RunD9(x64emu_t *emu, rex_t rex)
|
||||
uintptr_t RunD9(x64emu_t *emu, rex_t rex, uintptr_t addr)
|
||||
{
|
||||
uint8_t nextop;
|
||||
int32_t tmp32s;
|
||||
@@ -60,6 +60,17 @@ int RunD9(x64emu_t *emu, rex_t rex)
|
||||
case 0xD0: /* FNOP */
|
||||
break;
|
||||
|
||||
case 0xD8: /* FSTPNCE ST0, STx */
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
ST(nextop&7).q = ST0.q;
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xE0: /* FCHS */
|
||||
ST0.d = -ST0.d;
|
||||
break;
|
||||
@@ -210,49 +221,26 @@ int RunD9(x64emu_t *emu, rex_t rex)
|
||||
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:
|
||||
return 1;
|
||||
return 0;
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* FLD ST0, Ed float */
|
||||
GETED(0);
|
||||
fpu_do_push(emu);
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
ST0.d = *(float*)ED;
|
||||
else {
|
||||
memcpy(&f, ED, sizeof(float));
|
||||
ST0.d = f;
|
||||
}
|
||||
ST0.d = *(float*)ED;
|
||||
break;
|
||||
case 2: /* FST Ed, ST0 */
|
||||
GETED(0);
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
*(float*)ED = ST0.d;
|
||||
else {
|
||||
f = ST0.d;
|
||||
memcpy(ED, &f, sizeof(float));
|
||||
}
|
||||
*(float*)ED = ST0.d;
|
||||
break;
|
||||
case 3: /* FSTP Ed, ST0 */
|
||||
GETED(0);
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
*(float*)ED = ST0.d;
|
||||
else {
|
||||
f = ST0.d;
|
||||
memcpy(ED, &f, sizeof(float));
|
||||
}
|
||||
*(float*)ED = ST0.d;
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 4: /* FLDENV m */
|
||||
@@ -262,9 +250,8 @@ int RunD9(x64emu_t *emu, rex_t rex)
|
||||
break;
|
||||
case 5: /* FLDCW Ew */
|
||||
GETEW(0);
|
||||
emu->cw = EW->word[0];
|
||||
emu->cw.x16 = EW->word[0];
|
||||
// do something with cw?
|
||||
emu->round = (fpu_round_t)((emu->cw >> 10) & 3);
|
||||
break;
|
||||
case 6: /* FNSTENV m */
|
||||
// warning, incomplete
|
||||
@@ -276,11 +263,11 @@ int RunD9(x64emu_t *emu, rex_t rex)
|
||||
break;
|
||||
case 7: /* FNSTCW Ew */
|
||||
GETEW(0);
|
||||
EW->word[0] = emu->cw;
|
||||
EW->word[0] = emu->cw.x16;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return addr;
|
||||
}
|
||||
Loaded 100 of 947 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user