mirror of
https://github.com/ptitSeb/box64.git
synced 2026-11-08 10:10:25 -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 | ||
|
|
30302a049c | ||
|
|
bd432a3a15 | ||
|
|
b155850ad1 | ||
|
|
84a7f79315 | ||
|
|
3c84242cf2 | ||
|
|
3faf66a36b | ||
|
|
d94b47d1b0 | ||
|
|
6c07bc386b | ||
|
|
34f7571269 | ||
|
|
dc9144f8f4 | ||
|
|
5538ffde53 | ||
|
|
74cd8cd6fe | ||
|
|
1c83a9f0b7 | ||
|
|
929741e9f8 | ||
|
|
9a20052200 | ||
|
|
ee6c824ccf | ||
|
|
cbe7e1a5e7 | ||
|
|
1b605c4a4e | ||
|
|
9953760fe4 | ||
|
|
968cb3cea4 | ||
|
|
889bbf3e3f | ||
|
|
abb8d29cd4 | ||
|
|
aa4ec7b68c | ||
|
|
2e69f3f480 | ||
|
|
ebcc3b3a72 | ||
|
|
b4adb3f3c8 | ||
|
|
f779d4fadb | ||
|
|
c6b08a936b | ||
|
|
93bb6ebb0f | ||
|
|
780a450da2 | ||
|
|
3f536e4dca | ||
|
|
a4772ff2fa | ||
|
|
23a6d1a752 | ||
|
|
74b1f9ee29 | ||
|
|
e89a203481 | ||
|
|
3f53b616fe | ||
|
|
46e3b7a547 | ||
|
|
395a4901a7 | ||
|
|
6aa5bb3d8c | ||
|
|
f8c7a5f736 | ||
|
|
5ed7db41b3 | ||
|
|
53aff6de4b | ||
|
|
2593f6d267 | ||
|
|
5dd4f20822 | ||
|
|
dc83fd8842 | ||
|
|
8730cd85a2 | ||
|
|
aff3861067 | ||
|
|
4e93c2d327 | ||
|
|
709878793e | ||
|
|
7199742615 | ||
|
|
507ec5abfc | ||
|
|
d164e80f9a | ||
|
|
764b8a0faf | ||
|
|
c18a969ad0 | ||
|
|
4882f8f70e | ||
|
|
f0b9949aaf | ||
|
|
0276267d32 | ||
|
|
f2408e1f62 | ||
|
|
1f869f0e30 | ||
|
|
83f97f9b70 | ||
|
|
ead3217bf4 | ||
|
|
f2012fc636 | ||
|
|
16f82ba6b3 | ||
|
|
5cd8176478 | ||
|
|
ea0ee7c7aa | ||
|
|
18a1cc77d4 | ||
|
|
370286ee25 | ||
|
|
311e8ac3e3 | ||
|
|
716eb97af9 | ||
|
|
3623cb9785 | ||
|
|
3f641c2b67 | ||
|
|
94c3cec69f | ||
|
|
a9a82e581a | ||
|
|
0a8bbe93a5 | ||
|
|
1beba3e27a | ||
|
|
07a65d4827 | ||
|
|
35e35ec5db | ||
|
|
de2b3afa17 | ||
|
|
46ab4b5b71 | ||
|
|
1eaa7159a6 | ||
|
|
4015c26e68 | ||
|
|
b17d802476 | ||
|
|
9ebdf64298 | ||
|
|
fa07a0f331 | ||
|
|
44a20349e3 | ||
|
|
7f7003c484 | ||
|
|
d7ab5e25f0 | ||
|
|
5a563f1cc6 | ||
|
|
7c42cf2d95 | ||
|
|
30e128e41d | ||
|
|
795c405e81 | ||
|
|
515f4e8119 | ||
|
|
4a29c32d0c | ||
|
|
696b88375d | ||
|
|
8a354d4439 | ||
|
|
ace2803928 | ||
|
|
7943858290 | ||
|
|
8073bb279f | ||
|
|
293b07bbb6 | ||
|
|
b57f998c58 | ||
|
|
7fc31d593d | ||
|
|
010f3d9748 | ||
|
|
ff31d0b023 | ||
|
|
652e8318e6 | ||
|
|
e05796674b | ||
|
|
0ce169e7f5 | ||
|
|
726af707eb | ||
|
|
0b37d4aac2 | ||
|
|
749c871124 | ||
|
|
622baec952 | ||
|
|
a326c82158 | ||
|
|
9c47b1fbf9 | ||
|
|
b525b0bdd4 | ||
|
|
0a08b7da1a | ||
|
|
a996f4c091 | ||
|
|
e517e58776 | ||
|
|
d2cb088918 | ||
|
|
6ca94b9f3f | ||
|
|
d8ea2d637b | ||
|
|
a6dd5c9930 | ||
|
|
ec3341e5d6 | ||
|
|
a63e840674 | ||
|
|
0e9b61b3d8 | ||
|
|
4c2008f6cb | ||
|
|
430b7c665e | ||
|
|
90fe73333c | ||
|
|
dd60e17835 | ||
|
|
aad680d61d | ||
|
|
9d65062d35 | ||
|
|
2bd78e25fd | ||
|
|
b1bd9c6810 | ||
|
|
6f4ce37cce | ||
|
|
23bbab10b4 | ||
|
|
8b1f55aff0 | ||
|
|
b00764d658 | ||
|
|
97e9e5d2d2 | ||
|
|
db63885945 | ||
|
|
796d95528b | ||
|
|
c3fd9d03ba | ||
|
|
7a539e4ef7 | ||
|
|
bfd89b404a | ||
|
|
e8337ddd3a | ||
|
|
84e0b2a42d | ||
|
|
4ee2888711 | ||
|
|
24b781a641 | ||
|
|
3ceff2ce2e | ||
|
|
b2309cec52 | ||
|
|
e190bb4b52 | ||
|
|
5d9b14dac7 | ||
|
|
786ceec713 | ||
|
|
3c660f7f16 | ||
|
|
2f1024f167 | ||
|
|
6d41839341 | ||
|
|
ba4bf228cb | ||
|
|
ff909da96a | ||
|
|
0cdb134d45 | ||
|
|
ea6d95986e | ||
|
|
20e8333032 | ||
|
|
fc3b931911 | ||
|
|
a67606db8f | ||
|
|
ab1af8d709 | ||
|
|
ffaae3ef39 | ||
|
|
e3839f6a09 | ||
|
|
9e07083c0f | ||
|
|
77925f264f | ||
|
|
78b51bc367 | ||
|
|
55bc853659 | ||
|
|
97857d55a0 | ||
|
|
4bfacf8a7e | ||
|
|
23709c09c7 | ||
|
|
547b97d4cb | ||
|
|
d7483cb3a4 | ||
|
|
7224281cd6 | ||
|
|
e0dfef8461 | ||
|
|
27a07d23d7 | ||
|
|
30050fd7ec | ||
|
|
a7da857646 | ||
|
|
efd240742f | ||
|
|
d7ca4abf40 | ||
|
|
757b74e1d0 | ||
|
|
552258ed3c | ||
|
|
afc4cbc3b2 | ||
|
|
0a04c9ff39 | ||
|
|
a358167897 | ||
|
|
195f6a33bc | ||
|
|
5aab593a5a | ||
|
|
ca3247d21a | ||
|
|
511a7d2448 | ||
|
|
b6c172865b | ||
|
|
40de393aa5 | ||
|
|
fefda0f6e7 | ||
|
|
4302a311a4 | ||
|
|
ed2a792672 | ||
|
|
e60f8c9a3f | ||
|
|
909ae5ada9 | ||
|
|
4743f8fcc5 | ||
|
|
04e8eb1a45 | ||
|
|
666553c4a0 | ||
|
|
07a6640ff9 | ||
|
|
e005c60d78 | ||
|
|
9bf7185c7c | ||
|
|
97b86e2257 | ||
|
|
10effff239 | ||
|
|
a3f27f9a63 | ||
|
|
1f9db9ef08 | ||
|
|
91e13d3557 | ||
|
|
667dc36962 | ||
|
|
f5d06338c7 | ||
|
|
42ab23a833 | ||
|
|
e249a33d3e | ||
|
|
5f03d1b905 | ||
|
|
c85a2ac9ee | ||
|
|
0c069aaba1 | ||
|
|
1e010f38c9 | ||
|
|
8260931ad7 | ||
|
|
5e01769622 | ||
|
|
97a1da81af | ||
|
|
55e888074d | ||
|
|
255be6e786 | ||
|
|
42b18c57ce | ||
|
|
dd0f7c1d5c | ||
|
|
680a08fb5b | ||
|
|
203c40d27c | ||
|
|
0f3fe62327 | ||
|
|
eea3857065 | ||
|
|
a8fc74a033 | ||
|
|
895c8b7098 | ||
|
|
f3b300e9e0 | ||
|
|
ff82c956f1 | ||
|
|
6e1c0c1353 | ||
|
|
ffe2cd0203 | ||
|
|
ea2b95389b | ||
|
|
2fa366c7a8 | ||
|
|
b75eec2fea | ||
|
|
b932ad8c65 | ||
|
|
cc9f770d90 | ||
|
|
6a9d399648 | ||
|
|
fbb534917a | ||
|
|
41d3fb7432 | ||
|
|
5d1298ebe3 | ||
|
|
37b94ed266 | ||
|
|
40c58241ea | ||
|
|
194c346c18 | ||
|
|
11dae594a3 | ||
|
|
5918fe4b58 | ||
|
|
2cad9392c4 | ||
|
|
3d36eb6345 | ||
|
|
9d7652d3ba | ||
|
|
e905a72e03 | ||
|
|
99e02f978d | ||
|
|
89112197d4 | ||
|
|
96b27013f8 | ||
|
|
262d5670fe | ||
|
|
b7f16075ca | ||
|
|
d093585750 | ||
|
|
3b2797f1e1 | ||
|
|
284345d533 | ||
|
|
07767d42cc | ||
|
|
9d97ce087a | ||
|
|
3fa758e895 | ||
|
|
01fe333167 | ||
|
|
6390b1b9a8 | ||
|
|
f68082edad | ||
|
|
1874c57eae | ||
|
|
8130c110eb | ||
|
|
e6e9fae178 | ||
|
|
7042a1ae30 | ||
|
|
7d277cc1ec | ||
|
|
1ac0465a03 | ||
|
|
3533db97ff | ||
|
|
7888cae6c7 | ||
|
|
b021beba6a | ||
|
|
684d67d12e | ||
|
|
8d7683b851 | ||
|
|
e7290d78d5 | ||
|
|
4f0e98ade5 | ||
|
|
39dbfd9fd8 | ||
|
|
2d18558dc5 | ||
|
|
5fb9397521 | ||
|
|
f85e24dff8 | ||
|
|
2ea272fcd6 | ||
|
|
d3e85b439b | ||
|
|
ea837908b6 | ||
|
|
a1573835dd | ||
|
|
34355d6b0c | ||
|
|
9557e4711f | ||
|
|
6a1b9e050a | ||
|
|
6675b43dd0 | ||
|
|
79d7e9f8eb | ||
|
|
f5c9439f91 | ||
|
|
f73e4193f0 | ||
|
|
841003bc47 | ||
|
|
27cf5c81b2 | ||
|
|
323783bf49 | ||
|
|
fbd9604dc1 | ||
|
|
5494d417c0 | ||
|
|
472037cba2 | ||
|
|
1b19d8b909 | ||
|
|
c2909c32ab | ||
|
|
a7c0c01bf4 | ||
|
|
d80226ec61 | ||
|
|
da81ba5be8 | ||
|
|
f81874277c | ||
|
|
d93b97ee92 | ||
|
|
4812d20da5 | ||
|
|
734e7cd47c | ||
|
|
d052b35c40 | ||
|
|
2bd3a3ccfa | ||
|
|
1886c454ca | ||
|
|
91ee1afe24 | ||
|
|
d867f578df | ||
|
|
b48ba048ed | ||
|
|
35a21d8932 | ||
|
|
81ec174e2a | ||
|
|
400ea800d9 | ||
|
|
0e1215268a | ||
|
|
a72d257443 | ||
|
|
6a99a4b359 | ||
|
|
b6764d1d6f | ||
|
|
d5e105ce62 | ||
|
|
45ee1e3c3c | ||
|
|
b1d0dde0b4 | ||
|
|
cb06d28383 | ||
|
|
36bfcd21d4 | ||
|
|
faa48276e5 | ||
|
|
8e5d32430a | ||
|
|
ac2d5b17dd | ||
|
|
0e2c63d9fb | ||
|
|
71b446774c | ||
|
|
dac71e9f7b | ||
|
|
e1a2230e9c | ||
|
|
82bd4431e6 | ||
|
|
7262288502 | ||
|
|
bcb0bdea77 | ||
|
|
4ca58d1f99 | ||
|
|
0c27b82ff3 | ||
|
|
289deb3655 | ||
|
|
8d69c17839 | ||
|
|
348cb57240 | ||
|
|
46f71f3947 | ||
|
|
0ba4b04078 | ||
|
|
5a5f572162 | ||
|
|
fb5bc122cc | ||
|
|
4c328d0fca | ||
|
|
dbce2758b2 | ||
|
|
837f7edd55 | ||
|
|
f054fb3a5f | ||
|
|
96831b144c | ||
|
|
d75116dab7 | ||
|
|
8da46ee305 | ||
|
|
4cac721e74 | ||
|
|
3fda41cbf6 | ||
|
|
053d5e9b8d | ||
|
|
40cb14bf31 | ||
|
|
27d18e4169 | ||
|
|
5403002a36 | ||
|
|
22f1a6c5ca | ||
|
|
783e9a4b74 | ||
|
|
202a067a61 | ||
|
|
f2d1a8bc70 | ||
|
|
b6bc7922b3 | ||
|
|
7e4af27ba7 | ||
|
|
06bbf93bf8 | ||
|
|
e08bdd644b | ||
|
|
1c5ddfafcd | ||
|
|
0f4db4c230 | ||
|
|
960ce86289 | ||
|
|
b2bd3103d8 | ||
|
|
745fd1b702 | ||
|
|
6df1b65249 | ||
|
|
510f8d45e8 | ||
|
|
c5d328a5da | ||
|
|
1430c811cd | ||
|
|
ec2eadd893 | ||
|
|
56c272c17a | ||
|
|
6f92db542b | ||
|
|
8531750631 | ||
|
|
9414ece323 | ||
|
|
c64cb5b92b | ||
|
|
2b1e12dafd | ||
|
|
b4ca2be9e0 | ||
|
|
203de52d71 | ||
|
|
c48333db44 | ||
|
|
e3552befe9 | ||
|
|
6141421f92 | ||
|
|
911ecc4489 | ||
|
|
63ab450d87 | ||
|
|
bcc29168cd | ||
|
|
4a9b0128d7 | ||
|
|
6cc56ac5f7 | ||
|
|
f53c967e18 | ||
|
|
b309933571 | ||
|
|
c7e8044f92 | ||
|
|
29720048e2 | ||
|
|
716ac9e041 | ||
|
|
fb835fbe66 | ||
|
|
4aac3444bd | ||
|
|
0a343b72f2 | ||
|
|
ab9178f638 | ||
|
|
1b8d952d88 | ||
|
|
e8e966cd80 | ||
|
|
8b80cc328f | ||
|
|
72986e8ba3 | ||
|
|
3df01a153d | ||
|
|
5d5ef75337 | ||
|
|
c3ef6380a7 | ||
|
|
c2782b269f | ||
|
|
1cb55b2633 | ||
|
|
823c6a138a | ||
|
|
e10a78d671 | ||
|
|
04b9195cd2 | ||
|
|
3aa12a52eb | ||
|
|
5f31e0e093 | ||
|
|
39f2b508f8 | ||
|
|
5b5285940f | ||
|
|
c49da85606 | ||
|
|
5cc3512a59 | ||
|
|
cbd1d3781b | ||
|
|
5bca9b52b3 | ||
|
|
fd21d6a8da | ||
|
|
c8ebce5732 | ||
|
|
fce5aa5a6b | ||
|
|
2ac2996abd | ||
|
|
53fb83487a | ||
|
|
3597284e8d | ||
|
|
4e8f387f79 | ||
|
|
305e6326a6 | ||
|
|
e98c7eaa0f | ||
|
|
02462b2c12 | ||
|
|
4d9559f345 | ||
|
|
ed63000e23 | ||
|
|
cc307df592 | ||
|
|
2d321bbd33 | ||
|
|
5b5f7c133e | ||
|
|
69484d7f3c | ||
|
|
43f5438d93 | ||
|
|
2b920d6936 | ||
|
|
01bf3e741e | ||
|
|
f014d4580a | ||
|
|
1f02ab17e3 | ||
|
|
e1d8f1d7e5 | ||
|
|
c8640caba3 | ||
|
|
f4ea86378e | ||
|
|
16011f4b34 | ||
|
|
5a3316b872 | ||
|
|
9f50a19856 | ||
|
|
6207b3fa38 | ||
|
|
35d2103189 | ||
|
|
84626f065c | ||
|
|
eaedda8ceb | ||
|
|
4e9c25893c | ||
|
|
eb5bebb344 | ||
|
|
296ee1baca | ||
|
|
58b5c6ded9 | ||
|
|
ecc07a235c | ||
|
|
fc4f0e3bae | ||
|
|
e00d35f5bf | ||
|
|
790022483b | ||
|
|
100cdd329a | ||
|
|
9c441df959 | ||
|
|
a8ae44a881 | ||
|
|
2f5fe43955 | ||
|
|
86820cf1b1 | ||
|
|
e511e1bf96 | ||
|
|
5fb1c6c497 | ||
|
|
607bb28677 | ||
|
|
36e5fb50ec | ||
|
|
74405a8b00 | ||
|
|
4b1ecc16ff | ||
|
|
139d5128a0 | ||
|
|
7b8bd8a285 | ||
|
|
445d232ee7 | ||
|
|
8ad472c118 | ||
|
|
fd6895782f | ||
|
|
abdd03cdfa | ||
|
|
ba3359353f | ||
|
|
ca473b06dc | ||
|
|
2ee0230793 | ||
|
|
35119f8db2 | ||
|
|
c95af7c81b | ||
|
|
a9aa474884 | ||
|
|
259fe4a238 | ||
|
|
f73bbfc0af | ||
|
|
e7478f3390 | ||
|
|
9be89e8ba2 | ||
|
|
5287e42b02 | ||
|
|
e0a7f775c9 | ||
|
|
f1d238b78d | ||
|
|
41ebdc7604 | ||
|
|
e3fde0807f | ||
|
|
4007ff2610 | ||
|
|
27d79eddec | ||
|
|
0e5bc91a14 | ||
|
|
c715141bf0 | ||
|
|
3d656b5008 | ||
|
|
d84afba7c8 | ||
|
|
7559df965b | ||
|
|
10702c160a | ||
|
|
a66bb7453b | ||
|
|
5406a040fb | ||
|
|
77421d2eed | ||
|
|
78b9b0cec8 | ||
|
|
16a3d46193 | ||
|
|
2976bf5e6a | ||
|
|
b370540447 | ||
|
|
6d7c0f75e7 | ||
|
|
81a7eca5ef | ||
|
|
2711a7e522 | ||
|
|
cc8f926d66 | ||
|
|
486aa58b15 | ||
|
|
8711693698 | ||
|
|
e6f615a1f8 | ||
|
|
813ed6f9a1 | ||
|
|
85dba348a7 | ||
|
|
a7422d11ed | ||
|
|
b39fbc0cfd | ||
|
|
f000951fc9 | ||
|
|
edeac868d0 | ||
|
|
a618dee15c | ||
|
|
8b48773176 | ||
|
|
9a17d9a35e | ||
|
|
a2ca22972c | ||
|
|
b05c449dd0 | ||
|
|
bdb918c9c2 | ||
|
|
7ae9dca562 | ||
|
|
005e3ddf7d | ||
|
|
c5fbc5efd3 | ||
|
|
4b06a0126e | ||
|
|
f8ef852b46 | ||
|
|
741b03761a | ||
|
|
8ccde3ed4a | ||
|
|
b6ce8efa20 | ||
|
|
2bf49e8a11 | ||
|
|
0cfb48f3c7 | ||
|
|
fcd9eba0da | ||
|
|
6d7e729563 | ||
|
|
102744665c | ||
|
|
dd885a694e | ||
|
|
ecf8ffbbdc | ||
|
|
c1e67c31bc | ||
|
|
6eccdc1baf | ||
|
|
7aa7ef6baf | ||
|
|
66ed68ca48 | ||
|
|
d20d007933 | ||
|
|
a91d2d0841 | ||
|
|
649b7772f1 | ||
|
|
fe6304b7cd | ||
|
|
e9b6f3559b | ||
|
|
53b2578b8e | ||
|
|
9507601ee6 | ||
|
|
52e4edd147 | ||
|
|
acc3ed85cb | ||
|
|
dbbda60d9e | ||
|
|
401071c40a | ||
|
|
928eb2a32b | ||
|
|
1c0b1721cd | ||
|
|
15a7d0b9b5 | ||
|
|
6670e924bf | ||
|
|
5b5b974341 | ||
|
|
ad85b7c4c6 | ||
|
|
a5490dc6f2 | ||
|
|
5c52fa6007 | ||
|
|
f8ecf14763 | ||
|
|
d2f7e15fcd | ||
|
|
66ac772585 | ||
|
|
dd365e0b14 | ||
|
|
d612656978 | ||
|
|
91787c4dbf | ||
|
|
c534a9d78c | ||
|
|
06053027a9 | ||
|
|
9291d15215 | ||
|
|
d07036b8ec | ||
|
|
cb73eaf776 | ||
|
|
bb38d8d1ca | ||
|
|
cc269337f2 | ||
|
|
a2aa5fc650 | ||
|
|
26d4f21fa7 | ||
|
|
7f390a5499 | ||
|
|
b9f38bcefd | ||
|
|
81b1f61aec | ||
|
|
ab83d86300 | ||
|
|
450cad7a4d | ||
|
|
c1ee744205 | ||
|
|
f21afb3277 | ||
|
|
7948a25945 | ||
|
|
7711131d5c | ||
|
|
c6119efb04 | ||
|
|
d0dee6cb50 | ||
|
|
e3bbfe3052 | ||
|
|
85a460afb7 | ||
|
|
28a2dba9f7 | ||
|
|
4e7f86979d | ||
|
|
303390bf00 | ||
|
|
623e81a422 | ||
|
|
13e574db3f | ||
|
|
7bd4aae433 | ||
|
|
69382682c4 | ||
|
|
7535b4ac61 | ||
|
|
3bab7d6c53 | ||
|
|
a8a45aede3 | ||
|
|
28c6d72110 | ||
|
|
c3cd14f3c5 | ||
|
|
2010f8dcce | ||
|
|
abcb12f9ed | ||
|
|
283a4dda20 | ||
|
|
3355f39e9f | ||
|
|
a4cd4c0745 | ||
|
|
3834546100 | ||
|
|
a3d7f9cd85 | ||
|
|
10247fcf85 | ||
|
|
b1183e55fd | ||
|
|
b6c9377551 | ||
|
|
c9a4b94efe | ||
|
|
04658cafcc | ||
|
|
27b3a3f33c | ||
|
|
d60a0ef58d | ||
|
|
fff2effd5b | ||
|
|
bb7e473e7b | ||
|
|
908641a414 | ||
|
|
69bd28cc65 | ||
|
|
0126a0d575 | ||
|
|
6cee821138 | ||
|
|
bbed3403e8 | ||
|
|
9a0824af69 | ||
|
|
53375ca728 | ||
|
|
f0503b67eb | ||
|
|
9c0daf0ed5 | ||
|
|
796e6d3a87 | ||
|
|
6112505757 | ||
|
|
9b547c7884 | ||
|
|
1687c48c1b | ||
|
|
f5981c4dca | ||
|
|
6f183aa1cc | ||
|
|
56f6ad84bb | ||
|
|
ed9a29b25f | ||
|
|
20ba6261b6 | ||
|
|
905b27f216 | ||
|
|
c218631c56 | ||
|
|
bd600a6135 | ||
|
|
67c80f683e | ||
|
|
1fb65cbce2 | ||
|
|
7aa5705400 | ||
|
|
bd21214467 | ||
|
|
de8b4da6b5 | ||
|
|
9243ea4ca1 | ||
|
|
2e871fc68a | ||
|
|
30eb08f8af | ||
|
|
7f51495877 | ||
|
|
112bc0d83f | ||
|
|
501a4a8956 | ||
|
|
bb4c06f107 | ||
|
|
65fae1077f | ||
|
|
e3a36591aa | ||
|
|
a597f6701f | ||
|
|
3b19a7fe1d | ||
|
|
ccf9775658 | ||
|
|
762a499648 | ||
|
|
aa56188e7e | ||
|
|
1d92e65fcc | ||
|
|
a6f132f6da | ||
|
|
cb75b670b6 | ||
|
|
7bb9dd18da | ||
|
|
140254f311 | ||
|
|
56401f6675 | ||
|
|
99ba7707f6 | ||
|
|
ea1ef4e602 | ||
|
|
78b6113d8b | ||
|
|
59ab48b99e | ||
|
|
a7a58b920f | ||
|
|
1c26df2a90 | ||
|
|
c60e4839eb | ||
|
|
b626fc5095 | ||
|
|
bcd504eb05 | ||
|
|
7057b7f929 | ||
|
|
6af070e25f | ||
|
|
af1a7bd6f4 | ||
|
|
dfd3d0ec93 | ||
|
|
1791c0937a | ||
|
|
c2dd6a0c6a | ||
|
|
f300e76c9b | ||
|
|
8f6f880b6a | ||
|
|
3dcef655c3 | ||
|
|
4c476de74b | ||
|
|
c9e277aee5 | ||
|
|
689d6906ef | ||
|
|
1712afdae9 | ||
|
|
8428fafd3a | ||
|
|
3074846477 | ||
|
|
6c1825ba65 | ||
|
|
bef0a5f793 | ||
|
|
8e694eac57 | ||
|
|
8622f9fdc3 | ||
|
|
6e6a8f47af | ||
|
|
7a57c70d81 | ||
|
|
b2a1af1029 | ||
|
|
c44961c063 | ||
|
|
aceb234c2e | ||
|
|
dd6b60818c | ||
|
|
1978b16581 | ||
|
|
0d079b8c0b | ||
|
|
913029f4c5 | ||
|
|
c667c71a99 | ||
|
|
3cd8b9a44e | ||
|
|
126119b1fb | ||
|
|
701bf913e8 | ||
|
|
00b5944271 | ||
|
|
196076f952 | ||
|
|
e350224157 | ||
|
|
730e129a80 | ||
|
|
883fc1681d | ||
|
|
6b2b672c5e | ||
|
|
1d31bf699f | ||
|
|
c62728f44f | ||
|
|
90efb1ff31 | ||
|
|
7625cc7ceb | ||
|
|
a074115bf5 | ||
|
|
c3aa068179 | ||
|
|
e07be95646 | ||
|
|
0777a568d7 | ||
|
|
f6ce622841 | ||
|
|
508545aa87 | ||
|
|
52d86177c5 | ||
|
|
979d1cfba9 | ||
|
|
31a01aceab | ||
|
|
3b39d1270d | ||
|
|
d5b286c050 | ||
|
|
1f23848e25 | ||
|
|
db1c033c7c | ||
|
|
489afcfb41 | ||
|
|
5519ddad0b | ||
|
|
e788589944 | ||
|
|
7a894540b9 | ||
|
|
30f0f3a5a1 | ||
|
|
debc7284b3 | ||
|
|
60f5dfabd8 | ||
|
|
dd2f209096 | ||
|
|
3b181576c8 | ||
|
|
409334ea56 | ||
|
|
71218a6f70 | ||
|
|
a5be3727e9 | ||
|
|
836b646e24 | ||
|
|
15e4830dff | ||
|
|
ac1156d165 | ||
|
|
370ec24987 | ||
|
|
3bdcae10c8 | ||
|
|
681df1604d | ||
|
|
05abd88ea5 | ||
|
|
42670c0130 | ||
|
|
f4c15979db | ||
|
|
8d97f13677 | ||
|
|
75c4c3d6b9 | ||
|
|
a71e81c842 | ||
|
|
add55f3cec | ||
|
|
c6f6a9ef72 | ||
|
|
1c1e39ef64 | ||
|
|
f5655d85a3 | ||
|
|
c31262d339 | ||
|
|
570798358c | ||
|
|
05c9644ea6 | ||
|
|
051bd2b10b | ||
|
|
b1b9d10656 | ||
|
|
506f78eb32 | ||
|
|
1336ddfad7 | ||
|
|
f3617f720b | ||
|
|
844a1f43ed | ||
|
|
8e42412490 | ||
|
|
2737180a20 | ||
|
|
57e9e55705 | ||
|
|
3f3f8b41e9 | ||
|
|
d3ea390983 | ||
|
|
2f1cc844fd | ||
|
|
543af50ff8 | ||
|
|
f6444c8d45 | ||
|
|
df96dd0060 | ||
|
|
956e2aace3 | ||
|
|
1951d525d1 | ||
|
|
3d4d678bdc | ||
|
|
b78d92d288 | ||
|
|
e5dc4d7e78 | ||
|
|
cd247ef6c1 | ||
|
|
104cf8a58b | ||
|
|
976f175aa9 | ||
|
|
81a06c47a1 | ||
|
|
46b8c6bc83 | ||
|
|
5f83a3f98a | ||
|
|
2f6129bfd5 | ||
|
|
26698b6449 | ||
|
|
61839151c0 | ||
|
|
b38c9ea253 | ||
|
|
25754a47e0 | ||
|
|
278888c912 | ||
|
|
7faa4704e6 | ||
|
|
ba48b6c793 | ||
|
|
f8a969d43e | ||
|
|
55720342ad | ||
|
|
085239ef4a | ||
|
|
df61d561f6 | ||
|
|
3cd8b5f48b | ||
|
|
2e21e46e86 | ||
|
|
cb73a9a6bc | ||
|
|
5199df9b61 | ||
|
|
537ca9f724 | ||
|
|
fc5f5dab29 | ||
|
|
4be307820b | ||
|
|
15227bbc06 | ||
|
|
d0da2c24fb | ||
|
|
152a8a4666 | ||
|
|
86669beb7a | ||
|
|
ba2a70a484 | ||
|
|
88ffcf6396 | ||
|
|
4d347f9ff0 | ||
|
|
252258d138 | ||
|
|
e35b25015b | ||
|
|
422844f842 | ||
|
|
61725c8b49 | ||
|
|
727178df57 | ||
|
|
66b3303f22 | ||
|
|
47c3fad83b | ||
|
|
3928222395 | ||
|
|
414d33a46c | ||
|
|
40a2c8393e | ||
|
|
48fe298a36 | ||
|
|
2865f0eab2 | ||
|
|
a5780632ca | ||
|
|
bd5d29a825 | ||
|
|
5255935a31 | ||
|
|
a31ee062b6 | ||
|
|
c56c991bf7 | ||
|
|
5ea4b796a5 | ||
|
|
8fe7378f86 | ||
|
|
1224ffa7cd | ||
|
|
56766df719 | ||
|
|
e505e5e466 | ||
|
|
4cdc3c62b2 | ||
|
|
4402f08245 | ||
|
|
954830032b | ||
|
|
6f3fad8a16 | ||
|
|
2bb956bb06 | ||
|
|
7fa2a273d0 | ||
|
|
52e125e35a | ||
|
|
57bea35004 | ||
|
|
890842286b | ||
|
|
aec0ad9128 | ||
|
|
4f5b5a995b | ||
|
|
bcd07ff6c7 | ||
|
|
68d7188f3e | ||
|
|
a924a74d82 | ||
|
|
a20b830379 | ||
|
|
12fe96b114 | ||
|
|
3432721379 | ||
|
|
b39b7fd374 | ||
|
|
406ddff9a1 | ||
|
|
d16d985a48 | ||
|
|
0a2ea72d72 | ||
|
|
3b4de7152c | ||
|
|
5520dae2e7 | ||
|
|
7a7f26c80e | ||
|
|
35f4944afb | ||
|
|
0a107d10eb | ||
|
|
2c56ccfabe | ||
|
|
d1497e98db | ||
|
|
7925a8e1b3 | ||
|
|
d529bf3c0c | ||
|
|
802c5a9d5b | ||
|
|
3a22c36d04 | ||
|
|
512ee40dbc | ||
|
|
d84e1f49ce | ||
|
|
c4abaf8c8d | ||
|
|
59fe5f3572 | ||
|
|
18320e19bc | ||
|
|
248cd2e749 | ||
|
|
3b550eeed3 | ||
|
|
097c0ac0b7 | ||
|
|
7a95dcd6b6 | ||
|
|
47d0c04b30 | ||
|
|
16be2bd305 | ||
|
|
7cf6ee06a1 | ||
|
|
dd4c413e41 | ||
|
|
08d2ac41f6 | ||
|
|
fd939c6fce | ||
|
|
82755b5ef2 | ||
|
|
7b4cbee8e7 | ||
|
|
5346f594d4 | ||
|
|
6f217d78da | ||
|
|
cdf71c4cbc | ||
|
|
e93a280d2c | ||
|
|
51fa96c44b | ||
|
|
48d6135106 | ||
|
|
0d38b1cd91 | ||
|
|
f5c4deb42b | ||
|
|
069193e8b7 | ||
|
|
a424e996b3 | ||
|
|
3c81248335 | ||
|
|
1e3f277a71 | ||
|
|
3adeabb06d | ||
|
|
4593111871 | ||
|
|
7440be495e | ||
|
|
fded1a0718 | ||
|
|
ebbb2821d0 | ||
|
|
643b950eef | ||
|
|
63a20f537a | ||
|
|
ae94148bee | ||
|
|
9301eb9ee0 | ||
|
|
19448e242c | ||
|
|
f26c2f0812 | ||
|
|
6573476ea2 | ||
|
|
f73430a3f8 | ||
|
|
3bf90844b1 | ||
|
|
6546ae8e67 | ||
|
|
d01bdf9186 | ||
|
|
88b6cc1907 | ||
|
|
8922b63769 | ||
|
|
30d4713b28 | ||
|
|
498a52439c | ||
|
|
88798b78fc | ||
|
|
0ce7390ac1 | ||
|
|
00f5eb5338 | ||
|
|
d9967d7ea5 | ||
|
|
d42031293d | ||
|
|
76903904d0 | ||
|
|
a42f232b1e | ||
|
|
72a505a3e8 | ||
|
|
ae221ed5bd | ||
|
|
76115b30b8 | ||
|
|
7401d46bcd | ||
|
|
ee61d9c95a | ||
|
|
6db666c565 | ||
|
|
050acaa8c6 | ||
|
|
e83232fcf6 | ||
|
|
ece7ea36d9 | ||
|
|
73d27a625f | ||
|
|
a8d4f17add | ||
|
|
af6fb49e48 | ||
|
|
c593988bc1 | ||
|
|
2d590bb1f5 | ||
|
|
aef3677970 | ||
|
|
7d11254a52 | ||
|
|
3b9feeed12 | ||
|
|
6d3ca2df80 | ||
|
|
5d69ed5f4a | ||
|
|
81d13a8e0b | ||
|
|
544a2ac034 | ||
|
|
9a2bf37ac1 | ||
|
|
550d252386 | ||
|
|
2b3bdd7e60 | ||
|
|
4f38801ba6 | ||
|
|
31b41f5b94 | ||
|
|
03ce3c6592 | ||
|
|
2a4649f6ef | ||
|
|
96c3615ea5 | ||
|
|
adfcfafdc2 | ||
|
|
0a37f1cc30 | ||
|
|
70018a774b | ||
|
|
009bb94f17 | ||
|
|
0e0f1e2037 | ||
|
|
a0a0bc8270 | ||
|
|
25c532610b | ||
|
|
fcfd90b86f | ||
|
|
738d22a68a | ||
|
|
8c63b76343 | ||
|
|
ba7a04851f | ||
|
|
e3d15db6c5 | ||
|
|
ca46df09d8 | ||
|
|
f053e02868 | ||
|
|
42cbe1b397 | ||
|
|
42fe124a0e | ||
|
|
d809b59daa | ||
|
|
e14d4042d9 | ||
|
|
371b346bf7 | ||
|
|
b038dd5c9d | ||
|
|
2681a6db0d | ||
|
|
5ff1ea1435 | ||
|
|
759f165549 | ||
|
|
cb27ac8d93 | ||
|
|
035c77ad91 | ||
|
|
b45c249ed9 | ||
|
|
b90991f039 | ||
|
|
8d49ae5c68 | ||
|
|
49047cf972 | ||
|
|
aa5485ae27 | ||
|
|
fc0d9c5f92 | ||
|
|
8309c5feeb | ||
|
|
4693cac13b | ||
|
|
79f2b8448a | ||
|
|
7e09961ee7 | ||
|
|
21aded91f0 | ||
|
|
6b4bb5e7cb | ||
|
|
c1eef81fdb | ||
|
|
b1e6fa4f2b | ||
|
|
e672641878 | ||
|
|
fef0140098 | ||
|
|
4084eade0c | ||
|
|
748552d792 | ||
|
|
ff50b0c391 | ||
|
|
23e7d5c370 | ||
|
|
676b7523b3 | ||
|
|
880616397f | ||
|
|
ace8536987 | ||
|
|
3370ae4dcf | ||
|
|
8a6a1312f2 | ||
|
|
a9d633ab2d | ||
|
|
765a9d8325 | ||
|
|
67c6a661e5 | ||
|
|
b897d55873 | ||
|
|
7b099f9c64 | ||
|
|
c172fbd883 | ||
|
|
5fb581a51f | ||
|
|
f3a08a51ef | ||
|
|
a7b9590f6f | ||
|
|
998a114172 | ||
|
|
29f65bb6be | ||
|
|
cce9293413 | ||
|
|
b91a95ee49 | ||
|
|
0eb682a95b | ||
|
|
424312c2d8 | ||
|
|
969ee91506 | ||
|
|
f56ee97676 | ||
|
|
f667ec631d | ||
|
|
7bcf1cc0ae | ||
|
|
dba4ff3cff | ||
|
|
0ff030a44c | ||
|
|
7babbcf62b | ||
|
|
fd303c6e94 | ||
|
|
a8495b00f2 | ||
|
|
ae70f168a8 | ||
|
|
b239bec2c5 | ||
|
|
d0f05fed3b | ||
|
|
717c0e1299 | ||
|
|
8760064ddb | ||
|
|
ab0059eeee | ||
|
|
19a7d2139a | ||
|
|
5319117636 | ||
|
|
c5b32180d2 | ||
|
|
62baaf99b1 | ||
|
|
c03dd5951a | ||
|
|
555f4e132f | ||
|
|
c3209a2736 | ||
|
|
0b29d724db | ||
|
|
931a8063b4 | ||
|
|
c74406c89e | ||
|
|
c44b8b1936 | ||
|
|
b1671dd98d | ||
|
|
0baf0ff24a | ||
|
|
2929d7256b | ||
|
|
8d769dd3c2 | ||
|
|
e8d6f083a3 | ||
|
|
817c3d7058 | ||
|
|
e2a7dd0f17 | ||
|
|
f781537adb | ||
|
|
c2c65f46cb | ||
|
|
0f65adfaab | ||
|
|
efafe96b08 | ||
|
|
858957f6f7 | ||
|
|
128724d147 | ||
|
|
c6c6bfcf2c | ||
|
|
4f451ff653 | ||
|
|
7822f29140 | ||
|
|
98d434a0a9 | ||
|
|
61c1f7157c | ||
|
|
5ab4028257 | ||
|
|
717769f1cc | ||
|
|
7278bc9cde | ||
|
|
7bc67cd168 | ||
|
|
bc23a90ef7 | ||
|
|
2070b53967 | ||
|
|
37a8ac3b32 | ||
|
|
3b2e75055f | ||
|
|
9f5e12992a | ||
|
|
eede8e1e8d | ||
|
|
b40c4ebcd7 | ||
|
|
53e449a96f | ||
|
|
d35217d39d | ||
|
|
883463f2d5 | ||
|
|
9abfdb3431 | ||
|
|
e942a8433b | ||
|
|
0163746709 | ||
|
|
dfbdd81d41 | ||
|
|
b474a9061b | ||
|
|
eaeef7e9e9 | ||
|
|
30091b2af6 | ||
|
|
73b51adfb3 | ||
|
|
34a82f7bfc | ||
|
|
159bbcf4a4 | ||
|
|
398a8b12c2 | ||
|
|
d45558782f | ||
|
|
1c3f4c078f | ||
|
|
48588a2556 | ||
|
|
4ae5391637 | ||
|
|
28e11dec31 | ||
|
|
b343ab69a5 | ||
|
|
697dc5fa3f | ||
|
|
fa12161c47 | ||
|
|
9f0f1efafe | ||
|
|
aa4c56e466 | ||
|
|
09e1464bc8 | ||
|
|
b689c745a0 | ||
|
|
28c2c56271 | ||
|
|
2d666965cf | ||
|
|
444d5c7580 | ||
|
|
5d694fe2f2 | ||
|
|
ccd9692875 | ||
|
|
8c553cad5d | ||
|
|
a99a68b03a | ||
|
|
acb01382df | ||
|
|
23d63686e6 | ||
|
|
c0083beec0 | ||
|
|
1d680c2039 | ||
|
|
bb273b55e2 | ||
|
|
d119ae5ed4 | ||
|
|
d78dbbe4c7 | ||
|
|
663ac80fd0 | ||
|
|
2d34788607 | ||
|
|
cbf4e37bba | ||
|
|
74b70253b2 | ||
|
|
0343ee119c | ||
|
|
f9c9868349 | ||
|
|
1395090241 | ||
|
|
dc938e8a60 | ||
|
|
7dd4f1ab72 | ||
|
|
d53c9c1e87 | ||
|
|
424a08607c | ||
|
|
0d2a060e66 | ||
|
|
9748c55dd0 | ||
|
|
130d96b31e | ||
|
|
e6e420d9a3 | ||
|
|
bde4adcdef | ||
|
|
3746ae9cf3 | ||
|
|
0c4eed79da | ||
|
|
8bbd9abd27 | ||
|
|
dfa15ad9fc | ||
|
|
00ac1fdcd1 | ||
|
|
af7bfc7de7 | ||
|
|
e3759a5cd0 | ||
|
|
c5f4820b4e | ||
|
|
a3d9da2fd4 | ||
|
|
e592d2eb6d | ||
|
|
e57aaadb1d | ||
|
|
0d2492bfde | ||
|
|
1a3483e086 | ||
|
|
171c213b32 | ||
|
|
c4dcb316ca | ||
|
|
725f612eb5 | ||
|
|
3539ed5bfe | ||
|
|
a8bd94e34f | ||
|
|
0d59028eb2 | ||
|
|
7ae39b38a0 | ||
|
|
b69f9b9536 | ||
|
|
6dbc4d44a8 | ||
|
|
397eff9712 | ||
|
|
51c23856f3 | ||
|
|
6cb6605a63 | ||
|
|
6ad164d522 | ||
|
|
19915ad238 | ||
|
|
5e8fb55955 | ||
|
|
d535bf35a8 | ||
|
|
17d73a93f1 | ||
|
|
ac2f2516a2 | ||
|
|
8994f9580c | ||
|
|
6013325637 | ||
|
|
ba19837104 | ||
|
|
509a1bf56e | ||
|
|
5b07a475e1 | ||
|
|
bb97366338 | ||
|
|
a527fdcc28 | ||
|
|
5c3a4deed8 | ||
|
|
70b9bed510 | ||
|
|
37795375b6 | ||
|
|
903f9ddb41 | ||
|
|
4b6ade050f | ||
|
|
02cfa0be7f | ||
|
|
da7a7a4d0e | ||
|
|
84a1b6976f | ||
|
|
4d1641b321 | ||
|
|
ee561da549 | ||
|
|
ba1493857f | ||
|
|
fb7a0318a0 | ||
|
|
479ade9cb7 | ||
|
|
dfe62ceac8 | ||
|
|
a36c9bfe73 | ||
|
|
a7119cae76 | ||
|
|
c33368bfb4 | ||
|
|
886999bc5b | ||
|
|
1a750182d6 | ||
|
|
03a69053a6 | ||
|
|
5788d4af1e | ||
|
|
517fe28806 | ||
|
|
b272bdb198 | ||
|
|
910d22a532 | ||
|
|
2a85ea9c61 | ||
|
|
3ee5c792d1 | ||
|
|
8e377ca074 | ||
|
|
451cfa521b | ||
|
|
6d02f7f897 | ||
|
|
3e811f869e | ||
|
|
1f17a57528 | ||
|
|
8c2ea218a5 | ||
|
|
9f01b2ec0d | ||
|
|
86c5dfd664 | ||
|
|
c31aa8a78d | ||
|
|
648d99c9e6 | ||
|
|
cfe541e3ca | ||
|
|
b6faad0354 | ||
|
|
8aee3f4185 | ||
|
|
fe44725804 | ||
|
|
870e0872c0 | ||
|
|
2874e30991 | ||
|
|
d92b46426c | ||
|
|
1c34edb857 | ||
|
|
aba3bcc81a | ||
|
|
085529217e | ||
|
|
50d8016e86 | ||
|
|
4a033b8e76 | ||
|
|
4f5ad4b3ac | ||
|
|
104d51df8c | ||
|
|
5c9ab0a27d | ||
|
|
065d91cf9b | ||
|
|
acceb3155a | ||
|
|
4130e0847c | ||
|
|
37a451a38e | ||
|
|
dd26d06e1c | ||
|
|
235784b46f | ||
|
|
66af0f810c | ||
|
|
72b60a2ab3 | ||
|
|
40e6f46013 | ||
|
|
a701ff87ec | ||
|
|
6e78bc1726 | ||
|
|
3b4181c616 | ||
|
|
2bd3fa6aa7 | ||
|
|
4d0d971212 | ||
|
|
1e451e3353 | ||
|
|
207f829066 | ||
|
|
f1fba8eb42 | ||
|
|
146287331a | ||
|
|
490dcac380 | ||
|
|
e8264eb0db | ||
|
|
3c07dd58eb | ||
|
|
fcdd8fc383 | ||
|
|
0b56f5aebd | ||
|
|
178537116b | ||
|
|
11cfae2a98 | ||
|
|
348bd64449 | ||
|
|
b36eca9792 | ||
|
|
683b77c9bd | ||
|
|
7809f23d4b | ||
|
|
37a9549298 | ||
|
|
8fa2368a63 | ||
|
|
72ca99051b | ||
|
|
905e3ae583 | ||
|
|
29be84ba47 | ||
|
|
636c350461 | ||
|
|
89e305878b | ||
|
|
45873cc2b1 | ||
|
|
a32955ffec | ||
|
|
5b45f871df | ||
|
|
17bc603077 | ||
|
|
7af9158baa | ||
|
|
571a041c25 | ||
|
|
0a02340e35 | ||
|
|
12ee624358 | ||
|
|
571de7f07f | ||
|
|
b055c2be65 | ||
|
|
78750b96e5 | ||
|
|
ce51207e44 | ||
|
|
a3dcaf4284 | ||
|
|
181274636e | ||
|
|
c4198554ad | ||
|
|
ed45a8d666 | ||
|
|
5a8b5c8af4 | ||
|
|
1e3c599b4e | ||
|
|
41ca58a403 | ||
|
|
e09b18d3fb | ||
|
|
4b7958f447 | ||
|
|
b0b11572d7 | ||
|
|
c1684db78a | ||
|
|
fdbdc615da | ||
|
|
5354a134fc | ||
|
|
800d3fd109 | ||
|
|
b7f8a1eb8b | ||
|
|
dbeea3b8a1 | ||
|
|
888705c7dc | ||
|
|
d9e649c023 | ||
|
|
14da2a9a67 | ||
|
|
d7e712f48b | ||
|
|
0f9b48d446 | ||
|
|
6e90c47e74 | ||
|
|
365d2b0eb2 | ||
|
|
3642119665 | ||
|
|
705cb79819 | ||
|
|
d8e5c5372a | ||
|
|
714ccbc321 | ||
|
|
0917fbe0c4 | ||
|
|
1517177668 | ||
|
|
2487fb4d98 | ||
|
|
de0718811e | ||
|
|
12b9b1a6e9 | ||
|
|
1f819c4924 | ||
|
|
1d209596a3 | ||
|
|
b1d5e27564 | ||
|
|
732f2f106b | ||
|
|
db6319b90f | ||
|
|
601eb63c9a | ||
|
|
d237d5e807 | ||
|
|
da47d34705 | ||
|
|
ce5a5bf356 | ||
|
|
c754cb75b6 | ||
|
|
f084966fd3 | ||
|
|
79dd8c29ae | ||
|
|
a260dff197 | ||
|
|
f83179c665 | ||
|
|
31508f673c | ||
|
|
a1f87da9f5 | ||
|
|
eb102f8a82 | ||
|
|
e1a2439fbf | ||
|
|
9fb2cb86ed | ||
|
|
f6b646ef67 | ||
|
|
068025d919 | ||
|
|
f88f59926e | ||
|
|
c9d593fa17 | ||
|
|
ed452e81ae | ||
|
|
604da55f08 | ||
|
|
57a5d517c8 | ||
|
|
2b6fa580df | ||
|
|
7f750e7ac1 | ||
|
|
b9779c2184 | ||
|
|
e52c207c75 | ||
|
|
bfdcb023b3 | ||
|
|
dce3292fc7 | ||
|
|
98a567e102 | ||
|
|
d6123a87c5 | ||
|
|
f94ceccc8a | ||
|
|
cc97914ed8 | ||
|
|
829be9e506 | ||
|
|
bea68ddbfa | ||
|
|
fa039a1320 | ||
|
|
cdaf19899e | ||
|
|
b5847d83cb | ||
|
|
685cc7b0ba | ||
|
|
b14be7f614 | ||
|
|
35f8500acd | ||
|
|
cb0cceb9ae | ||
|
|
1405d83a56 | ||
|
|
0878acf04c | ||
|
|
735d9c107d | ||
|
|
daf148c4d6 | ||
|
|
922fa046bb | ||
|
|
b247fd04df | ||
|
|
0b53a98648 | ||
|
|
f76fa67303 | ||
|
|
e6d3812d6c | ||
|
|
c02946a913 | ||
|
|
8ec2851439 | ||
|
|
f2c68385ab | ||
|
|
f428001f42 | ||
|
|
83104b32b8 | ||
|
|
1a12bd7269 | ||
|
|
04aa1af72e | ||
|
|
466a8cb107 | ||
|
|
23c9d574d9 | ||
|
|
5cc73fdf40 | ||
|
|
3cfd4c8ec2 | ||
|
|
9eb6d49616 | ||
|
|
8bd81dffcf | ||
|
|
79ca411d6a | ||
|
|
9cdf1f9711 | ||
|
|
c8b6834a5e | ||
|
|
e15eb5a7f6 | ||
|
|
3d4acc3aef | ||
|
|
1349601269 | ||
|
|
0751aed1f0 | ||
|
|
4f2ed9ba62 | ||
|
|
707f41af39 | ||
|
|
3d400cf91b | ||
|
|
a77093e154 | ||
|
|
6676fe3b3b | ||
|
|
1d85580fbc | ||
|
|
f01e987d31 | ||
|
|
eb96a1c03a | ||
|
|
e99387aa83 | ||
|
|
f8341bf934 | ||
|
|
20ccf221a8 | ||
|
|
b98fe181e8 | ||
|
|
34eea95426 | ||
|
|
5f470be79e | ||
|
|
1c8683343b | ||
|
|
56f37e8745 | ||
|
|
910a466fad | ||
|
|
d3a15b7ab6 | ||
|
|
cd8ee4c4b4 | ||
|
|
c253e4a48e | ||
|
|
90bd5b0cb1 | ||
|
|
fd729da8f1 | ||
|
|
9bfc027b15 | ||
|
|
cedd8e3670 | ||
|
|
3c31ecb115 | ||
|
|
cc25976743 | ||
|
|
6fea5e5854 | ||
|
|
bf6ac0d608 | ||
|
|
cb7c7ad913 | ||
|
|
bd9cddf211 | ||
|
|
3d33454564 | ||
|
|
a70109be83 | ||
|
|
5ec0a88949 | ||
|
|
12de380799 | ||
|
|
89a3c359a6 | ||
|
|
848390d9eb | ||
|
|
2f89043b35 | ||
|
|
fcfd0d794b | ||
|
|
dbd83a8b28 | ||
|
|
36d62235b3 | ||
|
|
79c4c8bdd3 | ||
|
|
6be2c376e2 | ||
|
|
db22d8b1c9 | ||
|
|
e4fa7bc969 | ||
|
|
98b0ac713d | ||
|
|
74eea34c6e | ||
|
|
bbe817e3be | ||
|
|
f53775ac39 | ||
|
|
dfb1cd4876 | ||
|
|
c2c34ccba3 | ||
|
|
c8d005af84 | ||
|
|
7c651088b5 | ||
|
|
9a9d51440a | ||
|
|
4b3e632d14 | ||
|
|
b52b321969 | ||
|
|
e5b36d2997 | ||
|
|
cc2016bbc9 | ||
|
|
a68be9117b | ||
|
|
f4fceb53bc | ||
|
|
495d566401 | ||
|
|
7a056851d9 | ||
|
|
44eb9cf678 | ||
|
|
597a56d0ff | ||
|
|
967132b04e | ||
|
|
423795b49e | ||
|
|
27b7382be5 | ||
|
|
25d342f829 | ||
|
|
f683404db9 | ||
|
|
d8c3c38d69 | ||
|
|
0400bea3bd | ||
|
|
10088c6566 | ||
|
|
a2abb4e8b1 | ||
|
|
f1625c0d92 | ||
|
|
5c4b0baf8b | ||
|
|
af1b5a9a51 | ||
|
|
f5a7e63936 | ||
|
|
13da8f0d75 | ||
|
|
adea4ceef2 | ||
|
|
cc85f79322 | ||
|
|
c22782d2ab | ||
|
|
994a575d32 | ||
|
|
39faa1538d | ||
|
|
153343fa9e | ||
|
|
0d3e9f21ee | ||
|
|
8c01412156 | ||
|
|
bd46fd7d4f | ||
|
|
cb25e077f9 | ||
|
|
0551f13f0e | ||
|
|
0965273711 | ||
|
|
dd9e8ae8ff | ||
|
|
f08bc7846a | ||
|
|
bac90cfe57 | ||
|
|
6547166c2d | ||
|
|
5a07587437 | ||
|
|
6a14d26c1d | ||
|
|
477617240a | ||
|
|
e8d2b6d25d | ||
|
|
d1a037b38b | ||
|
|
a552e5a48f | ||
|
|
b553c3f3ac | ||
|
|
551542f99a | ||
|
|
1e5bfcdbcd | ||
|
|
c1b6cb7302 | ||
|
|
70f5003784 | ||
|
|
c2a0d7bc32 | ||
|
|
34c1fec8f7 | ||
|
|
14ec226747 | ||
|
|
aebad0cf18 | ||
|
|
ecac60f4c9 | ||
|
|
21f8b852f2 | ||
|
|
4919f161cc | ||
|
|
3dda84e58b | ||
|
|
0823bfaed2 | ||
|
|
3bcb72a083 | ||
|
|
634f3c0f58 | ||
|
|
f3d3a8a8ed | ||
|
|
721038513f | ||
|
|
195efffa15 | ||
|
|
ae4f43fdb9 | ||
|
|
4ce40ad239 | ||
|
|
ca345d7f55 | ||
|
|
066410a31d | ||
|
|
30e8fa9620 | ||
|
|
64826243dd | ||
|
|
2357057bb5 | ||
|
|
c257075df0 | ||
|
|
b1fa994d82 | ||
|
|
56daf71a86 | ||
|
|
4ac26b61b3 | ||
|
|
cd3a042776 | ||
|
|
7fd7479b84 | ||
|
|
9a8c07faf5 | ||
|
|
335777a681 | ||
|
|
9479d7ae07 | ||
|
|
4827427ac0 | ||
|
|
8e732046ba | ||
|
|
f08b88cce5 | ||
|
|
5a244911cc | ||
|
|
02161dc4d7 | ||
|
|
a62f686024 | ||
|
|
1b09e8a6b0 | ||
|
|
23917fa07e | ||
|
|
0a7963588e | ||
|
|
42d281bfe3 | ||
|
|
5e28ebef06 | ||
|
|
3fa01e53b9 | ||
|
|
ecac1815db | ||
|
|
79f365753e | ||
|
|
64b7198144 | ||
|
|
f3743b6599 | ||
|
|
8a0af31a49 | ||
|
|
044b88dbce | ||
|
|
acf06e6a94 | ||
|
|
c8922d2efd | ||
|
|
3786e7569d | ||
|
|
70ad747a9c | ||
|
|
ce322774d8 | ||
|
|
7309be6339 | ||
|
|
5edc83c556 | ||
|
|
2c86fb8c73 | ||
|
|
25937c5b73 | ||
|
|
43833df092 | ||
|
|
93c19dc3f8 | ||
|
|
a4e53b929b | ||
|
|
18534d56e2 | ||
|
|
fd35361614 | ||
|
|
85dfd5b978 | ||
|
|
b23fcc83c1 | ||
|
|
d625cf68e5 | ||
|
|
b7683b77a7 | ||
|
|
3b81d44491 | ||
|
|
949bbb40eb | ||
|
|
5ce5951f5d | ||
|
|
09428c185e | ||
|
|
ad1bfc57b4 | ||
|
|
b971a37ee3 | ||
|
|
3ca6ac6145 | ||
|
|
c2f4ce9c5a | ||
|
|
66fee75fc2 | ||
|
|
367e4ac3f7 | ||
|
|
094f961a0a | ||
|
|
be676d7fa6 | ||
|
|
32d92866e9 | ||
|
|
de8a3de7ae | ||
|
|
cdd33ffec4 | ||
|
|
340bdb0b6c | ||
|
|
7f4762e632 | ||
|
|
22b4b9c18d | ||
|
|
d31a6c0ba6 | ||
|
|
59779aea37 | ||
|
|
50fa1046c7 | ||
|
|
0e958fed2e | ||
|
|
def0f3564c | ||
|
|
7da2c56d0a | ||
|
|
1321431812 | ||
|
|
d93a243738 | ||
|
|
fa24bbd96a | ||
|
|
5eca802a5a | ||
|
|
89d6f73aff | ||
|
|
0bb2043f97 | ||
|
|
62c22e55e7 | ||
|
|
23eef578f7 | ||
|
|
ce8a482a62 | ||
|
|
76f5319b05 | ||
|
|
448e5155a4 | ||
|
|
3ee26b727c | ||
|
|
544a496f08 | ||
|
|
14f0497e64 | ||
|
|
9ab80d228b | ||
|
|
3f4599e562 | ||
|
|
973714b4cc | ||
|
|
bb3458e26b | ||
|
|
0692d4f3f2 | ||
|
|
7a08d50f18 | ||
|
|
987e6e03f1 | ||
|
|
5004513596 | ||
|
|
749961af32 | ||
|
|
eda8b442e0 | ||
|
|
9d0e59b31c | ||
|
|
1771694ee1 | ||
|
|
85d16af0d0 | ||
|
|
a80c739067 | ||
|
|
73b2eb4a72 | ||
|
|
4c7cbe4128 | ||
|
|
343174fd47 | ||
|
|
3c20930550 | ||
|
|
0e109a9e33 |
No files matched your search
@@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: ptitSeb
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: paypal.me/0ptitSeb
|
||||
@@ -0,0 +1,95 @@
|
||||
### Manual build Box64 with Github Action
|
||||
name: Custom build Box64
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
platform:
|
||||
description: 'Target platform name'
|
||||
required: true
|
||||
default: 'GENERIC_ARM'
|
||||
type: choice
|
||||
options:
|
||||
- X64
|
||||
- GENERIC_ARM
|
||||
- PHYTIUM
|
||||
- RK3326
|
||||
- RK3399
|
||||
- RK3588
|
||||
- RPI4ARM64
|
||||
- SD845
|
||||
- TEGRAX1
|
||||
build_type:
|
||||
description: 'Build type'
|
||||
required: true
|
||||
default: 'RelWithDebInfo'
|
||||
type: choice
|
||||
options:
|
||||
- RelWithDebInfo
|
||||
- Release
|
||||
- Debug
|
||||
- MinSizeRel
|
||||
dynarec:
|
||||
description: 'Enable dynarec'
|
||||
required: false
|
||||
default: 'true'
|
||||
type: boolean
|
||||
trace:
|
||||
description: 'Enable trace'
|
||||
required: false
|
||||
default: 'false'
|
||||
type: boolean
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Checkout Box64 Repository"
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: "Environment preparation"
|
||||
run: |
|
||||
sudo apt-get update
|
||||
if [[ ${{ github.event.inputs.platform }} != 'X64' && ${{ github.event.inputs.platform }} != 'GENERIC_ARM' ]]; then
|
||||
echo "BOX64_PLATFORM_MARCRO=-D${{ github.event.inputs.platform }}=1" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-aarch64-linux-gnu cmake make python3
|
||||
else
|
||||
if [[ ${{ github.event.inputs.platform }} == 'X64' ]]; then
|
||||
echo "BOX64_PLATFORM_MARCRO=-DLD80BITS=1 -DNOALIGN=1" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git cmake make python3
|
||||
else
|
||||
echo BOX64_PLATFORM_MARCRO="-DARM_DYNAREC=ON" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-aarch64-linux-gnu cmake make python3
|
||||
fi
|
||||
fi
|
||||
|
||||
- name: "Display Build info"
|
||||
run: |
|
||||
echo "CMake Platform Macro: ${{ env.BOX64_PLATFORM_MARCRO }}"
|
||||
echo "CMake C Compiler: ${{ env.BOX64_COMPILER }}"
|
||||
echo "Build type: ${{ github.event.inputs.build_type }}"
|
||||
echo "Dynarec Enabled: ${{ github.event.inputs.dynarec }}"
|
||||
echo "Trace Enabled: ${{ github.event.inputs.trace }}"
|
||||
|
||||
- name: "Build Box64"
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=${{ env.BOX64_COMPILER }} ${{ env.BOX64_PLATFORM_MARCRO }}\
|
||||
-DCMAKE_BUILD_TYPE=${{ github.event.inputs.build_type }}\
|
||||
-DARM_DYNAREC:BOOL=${{ github.event.inputs.dynarec }}\
|
||||
-DHAVE_TRACE:BOOL=${{ github.event.inputs.trace }}\
|
||||
-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON
|
||||
make -j$(nproc) VERBOSE=1
|
||||
|
||||
- name: "Upload Artifact"
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: box64-${{ github.event.inputs.platform }}-${{ github.event.inputs.build_type }}
|
||||
path: build/box64
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
### Auto build Box64 and release its binary with Github Action
|
||||
name: Build and Release Box64
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
push:
|
||||
paths:
|
||||
- "**/*.c"
|
||||
- "**/*.h"
|
||||
- "**/*.S"
|
||||
- "**/*.py"
|
||||
- "CMakeLists.txt"
|
||||
- "**/*.yml"
|
||||
pull_request:
|
||||
types: [assigned, opened, synchronize, reopened]
|
||||
paths:
|
||||
- "**/*.c"
|
||||
- "**/*.h"
|
||||
- "**/*.S"
|
||||
- "**/*.py"
|
||||
- "CMakeLists.txt"
|
||||
- "**/*.yml"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
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: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: "Checkout Box64 Repository"
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: "Environment preparation"
|
||||
run: |
|
||||
sudo apt-get update
|
||||
if [[ ${{ matrix.platform }} != 'X64' && ${{ matrix.platform }} != 'OTHER_ARM' && ${{ matrix.platform }} != 'RISCV' ]]; then
|
||||
echo "BOX64_PLATFORM_MARCRO=-D${{ matrix.platform }}=1" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-aarch64-linux-gnu cmake make python3
|
||||
else
|
||||
if [[ ${{ matrix.platform }} == 'X64' ]]; then
|
||||
echo "BOX64_PLATFORM_MARCRO=-DLD80BITS=1 -DNOALIGN=1" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git cmake make python3
|
||||
elif [[ ${{ matrix.platform }} == 'RISCV' ]]; then
|
||||
echo BOX64_PLATFORM_MARCRO="-DRV64=ON" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=riscv64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-riscv64-linux-gnu cmake make python3
|
||||
else
|
||||
echo BOX64_PLATFORM_MARCRO="-DARM_DYNAREC=ON" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-aarch64-linux-gnu cmake make python3
|
||||
fi
|
||||
fi
|
||||
if [[ ${{ matrix.type }} == 'Release' ]]; then
|
||||
echo BOX64_BUILD_TYPE=Release >> $GITHUB_ENV
|
||||
echo BOX64_HAVE_TRACE=0 >> $GITHUB_ENV
|
||||
else
|
||||
echo BOX64_BUILD_TYPE=RelWithDebInfo >> $GITHUB_ENV
|
||||
echo BOX64_HAVE_TRACE=1 >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: "Display Build info"
|
||||
run: |
|
||||
echo "CMake Platform Macro: ${{ env.BOX64_PLATFORM_MARCRO }}"
|
||||
echo "CMake C Compiler: ${{ env.BOX64_COMPILER }}"
|
||||
echo "Build type: ${{ env.BOX64_BUILD_TYPE }}"
|
||||
echo "Trace Enabled: ${{ env.BOX64_HAVE_TRACE }}"
|
||||
|
||||
- name: "Build Box64"
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=${{ env.BOX64_COMPILER }}\
|
||||
${{ env.BOX64_PLATFORM_MARCRO }}\
|
||||
-DCMAKE_BUILD_TYPE=${{ env.BOX64_BUILD_TYPE }}\
|
||||
-DHAVE_TRACE=${{ env.BOX64_HAVE_TRACE }}\
|
||||
-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON
|
||||
make -j$(nproc) VERBOSE=1
|
||||
|
||||
- name: "Test Box64"
|
||||
if: ${{ matrix.platform == 'X64' }}
|
||||
run: |
|
||||
cd build
|
||||
ctest -j$(nproc)
|
||||
|
||||
- name: "Upload Artifact"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: box64-${{ matrix.platform }}-${{ matrix.type }}
|
||||
path: build/box64
|
||||
@@ -55,7 +55,13 @@ dkms.conf
|
||||
build/
|
||||
build*/
|
||||
.vscode
|
||||
.cache
|
||||
.gdb_history
|
||||
src/git_head.h
|
||||
backup/
|
||||
|
||||
# LLVMprivateGenerator
|
||||
/LLVMprivateGenerator/*
|
||||
!/LLVMprivateGenerator/Makefile
|
||||
!/LLVMprivateGenerator/main.cpp
|
||||
!/LLVMprivateGenerator/registered_structs.cpp
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
language: c
|
||||
arch:
|
||||
- amd64
|
||||
- arm64-graviton2
|
||||
os: linux
|
||||
dist: focal
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- python3
|
||||
|
||||
#Build steps
|
||||
before_script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- if [ "$TRAVIS_CPU_ARCH" = "arm64" ]; then cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo ; else cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo ; fi
|
||||
|
||||
script:
|
||||
- make
|
||||
- ctest --output-on-failure
|
||||
@@ -1,7 +0,0 @@
|
||||
Current version
|
||||
======
|
||||
* Using box86 as a base, implemented most planned box64 part except dyanrec
|
||||
* Wrapped a few libs
|
||||
* ELF loader a bit crude, but seems working
|
||||
* Signal handling implemented
|
||||
* MMX and x87 are sharing their registers
|
||||
+594
-67
@@ -1,12 +1,75 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.4)
|
||||
|
||||
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 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 "")
|
||||
set(ARM_DYNAREC OFF CACHE BOOL "")
|
||||
endif()
|
||||
if(RV64)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
set(ARM_DYNAREC OFF CACHE BOOL "")
|
||||
set(PAGE16K OFF CACHE BOOL "")
|
||||
endif()
|
||||
if(PPC64LE)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
set(ARM_DYNAREC OFF CACHE BOOL "")
|
||||
set(PAGE16K OFF CACHE BOOL "")
|
||||
endif()
|
||||
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 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)
|
||||
@@ -28,23 +91,90 @@ project(box64 C ASM)
|
||||
|
||||
enable_testing()
|
||||
|
||||
set(default_build_type "RelwithDebInfo")
|
||||
set(default_build_type "RelWithDebInfo")
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
message(STATUS "Setting build type to '${default_build_type}' as none was specified.")
|
||||
set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE)
|
||||
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 -mfpu=neon-fp-armv8)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8")
|
||||
endif()
|
||||
if(RK3399)
|
||||
add_definitions(-pipe -march=armv8-a+crc -mtune=cortex-a72)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc -mtune=cortex-a72")
|
||||
elseif(RK3326)
|
||||
add_definitions(-DRK3326)
|
||||
add_definitions(-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a35+crypto)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a35+crypto")
|
||||
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)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a73.cortex-a53+crypto")
|
||||
elseif(TEGRAX1)
|
||||
add_definitions(-DTEGRAX1)
|
||||
add_definitions(-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a57+crypto)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a57+crypto")
|
||||
elseif(PHYTIUM)
|
||||
add_definitions(-DPHYSIUM)
|
||||
add_definitions(-pipe -march=armv8.1-a+crc+simd+crypto)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8.1-a+crc+simd+crypto+aes")
|
||||
elseif(SD845)
|
||||
add_definitions(-DSD845)
|
||||
add_definitions(-pipe -march=armv8.2-a+simd+crypto -mtune=cortex-a75.cortex-a55)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8.2-a+simd+crypto -mtune=cortex-a75.cortex-a55")
|
||||
elseif(M1)
|
||||
add_definitions(-DM1)
|
||||
add_definitions(-pipe -march=armv8.5-a+simd+crypto)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8.5-a+simd+crypto")
|
||||
elseif(LARCH64)
|
||||
add_definitions(-DLA464)
|
||||
add_definitions(-pipe -march=loongarch64)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=loongarch64")
|
||||
elseif(RV64)
|
||||
add_definitions(-DRV64)
|
||||
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)
|
||||
@@ -52,12 +182,13 @@ if(NOGIT)
|
||||
endif()
|
||||
|
||||
if(HAVE_TRACE)
|
||||
set(BOX64 box64t)
|
||||
set(BOX64 box64)
|
||||
else()
|
||||
set(BOX64 box64)
|
||||
endif()
|
||||
|
||||
set(BOX64_ELF_ADDRESS "0x50062800000") #random load address...
|
||||
#set(BOX64_ELF_ADDRESS "0x500062800000") #random load address...
|
||||
set(BOX64_ELF_ADDRESS "0x34800000") #low address
|
||||
|
||||
if(LD80BITS)
|
||||
add_definitions(-DHAVE_LD80BITS)
|
||||
@@ -71,6 +202,16 @@ if(HAVE_TRACE)
|
||||
add_definitions(-DHAVE_TRACE)
|
||||
endif()
|
||||
|
||||
if(ARM_DYNAREC)
|
||||
add_definitions(-DDYNAREC)
|
||||
add_definitions(-DARM64)
|
||||
enable_language(ASM)
|
||||
include_directories("${BOX64_ROOT}/src/dynarec/arm64")
|
||||
set(DYNAREC ON)
|
||||
else()
|
||||
set(DYNAREC OFF)
|
||||
endif()
|
||||
|
||||
set(BOX64_ROOT ${CMAKE_SOURCE_DIR})
|
||||
|
||||
add_definitions(-std=gnu11 -funwind-tables -fvisibility=hidden)
|
||||
@@ -80,6 +221,8 @@ if(USE_CCACHE)
|
||||
if(CCACHE_FOUND)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
|
||||
else()
|
||||
message(SEND_ERROR "ccache not found!")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -100,7 +243,10 @@ 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"
|
||||
"${BOX64_ROOT}/src/elfs/elfloader.c"
|
||||
"${BOX64_ROOT}/src/elfs/elfparser.c"
|
||||
"${BOX64_ROOT}/src/elfs/elfload_dump.c"
|
||||
@@ -113,8 +259,21 @@ set(ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/emu/x64run64.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run66.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run660f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run6664.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run66d9.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run66dd.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run66f0.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run67.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run670f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run6766.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run67660f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64rund8.c"
|
||||
"${BOX64_ROOT}/src/emu/x64rund9.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runda.c"
|
||||
"${BOX64_ROOT}/src/emu/x64rundb.c"
|
||||
"${BOX64_ROOT}/src/emu/x64rundc.c"
|
||||
"${BOX64_ROOT}/src/emu/x64rundd.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runde.c"
|
||||
"${BOX64_ROOT}/src/emu/x64rundf.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runf0.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runf20f.c"
|
||||
@@ -125,43 +284,230 @@ set(ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/emu/x64trace.c"
|
||||
"${BOX64_ROOT}/src/librarian/librarian.c"
|
||||
"${BOX64_ROOT}/src/librarian/library.c"
|
||||
"${BOX64_ROOT}/src/librarian/dictionnary.c"
|
||||
"${BOX64_ROOT}/src/librarian/globalsymbols.c"
|
||||
"${BOX64_ROOT}/src/librarian/symbols.c"
|
||||
"${BOX64_ROOT}/src/libtools/auxval.c"
|
||||
"${BOX64_ROOT}/src/libtools/obstack.c"
|
||||
"${BOX64_ROOT}/src/libtools/myalign.c"
|
||||
"${BOX64_ROOT}/src/libtools/sdl1rwops.c"
|
||||
"${BOX64_ROOT}/src/libtools/sdl2rwops.c"
|
||||
"${BOX64_ROOT}/src/libtools/signals.c"
|
||||
"${BOX64_ROOT}/src/libtools/threads.c"
|
||||
"${BOX64_ROOT}/src/tools/box64stack.c"
|
||||
"${BOX64_ROOT}/src/tools/bridge.c"
|
||||
"${BOX64_ROOT}/src/tools/callback.c"
|
||||
"${BOX64_ROOT}/src/tools/my_cpuid.c"
|
||||
"${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"
|
||||
)
|
||||
|
||||
set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibc.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibm.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibdl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibpthread.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibrt.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedalure.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedalut.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedatk.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedatkbridge.c"
|
||||
"${BOX64_ROOT}/src/wrapped/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"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappeddbus.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappeddbusglib1.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedexpat.c"
|
||||
"${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"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedglib2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgmodule2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgmp.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgnutls.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgobject2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgssapi.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgssapikrb5.c"
|
||||
"${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"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibasound.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibc.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibcrypt.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibcups.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibdl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/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"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibncurses6.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibncursesw.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibncursesw6.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibogg.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibpanel.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibpci.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibpcre.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibpthread.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibresolv.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibrt.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibsm.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibsndfile.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibssl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibtinfo.c"
|
||||
"${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"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxau.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcb.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbdri2.c"
|
||||
"${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"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxdamage.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxdmcp.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxext.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxfixes.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxft.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxi.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxmu.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxpm.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxpresent.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxrandr.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxrender.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxss.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxt.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxtst.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxxf86vm.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibz.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlzma.c"
|
||||
"${BOX64_ROOT}/src/wrapped/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"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappednssutil3.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedopenal.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpango.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpangocairo.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpangoft2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedplc4.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedplds4.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpng16.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpulse.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpulsesimple.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl1.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl1image.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl1mixer.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl1net.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl1sound.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl1ttf.c"
|
||||
"${BOX64_ROOT}/src/wrapped/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"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl2mixer.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl2net.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl2ttf.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedselinux.c"
|
||||
"${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"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedxml2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedxslt.c"
|
||||
"${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(
|
||||
OUTPUT "${BOX64_ROOT}/src/wrapped/generated/functions_list.txt"
|
||||
COMMAND "${PYTHON_EXECUTABLE}" "${BOX64_ROOT}/rebuild_wrappers.py"
|
||||
"${BOX64_ROOT}"
|
||||
"PANDORA" "HAVE_LD80BITS" "NOALIGN" "HAVE_TRACE" "--"
|
||||
COMMAND "${PYTHON_EXECUTABLE}" "${BOX64_ROOT}/rebuild_wrappers.py"
|
||||
"${BOX64_ROOT}"
|
||||
"PANDORA" "HAVE_LD80BITS" "NOALIGN" "HAVE_TRACE" "--"
|
||||
${WRAPPEDS_HEAD}
|
||||
MAIN_DEPENDENCY "${BOX64_ROOT}/rebuild_wrappers.py"
|
||||
DEPENDS ${WRAPPEDS} ${WRAPPEDS_HEAD}
|
||||
@@ -172,53 +518,160 @@ add_custom_command(
|
||||
# OUTPUT "${BOX64_ROOT}/src/dynarec/last_run.txt"
|
||||
# COMMAND "${PYTHON_EXECUTABLE}" "${BOX64_ROOT}/rebuild_printer.py" "${BOX64_ROOT}"
|
||||
# MAIN_DEPENDENCY "${BOX64_ROOT}/rebuild_printer.py"
|
||||
# DEPENDS "${BOX64_ROOT}/src/dynarec/arm_instructions.txt"
|
||||
# BYPRODUCTS "${BOX64_ROOT}/src/dynarec/arm_printer.c"
|
||||
# DEPENDS "${BOX64_ROOT}/src/dynarec/arm64_instructions.txt"
|
||||
# BYPRODUCTS "${BOX64_ROOT}/src/dynarec/arm64_printer.c"
|
||||
#)
|
||||
|
||||
add_custom_target(WRAPPERS DEPENDS "${BOX64_ROOT}/src/wrapped/generated/functions_list.txt")
|
||||
#add_custom_target(PRINTER DEPENDS "${BOX64_ROOT}/src/dynarec/last_run.txt")
|
||||
|
||||
if(DYNAREC)
|
||||
set(DYNAREC_SRC
|
||||
"${BOX64_ROOT}/src/dynarec/dynablock.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_native.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(ARM_DYNAREC)
|
||||
set(DYNAREC_SRC
|
||||
${DYNAREC_SRC}
|
||||
|
||||
"${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"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/arm64_next.S"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/arm64_lock.S"
|
||||
)
|
||||
|
||||
set(DYNAREC_PASS
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_helper.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_emit_tests.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_emit_math.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_emit_logic.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_emit_shift.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_00.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_0f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_64.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_65.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_66.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_67.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_d8.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_d9.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_da.c"
|
||||
"${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_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"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(DYNAREC)
|
||||
set(DYNAREC_PASS
|
||||
"${BOX64_ROOT}/src/wrapped/generated/wrapper.h"
|
||||
${DYNAREC_PASS}
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_native_pass.c"
|
||||
)
|
||||
|
||||
add_library(dynarec_native OBJECT ${DYNAREC_SRC})
|
||||
|
||||
add_library(native_pass0 OBJECT ${DYNAREC_PASS})
|
||||
set_target_properties(native_pass0 PROPERTIES COMPILE_FLAGS "-DSTEP=0")
|
||||
add_library(native_pass1 OBJECT ${DYNAREC_PASS})
|
||||
set_target_properties(native_pass1 PROPERTIES COMPILE_FLAGS "-DSTEP=1")
|
||||
add_library(native_pass2 OBJECT ${DYNAREC_PASS})
|
||||
set_target_properties(native_pass2 PROPERTIES COMPILE_FLAGS "-DSTEP=2")
|
||||
add_library(native_pass3 OBJECT ${DYNAREC_PASS})
|
||||
set_target_properties(native_pass3 PROPERTIES COMPILE_FLAGS "-DSTEP=3")
|
||||
add_dependencies(native_pass0 WRAPPERS)
|
||||
add_dependencies(native_pass1 WRAPPERS)
|
||||
add_dependencies(native_pass2 WRAPPERS)
|
||||
add_dependencies(native_pass3 WRAPPERS)
|
||||
|
||||
add_library(dynarec STATIC
|
||||
$<TARGET_OBJECTS:dynarec_native>
|
||||
$<TARGET_OBJECTS:native_pass0>
|
||||
$<TARGET_OBJECTS:native_pass1>
|
||||
$<TARGET_OBJECTS:native_pass2>
|
||||
$<TARGET_OBJECTS:native_pass3>
|
||||
)
|
||||
endif()
|
||||
|
||||
# creates git_head.h
|
||||
#if(ARM_DYNAREC)
|
||||
# add_custom_command(
|
||||
# OUTPUT "${BOX64_ROOT}/src/git_head.h"
|
||||
# COMMAND bash -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\">\"${BOX64_ROOT}/src/git_head.h\""
|
||||
# DEPENDS dynarec ${ELFLOADER_SRC} ${WRAPPEDS}
|
||||
# VERBATIM)
|
||||
#else()
|
||||
if(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 sh -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\">\"${BOX64_ROOT}/src/git_head.h\""
|
||||
DEPENDS ${ELFLOADER_SRC} ${WRAPPEDS}
|
||||
VERBATIM)
|
||||
#endif()
|
||||
endif()
|
||||
|
||||
add_executable(${BOX64} ${ELFLOADER_SRC} ${WRAPPEDS} "${BOX64_ROOT}/src/git_head.h")
|
||||
set_target_properties(${BOX64} PROPERTIES ENABLE_EXPORTS ON)
|
||||
add_dependencies(${BOX64} WRAPPERS)
|
||||
#add_dependencies(${BOX64} PRINTER)
|
||||
target_link_libraries(${BOX64} m dl rt pthread)
|
||||
if(ARM_DYNAREC)
|
||||
#target_link_libraries(${BOX64} c m dl rt pthread resolv)
|
||||
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()
|
||||
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.13")
|
||||
set_target_properties(${BOX64} PROPERTIES LINK_FLAGS "-rdynamic -Wl,-Ttext-segment,${BOX64_ELF_ADDRESS}")
|
||||
if(NOT NOLOADADDR)
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
||||
set_target_properties(${BOX64} PROPERTIES LINK_FLAGS "-Wl,--image-base=${BOX64_ELF_ADDRESS}")
|
||||
else()
|
||||
set_target_properties(${BOX64} PROPERTIES LINK_FLAGS "-Wl,-Ttext-segment,${BOX64_ELF_ADDRESS}")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
target_link_options(${BOX64} PUBLIC -rdynamic)
|
||||
target_link_options(${BOX64} PUBLIC -Wl,-Ttext-segment,${BOX64_ELF_ADDRESS})
|
||||
# If symbols are missing, try this: target_link_options(${BOX64} PUBLIC -rdynamic)
|
||||
if(NOT NOLOADADDR)
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
||||
target_link_options(${BOX64} PUBLIC LINKER:--image-base=${BOX64_ELF_ADDRESS})
|
||||
else()
|
||||
target_link_options(${BOX64} PUBLIC LINKER:-Ttext-segment,${BOX64_ELF_ADDRESS})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "i686" _x86)
|
||||
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "x86_64" _x86_64)
|
||||
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "aarch64" _aarch64)
|
||||
|
||||
if(_x86_64 OR _aarch64)
|
||||
add_definitions(-DCONFIG_64BIT)
|
||||
endif()
|
||||
|
||||
if(NOT _x86 AND NOT _x86_64)
|
||||
install(TARGETS ${BOX64}
|
||||
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)
|
||||
@@ -231,81 +684,155 @@ if(NOT TARGET uninstall)
|
||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
||||
endif()
|
||||
|
||||
add_test(test01 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test01 -D TEST_OUTPUT=tmpfile.txt
|
||||
set(CPACK_GENERATOR "DEB")
|
||||
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "ptitSeb")
|
||||
set(CPACK_PACKAGE_CONTACT "[email protected]")
|
||||
set(CPACK_PACKAGE_DESCRIPTION "Box64 - Linux Userspace x86_64 Emulator with a twist")
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6")
|
||||
set(CPACK_PACKAGE_HOMEPAGE_URL, "https://box86.org")
|
||||
file(STRINGS "${BOX64_ROOT}/src/box64version.h" TEMP_STRING REGEX "BOX64_MAJOR\\s*")
|
||||
string(REGEX REPLACE "BOX64_MAJOR" "" TEMP_STRING ${TEMP_STRING})
|
||||
string(REGEX MATCH "[0-9]" BOX64_MAJOR ${TEMP_STRING})
|
||||
file(STRINGS "${BOX64_ROOT}/src/box64version.h" TEMP_STRING REGEX "BOX64_MINOR\\s*")
|
||||
string(REGEX REPLACE "BOX64_MINOR" "" TEMP_STRING ${TEMP_STRING})
|
||||
string(REGEX MATCH "[0-9]" BOX64_MINOR ${TEMP_STRING})
|
||||
file(STRINGS "${BOX64_ROOT}/src/box64version.h" TEMP_STRING REGEX "BOX64_REVISION\\s*")
|
||||
string(REGEX REPLACE "BOX64_REVISION" "" TEMP_STRING ${TEMP_STRING})
|
||||
string(REGEX MATCH "[0-9]" BOX64_REVISION ${TEMP_STRING})
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${BOX64_MAJOR})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${BOX64_MINOR})
|
||||
set(CPACK_PACKAGE_VERSION_PATCH ${BOX64_REVISION})
|
||||
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_SOURCE_DIR}/postinst")
|
||||
if(_aarch64)
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "arm64")
|
||||
elseif(_x86_64)
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "x86_64")
|
||||
else()
|
||||
#probably wrong...
|
||||
execute_process(COMMAND "dpkg --print-architecture" OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
|
||||
endif()
|
||||
set(CPACK_DEBIAN_FILE_NAME "${BOX64}-${BOX64_MAJOR}.${BOX64_MINOR}.${BOX64_REVISION}_Linux-${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")
|
||||
INCLUDE(CPack)
|
||||
|
||||
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}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test02 -D TEST_OUTPUT=tmpfile.txt
|
||||
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}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test03 -D TEST_OUTPUT=tmpfile.txt
|
||||
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}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test04 -D TEST_ARGS2=yeah -D TEST_OUTPUT=tmpfile.txt
|
||||
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}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test05 -D TEST_ARGS2=7 -D TEST_OUTPUT=tmpfile.txt
|
||||
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}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test06 -D TEST_OUTPUT=tmpfile.txt
|
||||
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}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test07 -D TEST_OUTPUT=tmpfile.txt
|
||||
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}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test08 -D TEST_OUTPUT=tmpfile.txt
|
||||
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}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test09 -D TEST_OUTPUT=tmpfile.txt
|
||||
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}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test10 -D TEST_OUTPUT=tmpfile.txt
|
||||
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}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test11 -D TEST_OUTPUT=tmpfile.txt
|
||||
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}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test12 -D TEST_OUTPUT=tmpfile.txt
|
||||
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}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test13 -D TEST_OUTPUT=tmpfile.txt
|
||||
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}
|
||||
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test14 -D TEST_OUTPUT=tmpfile.txt
|
||||
#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 )
|
||||
|
||||
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests/extensions/*.c")
|
||||
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(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 )
|
||||
|
||||
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_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
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref18.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(backtrace ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test19 -D TEST_OUTPUT=tmpfile19.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref19.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
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}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/extensions/${testname} -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/extensions/${testname} -D TEST_OUTPUT=tmpfile-${testname}.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/extensions/${testname}.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake)
|
||||
endforeach()
|
||||
@@ -0,0 +1,12 @@
|
||||
all: dumpSigs
|
||||
|
||||
dumpSigs: main.o registered_structs.o
|
||||
g++ -g3 -std=gnu++17 -fno-rtti main.o registered_structs.o -o dumpSigs "-L$(LLVM_install_dir)/lib" -lclang-cpp -lclangTooling -Wl,-rpath "-Wl,$(LLVM_install_dir)/lib"
|
||||
|
||||
main.o: main.cpp
|
||||
g++ -g3 -std=gnu++17 -fno-rtti -c main.cpp -Wfatal-errors "-I$(LLVM_install_dir)/include" -o main.o
|
||||
registered_structs.o: registered_structs.cpp
|
||||
g++ -g3 -std=gnu++17 -fno-rtti -c registered_structs.cpp -Wfatal-errors -o registered_structs.o
|
||||
|
||||
clean:
|
||||
$(RM) dumpSigs main.o registered_structs.o
|
||||
@@ -0,0 +1,458 @@
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <numeric>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
#include <clang/AST/ASTConsumer.h>
|
||||
#include <clang/AST/Decl.h>
|
||||
#include <clang/AST/Mangle.h>
|
||||
#include <clang/AST/PrettyPrinter.h>
|
||||
#include <clang/AST/RecursiveASTVisitor.h>
|
||||
#include <clang/Frontend/CompilerInstance.h>
|
||||
#include <clang/Frontend/FrontendActions.h>
|
||||
#include <clang/Tooling/CommonOptionsParser.h>
|
||||
#include <clang/Tooling/Tooling.h>
|
||||
|
||||
clang::MangleContext *mangler = nullptr;
|
||||
|
||||
std::unordered_map<std::string, std::pair<std::string, bool>> funMap;
|
||||
std::vector<std::string> funList;
|
||||
|
||||
bool isTypeTrivial(const clang::QualType &q, const clang::QualType *qorig);
|
||||
clang::QualType getPointedType(const clang::QualType q) {
|
||||
if (const clang::PointerType *p = q->getAs<clang::PointerType>())
|
||||
return getPointedType(p->getPointeeType());
|
||||
else if (const clang::ReferenceType *r = q->getAs<clang::ReferenceType>())
|
||||
return getPointedType(r->getPointeeType());
|
||||
else
|
||||
return q;
|
||||
}
|
||||
|
||||
std::string record2name(const clang::RecordDecl &q, const clang::QualType *qorig) {
|
||||
std::string s = q.getNameAsString();
|
||||
if (s == "") {
|
||||
if (!qorig) return "????.!";
|
||||
if (const clang::TypedefType *tt = (*qorig)->getAs<clang::TypedefType>()) {
|
||||
// Typedef
|
||||
if (clang::TypedefNameDecl *td = tt->getDecl()) {
|
||||
return td->getNameAsString();
|
||||
} else {
|
||||
return "<typedef with no declaration>";
|
||||
}
|
||||
} else {
|
||||
return std::string("<unknown type ") + (*qorig)->getTypeClassName() + ">";
|
||||
}
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
char ptr2char(const std::string &str) __attribute__((const));
|
||||
const char *ptr2str(const std::string &str) __attribute__((const));
|
||||
char type2char(const clang::QualType &qual /* Canonical */, const clang::QualType *qorig) {
|
||||
if (qual->isBuiltinType()) {
|
||||
switch (static_cast<const clang::BuiltinType&>(*qual).getKind()) {
|
||||
case clang::BuiltinType::Kind::Void:
|
||||
return 'v';
|
||||
case clang::BuiltinType::Kind::Bool:
|
||||
return 'i';
|
||||
case clang::BuiltinType::Kind::Char_U:
|
||||
return 'C';
|
||||
case clang::BuiltinType::Kind::Char_S:
|
||||
return 'c';
|
||||
case clang::BuiltinType::Kind::Char8:
|
||||
return 'c';
|
||||
case clang::BuiltinType::Kind::UChar:
|
||||
return 'C';
|
||||
case clang::BuiltinType::Kind::SChar:
|
||||
return 'c';
|
||||
case clang::BuiltinType::Kind::WChar_U:
|
||||
return 'W';
|
||||
case clang::BuiltinType::Kind::UShort:
|
||||
return 'W';
|
||||
case clang::BuiltinType::Kind::WChar_S:
|
||||
return 'w';
|
||||
case clang::BuiltinType::Kind::Char16:
|
||||
return 'w';
|
||||
case clang::BuiltinType::Kind::Short:
|
||||
return 'w';
|
||||
case clang::BuiltinType::Kind::UInt:
|
||||
return 'u';
|
||||
case clang::BuiltinType::Kind::Char32:
|
||||
return 'i';
|
||||
case clang::BuiltinType::Kind::Int:
|
||||
return 'i';
|
||||
case clang::BuiltinType::Kind::ULong:
|
||||
return 'L';
|
||||
case clang::BuiltinType::Kind::Long:
|
||||
return 'l';
|
||||
case clang::BuiltinType::Kind::ULongLong:
|
||||
return 'U';
|
||||
case clang::BuiltinType::Kind::LongLong:
|
||||
return 'I';
|
||||
case clang::BuiltinType::Kind::UInt128:
|
||||
return 'H';
|
||||
case clang::BuiltinType::Kind::Int128:
|
||||
return 'H';
|
||||
case clang::BuiltinType::Kind::Float:
|
||||
return 'f';
|
||||
case clang::BuiltinType::Kind::Double:
|
||||
return 'd';
|
||||
case clang::BuiltinType::Kind::LongDouble:
|
||||
return 'D';
|
||||
case clang::BuiltinType::Kind::NullPtr:
|
||||
return 'p'; // nullptr_t
|
||||
|
||||
case clang::BuiltinType::Kind::Half:
|
||||
case clang::BuiltinType::Kind::BFloat16:
|
||||
case clang::BuiltinType::Kind::ShortAccum:
|
||||
case clang::BuiltinType::Kind::Accum:
|
||||
case clang::BuiltinType::Kind::LongAccum:
|
||||
case clang::BuiltinType::Kind::UShortAccum:
|
||||
case clang::BuiltinType::Kind::UAccum:
|
||||
case clang::BuiltinType::Kind::ULongAccum:
|
||||
case clang::BuiltinType::Kind::ShortFract:
|
||||
case clang::BuiltinType::Kind::Fract:
|
||||
case clang::BuiltinType::Kind::LongFract:
|
||||
case clang::BuiltinType::Kind::UShortFract:
|
||||
case clang::BuiltinType::Kind::UFract:
|
||||
case clang::BuiltinType::Kind::ULongFract:
|
||||
case clang::BuiltinType::Kind::SatShortAccum:
|
||||
case clang::BuiltinType::Kind::SatAccum:
|
||||
case clang::BuiltinType::Kind::SatLongAccum:
|
||||
case clang::BuiltinType::Kind::SatUShortAccum:
|
||||
case clang::BuiltinType::Kind::SatUAccum:
|
||||
case clang::BuiltinType::Kind::SatULongAccum:
|
||||
case clang::BuiltinType::Kind::SatShortFract:
|
||||
case clang::BuiltinType::Kind::SatFract:
|
||||
case clang::BuiltinType::Kind::SatLongFract:
|
||||
case clang::BuiltinType::Kind::SatUShortFract:
|
||||
case clang::BuiltinType::Kind::SatUFract:
|
||||
case clang::BuiltinType::Kind::SatULongFract:
|
||||
case clang::BuiltinType::Kind::Float16:
|
||||
case clang::BuiltinType::Kind::Float128:
|
||||
case clang::BuiltinType::Kind::Overload:
|
||||
case clang::BuiltinType::Kind::BoundMember:
|
||||
case clang::BuiltinType::Kind::PseudoObject:
|
||||
case clang::BuiltinType::Kind::Dependent:
|
||||
case clang::BuiltinType::Kind::UnknownAny:
|
||||
case clang::BuiltinType::Kind::ARCUnbridgedCast:
|
||||
case clang::BuiltinType::Kind::BuiltinFn:
|
||||
case clang::BuiltinType::Kind::ObjCId:
|
||||
case clang::BuiltinType::Kind::ObjCClass:
|
||||
case clang::BuiltinType::Kind::ObjCSel:
|
||||
#define IMAGE_TYPE(it, id, si, a, s) case clang::BuiltinType::Kind::id:
|
||||
#include <clang/Basic/OpenCLImageTypes.def>
|
||||
#undef IMAGE_TYPE
|
||||
case clang::BuiltinType::Kind::OCLSampler:
|
||||
case clang::BuiltinType::Kind::OCLEvent:
|
||||
case clang::BuiltinType::Kind::OCLClkEvent:
|
||||
case clang::BuiltinType::Kind::OCLQueue:
|
||||
case clang::BuiltinType::Kind::OCLReserveID:
|
||||
case clang::BuiltinType::Kind::IncompleteMatrixIdx:
|
||||
case clang::BuiltinType::Kind::OMPArraySection:
|
||||
case clang::BuiltinType::Kind::OMPArrayShaping:
|
||||
case clang::BuiltinType::Kind::OMPIterator:
|
||||
#define EXT_OPAQUE_TYPE(et, id, e) case clang::BuiltinType::Kind::id:
|
||||
#include <clang/Basic/OpenCLExtensionTypes.def>
|
||||
#define SVE_TYPE(n, id, si) case clang::BuiltinType::Kind::id:
|
||||
#include <clang/Basic/AArch64SVEACLETypes.def>
|
||||
#define PPC_VECTOR_TYPE(n, id, s) case clang::BuiltinType::Kind::id:
|
||||
#include <clang/Basic/PPCTypes.def>
|
||||
#undef EXT_OPAQUE_TYPE
|
||||
#undef SVE_TYPE
|
||||
#undef PPC_VECTOR_TYPE
|
||||
return '!';
|
||||
default:
|
||||
return ':';
|
||||
}
|
||||
} else if (qual->isEnumeralType()) {
|
||||
const clang::EnumDecl *ed = qual->getAs<clang::EnumType>()->getDecl();
|
||||
if (!ed) {
|
||||
return 'i';
|
||||
} else {
|
||||
return type2char(ed->getIntegerType().getCanonicalType(), qorig);
|
||||
}
|
||||
} else if (qual->isFunctionPointerType()) {
|
||||
return '@';
|
||||
} else if (qual->isAnyPointerType() || qual->isReferenceType()) {
|
||||
const clang::QualType &pointed = getPointedType(qual);
|
||||
if (isTypeTrivial(pointed, qorig)) {
|
||||
return 'p';
|
||||
} else if (const clang::RecordType *rct = pointed->getAs<clang::RecordType>()) {
|
||||
clang::RecordDecl *rc = rct->getDecl();
|
||||
if (!rc) {
|
||||
return '!';
|
||||
} else if (!rc->isCompleteDefinition()) {
|
||||
return 'p';
|
||||
} else {
|
||||
std::string str;
|
||||
if (qorig) {
|
||||
const clang::QualType qpted = getPointedType(*qorig);
|
||||
str = record2name(*rc, &qpted);
|
||||
} else {
|
||||
str = record2name(*rc, nullptr);
|
||||
}
|
||||
char ret = ptr2char(str);
|
||||
if (ret) return ret;
|
||||
else {
|
||||
return '!';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return '!';
|
||||
}
|
||||
} else if (const clang::RecordType *rct = qual->getAs<clang::RecordType>()) {
|
||||
clang::RecordDecl *rc = rct->getDecl();
|
||||
if (!rc) {
|
||||
return '?';
|
||||
} else if (rc->getNameAsString() == "__builtin_va_list") {
|
||||
// va_list
|
||||
return 'A';
|
||||
} else {
|
||||
return '?';
|
||||
}
|
||||
} else {
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
bool isTypeTrivial(const clang::QualType &q, const clang::QualType *qorig) {
|
||||
const char c = type2char(q, qorig);
|
||||
#define GO(chr) || (c == chr)
|
||||
return (c == 'v')
|
||||
GO('i') GO('u')
|
||||
GO('I') GO('U')
|
||||
GO('l') GO('L')
|
||||
GO('f') GO('d')
|
||||
GO('D') GO('K')
|
||||
GO('0') GO('1')
|
||||
GO('C') GO('c')
|
||||
GO('W') GO('w')
|
||||
GO('H')
|
||||
GO('p');
|
||||
#undef GO
|
||||
}
|
||||
bool isTypeValid(const clang::QualType &q, const clang::QualType *qorig) {
|
||||
const char c = type2char(q, qorig);
|
||||
if (c == 'A') return false;
|
||||
if (c == 'V') return false;
|
||||
return ((c >= '0') && (c <= '9')) || ((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'));
|
||||
}
|
||||
|
||||
const std::string type2string(const clang::QualType &qual, const clang::QualType *qorig) {
|
||||
if (qual->isBuiltinType()) {
|
||||
return std::string("(builtin) ") + static_cast<const clang::BuiltinType&>(*qual).getName(clang::PrintingPolicy{{}}).data();
|
||||
} else if (qual->isFunctionPointerType()) {
|
||||
return "Callback (function pointer)";
|
||||
} else if (qual->isAnyPointerType() || qual->isReferenceType()) {
|
||||
std::string prefix = qual->isAnyPointerType() ? "Pointer to " : "Reference to ";
|
||||
const clang::QualType &pointed = getPointedType(qual);
|
||||
if (isTypeTrivial(pointed, qorig)) {
|
||||
return prefix + "trivial object " + type2string(pointed, qorig) + " (" + type2char(pointed, qorig) + ")";
|
||||
} else if (const clang::RecordType *rct = pointed->getAs<clang::RecordType>()) {
|
||||
clang::RecordDecl *rc = rct->getDecl();
|
||||
if (!rc) {
|
||||
return prefix + "unknown record";
|
||||
} else if (!rc->isCompleteDefinition()) {
|
||||
return prefix + "incomplete record " + rc->getNameAsString();
|
||||
} else {
|
||||
std::string str;
|
||||
if (qorig) {
|
||||
const clang::QualType qpted = getPointedType(*qorig);
|
||||
str = record2name(*rc, &qpted);
|
||||
} else {
|
||||
str = record2name(*rc, nullptr);
|
||||
}
|
||||
const char *ret = ptr2str(str);
|
||||
if (ret[0] != '\0') {
|
||||
return prefix + ret;
|
||||
} else {
|
||||
if (mangler && mangler->shouldMangleDeclName(rc)) {
|
||||
std::string mangled;
|
||||
{
|
||||
llvm::raw_string_ostream strstr{mangled};
|
||||
mangler->mangleName(rc, strstr);
|
||||
}
|
||||
return prefix + "unknown record " + str + " (=== " + mangled + ")";
|
||||
} else {
|
||||
return prefix + "unknown record " + str;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return prefix + "non-trivial or typedef'ed object " + type2string(pointed, qorig) + " (" + type2char(pointed, qorig) + ")";
|
||||
//return "Pointer (maybe to callback)";
|
||||
}
|
||||
} else if (qual->isEnumeralType()) {
|
||||
const clang::EnumDecl *ed = qual->getAs<clang::EnumType>()->getDecl();
|
||||
if (!ed) {
|
||||
return "Enumeration with unknown underlying integer type (assuming int)";
|
||||
} else {
|
||||
return "Enumeration with underlying type " + type2string(ed->getIntegerType().getCanonicalType(), nullptr);
|
||||
}
|
||||
} else if (const clang::RecordType *rct = qual->getAs<clang::RecordType>()) {
|
||||
clang::RecordDecl *rc = rct->getDecl();
|
||||
if (!rc) {
|
||||
return "Unknown record";
|
||||
} else if (rc->getNameAsString() == "__builtin_va_list") {
|
||||
return "va_list";
|
||||
} else {
|
||||
return "Unknown record " + std::string(rc->getName().data());
|
||||
}
|
||||
} else {
|
||||
return std::string("??? ") + qual->getTypeClassName();
|
||||
}
|
||||
}
|
||||
|
||||
class Visitor : public clang::RecursiveASTVisitor<Visitor> {
|
||||
public:
|
||||
clang::ASTContext &context;
|
||||
|
||||
bool shouldVisitTemplateInstantiations() const /* override */ { return true; }
|
||||
|
||||
Visitor(clang::CompilerInstance &ci) : context(ci.getASTContext()) {
|
||||
if (!mangler) {
|
||||
mangler = clang::ItaniumMangleContext::create(context, ci.getDiagnostics());
|
||||
}
|
||||
}
|
||||
|
||||
~Visitor() {
|
||||
if (mangler) {
|
||||
delete mangler;
|
||||
mangler = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool VisitDecl(clang::Decl *decl) /* override */ {
|
||||
std::cerr << std::flush;
|
||||
if (!decl) return true;
|
||||
|
||||
if ((decl->getKind() >= clang::Decl::Kind::firstFunction) && (decl->getKind() <= clang::Decl::Kind::lastFunction)) {
|
||||
clang::DeclaratorDecl *ddecl = static_cast<clang::DeclaratorDecl*>(decl);
|
||||
std::cout << "Function detected!\n";
|
||||
|
||||
std::string funName{ddecl->getName()};
|
||||
|
||||
auto niceprint = [](const std::string &infotype, const auto &dat){ std::cout << " " << infotype << ": " << dat << "\n"; };
|
||||
niceprint("Function name", funName);
|
||||
if (mangler && mangler->shouldMangleDeclName(ddecl)) {
|
||||
std::string mangled;
|
||||
{
|
||||
llvm::raw_string_ostream strstr{mangled};
|
||||
mangler->mangleName(ddecl, strstr);
|
||||
}
|
||||
niceprint("Function mangled name", mangled);
|
||||
funName = std::move(mangled);
|
||||
}
|
||||
|
||||
bool valid;
|
||||
std::string funTypeStr{""};
|
||||
if (ddecl->getFunctionType()->isFunctionNoProtoType()) {
|
||||
const clang::FunctionNoProtoType *funType = static_cast<const clang::FunctionNoProtoType*>(ddecl->getFunctionType());
|
||||
const auto &retType = funType->getReturnType();
|
||||
|
||||
niceprint("Function return type", type2string(retType, &retType));
|
||||
niceprint("Canonical function return type",
|
||||
type2string(retType.getCanonicalType(), &retType) +
|
||||
" (" + type2char(retType.getCanonicalType(), &retType) + ")");
|
||||
niceprint("Is sugared", funType->isSugared());
|
||||
if (funType->isSugared()) {
|
||||
clang::QualType qft{funType, 0};
|
||||
niceprint("Desugared", type2string(funType->desugar(), &qft));
|
||||
}
|
||||
|
||||
funTypeStr = type2char(retType.getCanonicalType(), &retType) + std::string("Fv");
|
||||
valid = isTypeValid(retType.getCanonicalType(), &retType);
|
||||
} else {
|
||||
const clang::FunctionProtoType *funType = static_cast<const clang::FunctionProtoType*>(ddecl->getFunctionType());
|
||||
const auto &retType = funType->getReturnType();
|
||||
|
||||
niceprint("Function return type", type2string(retType, &retType));
|
||||
niceprint("Canonical function return type",
|
||||
type2string(retType.getCanonicalType(), &retType)
|
||||
+ " (" + type2char(retType.getCanonicalType(), &retType) + ")");
|
||||
niceprint("Parameter count", funType->getNumParams());
|
||||
for (const clang::QualType &type : funType->getParamTypes()) {
|
||||
niceprint(" " + type2string(type, &type),
|
||||
type2string(type.getCanonicalType(), &type) + " (" + type2char(type.getCanonicalType(), &type) + ")");
|
||||
}
|
||||
niceprint("Variadic function", funType->isVariadic() ? "yes" : "no");
|
||||
|
||||
funTypeStr =
|
||||
type2char(retType.getCanonicalType(), &retType) +
|
||||
((funType->getNumParams() == 0)
|
||||
? std::string("Fv") : std::accumulate(funType->getParamTypes().begin(), funType->getParamTypes().end(), std::string("F"),
|
||||
[](const std::string &acc, const clang::QualType &qual){ return acc + type2char(qual.getCanonicalType(), &qual); }));
|
||||
if (funType->isVariadic()) funTypeStr += "V";
|
||||
valid = !funType->isVariadic() &&
|
||||
std::accumulate(funType->getParamTypes().begin(), funType->getParamTypes().end(), isTypeValid(retType.getCanonicalType(), &retType),
|
||||
[](bool acc, const clang::QualType &qual){ return acc && isTypeValid(qual.getCanonicalType(), &qual); });
|
||||
}
|
||||
|
||||
niceprint("Conclusion", "");
|
||||
niceprint("Function final name", funName);
|
||||
niceprint("Function type", funTypeStr);
|
||||
niceprint("Valid function type", valid ? "yes" : "no");
|
||||
std::cout << "\n";
|
||||
|
||||
funMap[funName] = std::make_pair(funTypeStr, valid);
|
||||
funList.push_back(funName);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class Consumer : public clang::ASTConsumer {
|
||||
public:
|
||||
Visitor visitor;
|
||||
|
||||
Consumer(clang::CompilerInstance &ci) : visitor(ci) {
|
||||
}
|
||||
|
||||
void HandleTranslationUnit(clang::ASTContext &context) override {
|
||||
visitor.TraverseDecl(context.getTranslationUnitDecl());
|
||||
}
|
||||
};
|
||||
|
||||
class Action : public clang::ASTFrontendAction {
|
||||
public:
|
||||
virtual std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance &ci, llvm::StringRef inFile) override {
|
||||
return std::make_unique<Consumer>(ci);
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
if (argc < 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " (filenames) -- [-I...]" << std::endl;
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*int fakeargc = argc + 1;
|
||||
const char **fakeargv = new const char*[fakeargc];
|
||||
memcpy(fakeargv, argv, argc * sizeof(char*));
|
||||
fakeargv[fakeargc - 1] = "--";*/
|
||||
llvm::cl::OptionCategory opcat{""};
|
||||
clang::tooling::CommonOptionsParser op{argc, argv, opcat};
|
||||
std::vector<std::string> paths; for (int i = 1; i < argc; ++i) paths.push_back(argv[i]);
|
||||
|
||||
clang::tooling::ClangTool tool{op.getCompilations(), paths};
|
||||
|
||||
tool.run(clang::tooling::newFrontendActionFactory<Action>().get());
|
||||
|
||||
std::cout << "Done, outputing output.h" << std::endl;
|
||||
std::sort(funList.begin(), funList.end());
|
||||
std::fstream file{"output.h", std::ios_base::out};
|
||||
for (const std::string &funName : funList) {
|
||||
if (!funMap[funName].second) {
|
||||
file << "//";
|
||||
}
|
||||
file << "GO(" << funName << ", " << funMap[funName].first << ")\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
#include <string>
|
||||
|
||||
#define ALL START() \
|
||||
/* libc */ \
|
||||
STRUCT("_IO_FILE", "a FILE") \
|
||||
STRUCT("_G_fpos_t", "a file position") \
|
||||
STRUCT("sockaddr", "a socket address") \
|
||||
STRUCT("itimerspec", "an itimerspec") \
|
||||
STRUCT("timespec", "a timespec") \
|
||||
STRUCT("itimerval", "an itimerval") \
|
||||
STRUCT("timeval", "a timeval") \
|
||||
STRUCT("timex", "a timex") \
|
||||
STRUCT("timezone", "a timezone") \
|
||||
STRUCT("dirent", "a dirent") \
|
||||
STRUCT("dirent64", "a dirent64") \
|
||||
STRUCT("__dirstream", "a dir stream") \
|
||||
STRUCT("tm", "a time structure (tm)") \
|
||||
STRUCT("cmsghdr", "a cmsghdr") \
|
||||
STRUCT("msghdr", "a msghdr") \
|
||||
STRUCT("rpcent", "an rpcent") \
|
||||
STRUCT("random_data", "a random_data structure") \
|
||||
STRUCT("drand48_data", "a drand48_data structure") \
|
||||
STRUCT("termios", "a termios") \
|
||||
STRUCT("iovec", "an iovec") \
|
||||
STRUCT("file_handle", "a file handle") \
|
||||
STRUCT("lconv", "an lconv") \
|
||||
STRUCT("__locale_struct", "a locale structure") \
|
||||
STRUCT("aliasent", "an alias") \
|
||||
STRUCT("fstab", "an fstab") \
|
||||
STRUCT("group", "a group") \
|
||||
STRUCT("hostent", "a hostent") \
|
||||
STRUCT("protoent", "a protoent") \
|
||||
STRUCT("passwd", "a password") \
|
||||
STRUCT("spwd", "an spwd") \
|
||||
STRUCT("ttyent", "a ttyent") \
|
||||
STRUCT("utmp", "an utmp structure") \
|
||||
STRUCT("utmpx", "an utmpx structure") \
|
||||
STRUCT("ifaddrs", "an ifaddrs structure") \
|
||||
STRUCT("statfs", "a statfs structure") \
|
||||
STRUCT("statfs64", "a statfs64 structure") \
|
||||
STRUCT("statvfs", "a statvfs structure") \
|
||||
STRUCT("statvfs64", "a statvfs64 structure") \
|
||||
STRUCT("timeb", "a timeb structure") \
|
||||
STRUCT("_ftsent", "an _ftsent structure") \
|
||||
STRUCT("sysinfo", "a sysinfo structure") \
|
||||
STRUCT("rlimit", "an rlimit structure") \
|
||||
STRUCT("rlimit64", "an rlimit64 structure") \
|
||||
STRUCT("rusage", "an rusage structure") \
|
||||
STRUCT("entry", "an entry structure") \
|
||||
STRUCT("pollfd", "a pollfd structure") \
|
||||
STRUCT("re_pattern_buffer", "a re_pattern_buffer structure") \
|
||||
STRUCT("sembuf", "a sembuf structure") \
|
||||
STRUCT("tms", "a tms structure") \
|
||||
STRUCT("utsname", "an utsname structure") \
|
||||
STRUCT("utimbuf", "an utimbuf structure") \
|
||||
STRUCT2("__va_list_tag", "__va_list_tag (aka, a va_list)", 'A') \
|
||||
/* ncurses */ \
|
||||
STRUCT("_win_st", "a _win_st structure") \
|
||||
STRUCT("MEVENT", "an MEVENT structure") \
|
||||
TYPEDEF("cchar_t", "a cchar_t") \
|
||||
/* zlib */ \
|
||||
STRUCT("gz_header_s", "a gz_header_s structure") \
|
||||
STRUCT("gzFile_s", "a gzFile_s structure") \
|
||||
STRUCT("z_stream_s", "a z_stream_s structure") \
|
||||
\
|
||||
END()
|
||||
|
||||
#define START()
|
||||
#define STRUCT(s, ret) if (str == s) { return 'p'; } else
|
||||
#define STRUCT2(s, ret, c) if (str == s) { return c; } else
|
||||
#define TYPEDEF(s, ret) if (str == s) { return 'p'; } else
|
||||
#define END() { return 0; }
|
||||
char ptr2char(const std::string &str) {
|
||||
/*if ((str == "_IO_FILE")
|
||||
|| (str == "_G_fpos_t")
|
||||
|| (str == "sockaddr")
|
||||
|| (str == "itimerspec")
|
||||
|| (str == "timespec")
|
||||
|| (str == "itimerval")
|
||||
|| (str == "timeval")
|
||||
|| (str == "timex")
|
||||
|| (str == "timezone")
|
||||
|| (str == "dirent")
|
||||
|| (str == "dirent64")
|
||||
|| (str == "__dirstream")
|
||||
|| (str == "tm")
|
||||
|| (str == "cmsghdr")
|
||||
|| (str == "msghdr")
|
||||
|| (str == "rpcent")
|
||||
|| (str == "random_data")
|
||||
|| (str == "drand48_data")
|
||||
|| (str == "termios")
|
||||
|| (str == "iovec")
|
||||
|| (str == "file_handle")
|
||||
|| (str == "lconv")
|
||||
|| (str == "__locale_struct")
|
||||
|| (str == "aliasent")
|
||||
|| (str == "fstab")
|
||||
|| (str == "group")
|
||||
|| (str == "hostent")
|
||||
|| (str == "protoent")
|
||||
|| (str == "passwd")
|
||||
|| (str == "spwd")
|
||||
|| (str == "ttyent")
|
||||
|| (str == "utmp")
|
||||
|| (str == "utmpx")
|
||||
|| (str == "ifaddrs")
|
||||
|| (str == "statfs")
|
||||
|| (str == "statfs64")
|
||||
|| (str == "statvfs")
|
||||
|| (str == "timeb")
|
||||
|| (str == "_ftsent")
|
||||
|| (str == "sysinfo")
|
||||
|| (str == "rlimit")
|
||||
|| (str == "rlimit64")
|
||||
|| (str == "rusage")
|
||||
|| (str == "entry")
|
||||
|| (str == "pollfd")
|
||||
|| (str == "re_pattern_buffer")
|
||||
|| (str == "sembuf")
|
||||
|| (str == "tms")
|
||||
|| (str == "utsname")
|
||||
|| (str == "utimbuf")
|
||||
// ncurses
|
||||
|| (str == "_win_st")
|
||||
|
||||
|| (str == "cchar_t")
|
||||
) {
|
||||
// FILE*, fpos_t*, ...
|
||||
return 'p';
|
||||
} else if (str == "__va_list_tag") {
|
||||
return 'A';
|
||||
} else {
|
||||
return 0;
|
||||
}*/
|
||||
ALL
|
||||
}
|
||||
#undef END
|
||||
#undef TYPEDEF
|
||||
#undef STRUCT2
|
||||
#undef STRUCT
|
||||
#undef START
|
||||
|
||||
#define START()
|
||||
#define STRUCT(s, ret) if (str == s) { return ret; } else
|
||||
#define STRUCT2(s, ret, c) if (str == s) { return ret; } else
|
||||
#define TYPEDEF(s, ret) if (str == s) { return ret; } else
|
||||
#define END() return "";
|
||||
const char *ptr2str(const std::string &str) {
|
||||
/*if (str == "_IO_FILE") {
|
||||
return "a FILE";
|
||||
} else if (str == "_G_fpos_t") {
|
||||
return "a file position";
|
||||
} else if (str == "sockaddr") {
|
||||
return "a socket address";
|
||||
} else if (str == "itimerspec") {
|
||||
return "an itimerspec";
|
||||
} else if (str == "timespec") {
|
||||
return "a timespec";
|
||||
} else if (str == "itimerval") {
|
||||
return "an itimerval";
|
||||
} else if (str == "timeval") {
|
||||
return "a timeval";
|
||||
} else if (str == "timex") {
|
||||
return "a timex";
|
||||
} else if (str == "timezone") {
|
||||
return "a timezone";
|
||||
} else if (str == "dirent") {
|
||||
return "a dirent";
|
||||
} else if (str == "dirent64") {
|
||||
return "a dirent64";
|
||||
} else if (str == "__dirstream") {
|
||||
return "a dir stream";
|
||||
} else if (str == "tm") {
|
||||
return "a time structure (tm)";
|
||||
} else if (str == "cmsghdr") {
|
||||
return "a cmsghdr";
|
||||
} else if (str == "msghdr") {
|
||||
return "a msghdr";
|
||||
} else if (str == "rpcent") {
|
||||
return "an rpcent";
|
||||
} else if (str == "random_data") {
|
||||
return "a random_data structure";
|
||||
} else if (str == "drand48_data") {
|
||||
return "a drand48_data structure";
|
||||
} else if (str == "termios") {
|
||||
return "a termios";
|
||||
} else if (str == "iovec") {
|
||||
return "an iovec";
|
||||
} else if (str == "file_handle") {
|
||||
return "a file handle";
|
||||
} else if (str == "lconv") {
|
||||
return "an lconv";
|
||||
} else if (str == "__locale_struct") {
|
||||
return "a locale structure";
|
||||
} else if (str == "aliasent") {
|
||||
return "an alias";
|
||||
} else if (str == "fstab") {
|
||||
return "an fstab";
|
||||
} else if (str == "group") {
|
||||
return "a group";
|
||||
} else if (str == "hostent") {
|
||||
return "a hostent";
|
||||
} else if (str == "protoent") {
|
||||
return "a protoent";
|
||||
} else if (str == "passwd") {
|
||||
return "a password";
|
||||
} else if (str == "spwd") {
|
||||
return "an spwd";
|
||||
} else if (str == "ttyent") {
|
||||
return "a ttyent";
|
||||
} else if (str == "utmp") {
|
||||
return "an utmp structure";
|
||||
} else if (str == "utmpx") {
|
||||
return "an utmpx structure";
|
||||
} else if (str == "ifaddrs") {
|
||||
return "an ifaddrs structure";
|
||||
} else if (str == "statfs") {
|
||||
return "a statfs structure";
|
||||
} else if (str == "statfs64") {
|
||||
return "a statfs64 structure";
|
||||
} else if (str == "statvfs") {
|
||||
return "a statvfs structure";
|
||||
} else if (str == "statvfs64") {
|
||||
return "a statvfs64 structure";
|
||||
} else if (str == "timeb") {
|
||||
return "a timeb structure";
|
||||
} else if (str == "_ftsent") {
|
||||
return "an _ftsent structure";
|
||||
} else if (str == "sysinfo") {
|
||||
return "a sysinfo structure";
|
||||
} else if (str == "rlimit") {
|
||||
return "an rlimit structure";
|
||||
} else if (str == "rlimit64") {
|
||||
return "an rlimit64 structure";
|
||||
} else if (str == "rusage") {
|
||||
return "an rusage structure";
|
||||
} else if (str == "entry") {
|
||||
return "an entry structure";
|
||||
} else if (str == "pollfd") {
|
||||
return "a pollfd structure";
|
||||
} else if (str == "re_pattern_buffer") {
|
||||
return "a re_pattern_buffer structure";
|
||||
} else if (str == "sembuf") {
|
||||
return "a sembuf structure";
|
||||
} else if (str == "tms") {
|
||||
return "a tms structure";
|
||||
} else if (str == "utsname") {
|
||||
return "an utsname structure";
|
||||
} else if (str == "utimbuf") {
|
||||
return "an utimbuf structure";
|
||||
} else if (str == "__va_list_tag") {
|
||||
return "__va_list_tag (aka, a va_list)";
|
||||
// ncurses
|
||||
} else if (str == "_win_st") {
|
||||
return "a _win_st structure";
|
||||
|
||||
} else if (str == "cchar_t") {
|
||||
return "a cchar_t";
|
||||
} else return "";*/
|
||||
ALL
|
||||
}
|
||||
#undef END
|
||||
#undef TYPEDEF
|
||||
#undef STRUCT2
|
||||
#undef STRUCT
|
||||
#undef START
|
||||
@@ -1,7 +0,0 @@
|
||||
# box64
|
||||
|
||||
Linux Userspace x86_64 Emulator with a twist
|
||||
|
||||
----
|
||||
|
||||
Box64 lets you run x86_64 Linux programs (such as games) on non-x86_64 Linux systems, like ARM (host system needs to be 64bit little-endian).
|
||||
Vendored
+98
@@ -0,0 +1,98 @@
|
||||
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
|
||||
* Many small fixes and improvement to get SteamPlay (i.e. proton) working (along with box86)
|
||||
* Added some workaround for program calling uname to mimic x86_64 system
|
||||
* Added some granularity to mmap, and generic memory protection tracking improvment, to mimic x86 system (for wine stagging and proton)
|
||||
* Better clone syscall and libc implementation
|
||||
* Improved wrapping of GTK libs
|
||||
* More wrapped libs (more gtk libs, like gstreamer-1.0 among other non-gtk libs too)
|
||||
* More wrapped functions(with some tricky one, like dladdr1)
|
||||
* Some fixes and improvment to some wrapped functions
|
||||
* Refactor Dynarec:
|
||||
* - better handling of SSE/x87 registers
|
||||
* - optimisation to limit float/double conversion
|
||||
* - better handling of "internal" jump inside a dynablock
|
||||
* - make adding new architecture easier, by sharing as much infrastructure as possible
|
||||
* Improved elfloader
|
||||
* Improved some tests
|
||||
* Improved a bit the "Hotpage" handling and messages
|
||||
* Added more dynarec opcodes
|
||||
* A few fixes in some Dynarec opcodes
|
||||
* A bit more optimisation in some Dynarec opcodes
|
||||
* Don't quit on unsupported syscall, return -1 / ENOSYS error
|
||||
* Added some more Syscall
|
||||
* Wrapped Vulkan library. Vulkan and dxvk now supported!
|
||||
* Support building on PPC64LE (interpretor only)
|
||||
* Added support for Risc-V (interpretor only)
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Tue, 18 Jan 2022 11:20:33 -0500
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
11
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
Source: box64
|
||||
Section: utils
|
||||
Priority: optional
|
||||
Maintainer: Ryan Fortner <[email protected]>
|
||||
Build-Depends: cmake, debhelper (>=11~), python3
|
||||
Standards-Version: 4.1.4
|
||||
Homepage: https://github.com/ptitSeb/box64
|
||||
|
||||
Package: box64
|
||||
Architecture: any
|
||||
Multi-Arch: foreign
|
||||
Depends: ${misc:Depends}, ${shlibs:Depends}
|
||||
Description: Linux Userspace x86_64 Emulator with a twist, targeted at ARM Linux devices
|
||||
Box86 lets you run x86_64 Linux programs (such as games) on non-x86 Linux systems, like ARM (host system needs to be 64bit little-endian).
|
||||
Vendored
+26
@@ -0,0 +1,26 @@
|
||||
Format-Specification: http://dep.debian.net/deps/dep5/
|
||||
|
||||
Files: *
|
||||
Copyright: © 2022 Sebastien Chevalier
|
||||
License: MIT
|
||||
|
||||
License: MIT
|
||||
Copyright (c) 2018-2021 Sebastien Chevalier ("ptitSeb")
|
||||
.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
.
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
box64: no-manual-page
|
||||
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
%:
|
||||
dh $@
|
||||
|
||||
override_dh_auto_configure:
|
||||
dh_auto_configure -- \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DARM_DYNAREC=1
|
||||
|
||||
override_dh_shlibdeps:
|
||||
dh_shlibdeps --exclude=libgcc_s.so.1 --exclude=libpng12.so.0 --exclude=libstdc++.so.6
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
3.0 (quilt)
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
Bug-Database: https://github.com/ptitSeb/box64/issues
|
||||
Bug-Submit: https://github.com/ptitSeb/box64/issues/new
|
||||
Repository: https://github.com/ptitSeb/box64.git
|
||||
Repository-Browse: https://github.com/ptitSeb/box64
|
||||
Security-Contact: [email protected]
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
version=3
|
||||
@@ -0,0 +1,171 @@
|
||||
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
|
||||
* Many small fixes and improvement to get SteamPlay (i.e. proton) working (along with box86)
|
||||
* Added some workaround for program calling uname to mimic x86_64 system
|
||||
* Added some granularity to mmap, and generic memory protection tracking improvment, to mimic x86 system (for wine stagging and proton)
|
||||
* Better clone syscall and libc implementation
|
||||
* Improved wrapping of GTK libs
|
||||
* More wrapped libs (more gtk libs, like gstreamer-1.0 among other non-gtk libs too)
|
||||
* More wrapped functions(with some tricky one, like dladdr1)
|
||||
* Some fixes and improvment to some wrapped functions
|
||||
* Refactor Dynarec:
|
||||
* better handling of SSE/x87 registers
|
||||
* optimisation to limit float/double conversion
|
||||
* better handling of "internal" jump inside a dynablock
|
||||
* make adding new architecture easier, by sharing as much infrastructure as possible
|
||||
* Improved elfloader
|
||||
* Improved some tests
|
||||
* Improved a bit the "Hotpage" handling and messages
|
||||
* Added more dynarec opcodes
|
||||
* A few fixes in some Dynarec opcodes
|
||||
* A bit more optimisation in some Dynarec opcodes
|
||||
* Don't quit on unsupported syscall, return -1 / ENOSYS error
|
||||
* Added some more Syscall
|
||||
* Wrapped Vulkan library. Vulkan and dxvk now supported!
|
||||
* Support building on PPC64LE (interpretor only)
|
||||
* Added support for Risc-V (interpretor only)
|
||||
|
||||
v0.1.6
|
||||
======
|
||||
* Introduce "HotPage", to temporarily disable Dynarec on a page were writing is also occuring (can help speed up C# code)
|
||||
* Some work on Dynarec to limit the number of mutex use, and also allow smaller block to be built (for JIT'd programs)
|
||||
* Introduce BOX64_DYNAREC_STRONGMEM for the (Arm) dynarec to emulate StrngMemory Model (needed by some games, like RimWorld)
|
||||
* More functions wrapped
|
||||
* Improve speed of the custom allocator used by dynarec and Hash (speedup loading)
|
||||
* Added a workaround for streamwebhelper to not load it
|
||||
* More opcodes added
|
||||
* More wrapped libraries, including gtk2
|
||||
* Added a fix for linking box64 on system using glibc 2.34+
|
||||
* Some residual fixes on thread attribute handling
|
||||
* Better handling of app that want 32bits jumps, like unity3d/mono (thanks mogery)
|
||||
* More ARM hardware option in CMake (Phytium, NX...)
|
||||
* Added loongarch64 support (interpretor only)
|
||||
* Some fixes to elfloader
|
||||
* Added a mecanism to cancel a Dynarec block construction if it triggers a segfault (instead of a crash)
|
||||
|
||||
v0.1.4
|
||||
======
|
||||
* Reworked README a bit
|
||||
* Added some more wrapped libs
|
||||
* Added some SSE4x opcodes
|
||||
* Preliminary support for VSyscall (still missing VDSO)
|
||||
* Added support for AES-NI cpu extension, also in Dynarec (and using ARM extension if present)
|
||||
* Added some syscall
|
||||
* Added some more wrapped functions
|
||||
* Improvment to the handling of longjmp inside signal handlers
|
||||
* Improved wrapper helpers (from rajdakin)
|
||||
* Some fixes to opcodes (especially C2 flags for some x87 opcodes)
|
||||
* Handling of some specific opcode as privileged instruction (instead of NOP)
|
||||
* Fixed ELF signature detection
|
||||
* Some fixes to a few env. var. handling
|
||||
|
||||
v0.1.2
|
||||
======
|
||||
* OpenSource!
|
||||
* A few more opcode added to the Interpretor and the Dynarec
|
||||
* Improved Native Function calling
|
||||
* Added some function to limit allocated memory to 47bits space (for Wine)
|
||||
* Improved and Fixed the functions to limit allocated memory to 32bits space
|
||||
* Wine is starting now, but not everything and every version works
|
||||
|
||||
v0.1.0
|
||||
======
|
||||
* Improvement to ElfLoader
|
||||
* More opcode added to the Dynarec
|
||||
* More lib wrapping
|
||||
* Some fixes to a few function signature
|
||||
* Improvement to Signal handling, and internal mutex handling
|
||||
* A few fixes to some dynarec opcodes
|
||||
* A few fixes to some interpretor opcodes
|
||||
|
||||
v0.0.8
|
||||
======
|
||||
* Improvement to SSE/x87 handling
|
||||
* More opcode added to the Dynarec
|
||||
* More lib wrapping
|
||||
|
||||
v0.0.6
|
||||
======
|
||||
* Added Dynarec for ARM64
|
||||
* Many general CPU opcode added to the Dynarec
|
||||
* Many SSEx opcodes added to the Dynarec
|
||||
* Added a few more symbols in libc
|
||||
* A few changes to the "thread once" handling
|
||||
* New Logo and Icon from @grayduck
|
||||
|
||||
v0.0.4
|
||||
======
|
||||
* Added a lot of opcodes
|
||||
* Added SDL1 and SDL2 wrapping
|
||||
* OpenGL/GLU wrapping done
|
||||
* libasound / libpulse wrapping done
|
||||
* libopenal / libalure / libalut wrapping done
|
||||
* Many X11 libs wrapped
|
||||
* Added "install" with binfmt integration
|
||||
* A few games are actualy starting now (old WorldOfGoo, Into The Breach, VVVVVV and Thimbeweed Park)
|
||||
|
||||
v0.0.2
|
||||
======
|
||||
* Using box86 as a base, implemented most planned box64 part except dynarec
|
||||
* Wrapped a few libs
|
||||
* ELF loader a bit crude, but seems working
|
||||
* Signal handling implemented
|
||||
* MMX and x87 are sharing their registers
|
||||
Executable
+285
@@ -0,0 +1,285 @@
|
||||
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:
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make -j4
|
||||
sudo make install
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
|
||||
#### for 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:
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DRPI4ARM64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make -j4
|
||||
sudo make install
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
|
||||
#### for TEGRA X1
|
||||
|
||||
Using a 64bit OS:
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DTEGRAX1=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 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:
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DSD845=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 Phytium
|
||||
|
||||
Using a 64bit OS:
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DPHYTIUM=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 M1
|
||||
|
||||
Only test on Asahi for now, using the default "16K page" kernel
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DM1=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make -j4
|
||||
sudo make install
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
|
||||
|
||||
#### for Other ARM64 Linux platforms
|
||||
|
||||
`mkdir build; cd build; cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j$(nproc)`
|
||||
|
||||
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:
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DLARCH64=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 RISC-V
|
||||
|
||||
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 -j`nproc`
|
||||
sudo make install
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
|
||||
#### for PowerPC 64 LE
|
||||
|
||||
Using a 64bit OS:
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DPPC64LE=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 LX2160A
|
||||
|
||||
Using a 64bit OS:
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DLX2160A=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make -j$(nproc)
|
||||
sudo make install
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
|
||||
#### for x86_64 Linux
|
||||
|
||||
`mkdir build; cd build; cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j$(nproc)`
|
||||
|
||||
If you encounter some linking errors, try using `NOLOADADDR=ON` (`cmake -DNOLOADADDR=ON; make -j$(nproc)`).
|
||||
|
||||
### use ccmake
|
||||
|
||||
Alternatively, you can **use the curses-bases ccmake (or any other gui frontend for cmake)** to select wich platform to use interactively.
|
||||
|
||||
### Customize your build
|
||||
|
||||
#### Use ccache if you have it
|
||||
|
||||
Add `-DUSE_CCACHE=1` if you have ccache (it's better if you plan to touch the sources)
|
||||
|
||||
#### To have some debug info
|
||||
|
||||
The `-DCMAKE_BUILD_TYPE=RelWithDebInfo` argument makes a build that is both optimized for speed, and has debug information embedded. That way, if you have a crash or try to analyse performance, you'll have some symbols.
|
||||
|
||||
#### To have a Trace Enabled build
|
||||
|
||||
To have a trace enabled build (***the interpreter will be slightly slower***), add `-DHAVE_TRACE=1`. But you will need to have the [Zydis library](https://github.com/zyantific/zydis) in your `LD_LIBRARY_PATH` or in the system library folders at runtime.
|
||||
|
||||
#### To have ARM Dynarec
|
||||
|
||||
Dynarec is only available on ARM (for the meantime), Activate it by using `-DARM_DYNAREC=1`.
|
||||
###### *Note: VFPv3 and NEON are required for Dynarec.*
|
||||
|
||||
#### Not building from a git clone
|
||||
|
||||
If you are not building from a git clone (for example, downloading a release source code zip from github), you need to use `-DNOGIT=1` from cmake to be able to build (box64 uses git SHA1 to show last commit in version number).
|
||||
|
||||
----
|
||||
|
||||
Testing
|
||||
----
|
||||
A few tests are included with box64.
|
||||
|
||||
They can be launched using the `ctest` command.
|
||||
|
||||
The tests are very basic and only tests some functionality for now.
|
||||
|
||||
----
|
||||
|
||||
Debian Packaging
|
||||
----
|
||||
Box64 can also be packaged into a .deb file with `DEB_BUILD_OPTIONS=nostrip dpkg-buildpackage -us -uc -nc`.
|
||||
+122
@@ -0,0 +1,122 @@
|
||||

|
||||
|
||||
Linux Userspace x86_64 Emulator with a twist
|
||||
|
||||
[View changelog](https://github.com/ptitSeb/box64/blob/main/docs/CHANGELOG.md) | [中文](https://github.com/ptitSeb/box64/blob/main/docs/README_CN.md) | [Report an error](https://github.com/ptitSeb/box64/issues/new)
|
||||
|
||||
     
|
||||
|
||||
----
|
||||
|
||||
Box64 lets you run x86_64 Linux programs (such as games) on non-x86_64 Linux systems, like ARM (host system needs to be 64-bit little-endian).
|
||||
|
||||
You can find many Box64 videos on the [MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ), [Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g) or [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA) YouTube channels.
|
||||
|
||||
Since Box64 uses the native versions of some "system" libraries, like libc, libm, SDL, and OpenGL, it's easy to integrate and use with most applications, and performance can be surprisingly high in many cases. Take a look at thoses bench analysis for an example [here](https://box86.org/index.php/2021/06/game-performances/).
|
||||
|
||||
Box64 integrates with DynaRec (dynamic recompiler) for the ARM64 platform, providing a speed boost between 5 to 10 times faster than using only the interpreter. Some high level information on how DynaRec works can be found [here](https://box86.org/2021/07/inner-workings-a-high%e2%80%91level-view-of-box86-and-a-low%e2%80%91level-view-of-the-dynarec/).
|
||||
|
||||
Some x64 internal opcodes use parts of "Realmode X86 Emulator Library", see [x64primop.c](../src/emu/x64primop.c) for copyright details
|
||||
|
||||
<img src="img/Box64Icon.png" width="96" height="96">
|
||||
|
||||
Logo and Icon made by @grayduck, thanks!
|
||||
|
||||
----
|
||||
|
||||
Usage
|
||||
----
|
||||
|
||||
There are a few environment variables to control the behaviour of Box64.
|
||||
|
||||
See [here](USAGE.md) for all the environment variables and what they do.
|
||||
|
||||
Note: Box64's Dynarec uses a mechanism with Memory Protection and a SegFault signal handler to handle JIT code. In simpler terms, if you want to use GDB to debug a running program that use JIT'd code (like mono/Unity3D), you will still have many "normal" segfaults triggering. It is suggested to use something like `handle SIGSEGV nostop` in GDB to not stop at each segfault, and maybe put a breakpoint inside `my_memprotectionhandler` in `signals.c` if you want to trap SegFaults.
|
||||
|
||||
----
|
||||
|
||||
Compiling/Installation
|
||||
----
|
||||
> Compilation instructions can be found [here](COMPILE.md).
|
||||
|
||||
----
|
||||
|
||||
Version history/Change log
|
||||
----
|
||||
|
||||
The change log is available [here](CHANGELOG.md).
|
||||
|
||||
----
|
||||
|
||||
Notes about 32-bit platforms
|
||||
----
|
||||
|
||||
Because Box64 works by directly translating function calls from x86_64 to host system, the host system (the one Box64 is running on) needs to have 64-bit libraries. Box64 doesn't include any 64-bit <-> 32-bit translation.
|
||||
|
||||
So understand that box64 will only runs 64-bit linux binaries. For 32-bit binaries, you need box86 (with all the multiarch or proot trickery it imply on 64-bit OS).
|
||||
Note that many installer (mojo setup based) will fall back to "x86" when detecting ARM64 OS, and so will try to use box86 for the setup, even if an x86_64 version exist. You can hack your way around with a fake "uname" that return "x86_64" when the argument is "-m"
|
||||
|
||||
----
|
||||
|
||||
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 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.
|
||||
|
||||
----
|
||||
|
||||
Notes about GTK programs
|
||||
----
|
||||
|
||||
GTK libraries are now wrapped on box64, both gtk2 and gtk3.
|
||||
|
||||
----
|
||||
|
||||
Notes about Steam
|
||||
----
|
||||
|
||||
Note that Steam is a hybrid 32-bit / 64-bit. You NEED box86 to run Steam, as the client app is a 32-bit binary. It also uses a 64-bit local server binaries, but like most stuff using libcef/chromium, it's not working correctly on box64 for now.
|
||||
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).
|
||||
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, so some extensions may be missing depending on your graphics card.
|
||||
|
||||
----
|
||||
|
||||
Final word
|
||||
----
|
||||
|
||||
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, 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/))
|
||||
|
||||
And I also thank the many other people who participated even once in this project.
|
||||
|
||||
(If you use Box64 in your project, please don't forget to mention it!)
|
||||
@@ -0,0 +1,119 @@
|
||||
# box64
|
||||
|
||||

|
||||
Linux上用户空间的x86_64应用模拟器
|
||||
|
||||
----
|
||||

|
||||
|
||||
[English](README.md)
|
||||
|
||||
在ARM或其他非X86_64架构的Linux操作系统上,使用Box64可以运行x86_64 Linux程序(例如游戏),请注意,主机系统需要**64位小端**。
|
||||
|
||||
您可以在Youtube的[MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)、[Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)或[The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA)频道找到更多Box64视频。
|
||||
|
||||
Box64使用了一些“系统”库的原生版本,例如libc、libm、SDL和OpenGL,所以它很容易与大多数应用程序集成和使用,并且在很多情况下性能会出奇的高。点击[此处](https://box86.org/index.php/2021/06/game-performances/)查看示例的基准测试分析。
|
||||
|
||||
Box64为ARM64平台集成了DynaRec(动态重编译器),比仅使用解释器提升5到10倍性能。关于Dynarec如何工作的更多信息,可以在[这里](https://box86.org/2021/07/inner-workings-a-high%e2%80%91level-view-of-box86-and-a-low%e2%80%91level-view-of-the-dynarec/)找到。
|
||||
|
||||
注:DynaRec需要针对不同平台编写一部分汇编代码,目前仅支持ARM64。
|
||||
|
||||
一些x64内部操作码使用“Realmode X86 Emulator Library”的部分内容,请参阅[x64primop.c](../src/emu/x64primop.c)了解版权详情
|
||||
|
||||
<img src="img/Box64Icon.png" width="96" height="96">
|
||||
|
||||
Logo和图标由grayduck制作,感谢!
|
||||
|
||||
----
|
||||
|
||||
使用方法
|
||||
----
|
||||
|
||||
若干环境变量可以设置Box64的行为。
|
||||
|
||||
点击[这里](USAGE.md)了解所有的环境变量和它们的作用。
|
||||
|
||||
请注意:Box64的Dynarec提供了一种机制来处理JIT代码,包含内存保护和段错误信号处理程序。简单地说,如果您想用GDB来调试一个使用JIT代码的运行程序(比如mono/Unity3D),您仍然会触发很多“正常”的段错误。建议在GDB中使用类似于`handle SIGSEGV nostop`的东西,不要在每个段错误时都停止,如果您想捕获段错误,可以在`signals.c`中的`my_memprotectionhandler`中放置一个断点。
|
||||
|
||||
----
|
||||
|
||||
编译/安装
|
||||
----
|
||||
> 编译说明可以在[这里](COMPILE.md)查看。
|
||||
|
||||
----
|
||||
|
||||
版本历史
|
||||
----
|
||||
|
||||
版本日志在[这里](CHANGELOG.md)。
|
||||
|
||||
----
|
||||
|
||||
32位平台的注意事项
|
||||
----
|
||||
|
||||
Box64的工作原理是直接将函数调用从x86_64转换到主机系统,主机系统(Box64运行的系统)需要有64位的库。Box64并不包括任何64位<->32位的转换。
|
||||
|
||||
所以请理解,Box64只能运行64位的Linux二进制文件。对于32位的二进制文件,需要Box86(在64位的操作系统上需要所有的multiarch库或一些proot技巧)。
|
||||
|
||||
请注意,许多(基于mojo的)安装程序,即使存在x86_64版本,但在检测到架构为ARM64时会退回到"x86",这时会尝试使用(如果有)box86进行安装。这时你可以使用一个假的"uname",当它的参数为"-m"时返回"x86_64"。
|
||||
|
||||
----
|
||||
|
||||
关于Unity游戏模拟的注意事项
|
||||
----
|
||||
|
||||
当前Unity游戏模拟是一件碰运气的事情。Unity使用Mono(它的信号表示,并不总能100%成功模拟)。
|
||||
|
||||
您还应该注意,一些Unity3D游戏需要OpenGL 3+,目前在ARM SBC(单板计算机)上提供OpenGL 3+是很棘手的。
|
||||
|
||||
所以,并不是所有的Unity游戏都能工作,而且可能需要很高的OpenGL配置,但现在很多游戏都能工作。
|
||||
|
||||
提示:如果游戏开始后在显示任何东西之前退出,在Pi4上使用`MESA_GL_VERSION_OVERRIDE=3.2`,在Panfrost上使用`PAN_MESA_DEBUG=gl3`来使用更高的配置文件。
|
||||
|
||||
----
|
||||
|
||||
关于GTK程序的注意事项
|
||||
----
|
||||
|
||||
GTK 庫現在包裝在 box64 上,但只有 gtk2,而不是 gtk3(與 box86 相反)。
|
||||
|
||||
----
|
||||
|
||||
关于Steam的注意事项
|
||||
----
|
||||
|
||||
Steam并不是32位/64位混合的,而是32位的,因此您需要Box86才能运行Steam。Steam也使用64位的本地服务器程序,但像大多数使用libcef/chromium的程序一样,在box64上暂时无法正常工作。
|
||||
所以:目前在box64上无法运行Steam。
|
||||
----
|
||||
|
||||
关于Wine的注意事项
|
||||
----
|
||||
|
||||
box64支持64位Wine,但请注意,64位的Wine还包含32位的组件,以便能够运行32位的Windws程序。32位程序需要Box86,没有它就不能运行。在Box64和Box86共存的系统上,设置64位Wine可以同时运行32位和64位windows程序(只需分别使用 `wine` 和 `wine64`)。
|
||||
|
||||
----
|
||||
|
||||
关于Vulkan注意事项
|
||||
----
|
||||
|
||||
Box64 包裝 Vulkan 庫。但請注意,它僅使用 RX550 卡進行了測試,根據您的圖形卡,可能會缺少某些擴展。
|
||||
|
||||
----
|
||||
|
||||
结语
|
||||
----
|
||||
|
||||
我要感谢所有为 box64 开发做出贡献的人。
|
||||
贡献方式有很多种:代码贡献、财务帮助、捐赠捐赠和广告合作!
|
||||
以下感谢不分先后:
|
||||
* 代码贡献:rajdakin, mogery
|
||||
* 财务帮助: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/))
|
||||
|
||||
我还要感谢很多人,即使他们只参与了一次本项目。
|
||||
|
||||
(如果你的项目中使用了Box64,请不要忘记提及!)
|
||||
Executable
+308
@@ -0,0 +1,308 @@
|
||||
|
||||
Usage
|
||||
----
|
||||
|
||||
There are many environment variables to control Box64 behaviour.
|
||||
Env. var with * can also be put inside box64rc files
|
||||
|
||||
#### 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 *
|
||||
Path to look for x86_64 libraries. Default is current folder and `lib` in current folder.
|
||||
Also, `/usr/lib/x86_64-linux-gnu` and `/lib/x86_64-linux-gnu` are added if they exist.
|
||||
|
||||
#### BOX64_PATH *
|
||||
Path to look for x86_64 executable. Default is current folder and `bin` in current folder.
|
||||
|
||||
#### BOX64_DLSYM_ERROR *
|
||||
Enables/Disables the logging of `dlsym` errors.
|
||||
* 0 : Don't log `dlsym` errors. (Default.)
|
||||
* 1 : Log dlsym errors.
|
||||
|
||||
#### BOX64_TRACE_FILE *
|
||||
Send all log and trace to a file instead of `stdout`
|
||||
Also, if name contains `%pid` then this is replaced by the actual PID of box64 instance
|
||||
End the filename with `+` to have thetrace appended instead of overwriten
|
||||
Use `stderr` to use this instead of default `stdout`
|
||||
|
||||
#### BOX64_TRACE *
|
||||
Only on build with trace enabled. Trace allow the logging of all instruction executed, along with register dump
|
||||
* 0 : No trace. (Default.)
|
||||
* 1 : Trace enabled. Trace start after the initialisation of all depending libraries is done.
|
||||
* symbolname : Trace only `symbolname` (trace is disable if the symbol is not found).
|
||||
* 0xXXXXXXX-0xYYYYYYY : Trace only between the 2 addresses.
|
||||
|
||||
#### BOX64_TRACE_INIT *
|
||||
Use BOX64_TRACE_INIT instead of BOX_TRACE to start trace before the initialisation of libraries and the running program
|
||||
* 0 : No trace. (Default.)
|
||||
* 1 : Trace enabled. The trace start with the initialisation of all depending libraries is done.
|
||||
|
||||
#### BOX64_TRACE_START *
|
||||
Only on builds with trace enabled.
|
||||
* NNNNNNN : Start trace only after NNNNNNNN opcode execute (number is an `uint64_t`).
|
||||
|
||||
#### BOX64_TRACE_XMM *
|
||||
Only on builds with trace enabled.
|
||||
* 0 : The XMM (i.e. SSE/SSE2) register will not be logged with the general and x86 registers. (Default.)
|
||||
* 1 : Dump the XMM registers.
|
||||
|
||||
#### BOX64_TRACE_EMM *
|
||||
Only on builds with trace enabled.
|
||||
* 0 : The EMM (i.e. MMX) register will not be logged with the general and x86 registers. (Default.)
|
||||
* 1 : Dump the EMM registers.
|
||||
|
||||
#### BOX64_TRACE_COLOR *
|
||||
Only on builds with trace enabled.
|
||||
* 0 : The general registers will always be the default white color. (Default.)
|
||||
* 1 : The general registers will change color in the dumps when they changed value.
|
||||
|
||||
#### BOX64_LOAD_ADDR *
|
||||
Try to load at 0xXXXXXX main binary (if binary is a PIE)
|
||||
* 0xXXXXXXXX : The load address . (Only active on PIE programs.)
|
||||
|
||||
#### BOX64_NOSIGSEGV *
|
||||
Disable handling of SigSEGV. (Very useful for debugging.)
|
||||
* 0 : Let the x86 program set sighandler for SEGV (Default.)
|
||||
* 1 : Disable the handling of SigSEGV.
|
||||
|
||||
#### BOX64_NOSIGILL *
|
||||
Disable handling of SigILL (to ease debugging mainly).
|
||||
* 0 : Let x86 program set sighandler for Illegal Instruction
|
||||
* 1 : Disables the handling of SigILL
|
||||
|
||||
#### BOX64_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_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 *
|
||||
Force libX11's GLX extension to be present.
|
||||
* 0 : Do not force libX11's GLX extension to be present.
|
||||
* 1 : GLX will always be present when using XQueryExtension. (Default.)
|
||||
|
||||
#### BOX64_DYNAREC_DUMP *
|
||||
Enables/disables Box64's Dynarec's dump.
|
||||
* 0 : Disable Dynarec's blocks dump. (Default.)
|
||||
* 1 : Enable Dynarec's blocks dump.
|
||||
* 2 : Enable Dynarec's blocks dump with some colors.
|
||||
|
||||
#### BOX64_DYNAREC_LOG *
|
||||
Set the level of DynaRec's logs.
|
||||
* 0 : NONE : No Logs for DynaRec. (Default.)
|
||||
* 1 :INFO : Minimum Dynarec Logs (only unimplemented OpCode).
|
||||
* 2 : DEBUG : Debug Logs for Dynarec (with details on block created / executed).
|
||||
* 3 : VERBOSE : All of the above plus more.
|
||||
|
||||
#### BOX64_DYNAREC *
|
||||
Enables/Disables Box64's Dynarec.
|
||||
* 0 : Disables Dynarec.
|
||||
* 1 : Enable Dynarec. (Default.)
|
||||
|
||||
#### BOX64_DYNAREC_TRACE *
|
||||
Enables/Disables trace for generated code.
|
||||
* 0 : Disable trace for generated code. (Default.)
|
||||
* 1 : Enable trace for generated code (like regular Trace, this will slow down the program a lot and generate huge logs).
|
||||
|
||||
#### BOX64_NODYNAREC *
|
||||
Forbid dynablock creation in the interval specified (helpfull for debugging behaviour difference between Dynarec and Interpretor)
|
||||
* 0xXXXXXXXX-0xYYYYYYYY : define the interval where dynablock cannot start (inclusive-exclusive)
|
||||
|
||||
#### BOX64_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_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 *
|
||||
Force the use of Double for x87 emulation
|
||||
* 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 *
|
||||
Enable/Disable generation of -NAN
|
||||
* 0 : Generate -NAN like on x86
|
||||
* 1 : Don't do anything special with NAN, to go as fast as possible (default, faster)
|
||||
|
||||
#### 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
|
||||
|
||||
#### BOX64_LD_PRELOAD
|
||||
* XXXX[:YYYYY] force loading XXXX (and YYYY...) libraries with the binary
|
||||
PreLoaded libs can be emulated or native, and are treated the same way as if they were comming from the binary
|
||||
|
||||
#### BOX64_EMULATED_LIBS *
|
||||
* XXXX[:YYYYY] force lib XXXX (and YYYY...) to be emulated (and not wrapped)
|
||||
Some games uses an old version of some libraries, with an ABI incompatible with native version.
|
||||
Note that LittleInferno for example is auto detected, and libvorbis.so.0 is automatical added to emulated libs, and same for Don't Starve (and Together / Server variant) that use an old SDL2 too
|
||||
|
||||
#### BOX64_ALLOWMISSINGLIBS *
|
||||
Allow Box64 to continue even if a library is missing.
|
||||
* 0 : Box64 will stop if a library cannot be loaded. (Default.)
|
||||
* 1 : Continue even if a needed library cannot be loaded. Unadvised, this will, in most cases, crash later on.
|
||||
|
||||
#### BOX64_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 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_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 *
|
||||
Disables the loading of wrapped GTK libraries.
|
||||
* 0 : Load wrapped GTK libraries if found. (Default.)
|
||||
* 1 : Disables loading wrapped GTK libraries.
|
||||
|
||||
#### 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_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)
|
||||
then probably need to `finish` 1 or 2 functions (inside `usleep(..)`) and then you'll be in `my_box64signalhandler`,
|
||||
just before the printf of the Segfault message. Then simply
|
||||
`set waiting=0` to exit the infinite loop.
|
||||
* 2 : Launch `gdbserver` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process, and go in an endless loop, waiting.
|
||||
Use `gdb /PATH/TO/box64` and then `target remote 127.0.0.1:1234` to connect to the gdbserver (or use actual IP if not on the machine). After that, the procedure is the same as with ` BOX64_JITGDB=1`.
|
||||
This mode can be usefullwhen programs redirect all console output to a file (like Unity3D Games)
|
||||
|
||||
#### 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.
|
||||
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 180 KiB |
@@ -0,0 +1,38 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-arm64-git
|
||||
pkgver=r1495.e6e9fae
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-arm64-git}-git" "${pkgname%-arm64-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-arm64-git}-git" "${pkgname%-arm64-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-arm64-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-arm64-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-arm64-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-arm64-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-arm64-git
|
||||
pkgver=r1495.e6e9fae
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-arm64-git}-git" "${pkgname%-arm64-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-arm64-git}-git" "${pkgname%-arm64-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-arm64-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-arm64-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-arm64-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-arm64-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-lx2160a-git
|
||||
pkgver=r1495.e6e9fae
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-lx2160a-git}-git" "${pkgname%-lx2160a-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-lx2160a-git}-git" "${pkgname%-lx2160a-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-lx2160a-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-lx2160a-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DLX2160A=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-lx2160a-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-lx2160a-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-lx2160a-git
|
||||
pkgver=r1495.e6e9fae
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-lx2160a-git}-git" "${pkgname%-lx2160a-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-lx2160a-git}-git" "${pkgname%-lx2160a-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-lx2160a-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-lx2160a-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DLX2160A=1 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-lx2160a-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-lx2160a-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-rk3399-git
|
||||
pkgver=r1495.e6e9fae
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-rk3399-git}-git" "${pkgname%-rk3399-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-rk3399-git}-git" "${pkgname%-rk3399-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-rk3399-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-rk3399-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-rk3399-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-rk3399-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-rk3399-git
|
||||
pkgver=r1495.e6e9fae
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-rk3399-git}-git" "${pkgname%-rk3399-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-rk3399-git}-git" "${pkgname%-rk3399-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-rk3399-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-rk3399-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-rk3399-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-rk3399-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-rpi-git
|
||||
pkgver=r1495.e6e9fae
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-rpi-git}-git" "${pkgname%-rpi-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-rpi-git}-git" "${pkgname%-rpi-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-rpi-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-rpi-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DRPI4ARM64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-rpi-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-rpi-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-rpi-git
|
||||
pkgver=r1495.e6e9fae
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-rpi-git}-git" "${pkgname%-rpi-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-rpi-git}-git" "${pkgname%-rpi-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-rpi-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-rpi-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DRPI4ARM64=1 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-rpi-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-rpi-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-tegra-git
|
||||
pkgver=r1495.e6e9fae
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-tegra-git}-git" "${pkgname%-tegra-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-tegra-git}-git" "${pkgname%-tegra-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-tegra-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-tegra-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DTEGRAX1=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-tegra-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-tegra-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-tegra-git
|
||||
pkgver=r1495.e6e9fae
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-tegra-git}-git" "${pkgname%-tegra-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-tegra-git}-git" "${pkgname%-tegra-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-tegra-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-tegra-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DTEGRAX1=1 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-tegra-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-tegra-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-x64-git
|
||||
pkgver=r1495.e6e9fae
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-x64-git}-git" "${pkgname%-x64-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-x64-git}-git" "${pkgname%-x64-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-x64-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-x64-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-x64-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-x64-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-x64-git
|
||||
pkgver=r1495.e6e9fae
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-x64-git}-git" "${pkgname%-x64-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-x64-git}-git" "${pkgname%-x64-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-x64-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-x64-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-x64-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-x64-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
# The directory containing all PKGBUILDs for BOX64
|
||||
## FAQ
|
||||
### 1. How to use it?
|
||||
Just download the `PKGBUILD-<your-platform>` (no need to download the whole repository), go to directory where you downloaded and type:
|
||||
```sh
|
||||
mv ./PKGBUILD-<your-platform> ./PKGBUILD
|
||||
cd ..
|
||||
makepkg -si
|
||||
```
|
||||
This will copy the PKGBUILD for your platform (where you type your platform name instead of `<your-platform>`), build it and install the PKGBUILD on 64-bit Archlinux ARM.
|
||||
|
||||
In the future, I might try to do an unified PKGBUILD for all platforms that will recognize your platform automatically.
|
||||
|
||||
### 2. What platforms are currently supported.
|
||||
All specified in [COMPILE.md](../docs/COMPILE.md).
|
||||
|
||||
### 3. Any advantages with this solution?
|
||||
This might give you some advantages like:
|
||||
- automatic updates (with some AUR frontends like [`pamac-aur`](https://aur.archlinux.org/packages/pamac-aur/) or [`yay`](https://aur.archlinux.org/packages/yay));
|
||||
- easily uninstall with `pacman -R` when no needed (no need other scripts nor Makefile to do this);
|
||||
- your `box64` installation is recognized as a package (where it wasn't when installing with `make install`).
|
||||
|
||||
|
||||
### Note: You can use [makedeb](https://github.com/makedeb/makedeb) (or) [pkgbuild2spec](https://github.com/prozum/pkgbuild2spec) to compile box64 to .deb or .rpm installer files.
|
||||
+1315
-488
File diff suppressed because it is too large.
Load diff
@@ -32,6 +32,9 @@ execute_process(
|
||||
|
||||
# if the return value is !=0 bail out
|
||||
if( TEST_RESULT )
|
||||
get_filename_component(TESTNAME "${TEST_ARGS}" NAME)
|
||||
file(RENAME "${TEST_OUTPUT}" "${CMAKE_BINARY_DIR}/${TESTNAME}.out")
|
||||
file(WRITE "${CMAKE_BINARY_DIR}/${TESTNAME}.err" ${TEST_ERROR})
|
||||
message( FATAL_ERROR "Failed: Test program ${TEST_PROGRAM} exited != 0.\n${TEST_ERROR}" )
|
||||
endif( TEST_RESULT )
|
||||
|
||||
@@ -43,8 +46,16 @@ execute_process(
|
||||
|
||||
# again, if return value is !=0 scream and shout
|
||||
if( TEST_RESULT )
|
||||
get_filename_component(TESTNAME "${TEST_ARGS}" NAME)
|
||||
file(RENAME "${TEST_OUTPUT}" "${CMAKE_BINARY_DIR}/${TESTNAME}.out")
|
||||
file(WRITE "${CMAKE_BINARY_DIR}/${TESTNAME}.err" ${TEST_ERROR})
|
||||
message( FATAL_ERROR "Failed: The output of ${TEST_PROGRAM} did not match ${TEST_REFERENCE}")
|
||||
endif( TEST_RESULT )
|
||||
|
||||
# remove the temporary files if they exist
|
||||
if( EXISTS ${TEST_OUTPUT} )
|
||||
file(REMOVE "${TEST_OUTPUT}")
|
||||
endif()
|
||||
|
||||
# everything went fine...
|
||||
message( "Passed: The output of ${TEST_PROGRAM} matches ${TEST_REFERENCE}" )
|
||||
+174
-72
@@ -5,6 +5,7 @@
|
||||
#include <dlfcn.h>
|
||||
#include <signal.h>
|
||||
#include <sys/mman.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "box64context.h"
|
||||
#include "debug.h"
|
||||
@@ -18,6 +19,8 @@
|
||||
#include "wrapper.h"
|
||||
#include "x64emu.h"
|
||||
#include "signals.h"
|
||||
#include "rcfile.h"
|
||||
#include "gltools.h"
|
||||
|
||||
EXPORTDYN
|
||||
void initAllHelpers(box64context_t* context)
|
||||
@@ -27,6 +30,7 @@ void initAllHelpers(box64context_t* context)
|
||||
return;
|
||||
my_context = context;
|
||||
init_pthread_helper();
|
||||
init_bridge_helper();
|
||||
init_signal_helper(context);
|
||||
inited = 1;
|
||||
}
|
||||
@@ -37,9 +41,10 @@ void finiAllHelpers(box64context_t* context)
|
||||
static int finied = 0;
|
||||
if(finied)
|
||||
return;
|
||||
DeleteParams();
|
||||
fini_pthread_helper(context);
|
||||
fini_signal_helper();
|
||||
cleanAlternate();
|
||||
fini_bridge_helper();
|
||||
fini_custommem_helper(context);
|
||||
finied = 1;
|
||||
}
|
||||
@@ -61,12 +66,117 @@ 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);
|
||||
|
||||
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_trace, 7)
|
||||
#ifdef DYNAREC
|
||||
GO(my_context->mutex_dyndump, 8)
|
||||
#else
|
||||
GO(my_context->mutex_lock, 8)
|
||||
#endif
|
||||
GO(my_context->mutex_tls, 9)
|
||||
GO(my_context->mutex_thread, 10)
|
||||
GO(my_context->mutex_bridge, 11)
|
||||
#undef GO
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void relockMutex(int locks)
|
||||
{
|
||||
relockCustommemMutex(locks);
|
||||
#define GO(A, B) \
|
||||
if(locks&(1<<B)) \
|
||||
mutex_trylock(&A); \
|
||||
|
||||
GO(my_context->mutex_trace, 7)
|
||||
#ifdef DYNAREC
|
||||
GO(my_context->mutex_dyndump, 8)
|
||||
#else
|
||||
GO(my_context->mutex_lock, 8)
|
||||
#endif
|
||||
GO(my_context->mutex_tls, 9)
|
||||
GO(my_context->mutex_thread, 10)
|
||||
GO(my_context->mutex_bridge, 11)
|
||||
#undef GO
|
||||
}
|
||||
|
||||
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_lock, &attr);
|
||||
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)
|
||||
{
|
||||
// (re)init mutex if it was lock before the fork
|
||||
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)
|
||||
{
|
||||
@@ -77,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;
|
||||
@@ -86,37 +198,43 @@ box64context_t *NewBox64Context(int argc)
|
||||
|
||||
context->maplib = NewLibrarian(context, 1);
|
||||
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, vFv, x64Syscall, 0);
|
||||
context->vsyscall = AddBridge(context->system, vFEv, x64Syscall, 0, NULL);
|
||||
// create the vsyscalls
|
||||
context->vsyscalls[0] = AddVSyscall(context->system, 96);
|
||||
context->vsyscalls[1] = AddVSyscall(context->system, 201);
|
||||
context->vsyscalls[2] = AddVSyscall(context->system, 309);
|
||||
// create the alternate to map at address
|
||||
addAlternate((void*)0xffffffffff600000, (void*)context->vsyscalls[0]);
|
||||
addAlternate((void*)0xffffffffff600400, (void*)context->vsyscalls[1]);
|
||||
addAlternate((void*)0xffffffffff600800, (void*)context->vsyscalls[2]);
|
||||
// get handle to box64 itself
|
||||
context->box64lib = dlopen(NULL, RTLD_NOW|RTLD_GLOBAL);
|
||||
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);
|
||||
|
||||
pthread_mutex_init(&context->mutex_once, NULL);
|
||||
pthread_mutex_init(&context->mutex_once2, NULL);
|
||||
pthread_mutex_init(&context->mutex_trace, NULL);
|
||||
#ifndef DYNAREC
|
||||
pthread_mutex_init(&context->mutex_lock, NULL);
|
||||
#else
|
||||
pthread_mutex_init(&context->mutex_dyndump, NULL);
|
||||
#endif
|
||||
pthread_mutex_init(&context->mutex_tls, NULL);
|
||||
pthread_mutex_init(&context->mutex_thread, NULL);
|
||||
pthread_key_create(&context->tlskey, free_tlsdatasize);
|
||||
|
||||
|
||||
for (int i=0; i<8; ++i) context->canary[i] = 1 + getrand(255);
|
||||
context->canary[getrand(4)] = 0;
|
||||
printf_log(LOG_DEBUG, "Setting up canary (for Stack protector) at FS:0x14, value:%08X\n", *(uint32_t*)context->canary);
|
||||
printf_log(LOG_DEBUG, "Setting up canary (for Stack protector) at FS:0x28, value:%08X\n", *(uint32_t*)context->canary);
|
||||
|
||||
initAllHelpers(context);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
void freeALProcWrapper(box64context_t* context);
|
||||
EXPORTDYN
|
||||
void FreeBox64Context(box64context_t** context)
|
||||
{
|
||||
@@ -128,15 +246,18 @@ void FreeBox64Context(box64context_t** context)
|
||||
|
||||
box64context_t* ctx = *context; // local copy to do the cleanning
|
||||
|
||||
if(ctx->local_maplib)
|
||||
FreeLibrarian(&ctx->local_maplib, NULL);
|
||||
if(ctx->maplib)
|
||||
FreeLibrarian(&ctx->maplib, NULL);
|
||||
FreeDictionnary(&ctx->versym);
|
||||
FreeDefaultVersion(&ctx->globaldefver);
|
||||
FreeDefaultVersion(&ctx->weakdefver);
|
||||
|
||||
for(int i=0; i<ctx->elfsize; ++i) {
|
||||
FreeElfHeader(&ctx->elfs[i]);
|
||||
}
|
||||
free(ctx->elfs);
|
||||
|
||||
if(ctx->maplib)
|
||||
FreeLibrarian(&ctx->maplib);
|
||||
if(ctx->local_maplib)
|
||||
FreeLibrarian(&ctx->local_maplib);
|
||||
box_free(ctx->elfs);
|
||||
|
||||
FreeCollection(&ctx->box64_path);
|
||||
FreeCollection(&ctx->box64_ld_lib);
|
||||
@@ -148,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;
|
||||
}
|
||||
@@ -173,15 +294,17 @@ void FreeBox64Context(box64context_t** context)
|
||||
|
||||
FreeDLPrivate(&ctx->dlprivate);
|
||||
|
||||
free(ctx->stack);
|
||||
|
||||
free(ctx->fullpath);
|
||||
free(ctx->box64path);
|
||||
box_free(ctx->fullpath);
|
||||
box_free(ctx->box64path);
|
||||
box_free(ctx->bashpath);
|
||||
|
||||
FreeBridge(&ctx->system);
|
||||
|
||||
// freeGLProcWrapper(ctx);
|
||||
// freeALProcWrapper(ctx);
|
||||
freeGLProcWrapper(ctx);
|
||||
freeALProcWrapper(ctx);
|
||||
|
||||
if(ctx->stack_clone)
|
||||
box_free(ctx->stack_clone);
|
||||
|
||||
|
||||
void* ptr;
|
||||
@@ -192,27 +315,27 @@ void FreeBox64Context(box64context_t** context)
|
||||
pthread_key_delete(ctx->tlskey);
|
||||
|
||||
if(ctx->tlsdata)
|
||||
free(ctx->tlsdata);
|
||||
box_free(ctx->tlsdata);
|
||||
|
||||
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_lock);
|
||||
#else
|
||||
pthread_mutex_destroy(&ctx->mutex_dyndump);
|
||||
#endif
|
||||
pthread_mutex_destroy(&ctx->mutex_tls);
|
||||
pthread_mutex_destroy(&ctx->mutex_thread);
|
||||
|
||||
free_neededlib(&ctx->neededlibs);
|
||||
free_neededlib(ctx->neededlibs);
|
||||
ctx->neededlibs = NULL;
|
||||
|
||||
if(ctx->emu_sig)
|
||||
FreeX64Emu(&ctx->emu_sig);
|
||||
|
||||
finiAllHelpers(ctx);
|
||||
|
||||
free(ctx);
|
||||
#ifndef DYNAREC
|
||||
pthread_mutex_destroy(&ctx->mutex_trace);
|
||||
pthread_mutex_destroy(&ctx->mutex_lock);
|
||||
pthread_mutex_destroy(&ctx->mutex_tls);
|
||||
pthread_mutex_destroy(&ctx->mutex_thread);
|
||||
pthread_mutex_destroy(&ctx->mutex_bridge);
|
||||
#endif
|
||||
|
||||
freeCycleLog(ctx);
|
||||
|
||||
box_free(ctx);
|
||||
}
|
||||
|
||||
int AddElfHeader(box64context_t* ctx, elfheader_t* head) {
|
||||
@@ -220,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++;
|
||||
@@ -231,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
|
||||
@@ -244,24 +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;
|
||||
if(needed->size == needed->cap) {
|
||||
needed->cap += 8;
|
||||
needed->libs = (library_t**)realloc(needed->libs, needed->cap*sizeof(library_t*));
|
||||
}
|
||||
needed->libs[needed->size++] = lib;
|
||||
}
|
||||
|
||||
void free_neededlib(needed_libs_t* needed)
|
||||
{
|
||||
if(!needed)
|
||||
return;
|
||||
needed->cap = 0;
|
||||
needed->size = 0;
|
||||
if(needed->libs)
|
||||
free(needed->libs);
|
||||
needed->libs = NULL;
|
||||
}
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
#define __BOX64_VERSION_H_
|
||||
|
||||
#define BOX64_MAJOR 0
|
||||
#define BOX64_MINOR 0
|
||||
#define BOX64_MINOR 2
|
||||
#define BOX64_REVISION 2
|
||||
|
||||
#endif //__BOX64_VERSION_H_
|
||||
#endif //__BOX64_VERSION_H_
|
||||
+1381
-690
File diff suppressed because it is too large.
Load diff
Executable
+1804
File diff suppressed because it is too large.
Load diff
Executable
+56
@@ -0,0 +1,56 @@
|
||||
//arm epilog for dynarec
|
||||
//Save stuff, prepare stack and register
|
||||
//called with pointer to emu as 1st parameter
|
||||
//and address to jump to as 2nd parameter
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.global arm64_epilog
|
||||
arm64_epilog:
|
||||
//update register -> emu
|
||||
stp x10, x11, [x0, (8 * 0)]
|
||||
stp x12, x13, [x0, (8 * 2)]
|
||||
stp x14, x15, [x0, (8 * 4)]
|
||||
stp x16, x17, [x0, (8 * 6)]
|
||||
stp x18, x19, [x0, (8 * 8)]
|
||||
stp x20, x21, [x0, (8 * 10)]
|
||||
stp x22, x23, [x0, (8 * 12)]
|
||||
stp x24, x25, [x0, (8 * 14)]
|
||||
stp x26, x27, [x0, (8 * 16)] // put back reg value in emu, including EIP (so x27 must be EIP now)
|
||||
//restore all used register
|
||||
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)]
|
||||
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 x30, x29, [sp], 16 // saved lr
|
||||
//end, return...
|
||||
ret
|
||||
|
||||
|
||||
.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)]
|
||||
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 x30, x29, [sp], 16 // saved lr
|
||||
//end, return...
|
||||
ret
|
||||
Executable
+234
@@ -0,0 +1,234 @@
|
||||
//arm lock helper
|
||||
//there is 2 part: read and write
|
||||
// write return 0 on success, 1 on fail (value has been changed)
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.global arm64_lock_read_b
|
||||
.global arm64_lock_write_b
|
||||
.global arm64_lock_read_h
|
||||
.global arm64_lock_write_h
|
||||
.global arm64_lock_read_d
|
||||
.global arm64_lock_write_d
|
||||
.global arm64_lock_read_dd
|
||||
.global arm64_lock_write_dd
|
||||
.global arm64_lock_read_dq
|
||||
.global arm64_lock_write_dq
|
||||
.global arm64_lock_xchg
|
||||
.global arm64_lock_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
|
||||
// address is x0, return is x0
|
||||
ldaxrb w0, [x0]
|
||||
ret
|
||||
|
||||
arm64_lock_write_b:
|
||||
// address is x0, value is x1, return is x0
|
||||
mov x2, x0
|
||||
stlxrb w0, w1, [x2]
|
||||
dmb ish
|
||||
ret
|
||||
|
||||
arm64_lock_read_h:
|
||||
dmb ish
|
||||
// address is x0, return is x0
|
||||
ldaxrh w0, [x0]
|
||||
ret
|
||||
|
||||
arm64_lock_write_h:
|
||||
// address is x0, value is x1, return is x0
|
||||
mov x2, x0
|
||||
stlxrh w0, w1, [x2]
|
||||
dmb ish
|
||||
ret
|
||||
|
||||
arm64_lock_read_d:
|
||||
dmb ish
|
||||
// address is x0, return is x0
|
||||
ldaxr w0, [x0]
|
||||
ret
|
||||
|
||||
arm64_lock_write_d:
|
||||
// address is x0, value is w1, return is x0
|
||||
mov x2, x0
|
||||
stlxr w0, w1, [x2]
|
||||
dmb ish
|
||||
ret
|
||||
|
||||
arm64_lock_read_dd:
|
||||
dmb ish
|
||||
// address is x0, return is x0
|
||||
ldaxr x0, [x0]
|
||||
ret
|
||||
|
||||
arm64_lock_write_dd:
|
||||
// address is x0, value is x1, return is x0
|
||||
mov x2, x0
|
||||
stlxr w0, x1, [x2]
|
||||
dmb ish
|
||||
ret
|
||||
|
||||
arm64_lock_read_dq:
|
||||
dmb ish
|
||||
// address is r2, return is r0, r1
|
||||
ldaxp x4, x3, [x2]
|
||||
str x4, [x0]
|
||||
str x3, [x1]
|
||||
ret
|
||||
|
||||
arm64_lock_write_dq:
|
||||
// address is r2, value is r0, r1, return is r0
|
||||
// r0 needs to be aligned
|
||||
stlxp w3, x0, x1, [x2]
|
||||
mov w0, w3
|
||||
dmb ish
|
||||
ret
|
||||
|
||||
|
||||
arm64_lock_xchg:
|
||||
dmb ish
|
||||
arm64_lock_xchg_0:
|
||||
// address is x0, value is x1, return old value in x0
|
||||
ldaxr x2, [x0]
|
||||
stlxr w3, x1, [x0]
|
||||
cbnz w3, arm64_lock_xchg_0
|
||||
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
|
||||
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, 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
|
||||
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 2f
|
||||
stlxr w4, x1, [x0]
|
||||
cbnz w4, 1b
|
||||
mov x0, x1
|
||||
ret
|
||||
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
|
||||
Executable
+66
@@ -0,0 +1,66 @@
|
||||
#ifndef __ARM64_LOCK__H__
|
||||
#define __ARM64_LOCK__H__
|
||||
#include <stdint.h>
|
||||
|
||||
// LDAXRB of ADDR
|
||||
extern uint8_t arm64_lock_read_b(void* addr);
|
||||
// STLXRB of ADDR, return 0 if ok, 1 if not
|
||||
extern int arm64_lock_write_b(void* addr, uint8_t val);
|
||||
|
||||
// LDAXRH of ADDR
|
||||
extern uint16_t arm64_lock_read_h(void* addr);
|
||||
// STLXRH of ADDR, return 0 if ok, 1 if not
|
||||
extern int arm64_lock_write_h(void* addr, uint16_t val);
|
||||
|
||||
// LDAXR of ADDR
|
||||
extern uint32_t arm64_lock_read_d(void* addr);
|
||||
// STLXR of ADDR, return 0 if ok, 1 if not
|
||||
extern int arm64_lock_write_d(void* addr, uint32_t val);
|
||||
|
||||
// LDAXR of ADDR
|
||||
extern uint64_t arm64_lock_read_dd(void* addr);
|
||||
// STLXR of ADDR, return 0 if ok, 1 if not
|
||||
extern int arm64_lock_write_dd(void* addr, uint64_t val);
|
||||
|
||||
// LDAXRD of ADDR
|
||||
extern void arm64_lock_read_dq(uint64_t * a, uint64_t* b, void* addr);
|
||||
// STLXRD of ADDR, return 0 if ok, 1 if not
|
||||
extern int arm64_lock_write_dq(uint64_t a, uint64_t b, void* addr);
|
||||
|
||||
// Atomicaly exchange value at [p] with val, return old p
|
||||
extern uintptr_t arm64_lock_xchg(void* p, uintptr_t val);
|
||||
|
||||
// Atomicaly 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__
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
//arm update linker table for dynarec
|
||||
//called with pointer to emu as 1st parameter
|
||||
//and address of table to as 2nd parameter
|
||||
//ip is at r12
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.extern LinkNext
|
||||
|
||||
.global arm64_next
|
||||
|
||||
.8byte 0 // NULL pointer before arm64_next, for getDB
|
||||
arm64_next:
|
||||
// emu is r0
|
||||
// IP address is r1
|
||||
sub sp, sp, (8 * 12)
|
||||
stp x0, x1, [sp, (8 * 0)]
|
||||
stp x10, x11, [sp, (8 * 2)]
|
||||
stp x12, x13, [sp, (8 * 4)]
|
||||
stp x14, x15, [sp, (8 * 6)]
|
||||
stp x16, x17, [sp, (8 * 8)]
|
||||
stp x18, x27, [sp, (8 * 10)] // also save x27(rip) to allow change in LinkNext
|
||||
|
||||
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
|
||||
// preserve return value
|
||||
mov x3, x0
|
||||
// pop regs
|
||||
ldp x0, x1, [sp, (8 * 0)]
|
||||
ldp x10, x11, [sp, (8 * 2)]
|
||||
ldp x12, x13, [sp, (8 * 4)]
|
||||
ldp x14, x15, [sp, (8 * 6)]
|
||||
ldp x16, x17, [sp, (8 * 8)]
|
||||
ldp x18, x27, [sp, (8 * 10)]
|
||||
add sp, sp, (8 * 12)
|
||||
// return offset is jump address
|
||||
br x3
|
||||
|
||||
Executable
+1373
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,6 @@
|
||||
#ifndef _ARM_PRINTER_H_
|
||||
#define _ARM_PRINTER_H_
|
||||
|
||||
const char* arm64_print(uint32_t opcode, uint64_t addr);
|
||||
|
||||
#endif //_ARM_PRINTER_H_
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
//arm prologue for dynarec
|
||||
//Save stuff, prepare stack and register
|
||||
//called with pointer to emu as 1st parameter
|
||||
//and address to jump to as 2nd parameter
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.extern arm64_next
|
||||
|
||||
.global arm64_prolog
|
||||
arm64_prolog:
|
||||
//save all 18 used register
|
||||
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)]
|
||||
stp x27, X28, [sp, (8 * 8)]
|
||||
stp d8, d9, [sp, (8 *10)]
|
||||
stp d10, d11, [sp, (8 *12)]
|
||||
stp d12, d13, [sp, (8 *14)]
|
||||
stp d14, d15, [sp, (8 *16)]
|
||||
//vpush {d8-d15} // save NEON regs?
|
||||
//setup emu -> register
|
||||
ldp x10, x11, [x0, (8 * 0)]
|
||||
ldp x12, x13, [x0, (8 * 2)]
|
||||
ldp x14, x15, [x0, (8 * 4)]
|
||||
ldp x16, x17, [x0, (8 * 6)]
|
||||
ldp x18, x19, [x0, (8 * 8)]
|
||||
ldp x20, x21, [x0, (8 * 10)]
|
||||
ldp x22, x23, [x0, (8 * 12)]
|
||||
ldp x24, x25, [x0, (8 * 14)]
|
||||
ldp x26, x27, [x0, (8 * 16)]
|
||||
// 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
|
||||
Executable
+2559
File diff suppressed because it is too large.
Load diff
Executable
+1956
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
Executable
+925
@@ -0,0 +1,925 @@
|
||||
#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_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
int16_t i16;
|
||||
uint16_t u16;
|
||||
uint64_t u64;
|
||||
int32_t i32;
|
||||
int64_t j64;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1;
|
||||
int64_t fixedaddress;
|
||||
int lock;
|
||||
MAYUSE(u8);
|
||||
MAYUSE(u16);
|
||||
MAYUSE(u64);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(lock);
|
||||
|
||||
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 66 are ignored
|
||||
rex.rex = 0;
|
||||
while(opcode>=0x40 && opcode<=0x4f) {
|
||||
rex.rex = opcode;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
if(rex.w && opcode!=0x0f) // rex.w cancels "66", but not for 66 0f type of prefix
|
||||
return dynarec64_00(dyn, addr-1, ip, ninst, rex, rep, ok, need_epilog); // addr-1, to "put back" opcode
|
||||
|
||||
switch(opcode) {
|
||||
case 0x01:
|
||||
INST_NAME("ADD Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_add16(dyn, ninst, x1, x2, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x03:
|
||||
INST_NAME("ADD Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_add16(dyn, ninst, x1, x2, x3, x4);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x05:
|
||||
INST_NAME("ADD AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_add16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x09:
|
||||
INST_NAME("OR Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_or16(dyn, ninst, x1, x2, x4, x2);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x0B:
|
||||
INST_NAME("OR Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_or16(dyn, ninst, x1, x2, x4, x3);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x0D:
|
||||
INST_NAME("OR AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_or16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x0F:
|
||||
addr = dynarec64_660F(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("ADC Ew, Gw");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_adc16(dyn, ninst, x1, x2, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x13:
|
||||
INST_NAME("ADC Gw, Ew");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_adc16(dyn, ninst, x1, x2, x4, x3);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x15:
|
||||
INST_NAME("ADC AX, Iw");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_adc16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x19:
|
||||
INST_NAME("SBB Ew, Gw");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_sbb16(dyn, ninst, x1, x2, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x1B:
|
||||
INST_NAME("SBB Gw, Ew");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_sbb16(dyn, ninst, x1, x2, x4, x3);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x1D:
|
||||
INST_NAME("SBB AX, Iw");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i16 = F16S;
|
||||
UXTHw(x1, xRAX);
|
||||
MOVZw(x2, i16);
|
||||
emit_sbb16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x21:
|
||||
INST_NAME("AND Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_and16(dyn, ninst, x1, x2, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x23:
|
||||
INST_NAME("AND Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_and16(dyn, ninst, x1, x2, x3, x4);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x25:
|
||||
INST_NAME("AND AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_and16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x29:
|
||||
INST_NAME("SUB Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_sub16(dyn, ninst, x1, x2, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x2B:
|
||||
INST_NAME("SUB Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_sub16(dyn, ninst, x1, x2, x3, x4);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("SUB AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_sub16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x31:
|
||||
INST_NAME("XOR Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_xor16(dyn, ninst, x1, x2, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x33:
|
||||
INST_NAME("XOR Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_xor16(dyn, ninst, x1, x2, x3, x4);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x35:
|
||||
INST_NAME("XOR AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_xor16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x39:
|
||||
INST_NAME("CMP Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
case 0x3B:
|
||||
INST_NAME("CMP Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
case 0x3D:
|
||||
INST_NAME("CMP AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
if(i32) {
|
||||
MOV32w(x2, i32);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
} else {
|
||||
emit_cmp16_0(dyn, ninst, x1, x3, x4);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x64:
|
||||
addr = dynarec64_6664(dyn, addr, ip, ninst, rex, _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:
|
||||
case 0x6B:
|
||||
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, (opcode==0x69)?2:1);
|
||||
if(opcode==0x69) i32 = F16S; else i32 = F8S;
|
||||
MOV32w(x2, i32);
|
||||
MULw(x2, x2, x1);
|
||||
UFLAG_RES(x2);
|
||||
gd=x2;
|
||||
GWBACK;
|
||||
break;
|
||||
|
||||
case 0x70:
|
||||
case 0x71:
|
||||
case 0x72:
|
||||
case 0x73:
|
||||
case 0x74:
|
||||
case 0x75:
|
||||
case 0x76:
|
||||
case 0x77:
|
||||
case 0x78:
|
||||
case 0x79:
|
||||
case 0x7a:
|
||||
case 0x7b:
|
||||
case 0x7c:
|
||||
case 0x7d:
|
||||
case 0x7e:
|
||||
case 0x7f:
|
||||
// just use regular conditional jump
|
||||
return dynarec64_00(dyn, addr-1, ip, ninst, rex, rep, ok, need_epilog);
|
||||
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: //ADD
|
||||
if(opcode==0x81) {INST_NAME("ADD Ew, Iw");} else {INST_NAME("ADD Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_add16(dyn, ninst, ed, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1: //OR
|
||||
if(opcode==0x81) {INST_NAME("OR Ew, Iw");} else {INST_NAME("OR Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_or16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 2: //ADC
|
||||
if(opcode==0x81) {INST_NAME("ADC Ew, Iw");} else {INST_NAME("ADC Ew, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_adc16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 3: //SBB
|
||||
if(opcode==0x81) {INST_NAME("SBB Ew, Iw");} else {INST_NAME("SBB Ew, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_sbb16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 4: //AND
|
||||
if(opcode==0x81) {INST_NAME("AND Ew, Iw");} else {INST_NAME("AND Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_and16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 5: //SUB
|
||||
if(opcode==0x81) {INST_NAME("SUB Ew, Iw");} else {INST_NAME("SUB Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_sub16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 6: //XOR
|
||||
if(opcode==0x81) {INST_NAME("XOR Ew, Iw");} else {INST_NAME("XOR Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_xor16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 7: //CMP
|
||||
if(opcode==0x81) {INST_NAME("CMP Ew, Iw");} else {INST_NAME("CMP Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
if(i16) {
|
||||
MOVZw(x2, i16);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
} else
|
||||
emit_cmp16_0(dyn, ninst, x1, x3, x4);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x85:
|
||||
INST_NAME("TEST Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEW(x1, 0);
|
||||
GETGW(x2);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
|
||||
case 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;
|
||||
GETGD; // don't need GETGW here
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
if(ed!=gd) {
|
||||
BFIx(ed, gd, 0, 16);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<1, 1, rex, &lock, 0, 0);
|
||||
STRH_U12(gd, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gw, Ew");
|
||||
nextop = F8;
|
||||
GETGD; // don't need GETGW neither
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
if(ed!=gd) {
|
||||
BFIx(gd, ed, 0, 16);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<1, 1, rex, &lock, 0, 0);
|
||||
SMREADLOCK(lock);
|
||||
LDRH_U12(x1, ed, fixedaddress);
|
||||
BFIx(gd, x1, 0, 16);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x90:
|
||||
case 0x91:
|
||||
case 0x92:
|
||||
case 0x93:
|
||||
case 0x94:
|
||||
case 0x95:
|
||||
case 0x96:
|
||||
case 0x97:
|
||||
gd = xRAX+(opcode&0x07)+(rex.b<<3);
|
||||
if(gd==xRAX) {
|
||||
INST_NAME("NOP");
|
||||
} else {
|
||||
INST_NAME("XCHG AX, Reg");
|
||||
MOVw_REG(x2, xRAX);
|
||||
BFIx(xRAX, gd, 0, 16);
|
||||
BFIx(gd, x2, 0, 16);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x98:
|
||||
INST_NAME("CBW");
|
||||
SXTBw(x1, xRAX);
|
||||
BFIw(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0xA1:
|
||||
INST_NAME("MOV EAX,Od");
|
||||
u64 = F64;
|
||||
MOV64x(x1, u64);
|
||||
LDRH_U12(x2, x1, 0);
|
||||
BFIx(xRAX, x2, 0, 16);
|
||||
break;
|
||||
|
||||
case 0xA3:
|
||||
INST_NAME("MOV Od,EAX");
|
||||
u64 = F64;
|
||||
MOV64x(x1, u64);
|
||||
STRH_U12(xRAX, x1, 0);
|
||||
SMWRITE();
|
||||
break;
|
||||
|
||||
case 0xA5:
|
||||
if(rep) {
|
||||
INST_NAME("REP MOVSW");
|
||||
CBZx_NEXT(xRCX);
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
LDRH_S9_postindex(x1, xRSI, 2);
|
||||
STRH_S9_postindex(x1, xRDI, 2);
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CBNZx_MARK(xRCX);
|
||||
B_NEXT_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
LDRH_S9_postindex(x1, xRSI, -2);
|
||||
STRH_S9_postindex(x1, xRDI, -2);
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CBNZx_MARK2(xRCX);
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("MOVSW");
|
||||
GETDIR(x3, 2);
|
||||
LDRH_U12(x1, xRSI, 0);
|
||||
STRH_U12(x1, xRDI, 0);
|
||||
ADDx_REG(xRSI, xRSI, x3);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA9:
|
||||
INST_NAME("TEST AX,Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u16 = F16;
|
||||
MOV32w(x2, u16);
|
||||
UBFXx(x1, xRAX, 0, 16);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
|
||||
case 0xAB:
|
||||
if(rep) {
|
||||
INST_NAME("REP STOSW");
|
||||
CBZx_NEXT(xRCX);
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
STRH_S9_postindex(xRAX, xRDI, 2);
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CBNZx_MARK(xRCX);
|
||||
B_NEXT_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
STRH_S9_postindex(xRAX, xRDI, -2);
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CBNZx_MARK2(xRCX);
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("STOSW");
|
||||
GETDIR(x3, 2);
|
||||
STRH_U12(xRAX, xRDI, 0);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xB8:
|
||||
case 0xB9:
|
||||
case 0xBA:
|
||||
case 0xBB:
|
||||
case 0xBC:
|
||||
case 0xBD:
|
||||
case 0xBE:
|
||||
case 0xBF:
|
||||
INST_NAME("MOV Reg16, Iw");
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
gd = xRAX+(opcode&7)+(rex.b<<3);
|
||||
BFIx(gd, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0xC1:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ew, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(rol16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ew, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(ror16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Ew, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(rcl16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Ew, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(rcr16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
INST_NAME("SHL Ew, Ib");
|
||||
UFLAG_IF {MESSAGE(LOG_DUMP, "Need Optimization for flags\n");}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
UFLAG_IF {MOV32w(x2, (u8&0x1f));}
|
||||
UFLAG_OP12(ed, x2)
|
||||
LSLw_IMM(ed, ed, u8&0x1f);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shl16);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("SHR Ed, Ib");
|
||||
UFLAG_IF {MESSAGE(LOG_DUMP, "Need Optimization for flags\n");}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
UFLAG_IF {MOV32w(x2, (u8&0x1f));}
|
||||
UFLAG_OP12(ed, x2)
|
||||
LSRw_IMM(ed, ed, u8&0x1f);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shr16);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("SAR Ed, Ib");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
UFLAG_IF {MESSAGE(LOG_DUMP, "Need Optimization for flags\n");}
|
||||
GETSEW(x1, 1);
|
||||
u8 = F8;
|
||||
UFLAG_IF {MOV32w(x2, (u8&0x1f));}
|
||||
UFLAG_OP12(ed, x2)
|
||||
ASRw(ed, ed, (u8&0x1f));
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_sar16);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC7:
|
||||
INST_NAME("MOV Ew, Iw");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
BFIx(ed, x1, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<1, 1, rex, &lock, 0, 2);
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
STRH_U12(x1, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xD1:
|
||||
case 0xD3:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("ROL Ew, 1");
|
||||
MOV32w(x2, 1);
|
||||
} else {
|
||||
INST_NAME("ROL Ew, CL");
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100);
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEW(x1, 0);
|
||||
CALL_(rol16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("ROR Ew, 1");
|
||||
MOV32w(x2, 1);
|
||||
} else {
|
||||
INST_NAME("ROR Ew, CL");
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100);
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEW(x1, 0);
|
||||
CALL_(ror16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 2:
|
||||
if(opcode==0xD1) {INST_NAME("RCL Ew, 1"); } else { INST_NAME("RCL Ew, CL");}
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
if(opcode==0xD1) {MOV32w(x2, 1);} else {ANDw_mask(x2, xRCX, 0, 0b00100);}
|
||||
GETEW(x1, 0);
|
||||
CALL_(rcl16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 3:
|
||||
if(opcode==0xD1) {INST_NAME("RCR Ew, 1");} else {INST_NAME("RCR Ew, CL");}
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
if(opcode==0xD1) {MOV32w(x2, 1);} else {ANDw_mask(x2, xRCX, 0, 0b00100);}
|
||||
GETEW(x1, 0);
|
||||
CALL_(rcr16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("SHL Ew, 1");
|
||||
MOV32w(x4, 1);
|
||||
} else {
|
||||
INST_NAME("SHL Ew, CL");
|
||||
ANDw_mask(x4, xRCX, 0, 0b00100);
|
||||
}
|
||||
UFLAG_IF {MESSAGE(LOG_DUMP, "Need Optimization for flags\n");}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1, 0);
|
||||
UFLAG_OP12(ed, x4)
|
||||
LSLw_REG(ed, ed, x4);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shl16);
|
||||
break;
|
||||
case 5:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("SHR Ew, 1");
|
||||
MOV32w(x4, 1);
|
||||
} else {
|
||||
INST_NAME("SHR Ew, CL");
|
||||
ANDw_mask(x4, xRCX, 0, 0b00100);
|
||||
}
|
||||
UFLAG_IF {MESSAGE(LOG_DUMP, "Need Optimization for flags\n");}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1, 0);
|
||||
UFLAG_OP12(ed, x4)
|
||||
LSRw_REG(ed, ed, x4);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shr16);
|
||||
break;
|
||||
case 7:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("SAR Ew, 1");
|
||||
MOV32w(x4, 1);
|
||||
} else {
|
||||
INST_NAME("SAR Ew, CL");
|
||||
ANDw_mask(x4, xRCX, 0, 0b00100);
|
||||
}
|
||||
UFLAG_IF {MESSAGE(LOG_DUMP, "Need Optimization for flags\n");}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETSEW(x1, 0);
|
||||
UFLAG_OP12(ed, x4)
|
||||
ASRw_REG(ed, ed, x4);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_sar16);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
return dynarec64_66F0(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
|
||||
case 0xF7:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
case 1:
|
||||
INST_NAME("TEST Ew, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, 2);
|
||||
u16 = F16;
|
||||
MOV32w(x2, u16);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("NOT Ew");
|
||||
GETEW(x1, 0);
|
||||
MVNw_REG(ed, ed);
|
||||
EWBACK;
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("NEG Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, 0);
|
||||
emit_neg16(dyn, ninst, ed, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("MUL AX, Ew");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
UFLAG_DF(x1, d_mul16);
|
||||
GETEW(x1, 0);
|
||||
UXTHw(x2, xRAX);
|
||||
MULw(x1, x2, x1);
|
||||
UFLAG_RES(x1);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
BFXILx(xRDX, x1, 16, 16);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("IMUL AX, Ew");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
GETSEW(x1, 0);
|
||||
SXTHw(x2, xRAX);
|
||||
MULw(x1, x2, x1);
|
||||
UFLAG_RES(x1);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
BFXILx(xRDX, x1, 16, 16);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("DIV Ew");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEW(x1, 0);
|
||||
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");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
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;
|
||||
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("INC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
GETEW(x1, 0);
|
||||
emit_inc16(dyn, ninst, x1, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("DEC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
GETEW(x1, 0);
|
||||
emit_dec16(dyn, ninst, x1, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
Executable
+2200
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,153 @@
|
||||
#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"
|
||||
|
||||
#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 seg, int* ok, int* 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;
|
||||
while(opcode>=0x40 && opcode<=0x4f) {
|
||||
rex.rex = opcode;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
/*if(rex.w && opcode!=0x0f) { // rex.w cancels "66", but not for 66 0f type of prefix
|
||||
MESSAGE(LOG_DUMP, "Here!\n");
|
||||
return dynarec64_64(dyn, addr-2, ip, ninst, rex, rep, ok, need_epilog);
|
||||
}*/
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 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;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
FMOVD(v1, v0);
|
||||
} else {
|
||||
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;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x89:
|
||||
INST_NAME("MOV FS:Ew, Gw");
|
||||
nextop = F8;
|
||||
GETGD; // don't need GETGW here
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
if(rex.w) {
|
||||
MOVx_REG(ed, gd);
|
||||
} else {
|
||||
if(ed!=gd) {
|
||||
BFIx(ed, gd, 0, 16);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
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;
|
||||
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, FS:Ed");
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
if(rex.w) {
|
||||
MOVx_REG(gd, ed);
|
||||
} else {
|
||||
if(ed!=gd) {
|
||||
BFIx(gd, ed, 0, 16);
|
||||
}
|
||||
}
|
||||
} else { // mem <= reg
|
||||
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 {
|
||||
LDRH_REG(x1, ed, x4);
|
||||
BFIx(gd, x1, 0, 16);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
Executable
+985
@@ -0,0 +1,985 @@
|
||||
#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"
|
||||
|
||||
#define GETGX(a, w) \
|
||||
gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg(dyn, ninst, x1, gd, w)
|
||||
|
||||
#define GETGM(a) \
|
||||
gd = ((nextop&0x38)>>3); \
|
||||
a = mmx_get_reg(dyn, ninst, x1, x2, x3, gd)
|
||||
|
||||
#define GETGm gd = ((nextop&0x38)>>3)
|
||||
|
||||
uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
uint8_t gd, ed, 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;
|
||||
while(opcode>=0x40 && opcode<=0x4f) {
|
||||
rex.rex = opcode;
|
||||
opcode = F8;
|
||||
}
|
||||
rep = 0;
|
||||
while((opcode==0xF2) || (opcode==0xF3)) {
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
switch(opcode) {
|
||||
case 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;
|
||||
switch(opcode) {
|
||||
|
||||
case 0x2E:
|
||||
// no special check...
|
||||
case 0x2F:
|
||||
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:
|
||||
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:
|
||||
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;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
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;
|
||||
GETGD;
|
||||
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, &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;
|
||||
|
||||
case 0x8D:
|
||||
INST_NAME("LEA Gd, Ed");
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg? that's an invalid operation
|
||||
DEFAULT;
|
||||
} else { // mem <= reg
|
||||
// should a geted32 be created, to use 32bits regs instead of 64bits?
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, gd, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=gd) {
|
||||
MOVw_REG(gd, ed);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC1:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ed, Ib");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETED32(1);
|
||||
u8 = (F8)&(rex.w?0x3f:0x1f);
|
||||
emit_rol32c(dyn, ninst, rex, ed, u8, x3, x4);
|
||||
if(u8) { WBACK; }
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ed, Ib");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETED32(1);
|
||||
u8 = (F8)&(rex.w?0x3f:0x1f);
|
||||
emit_ror32c(dyn, ninst, rex, ed, u8, x3, x4);
|
||||
if(u8) { WBACK; }
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Ed, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETED32W(x4, x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(rex.w?((void*)rcl64):((void*)rcl32), ed, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Ed, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETED32W(x4, x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(rex.w?((void*)rcr64):((void*)rcr32), ed, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
INST_NAME("SHL Ed, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
GETED32(1);
|
||||
u8 = (F8)&(rex.w?0x3f:0x1f);
|
||||
emit_shl32c(dyn, ninst, rex, ed, u8, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("SHR Ed, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
GETED32(1);
|
||||
u8 = (F8)&(rex.w?0x3f:0x1f);
|
||||
emit_shr32c(dyn, ninst, rex, ed, u8, x3, x4);
|
||||
if(u8) {
|
||||
WBACK;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("SAR Ed, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
GETED32(1);
|
||||
u8 = (F8)&(rex.w?0x3f:0x1f);
|
||||
emit_sar32c(dyn, ninst, rex, ed, u8, x3, x4);
|
||||
if(u8) {
|
||||
WBACK;
|
||||
}
|
||||
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); \
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1 || \
|
||||
CHECK_CACHE()) { \
|
||||
/* out of the block */ \
|
||||
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&BARRIER_FLOAT)) \
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst); \
|
||||
} else { \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size);\
|
||||
B(i32); \
|
||||
} \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
|
||||
Bcond(YES, i32); \
|
||||
}
|
||||
case 0xE0:
|
||||
INST_NAME("LOOPNZ (32bits)");
|
||||
READFLAGS(X_ZF);
|
||||
i8 = F8S;
|
||||
MOVw_REG(x1, xRCX);
|
||||
SUBSw_U12(x1, x1, 1);
|
||||
BFIx(xRCX, x1, 0, 32);
|
||||
B_NEXT(cEQ); // ECX is 0, no LOOP
|
||||
TSTw_mask(xFlags, 0b011010, 0); //mask=0x40
|
||||
GO(cNE, cEQ);
|
||||
break;
|
||||
case 0xE1:
|
||||
INST_NAME("LOOPZ (32bits)");
|
||||
READFLAGS(X_ZF);
|
||||
i8 = F8S;
|
||||
MOVw_REG(x1, xRCX);
|
||||
SUBSw_U12(x1, x1, 1);
|
||||
BFIx(xRCX, x1, 0, 32);
|
||||
B_NEXT(cEQ); // ECX is 0, no LOOP
|
||||
TSTw_mask(xFlags, 0b011010, 0); //mask=0x40
|
||||
GO(cEQ, cNE);
|
||||
break;
|
||||
case 0xE2:
|
||||
INST_NAME("LOOP (32bits)");
|
||||
i8 = F8S;
|
||||
MOVw_REG(x1, xRCX);
|
||||
SUBSw_U12(x1, x1, 1);
|
||||
BFIx(xRCX, x1, 0, 32);
|
||||
GO(cEQ, cNE);
|
||||
break;
|
||||
case 0xE3:
|
||||
INST_NAME("JECXZ");
|
||||
i8 = F8S;
|
||||
MOVw_REG(x1, xRCX);
|
||||
TSTw_REG(x1, x1);
|
||||
GO(cNE, cEQ);
|
||||
break;
|
||||
#undef GO
|
||||
|
||||
case 0xE8:
|
||||
return dynarec64_00(dyn, addr-1, ip, ninst, rex, rep, ok, need_epilog); // addr-1, to "put back" opcode)
|
||||
|
||||
case 0xF7:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
case 1:
|
||||
INST_NAME("TEST Ed, Id");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED32H(x1, 4);
|
||||
i64 = F32S;
|
||||
MOV64xw(x2, i64);
|
||||
emit_test32(dyn, ninst, rex, ed, x2, x3, x4);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("NOT Ed");
|
||||
GETED32(0);
|
||||
MVNxw_REG(ed, ed);
|
||||
WBACK;
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("NEG Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED32(0);
|
||||
emit_neg32(dyn, ninst, rex, ed, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("MUL EAX, Ed");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
UFLAG_DF(x2, rex.w?d_mul64:d_mul32);
|
||||
GETED32(0);
|
||||
if(rex.w) {
|
||||
if(ed==xRDX) gd=x3; else gd=xRDX;
|
||||
UMULH(gd, xRAX, ed);
|
||||
MULx(xRAX, xRAX, ed);
|
||||
if(gd!=xRDX) {MOVx_REG(xRDX, gd);}
|
||||
} else {
|
||||
UMULL(xRDX, xRAX, ed); //64 <- 32x32
|
||||
MOVw_REG(xRAX, xRDX);
|
||||
LSRx(xRDX, xRDX, 32);
|
||||
}
|
||||
UFLAG_RES(xRAX);
|
||||
UFLAG_OP1(xRDX);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("IMUL EAX, Ed");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
UFLAG_DF(x2, rex.w?d_imul64:d_imul32);
|
||||
GETED32(0);
|
||||
if(rex.w) {
|
||||
if(ed==xRDX) gd=x3; else gd=xRDX;
|
||||
SMULH(gd, xRAX, ed);
|
||||
MULx(xRAX, xRAX, ed);
|
||||
if(gd!=xRDX) {MOVx_REG(xRDX, gd);}
|
||||
} else {
|
||||
SMULL(xRDX, xRAX, ed); //64 <- 32x32
|
||||
MOVw_REG(xRAX, xRDX);
|
||||
LSRx(xRDX, xRDX, 32);
|
||||
}
|
||||
UFLAG_RES(xRAX);
|
||||
UFLAG_OP1(xRDX);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("DIV Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
if(!rex.w) {
|
||||
SET_DFNONE(x2);
|
||||
GETED32(0);
|
||||
MOVw_REG(x3, xRAX);
|
||||
ORRx_REG_LSL(x3, x3, xRDX, 32);
|
||||
if(MODREG) {
|
||||
MOVw_REG(x4, ed);
|
||||
ed = x4;
|
||||
}
|
||||
UDIVx(x2, x3, ed);
|
||||
MSUBx(x4, x2, ed, xRAX);
|
||||
MOVw_REG(xRAX, x2);
|
||||
MOVw_REG(xRDX, x4);
|
||||
} else {
|
||||
if(ninst && dyn->insts
|
||||
&& dyn->insts[ninst-1].x64.addr
|
||||
&& *(uint8_t*)(dyn->insts[ninst-1].x64.addr)==0x31
|
||||
&& *(uint8_t*)(dyn->insts[ninst-1].x64.addr+1)==0xD2) {
|
||||
SET_DFNONE(x2);
|
||||
GETED32(0);
|
||||
UDIVx(x2, xRAX, ed);
|
||||
MSUBx(xRDX, x2, ed, xRAX);
|
||||
MOVx_REG(xRAX, x2);
|
||||
} else {
|
||||
GETED32H(x1, 0); // get edd changed addr, so cannot be called 2 times for same op...
|
||||
CBZxw_MARK(xRDX);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(div64, -1);
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
UDIVx(x2, xRAX, ed);
|
||||
MSUBx(xRDX, x2, ed, xRAX);
|
||||
MOVx_REG(xRAX, x2);
|
||||
SET_DFNONE(x2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("IDIV Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
if(!rex.w) {
|
||||
SET_DFNONE(x2)
|
||||
GETSED32w(0);
|
||||
MOVw_REG(x3, xRAX);
|
||||
ORRx_REG_LSL(x3, x3, xRDX, 32);
|
||||
SDIVx(x2, x3, wb);
|
||||
MSUBx(x4, x2, wb, x3);
|
||||
MOVw_REG(xRAX, x2);
|
||||
MOVw_REG(xRDX, x4);
|
||||
} else {
|
||||
if(ninst && dyn->insts
|
||||
&& dyn->insts[ninst-1].x64.addr
|
||||
&& *(uint8_t*)(dyn->insts[ninst-1].x64.addr)==0x48
|
||||
&& *(uint8_t*)(dyn->insts[ninst-1].x64.addr+1)==0x99) {
|
||||
SET_DFNONE(x2)
|
||||
GETED32(0);
|
||||
SDIVx(x2, xRAX, ed);
|
||||
MSUBx(xRDX, x2, ed, xRAX);
|
||||
MOVx_REG(xRAX, x2);
|
||||
} else {
|
||||
GETED32H(x1, 0); // get edd changed addr, so cannot be called 2 times for same op...
|
||||
CBZxw_MARK(xRDX);
|
||||
MVNx_REG(x2, xRDX);
|
||||
CBZxw_MARK(x2);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL((void*)idiv64, -1);
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
SDIVx(x2, xRAX, ed);
|
||||
MSUBx(xRDX, x2, ed, xRAX);
|
||||
MOVx_REG(xRAX, x2);
|
||||
SET_DFNONE(x2)
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
#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_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)rep; (void)need_epilog;
|
||||
|
||||
uint8_t nextop = F8;
|
||||
uint8_t ed;
|
||||
int64_t fixedaddress;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FADD ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, 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)) {
|
||||
FADDS(v1, v1, v2);
|
||||
} else {
|
||||
FADDD(v1, v1, v2);
|
||||
}
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
INST_NAME("FMUL ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, 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)) {
|
||||
FMULS(v1, v1, v2);
|
||||
} else {
|
||||
FMULD(v1, v1, v2);
|
||||
}
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
INST_NAME("FCOM ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, 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);
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
INST_NAME("FCOMP ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, 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 0xE0:
|
||||
case 0xE1:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
INST_NAME("FSUB ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, 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)) {
|
||||
FSUBS(v1, v1, v2);
|
||||
} else {
|
||||
FSUBD(v1, v1, v2);
|
||||
}
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FSUBR ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, 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)) {
|
||||
FSUBS(v1, v2, v1);
|
||||
} else {
|
||||
FSUBD(v1, v2, v1);
|
||||
}
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
INST_NAME("FDIV ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, 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)) {
|
||||
FDIVS(v1, v1, v2);
|
||||
} else {
|
||||
FDIVD(v1, v1, v2);
|
||||
}
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFA:
|
||||
case 0xFB:
|
||||
case 0xFC:
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
INST_NAME("FDIVR ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, 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)) {
|
||||
FDIVS(v1, v2, v1);
|
||||
} else {
|
||||
FDIVD(v1, v2, v1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FADD ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
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);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FADDD(v1, v1, s0);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FMUL ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
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);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FMULD(v1, v1, s0);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FCOM ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
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);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FCMPD(v1, s0);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FCOMP ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
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);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FCMPD(v1, s0);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
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, NULL, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FSUBD(v1, v1, s0);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FSUBR ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
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);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FSUBD(v1, s0, v1);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FDIV ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
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);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FDIVD(v1, v1, s0);
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FDIVR ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
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);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FDIVD(v1, s0, v1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,399 @@
|
||||
#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_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)rep; (void)need_epilog;
|
||||
|
||||
uint8_t nextop = F8;
|
||||
uint8_t ed;
|
||||
uint8_t wback, wb1;
|
||||
uint8_t u8;
|
||||
int64_t fixedaddress;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
int i1, i2, i3;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FLD STx");
|
||||
v2 = x87_do_push(dyn, ninst, x1, X87_ST(nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, (nextop&7)+1, X87_COMBINE(0, (nextop&7)+1));
|
||||
if(ST_IS_F(0)) {
|
||||
FMOVS(v2, v1);
|
||||
} else {
|
||||
FMOVD(v2, v1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
INST_NAME("FXCH ST0");
|
||||
break;
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
INST_NAME("FXCH STx");
|
||||
// swap the cache value, not the double value itself :p
|
||||
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;
|
||||
|
||||
case 0xD0:
|
||||
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);
|
||||
if(ST_IS_F(0)) {
|
||||
FNEGS(v1, v1);
|
||||
} else {
|
||||
FNEGD(v1, v1);
|
||||
}
|
||||
break;
|
||||
case 0xE1:
|
||||
INST_NAME("FABS");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
if(ST_IS_F(0)) {
|
||||
FABSS(v1, v1);
|
||||
} else {
|
||||
FABSD(v1, v1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xE4:
|
||||
INST_NAME("FTST");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
if(ST_IS_F(0)) {
|
||||
FCMPS_0(v1);
|
||||
} else {
|
||||
FCMPD_0(v1);
|
||||
}
|
||||
FCOM(x1, x2, x3); // same flags...
|
||||
break;
|
||||
case 0xE5:
|
||||
INST_NAME("FXAM");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_refresh(dyn, ninst, x1, x2, 0);
|
||||
CALL(fpu_fxam, -1); // should be possible inline, but is it worth it?
|
||||
break;
|
||||
|
||||
case 0xE8:
|
||||
INST_NAME("FLD1");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
FMOVS_8(v1, 0b01110000);
|
||||
} else {
|
||||
FMOVD_8(v1, 0b01110000);
|
||||
}
|
||||
break;
|
||||
case 0xE9:
|
||||
INST_NAME("FLDL2T");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
FTABLE64(v1, L2T);
|
||||
break;
|
||||
case 0xEA:
|
||||
INST_NAME("FLDL2E");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
FTABLE64(v1, L2E);
|
||||
break;
|
||||
case 0xEB:
|
||||
INST_NAME("FLDPI");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
FTABLE64(v1, PI);
|
||||
break;
|
||||
case 0xEC:
|
||||
INST_NAME("FLDLG2");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
FTABLE64(v1, LG2);
|
||||
break;
|
||||
case 0xED:
|
||||
INST_NAME("FLDLN2");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
FTABLE64(v1, LN2);
|
||||
break;
|
||||
case 0xEE:
|
||||
INST_NAME("FLDZ");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
VEOR(v1, v1, v1);
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
INST_NAME("F2XM1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_f2xm1, -1);
|
||||
break;
|
||||
case 0xF1:
|
||||
INST_NAME("FYL2X");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fyl2x, -1);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF2:
|
||||
INST_NAME("FPTAN");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_ftan, -1);
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
FMOVS_8(v1, 0b01110000);
|
||||
} else {
|
||||
FMOVD_8(v1, 0b01110000);
|
||||
}
|
||||
break;
|
||||
case 0xF3:
|
||||
INST_NAME("FPATAN");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fpatan, -1);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF4:
|
||||
INST_NAME("FXTRACT");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_do_push_empty(dyn, ninst, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fxtract, -1);
|
||||
break;
|
||||
case 0xF5:
|
||||
INST_NAME("FPREM1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fprem1, -1);
|
||||
break;
|
||||
case 0xF6:
|
||||
INST_NAME("FDECSTP");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
LDRw_U12(x2, xEmu, offsetof(x64emu_t, top));
|
||||
SUBw_U12(x2, x2, 1);
|
||||
ANDw_mask(x2, x2, 0, 2); //mask=7
|
||||
STRw_U12(x2, xEmu, offsetof(x64emu_t, top));
|
||||
break;
|
||||
case 0xF7:
|
||||
INST_NAME("FINCSTP");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
LDRw_U12(x2, xEmu, offsetof(x64emu_t, top));
|
||||
ADDw_U12(x2, x2, 1);
|
||||
ANDw_mask(x2, x2, 0, 2); //mask=7
|
||||
STRw_U12(x2, xEmu, offsetof(x64emu_t, top));
|
||||
break;
|
||||
case 0xF8:
|
||||
INST_NAME("FPREM");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fprem, -1);
|
||||
break;
|
||||
case 0xF9:
|
||||
INST_NAME("FYL2XP1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fyl2xp1, -1);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xFA:
|
||||
INST_NAME("FSQRT");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
if(ST_IS_F(0)) {
|
||||
FSQRTS(v1, v1);
|
||||
} else {
|
||||
FSQRTD(v1, v1);
|
||||
}
|
||||
break;
|
||||
case 0xFB:
|
||||
INST_NAME("FSINCOS");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_do_push_empty(dyn, ninst, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fsincos, -1);
|
||||
break;
|
||||
case 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);
|
||||
#else
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x3);
|
||||
if(ST_IS_F(0)) {
|
||||
FRINTIS(v1, v1);
|
||||
} else {
|
||||
FRINTID(v1, v1);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
#endif
|
||||
break;
|
||||
case 0xFD:
|
||||
INST_NAME("FSCALE");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fscale, -1);
|
||||
break;
|
||||
case 0xFE:
|
||||
INST_NAME("FSIN");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_fsin, -1);
|
||||
break;
|
||||
case 0xFF:
|
||||
INST_NAME("FCOS");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_fcos, -1);
|
||||
break;
|
||||
|
||||
|
||||
case 0xD1:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
case 0xEF:
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FLD ST0, float[ED]");
|
||||
v1 = x87_do_push(dyn, ninst, x1, box64_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
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, v1);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FST 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);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
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, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
MOV32w(x2, 0);
|
||||
CALL(fpu_loadenv, -1);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FLDCW Ew");
|
||||
GETEW(x1, 0);
|
||||
STRH_U12(x1, xEmu, offsetof(x64emu_t, cw)); // hopefully cw is not too far for an imm8
|
||||
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, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
MOV32w(x2, 0);
|
||||
CALL(fpu_savenv, -1);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FNSTCW Ew");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
ed = x1;
|
||||
wb1 = 1;
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, cw));
|
||||
EWBACK;
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,383 @@
|
||||
#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_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)rep; (void)need_epilog;
|
||||
|
||||
uint8_t nextop = F8;
|
||||
uint8_t ed;
|
||||
uint8_t wback;
|
||||
uint8_t u8;
|
||||
int64_t fixedaddress;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
int64_t j64;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(j64);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FCMOVNB ST0, STx");
|
||||
READFLAGS(X_CF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
TSTw_mask(xFlags, 0, 0); //mask=1<<F_CF
|
||||
if(ST_IS_F(0)) {
|
||||
FCSELS(v1, v2, v1, cEQ);
|
||||
} else {
|
||||
FCSELD(v1, v2, v1, cEQ); // F_CF==0
|
||||
}
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
INST_NAME("FCMOVNE ST0, STx");
|
||||
READFLAGS(X_ZF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
TSTw_mask(xFlags, 0b011010, 0); //mask=1<<F_ZF
|
||||
if(ST_IS_F(0)) {
|
||||
FCSELS(v1, v2, v1, cEQ);
|
||||
} else {
|
||||
FCSELD(v1, v2, v1, cEQ); // F_ZF==0
|
||||
}
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
INST_NAME("FCMOVNBE ST0, STx");
|
||||
READFLAGS(X_CF|X_ZF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
MOV32w(x1, (1<<F_CF)|(1<<F_ZF));
|
||||
TSTw_REG(xFlags, x1);
|
||||
if(ST_IS_F(0)) {
|
||||
FCSELS(v1, v2, v1, cEQ);
|
||||
} else {
|
||||
FCSELD(v1, v2, v1, cEQ); // F_CF==0 & F_ZF==0
|
||||
}
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
INST_NAME("FCMOVNU ST0, STx");
|
||||
READFLAGS(X_PF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
TSTw_mask(xFlags, 0b011110, 0); //mask=1<<F_PF
|
||||
if(ST_IS_F(0)) {
|
||||
FCSELS(v1, v2, v1, cEQ);
|
||||
} else {
|
||||
FCSELD(v1, v2, v1, cEQ); // F_PF==0
|
||||
}
|
||||
break;
|
||||
case 0xE1:
|
||||
INST_NAME("FDISI8087_NOP"); // so.. NOP?
|
||||
break;
|
||||
case 0xE2:
|
||||
INST_NAME("FNCLEX");
|
||||
LDRH_U12(x2, xEmu, offsetof(x64emu_t, sw));
|
||||
MOV32w(x1, 0);
|
||||
BFIw(x2, x1, 0, 8); // IE .. PE, SF, ES
|
||||
BFIw(x2, x1, 15, 1); // B
|
||||
STRH_U12(x2, xEmu, offsetof(x64emu_t, sw));
|
||||
break;
|
||||
case 0xE3:
|
||||
INST_NAME("FNINIT");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
CALL(reset_fpu, -1);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FUCOMI ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, 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);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
INST_NAME("FCOMI ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, 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);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
|
||||
case 0xE0:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ed");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
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);
|
||||
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;
|
||||
#else
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
FRINTZD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
VSTR32_U12(s0, wback, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
MOV32w(x5, 0x80000000);
|
||||
STRw_U12(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 2:
|
||||
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
|
||||
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;
|
||||
#else
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
FRINTXD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
VSTR32_U12(s0, wback, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
MOV32w(x5, 0x80000000);
|
||||
STRw_U12(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FISTP Ed, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4); // x1 have the modified RPSCR reg
|
||||
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;
|
||||
#else
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
FRINTXD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
VSTR32_U12(s0, wback, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
MOV32w(x5, 0x80000000);
|
||||
STRw_U12(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FLD tbyte");
|
||||
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 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, NULL, 0, 0);
|
||||
STRx_U12(x5, ed, 0);
|
||||
STRH_U12(x6, ed, 8);
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FSTP tbyte");
|
||||
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
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
#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_DC(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("FADD 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);
|
||||
}
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
INST_NAME("FMUL 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);
|
||||
}
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
INST_NAME("FCOM 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);
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
INST_NAME("FCOMP ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, 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 0xE0:
|
||||
case 0xE1:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
INST_NAME("FSUBR 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);
|
||||
}
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FSUB 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);
|
||||
}
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
INST_NAME("FDIVR 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);
|
||||
}
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFA:
|
||||
case 0xFB:
|
||||
case 0xFC:
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
INST_NAME("FDIV 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);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
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, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v2, wback, fixedaddress);
|
||||
FADDD(v1, v1, v2);
|
||||
break;
|
||||
case 1:
|
||||
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, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v2, wback, fixedaddress);
|
||||
FMULD(v1, v1, v2);
|
||||
break;
|
||||
case 2:
|
||||
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, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v2, wback, fixedaddress);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 3:
|
||||
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, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v2, wback, fixedaddress);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
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, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v2, wback, fixedaddress);
|
||||
FSUBD(v1, v1, v2);
|
||||
break;
|
||||
case 5:
|
||||
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, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v2, wback, fixedaddress);
|
||||
FSUBD(v1, v2, v1);
|
||||
break;
|
||||
case 6:
|
||||
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, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v2, wback, fixedaddress);
|
||||
FDIVD(v1, v1, v2);
|
||||
break;
|
||||
case 7:
|
||||
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, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v2, wback, fixedaddress);
|
||||
FDIVD(v1, v2, v1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
#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_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)rep; (void)need_epilog;
|
||||
|
||||
uint8_t nextop = F8;
|
||||
uint8_t ed;
|
||||
int64_t fixedaddress;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
int64_t j64;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(j64);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FFREE STx");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
MOV32w(x1, nextop&7);
|
||||
CALL(fpu_do_free, -1);
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
INST_NAME("FST ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, 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)) {
|
||||
FMOVS(v2, v1);
|
||||
} else {
|
||||
FMOVD(v2, v1);
|
||||
}
|
||||
break;
|
||||
case 0xD8:
|
||||
INST_NAME("FSTP 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("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;
|
||||
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
INST_NAME("FUCOM ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, 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);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FUCOMP ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, 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 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFA:
|
||||
case 0xFB:
|
||||
case 0xFC:
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FLD double");
|
||||
v1 = x87_do_push(dyn, ninst, x3, NEON_CACHE_ST_D);
|
||||
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_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, 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, NULL, 0, 0);
|
||||
VSTR64_U12(v1, ed, fixedaddress);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
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, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(arm_frstor, -1);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FSAVE m108byte");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
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, NULL, 0, 0);
|
||||
LDRw_U12(x2, xEmu, offsetof(x64emu_t, top));
|
||||
LDRH_U12(x3, xEmu, offsetof(x64emu_t, sw));
|
||||
if(dyn->n.x87stack) {
|
||||
// update top
|
||||
if(dyn->n.x87stack>0) {
|
||||
SUBw_U12(x2, x2, dyn->n.x87stack);
|
||||
} else {
|
||||
ADDw_U12(x2, x2, -dyn->n.x87stack);
|
||||
}
|
||||
ANDw_mask(x2, x2, 0, 2);
|
||||
}
|
||||
BFIw(x3, x2, 11, 3); // inject TOP at bit 11 (3 bits)
|
||||
STRH_U12(x3, ed, fixedaddress); // store whole sw flags
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,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;
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "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_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)rep; (void)need_epilog;
|
||||
|
||||
uint8_t nextop = F8;
|
||||
uint8_t ed, wback, u8;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(j64);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FFREEP STx");
|
||||
// not handling Tag...
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xE0:
|
||||
INST_NAME("FNSTSW AX");
|
||||
LDRw_U12(x2, xEmu, offsetof(x64emu_t, top));
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
BFIw(x1, x2, 11, 3); // inject top
|
||||
BFIw(xRAX, x1, 0, 16);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FUCOMIP ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, 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);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
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("FCOMIP ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
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);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
case 0xE1:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFA:
|
||||
case 0xFB:
|
||||
case 0xFC:
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ew");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
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);
|
||||
} else {
|
||||
SCVTFDw(v1, x1);
|
||||
}
|
||||
break;
|
||||
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, NULL, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
// this version needs ARM v8.5, //TODO: add detection of this extension to use it
|
||||
FRINT32ZD(s0, v1);
|
||||
// no saturation instruction on Arm, so using NEON
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
SQXTN_H_S(s0, s0);
|
||||
VSTR16_U12(s0, wback, fixedaddress);
|
||||
#else
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
if(ST_IS_F(0)) {
|
||||
VFCVTZSs(s0, v1);
|
||||
} else {
|
||||
VFCVTZSd(s0, v1);
|
||||
SQXTN_S_D(s0, s0);
|
||||
}
|
||||
SQXTN_H_S(s0, s0);
|
||||
VSTR16_U12(s0, wback, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
MOV32w(x5, 0x8000);
|
||||
STRH_U12(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 2:
|
||||
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, NULL, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
FRINT32XD(s0, v1);
|
||||
// no saturation instruction on Arm, so using NEON
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
SQXTN_H_S(s0, s0);
|
||||
VSTR16_U12(s0, wback, fixedaddress);
|
||||
#else
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
if(ST_IS_F(0)) {
|
||||
FRINTXS(s0, v1);
|
||||
VFCVTZSs(s0, s0);
|
||||
} else {
|
||||
FRINTXD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
}
|
||||
SQXTN_H_S(s0, s0);
|
||||
VSTR16_U12(s0, wback, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
MOV32w(x5, 0x8000);
|
||||
STRH_U12(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FISTP Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, 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, NULL, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
FRINT32XD(s0, v1);
|
||||
// no saturation instruction on Arm, so using NEON
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
SQXTN_H_S(s0, s0);
|
||||
VSTR16_U12(s0, wback, fixedaddress);
|
||||
#else
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
if(ST_IS_F(0)) {
|
||||
FRINTXS(s0, v1);
|
||||
VFCVTZSs(s0, s0);
|
||||
} else {
|
||||
FRINTXD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
}
|
||||
SQXTN_H_S(s0, s0);
|
||||
VSTR16_U12(s0, wback, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
MOV32w(x5, 0x8000);
|
||||
STRH_U12(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FBLD ST0, tbytes");
|
||||
x87_do_push_empty(dyn, ninst, x1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 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, 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, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(fpu_fbst, -1);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 7:
|
||||
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, NULL, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
FRINT64XD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
VSTR64_U12(s0, wback, fixedaddress);
|
||||
#else
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
FRINTXD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
VSTR64_U12(s0, wback, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
ORRx_mask(x5, xZR, 1, 1, 0); //0x8000000000000000
|
||||
STRx_U12(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
Executable
+643
@@ -0,0 +1,643 @@
|
||||
#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 "../tools/bridge_private.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
// emit OR32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_or32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, rex.w?d_or64:d_or32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
ORRxw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit OR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_or32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, rex.w?d_or64:d_or32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
MOV64xw(s3, c);
|
||||
ORRxw_REG(s1, s1, s3);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit XOR32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_xor32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, rex.w?d_xor64:d_xor32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
EORxw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit XOR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_xor32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, rex.w?d_xor64:d_xor32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
MOV64xw(s3, c);
|
||||
EORxw_REG(s1, s1, s3);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit AND32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_and32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, rex.w?d_and64:d_and32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSxw_REG(s1, s1, s2);
|
||||
} else {
|
||||
ANDxw_REG(s1, s1, s2);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit AND32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_and32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, rex.w?d_and64:d_and32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
MOV64xw(s3, c);
|
||||
IFX(X_ALL) {
|
||||
ANDSxw_REG(s1, s1, s3);
|
||||
} else {
|
||||
ANDxw_REG(s1, s1, s3);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit OR8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, d_or8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
ORRw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit OR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_or8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
MOV32w(s3, c&0xff);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_or8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
ORRw_REG(s1, s1, s3);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit XOR8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, d_xor8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
EORx_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit XOR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_xor8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
MOV32w(s3, c&0xff);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_xor8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
EORw_REG(s1, s1, s3);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit AND8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, d_and8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_REG(s1, s1, s2);
|
||||
} else {
|
||||
ANDw_REG(s1, s1, s2);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw_REG(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit AND8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_and8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
MOV32w(s3, c&0xff);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_and8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_REG(s1, s1, s3);
|
||||
} else {
|
||||
ANDw_REG(s1, s1, s3);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// emit OR16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, d_or16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
ORRw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 15); //mask=0xffff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 15);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit OR16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
//void emit_or16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
//{
|
||||
// IFX(X_PEND) {
|
||||
// MOVW(s3, c);
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
// STR_IMM9(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
// SET_DF(s4, d_or16);
|
||||
// } else IFX(X_ALL) {
|
||||
// SET_DFNONE(s4);
|
||||
// }
|
||||
// if(c>=0 && c<256) {
|
||||
// IFX(X_ALL) {
|
||||
// ORRS_IMM8(s1, s1, c, 0);
|
||||
// } else {
|
||||
// ORR_IMM8(s1, s1, c, 0);
|
||||
// }
|
||||
// } else {
|
||||
// IFX(X_PEND) {} else {MOVW(s3, c);}
|
||||
// IFX(X_ALL) {
|
||||
// ORRS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
// } else {
|
||||
// ORR_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
// }
|
||||
// }
|
||||
// IFX(X_PEND) {
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, res));
|
||||
// }
|
||||
// IFX(X_CF | X_AF | X_ZF) {
|
||||
// BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
// }
|
||||
// IFX(X_OF) {
|
||||
// BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
// }
|
||||
// IFX(X_ZF) {
|
||||
// ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
// }
|
||||
// IFX(X_SF) {
|
||||
// MOV_REG_LSR_IMM5(s3, s1, 15);
|
||||
// BFI(xFlags, s3, F_SF, 1);
|
||||
// }
|
||||
// IFX(X_PF) {
|
||||
// emit_pf(dyn, ninst, s1, s3, s4);
|
||||
// }
|
||||
//}
|
||||
|
||||
// emit XOR16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, d_xor16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
EORw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 15); //mask=0xffff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 15);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit XOR16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
//void emit_xor16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
//{
|
||||
// IFX(X_PEND) {
|
||||
// MOVW(s3, c);
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
// STR_IMM9(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
// SET_DF(s4, d_xor16);
|
||||
// } else IFX(X_ALL) {
|
||||
// SET_DFNONE(s4);
|
||||
// }
|
||||
// if(c>=0 && c<256) {
|
||||
// IFX(X_ALL) {
|
||||
// XORS_IMM8(s1, s1, c);
|
||||
// } else {
|
||||
// XOR_IMM8(s1, s1, c);
|
||||
// }
|
||||
// } else {
|
||||
// IFX(X_PEND) {} else {MOVW(s3, c);}
|
||||
// IFX(X_ALL) {
|
||||
// XORS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
// } else {
|
||||
// XOR_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
// }
|
||||
// }
|
||||
// IFX(X_PEND) {
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, res));
|
||||
// }
|
||||
// IFX(X_CF | X_AF | X_ZF) {
|
||||
// BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
// }
|
||||
// IFX(X_OF) {
|
||||
// BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
// }
|
||||
// IFX(X_ZF) {
|
||||
// ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
// }
|
||||
// IFX(X_SF) {
|
||||
// MOV_REG_LSR_IMM5(s3, s1, 15);
|
||||
// BFI(xFlags, s3, F_SF, 1);
|
||||
// }
|
||||
// IFX(X_PF) {
|
||||
// emit_pf(dyn, ninst, s1, s3, s4);
|
||||
// }
|
||||
//}
|
||||
|
||||
// emit AND16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, d_and16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
IFX(X_ALL) {
|
||||
ANDSw_REG(s1, s1, s2);
|
||||
} else {
|
||||
ANDw_REG(s1, s1, s2);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw_REG(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 15);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit AND16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
//void emit_and16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
//{
|
||||
// IFX(X_PEND) {
|
||||
// MOVW(s3, c);
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
// STR_IMM9(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
// SET_DF(s4, d_and16);
|
||||
// } else IFX(X_ALL) {
|
||||
// SET_DFNONE(s4);
|
||||
// }
|
||||
// if(c>=0 && c<256) {
|
||||
// IFX(X_ALL) {
|
||||
// ANDS_IMM8(s1, s1, c);
|
||||
// } else {
|
||||
// AND_IMM8(s1, s1, c);
|
||||
// }
|
||||
// } else {
|
||||
// IFX(X_PEND) {} else {MOVW(s3, c);}
|
||||
// IFX(X_ALL) {
|
||||
// ANDS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
// } else {
|
||||
// AND_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
// }
|
||||
// }
|
||||
// IFX(X_PEND) {
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, res));
|
||||
// }
|
||||
// IFX(X_CF | X_AF | X_ZF) {
|
||||
// BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
// }
|
||||
// IFX(X_OF) {
|
||||
// BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
// }
|
||||
// IFX(X_ZF) {
|
||||
// ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
// }
|
||||
// IFX(X_SF) {
|
||||
// MOV_REG_LSR_IMM5(s3, s1, 15);
|
||||
// BFI(xFlags, s3, F_SF, 1);
|
||||
// }
|
||||
// IFX(X_PF) {
|
||||
// emit_pf(dyn, ninst, s1, s3, s4);
|
||||
// }
|
||||
//}
|
||||
Executable
+1768
File diff suppressed because it is too large.
Load diff
Executable
+436
@@ -0,0 +1,436 @@
|
||||
#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 "../tools/bridge_private.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
// emit SHL32 instruction, from s1 , shift s2, store result in s1 using s3 and s4 as scratch. s3 can be same as s2
|
||||
void emit_shl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
int64_t j64;
|
||||
MAYUSE(j64);
|
||||
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_shl64:d_shl32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPSxw_U12(s2, 0);
|
||||
Bcond(cNE, +8+((dyn->insts[ninst].x64.gen_flags&X_PEND)?4:0));
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
}
|
||||
IFX(X_CF | X_OF) {
|
||||
MOV32w(s4, rex.w?64:32);
|
||||
SUBxw_REG(s4, s4, s2);
|
||||
LSRxw_REG(s4, s1, s4);
|
||||
BFIw(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
LSLxw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPSxw_U12(s2, 1); // if s2==1
|
||||
IFX(X_SF) {} else {LSRxw(s4, s1, (rex.w)?63:31);}
|
||||
EORxw_REG(s4, s4, xFlags); // CF is set if OF is asked
|
||||
CSELw(s4, s4, wZR, cEQ);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHL32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shl32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_shl64:d_shl32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(c==0) {
|
||||
IFX(X_OF) {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_CF|X_OF) {
|
||||
LSRxw(s3, s1, (rex.w?64:32)-c);
|
||||
BFIxw(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
LSLxw(s1, s1, c);
|
||||
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
IFX(X_SF) {} else {LSRxw(s4, s1, (rex.w)?63:31);}
|
||||
EORxw_REG(s4, s4, xFlags); // CF is set if OF is asked
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
} else {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHR32 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s2 can be same as s3
|
||||
void emit_shr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
int64_t j64;
|
||||
MAYUSE(j64);
|
||||
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_shr64:d_shr32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_ALL) {
|
||||
CMPSxw_U12(s2, 0); //if(!c)
|
||||
IFX(X_PEND) {
|
||||
Bcond(cNE, +12);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
SUBxw_U12(s3, s2, 1);
|
||||
LSRxw_REG(s3, s1, s3);
|
||||
BFIw(xFlags, s3, 0, 1);
|
||||
}
|
||||
LSRxw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPSxw_U12(s2, 1); // if s2==1
|
||||
Bcond(cNE, 4+3*4);
|
||||
LSRxw(s4, s1, rex.w?62:30);
|
||||
EORw_REG_LSR(s4, s4, s4, 1);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit 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, uint32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_shr64:d_shr32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
LSRxw(s3, s1, c-1);
|
||||
BFIw(xFlags, s3, 0, 1);
|
||||
}
|
||||
LSRxw(s1, s1, c);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
LSRxw(s4, s1, rex.w?62:30);
|
||||
EORw_REG_LSR(s4, s4, s4, 1);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SAR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_sar32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_sar64:d_sar32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
ASRxw(s3, s1, c-1);
|
||||
BFIw(xFlags, s3, 0, 1);
|
||||
}
|
||||
ASRxw(s1, s1, c);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTw_REG(s1, s1);
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit ROL32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rol32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, 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, rex.w?d_rol64:d_rol32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
RORxw(s1, s1, (rex.w?64:32)-c);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, s1, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
ADDxw_REG_LSR(s3, s1, s1, rex.w?63:31);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit ROR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_ror32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_ror64:d_ror32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
RORxw(s1, s1, c);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
LSRxw(s3, s1, rex.w?63:31);
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
LSRxw(s3, s1, rex.w?62:30);
|
||||
EORxw_REG_LSR(s3, s3, s3, 1);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHRD32 instruction, from s1, fill s2 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shrd32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4)
|
||||
{
|
||||
c&=(rex.w?0x3f:0x1f);
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
// same flags computation as with shl64/shl32
|
||||
SET_DF(s4, rex.w?d_shl64:d_shl32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
LSRxw(s3, s1, c-1);
|
||||
BFIw(xFlags, s3, 0, 1);
|
||||
}
|
||||
LSRxw(s3, s1, c);
|
||||
ORRxw_REG_LSL(s1, s3, s2, (rex.w?64:32)-c);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
LSRxw(s4, s1, rex.w?62:30);
|
||||
EORw_REG_LSR(s4, s4, s4, 1);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
void emit_shld32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4)
|
||||
{
|
||||
c&=(rex.w?0x3f:0x1f);
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
// same flags computation as with shl64/shl32
|
||||
SET_DF(s4, rex.w?d_shl64:d_shl32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(c==0) {
|
||||
IFX(X_OF) {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_CF|X_OF) {
|
||||
LSRxw(s3, s1, (rex.w?64:32)-c);
|
||||
BFIxw(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
LSLxw(s3, s1, c);
|
||||
ORRxw_REG_LSR(s1, s3, s2, (rex.w?64:32)-c);
|
||||
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
UBFXxw(s3, s1, rex.w?63:31, 1);
|
||||
EORxw_REG(s3, s3, xFlags); // CF is set if OF is asked
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
} else {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
Executable
+368
@@ -0,0 +1,368 @@
|
||||
#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 "../tools/bridge_private.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
// emit CMP32 instruction, from cmp s1, s2, using s3 and s4 as scratch
|
||||
void emit_cmp32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s2);
|
||||
IFX_PENDOR0 {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_cmp64:d_cmp32);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_AF) {
|
||||
ORNxw_REG(s3, s2, s1); // s3 = ~op1 | op2
|
||||
BICxw(s4, s2, s1); // s4 = ~op1 & op2
|
||||
}
|
||||
SUBSxw_REG(s5, s1, s2); // res = s1 - s2
|
||||
IFX_PENDOR0 {
|
||||
STRxw_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_AF) {
|
||||
ANDxw_REG(s3, s3, s5); // s3 = (~op1 | op2) & res
|
||||
ORRxw_REG(s3, s3, s4); // s3 = (~op1 & op2) | ((~op1 | op2) & res)
|
||||
LSRxw(s4, s3, 3);
|
||||
BFIx(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
// inverted carry
|
||||
CSETw(s4, cCC);
|
||||
BFIw(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CSETw(s4, cVS);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s5, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP32 instruction, from cmp s1 , 0, using s3 and s4 as scratch
|
||||
void emit_cmp32_0(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
MOV64xw(s4, 0);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s4, xEmu, offsetof(x64emu_t, op2));
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
SET_DF(s4, rex.w?d_cmp64:d_cmp32);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
SUBSxw_U12(s3, s1, 0); // res = s1 - 0
|
||||
// and now the tricky ones (and mostly unused), PF and AF
|
||||
// bc = (res & (~d | s)) | (~d & s) => is 0 here...
|
||||
IFX(X_OF|X_AF|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_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP16 instruction, from cmp s1, s2, using s3 and s4 as scratch
|
||||
void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s2);
|
||||
IFX_PENDOR0 {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_cmp16);
|
||||
} else {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
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) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s4, s5, 15);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s)
|
||||
IFX(X_CF|X_AF|X_OF) {
|
||||
MVNw_REG(s4, s1); // s4 = ~d
|
||||
ORRw_REG(s4, s4, s2); // s4 = ~d | s
|
||||
ANDw_REG(s4, s4, s5); // s4 = res & (~d | s)
|
||||
BICw_REG(s3, s2, s1); // s3 = s & ~d
|
||||
ORRw_REG(s3, s4, s3); // s3 = (res & (~d | s)) | (s & ~d)
|
||||
IFX(X_CF) {
|
||||
LSRw(s4, s3, 15);
|
||||
BFIw(xFlags, s4, F_CF, 1); // CF : bc & 0x8000
|
||||
}
|
||||
IFX(X_AF) {
|
||||
LSRw(s4, s3, 3);
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_OF) {
|
||||
LSRw(s4, s3, 14);
|
||||
EORw_REG_LSR(s4, s4, s4, 1);
|
||||
BFIw(xFlags, s4, F_OF, 1); // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP16 instruction, from cmp s1 , #0, using s3 and s4 as scratch
|
||||
void emit_cmp16_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
MOV32w(s3, 0);
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
SET_DF(s3, d_cmp16);
|
||||
} else {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s) = 0
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 15); //mask=0xffff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s4, s1, 15);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
// emit CMP8 instruction, from cmp s1, s2, using s3 and s4 as scratch
|
||||
void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s2);
|
||||
IFX_PENDOR0 {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_cmp8);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
SUBSw_REG(s5, s1, s2); // res = s1 - s2
|
||||
} else {
|
||||
SUBw_REG(s5, s1, s2); // res = s1 - s2
|
||||
}
|
||||
IFX_PENDOR0 {
|
||||
STRB_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s5, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s)
|
||||
IFX(X_CF|X_AF|X_OF) {
|
||||
ORNw_REG(s4, s2, s1); // s4 = ~d | s
|
||||
ANDw_REG(s4, s4, s5); // s4 = res & (~d | s)
|
||||
BICw_REG(s3, s2, s1); // s3 = s & ~d
|
||||
ORRw_REG(s3, s4, s3); // s3 = (res & (~d | s)) | (s & ~d)
|
||||
IFX(X_CF) {
|
||||
LSRw(s4, s3, 7);
|
||||
BFIw(xFlags, s4, F_CF, 1); // CF : bc & 0x80
|
||||
}
|
||||
IFX(X_AF) {
|
||||
LSRw(s4, s3, 3);
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_OF) {
|
||||
LSRw(s4, s3, 6);
|
||||
EORw_REG_LSR(s4, s4, s4, 1);
|
||||
BFIw(xFlags, s4, F_OF, 1); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s3, s4);
|
||||
}
|
||||
}
|
||||
// emit CMP8 instruction, from cmp s1 , 0, using s3 and s4 as scratch
|
||||
void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
MOV32w(s4, 0);
|
||||
STRB_U12(s4, xEmu, offsetof(x64emu_t, op2));
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
SET_DF(s3, d_cmp8);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s) = 0
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 0b000111); //mask=000000ff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST32 instruction, from test s1, s2, using s3 and s4 as scratch
|
||||
void emit_test32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s2); MAYUSE(s3); MAYUSE(s4);
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, rex.w?d_tst64:d_tst32);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
ANDSxw_REG(s3, s1, s2); // res = s1 & s2
|
||||
IFX_PENDOR0 {
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s3, rex.w?63:31);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// PF: (((emu->x64emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
ANDw_mask(s3, s3, 0b011011, 0b000010); // 0xE0
|
||||
LSRw(s3, s3, 5);
|
||||
MOV64x(s4, (uintptr_t)GetParityTab());
|
||||
LDRw_REG_LSL2(s4, s4, s3);
|
||||
ANDw_mask(s3, s1, 0, 0b000100); // 0x1f
|
||||
LSRw_REG(s4, s4, s3);
|
||||
MVNx_REG(s4, s4);
|
||||
BFIw(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST16 instruction, from test s1, s2, using s3 and s4 as scratch
|
||||
void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s2);
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, d_tst16);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_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 {
|
||||
STRH_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s4, s5, 15);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// PF: (((emu->x64emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST8 instruction, from test s1, s2, using s3 and s4 as scratch
|
||||
void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s2);
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, d_tst8);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_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 {
|
||||
STRB_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s4, s5, 7);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// PF: (((emu->x64emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s3, s4);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
Executable
+417
@@ -0,0 +1,417 @@
|
||||
#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_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback;
|
||||
uint8_t u8;
|
||||
uint64_t u64, j64;
|
||||
int v0, v1;
|
||||
int q0;
|
||||
int d0, d1;
|
||||
int64_t fixedaddress;
|
||||
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(v0);
|
||||
MAYUSE(v1);
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x10:
|
||||
INST_NAME("MOVSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+ (rex.b<<3);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
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, NULL, 0, 0);
|
||||
VLDR64_U12(v0, ed, fixedaddress); // upper part reseted
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("MOVSD Ex, Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+ (rex.b<<3);
|
||||
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, NULL, 0, 0);
|
||||
VSTR64_U12(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
INST_NAME("MOVDDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
d0 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
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, NULL, 0, 0);
|
||||
VLDR64_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
VMOVeD(v0, 1, v0, 0);
|
||||
break;
|
||||
|
||||
case 0x2A:
|
||||
INST_NAME("CVTSI2SD Gx, Ed");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETED(0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if(rex.w) {
|
||||
SCVTFDx(d1, ed);
|
||||
} else {
|
||||
SCVTFDw(d1, ed);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
break;
|
||||
|
||||
case 0x2C:
|
||||
INST_NAME("CVTTSD2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
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;
|
||||
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;
|
||||
|
||||
|
||||
case 0x51:
|
||||
INST_NAME("SQRTSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
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);
|
||||
VORR(d1, d1, v1);
|
||||
} else {
|
||||
FSQRTD(d1, d0);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
break;
|
||||
|
||||
case 0x58:
|
||||
INST_NAME("ADDSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
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...
|
||||
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;
|
||||
case 0x59:
|
||||
INST_NAME("MULSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
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);
|
||||
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;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTSD2SS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEXSD(d0, 0, 0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FCVT_S_D(d1, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
|
||||
case 0x5C:
|
||||
INST_NAME("SUBSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
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);
|
||||
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;
|
||||
case 0x5D:
|
||||
INST_NAME("MINSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
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);
|
||||
FMINNMD(d0, v0, v1); // NaN handling may be slightly different, is that a problem?
|
||||
VMOVeD(v0, 0, d0, 0); // to not erase uper part
|
||||
#else
|
||||
FCMPD(v0, v1);
|
||||
B_NEXT(cLS); //Less than or equal
|
||||
VMOVeD(v0, 0, v1, 0); // to not erase uper part
|
||||
#endif
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
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);
|
||||
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;
|
||||
case 0x5F:
|
||||
INST_NAME("MAXSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
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);
|
||||
FMAXNMD(d0, v0, v1); // NaN handling may be slightly different, is that a problem?
|
||||
VMOVeD(v0, 0, d0, 0); // to not erase uper part
|
||||
#else
|
||||
FCMPD(v0, v1);
|
||||
B_NEXT(cGE); //Greater than or equal
|
||||
VMOVeD(v0, 0, v1, 0); // to not erase uper part
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0x70:
|
||||
INST_NAME("PSHUFLW Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 1);
|
||||
GETGX(v0, 1);
|
||||
|
||||
u8 = F8;
|
||||
// only low part need to be suffled. VTBL only handle 8bits value, so the 16bits suffles need to be changed in 8bits
|
||||
u64 = 0;
|
||||
for (int i=0; i<4; ++i) {
|
||||
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+0)<<(i*16+0);
|
||||
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+1)<<(i*16+8);
|
||||
}
|
||||
MOV64x(x2, u64);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VMOVQDfrom(d0, 0, x2);
|
||||
VTBL1_8(d0, v1, d0);
|
||||
VMOVeD(v0, 0, d0, 0);
|
||||
if(v0!=v1) {
|
||||
VMOVeD(v0, 1, v1, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7C:
|
||||
INST_NAME("HADDPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
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, NULL, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VLDR128_U12(v1, ed, fixedaddress);
|
||||
}
|
||||
VFADDPQS(v0, v0, v1);
|
||||
break;
|
||||
|
||||
case 0xC2:
|
||||
INST_NAME("CMPSD Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEXSD(v1, 0, 1);
|
||||
u8 = F8;
|
||||
FCMPD(v0, v1);
|
||||
switch(u8&7) {
|
||||
case 0: CSETMx(x2, cEQ); break; // Equal
|
||||
case 1: CSETMx(x2, cCC); break; // Less than
|
||||
case 2: CSETMx(x2, cLS); break; // Less or equal
|
||||
case 3: CSETMx(x2, cVS); break; // NaN
|
||||
case 4: CSETMx(x2, cNE); break; // Not Equal or unordered
|
||||
case 5: CSETMx(x2, cCS); break; // Greater or equal or unordered
|
||||
case 6: CSETMx(x2, cHI); break; // Greater or unordered, test inverted, N!=V so unordered or less than (inverted)
|
||||
case 7: CSETMx(x2, cVC); break; // not NaN
|
||||
}
|
||||
VMOVQDfrom(v0, 0, x2);
|
||||
break;
|
||||
|
||||
case 0xD0:
|
||||
INST_NAME("ADDSUBPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEXSD(v1, 0, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
static float addsubps[4] = {-1.f, 1.f, -1.f, 1.f};
|
||||
MAYUSE(addsubps);
|
||||
TABLE64(x2, (uintptr_t)&addsubps);
|
||||
VLDR128_U12(q0, x2, 0);
|
||||
VFMLAQS(v0, v1, q0);
|
||||
break;
|
||||
|
||||
case 0xD6:
|
||||
INST_NAME("MOVDQ2Q Gm, Ex");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
GETEXSD(v1, 0, 0);
|
||||
VMOV(v0, v1);
|
||||
break;
|
||||
|
||||
case 0xE6:
|
||||
INST_NAME("CVTPD2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
VFRINTIDQ(v0, v1);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
VFCVTNSQD(v0, v0); // convert double -> int64
|
||||
SQXTN_32(v0, v0); // convert int64 -> int32 with saturation in lower part, RaZ high part
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
INST_NAME("LDDQU Gx,Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 7, rex, NULL, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
Executable
+443
@@ -0,0 +1,443 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback;
|
||||
uint64_t u64;
|
||||
int v0, v1;
|
||||
int q0, q1;
|
||||
int d0, d1;
|
||||
int64_t fixedaddress;
|
||||
int64_t j64;
|
||||
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(v0);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(j64);
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x10:
|
||||
INST_NAME("MOVSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
|
||||
VMOVeS(v0, 0, q0, 0);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLDR32_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("MOVSS Ex, Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
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, NULL, 0, 0);
|
||||
VSTR32_U12(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
INST_NAME("MOVSLDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
GETGX_empty(q0);
|
||||
VTRNQ1_32(q0, q1, q1);
|
||||
break;
|
||||
|
||||
case 0x16:
|
||||
INST_NAME("MOVSHDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
GETGX_empty(q0);
|
||||
VTRNQ2_32(q0, q1, q1);
|
||||
break;
|
||||
|
||||
case 0x1E:
|
||||
INST_NAME("NOP / ENDBR32 / ENDBR64");
|
||||
nextop = F8;
|
||||
FAKEED;
|
||||
break;
|
||||
|
||||
case 0x2A:
|
||||
INST_NAME("CVTSI2SS Gx, Ed");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETED(0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if(rex.w) {
|
||||
SCVTFSx(d1, ed);
|
||||
} else {
|
||||
SCVTFSw(d1, ed);
|
||||
}
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
|
||||
case 0x2C:
|
||||
INST_NAME("CVTTSS2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
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;
|
||||
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);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FSQRTS(d1, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
case 0x52:
|
||||
INST_NAME("RSQRTSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
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
|
||||
// and want 1.0f = 0x3f800000
|
||||
// so 00111111 10000000 00000000 00000000
|
||||
// a = 0, b = 1, c = 1, d = 1, efgh=0
|
||||
// 0b01110000
|
||||
FMOVS_8(d0, 0b01110000);
|
||||
FSQRTS(d1, v1);
|
||||
FDIVS(d0, d0, d1);
|
||||
VMOVeS(v0, 0, d0, 0);
|
||||
break;
|
||||
case 0x53:
|
||||
INST_NAME("RCPSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEXSS(v1, 0, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FMOVS_8(d0, 0b01110000); //1.0f
|
||||
FDIVS(d0, d0, v1);
|
||||
VMOVeS(v0, 0, d0, 0);
|
||||
break;
|
||||
|
||||
case 0x58:
|
||||
INST_NAME("ADDSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FADDS(d1, v0, d0); // the high part of the vector is erased...
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("MULSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FMULS(d1, v0, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTSS2SD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEXSS(v1, 0, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FCVT_D_S(d0, v1);
|
||||
VMOVeD(v0, 0, d0, 0);
|
||||
break;
|
||||
case 0x5B:
|
||||
INST_NAME("CVTTPS2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(d0, 0, 0) ;
|
||||
GETGX_empty(v0);
|
||||
VFCVTZSQS(v0, d0);
|
||||
break;
|
||||
|
||||
case 0x5C:
|
||||
INST_NAME("SUBSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FSUBS(d1, v0, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("MINSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
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);
|
||||
FMINNMS(d0, v0, v1); // NaN handling may be slightly different, is that a problem?
|
||||
VMOVeS(v0, 0, d0, 0); // to not erase uper part
|
||||
#else
|
||||
FCMPS(v0, v1);
|
||||
B_NEXT(cLS); //Less than or equal
|
||||
VMOVeS(v0, 0, v1, 0); // to not erase uper part
|
||||
#endif
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FDIVS(d1, v0, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("MAXSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
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);
|
||||
FMAXNMS(d0, v0, v1); // NaN handling may be slightly different, is that a problem?
|
||||
VMOVeS(v0, 0, d0, 0); // to not erase uper part
|
||||
#else
|
||||
FCMPS(v0, v1);
|
||||
B_NEXT(cGE); //Greater than or equal
|
||||
VMOVeS(v0, 0, v1, 0); // to not erase uper part
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0x6F:
|
||||
INST_NAME("MOVDQU Gx,Ex");// no alignment constraint on NEON here, so same as MOVDQA
|
||||
nextop = F8;
|
||||
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);
|
||||
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) ;
|
||||
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
|
||||
u64 = 0;
|
||||
for (int i=0; i<4; ++i) {
|
||||
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+8)<<(i*16+0);
|
||||
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+9)<<(i*16+8);
|
||||
}
|
||||
MOV64x(x2, u64);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VMOVQDfrom(d0, 0, x2);
|
||||
VTBL1_8(d0, v1, d0);
|
||||
VMOVeD(v0, 1, d0, 0);
|
||||
if(v0!=v1) {
|
||||
VMOVeD(v0, 0, v1, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7E:
|
||||
INST_NAME("MOVQ Gx, Ex");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
|
||||
GETGX_empty(v0);
|
||||
FMOVD(v0, v1);
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x7F:
|
||||
INST_NAME("MOVDQU Ex,Gx");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
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, NULL, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xBC:
|
||||
INST_NAME("TZCNT Gd, Ed");
|
||||
SETFLAGS(X_CF|X_ZF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
TSTxw_REG(ed, ed);
|
||||
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(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1); // ZF = is dest 0?
|
||||
break;
|
||||
case 0xBD:
|
||||
INST_NAME("LZCNT Gd, Ed");
|
||||
SETFLAGS(X_CF|X_ZF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
TSTxw_REG(ed, ed);
|
||||
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(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);
|
||||
GETEXSS(v1, 0, 1);
|
||||
u8 = F8;
|
||||
FCMPS(v0, v1);
|
||||
switch(u8&7) {
|
||||
case 0: CSETMw(x2, cEQ); break; // Equal
|
||||
case 1: CSETMw(x2, cCC); break; // Less than
|
||||
case 2: CSETMw(x2, cLS); break; // Less or equal
|
||||
case 3: CSETMw(x2, cVS); break; // NaN
|
||||
case 4: CSETMw(x2, cNE); break; // Not Equal or unordered
|
||||
case 5: CSETMw(x2, cCS); break; // Greater or equal or unordered
|
||||
case 6: CSETMw(x2, cHI); break; // Greater or unordered, test inverted, N!=V so unordered or less than (inverted)
|
||||
case 7: CSETMw(x2, cVC); break; // not NaN
|
||||
}
|
||||
VMOVQSfrom(v0, 0, x2);
|
||||
break;
|
||||
|
||||
case 0xD6:
|
||||
INST_NAME("MOVQ2DQ Gx, Em");
|
||||
nextop = F8;
|
||||
GETGX_empty(v0);
|
||||
if(MODREG) {
|
||||
v1 = mmx_get_reg(dyn, ninst, x1, x2, x3, (nextop&7));
|
||||
VEORQ(v0, v0, v0); // usefull?
|
||||
VMOV(v0, v1);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xE6:
|
||||
INST_NAME("CVTDQ2PD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
SXTL_32(v0, v1);
|
||||
SCVTQFD(v0, v0); // there is only I64 -> Double vector conversion, not from i32
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
Executable
+946
@@ -0,0 +1,946 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "tools/bridge_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "signals.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "custommem.h"
|
||||
#include "bridge.h"
|
||||
|
||||
void arm_fstp(x64emu_t* emu, void* p)
|
||||
{
|
||||
if(ST0.q!=STld(0).uref)
|
||||
D2LD(&ST0.d, p);
|
||||
else
|
||||
memcpy(p, &STld(0).ld, 10);
|
||||
}
|
||||
|
||||
void arm_print_armreg(x64emu_t* emu, uintptr_t reg, uintptr_t n)
|
||||
{
|
||||
(void)emu;
|
||||
dynarec_log(LOG_DEBUG, "R%lu=0x%lx (%lu)\n", n, reg, reg);
|
||||
}
|
||||
|
||||
void arm_f2xm1(x64emu_t* emu)
|
||||
{
|
||||
ST0.d = exp2(ST0.d) - 1.0;
|
||||
}
|
||||
void arm_fyl2x(x64emu_t* emu)
|
||||
{
|
||||
ST(1).d = log2(ST0.d)*ST(1).d;
|
||||
}
|
||||
void arm_ftan(x64emu_t* emu)
|
||||
{
|
||||
ST0.d = tan(ST0.d);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
}
|
||||
void arm_fpatan(x64emu_t* emu)
|
||||
{
|
||||
ST1.d = atan2(ST1.d, ST0.d);
|
||||
}
|
||||
void arm_fxtract(x64emu_t* emu)
|
||||
{
|
||||
int32_t tmp32s = (ST1.q&0x7ff0000000000000LL)>>52;
|
||||
tmp32s -= 1023;
|
||||
ST1.d /= exp2(tmp32s);
|
||||
ST0.d = tmp32s;
|
||||
}
|
||||
void arm_fprem(x64emu_t* emu)
|
||||
{
|
||||
int32_t tmp32s = ST0.d / ST1.d;
|
||||
ST0.d -= ST1.d * tmp32s;
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C0 = (tmp32s&1);
|
||||
emu->sw.f.F87_C3 = ((tmp32s>>1)&1);
|
||||
emu->sw.f.F87_C1 = ((tmp32s>>2)&1);
|
||||
}
|
||||
void arm_fyl2xp1(x64emu_t* emu)
|
||||
{
|
||||
ST(1).d = log2(ST0.d + 1.0)*ST(1).d;
|
||||
}
|
||||
void arm_fsincos(x64emu_t* emu)
|
||||
{
|
||||
sincos(ST1.d, &ST1.d, &ST0.d);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
}
|
||||
void arm_frndint(x64emu_t* emu)
|
||||
{
|
||||
ST0.d = fpu_round(emu, ST0.d);
|
||||
}
|
||||
void arm_fscale(x64emu_t* emu)
|
||||
{
|
||||
if(ST0.d!=0.0)
|
||||
ST0.d *= exp2(trunc(ST1.d));
|
||||
}
|
||||
void arm_fsin(x64emu_t* emu)
|
||||
{
|
||||
ST0.d = sin(ST0.d);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
}
|
||||
void arm_fcos(x64emu_t* emu)
|
||||
{
|
||||
ST0.d = cos(ST0.d);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
}
|
||||
|
||||
void arm_fbld(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_fbld(emu, ed);
|
||||
}
|
||||
|
||||
void arm_fild64(x64emu_t* emu, int64_t* ed)
|
||||
{
|
||||
int64_t tmp;
|
||||
memcpy(&tmp, ed, sizeof(tmp));
|
||||
ST0.d = tmp;
|
||||
STll(0).sq = tmp;
|
||||
STll(0).sref = ST0.sq;
|
||||
}
|
||||
|
||||
void arm_fbstp(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_fbst(emu, ed);
|
||||
}
|
||||
|
||||
void arm_fistp64(x64emu_t* emu, int64_t* ed)
|
||||
{
|
||||
// used of memcpy to avoid aligments issues
|
||||
if(STll(0).sref==ST(0).sq) {
|
||||
memcpy(ed, &STll(0).sq, sizeof(int64_t));
|
||||
} else {
|
||||
int64_t tmp;
|
||||
if(isgreater(ST0.d, (double)(int64_t)0x7fffffffffffffffLL) || isless(ST0.d, (double)(int64_t)0x8000000000000000LL) || !isfinite(ST0.d))
|
||||
tmp = 0x8000000000000000LL;
|
||||
else
|
||||
tmp = fpu_round(emu, ST0.d);
|
||||
memcpy(ed, &tmp, sizeof(tmp));
|
||||
}
|
||||
}
|
||||
|
||||
void arm_fistt64(x64emu_t* emu, int64_t* ed)
|
||||
{
|
||||
// used of memcpy to avoid aligments issues
|
||||
int64_t tmp = ST0.d;
|
||||
memcpy(ed, &tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
void arm_fld(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
memcpy(&STld(0).ld, ed, 10);
|
||||
LD2D(&STld(0), &ST(0).d);
|
||||
STld(0).uref = ST0.q;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
uint8_t* p = ed;
|
||||
p += 28;
|
||||
for (int i=0; i<8; ++i) {
|
||||
LD2D(p, &ST(i).d);
|
||||
p+=10;
|
||||
}
|
||||
}
|
||||
void arm_frstor(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_loadenv(emu, (char*)ed, 0);
|
||||
|
||||
uint8_t* p = ed;
|
||||
p += 28;
|
||||
for (int i=0; i<8; ++i) {
|
||||
D2LD(&ST(i).d, p);
|
||||
p+=10;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void arm_fprem1(x64emu_t* emu)
|
||||
{
|
||||
// simplified version
|
||||
int32_t tmp32s = round(ST0.d / ST1.d);
|
||||
ST0.d -= ST1.d*tmp32s;
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C0 = (tmp32s&1);
|
||||
emu->sw.f.F87_C3 = ((tmp32s>>1)&1);
|
||||
emu->sw.f.F87_C1 = ((tmp32s>>2)&1);
|
||||
}
|
||||
|
||||
static uint8_t ff_mult(uint8_t a, uint8_t b)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
for(int i = 0; i < 8; i++) {
|
||||
if((b & 1) == 1)
|
||||
retval ^= a;
|
||||
|
||||
if((a & 0x80)) {
|
||||
a <<= 1;
|
||||
a ^= 0x1b;
|
||||
} else {
|
||||
a <<= 1;
|
||||
}
|
||||
|
||||
b >>= 1;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void arm_aesimc(x64emu_t* emu, int xmm)
|
||||
{
|
||||
sse_regs_t eax1 = emu->xmm[xmm];
|
||||
|
||||
for(int j=0; j<4; ++j) {
|
||||
emu->xmm[xmm].ub[0+j*4] = ff_mult(0x0E, eax1.ub[0+j*4]) ^ ff_mult(0x0B, eax1.ub[1+j*4]) ^ ff_mult(0x0D, eax1.ub[2+j*4]) ^ ff_mult(0x09, eax1.ub[3+j*4]);
|
||||
emu->xmm[xmm].ub[1+j*4] = ff_mult(0x09, eax1.ub[0+j*4]) ^ ff_mult(0x0E, eax1.ub[1+j*4]) ^ ff_mult(0x0B, eax1.ub[2+j*4]) ^ ff_mult(0x0D, eax1.ub[3+j*4]);
|
||||
emu->xmm[xmm].ub[2+j*4] = ff_mult(0x0D, eax1.ub[0+j*4]) ^ ff_mult(0x09, eax1.ub[1+j*4]) ^ ff_mult(0x0E, eax1.ub[2+j*4]) ^ ff_mult(0x0B, eax1.ub[3+j*4]);
|
||||
emu->xmm[xmm].ub[3+j*4] = ff_mult(0x0B, eax1.ub[0+j*4]) ^ ff_mult(0x0D, eax1.ub[1+j*4]) ^ ff_mult(0x09, eax1.ub[2+j*4]) ^ ff_mult(0x0E, eax1.ub[3+j*4]);
|
||||
}
|
||||
}
|
||||
void arm_aesmc(x64emu_t* emu, int xmm)
|
||||
{
|
||||
sse_regs_t eax1 = emu->xmm[xmm];
|
||||
|
||||
for(int j=0; j<4; ++j) {
|
||||
emu->xmm[xmm].ub[0+j*4] = ff_mult(0x02, eax1.ub[0+j*4]) ^ ff_mult(0x03, eax1.ub[1+j*4]) ^ eax1.ub[2+j*4] ^ eax1.ub[3+j*4] ;
|
||||
emu->xmm[xmm].ub[1+j*4] = eax1.ub[0+j*4] ^ ff_mult(0x02, eax1.ub[1+j*4]) ^ ff_mult(0x03, eax1.ub[2+j*4]) ^ eax1.ub[3+j*4] ;
|
||||
emu->xmm[xmm].ub[2+j*4] = eax1.ub[0+j*4] ^ eax1.ub[1+j*4] ^ ff_mult(0x02, eax1.ub[2+j*4]) ^ ff_mult(0x03, eax1.ub[3+j*4]);
|
||||
emu->xmm[xmm].ub[3+j*4] = ff_mult(0x03, eax1.ub[0+j*4]) ^ eax1.ub[1+j*4] ^ eax1.ub[2+j*4] ^ ff_mult(0x02, eax1.ub[3+j*4]);
|
||||
}
|
||||
}
|
||||
void arm_aesdlast(x64emu_t* emu, int xmm)
|
||||
{
|
||||
// A0 B1 C2 D3 E4 F5 G6 H7 I8 J9 Ka Lb Mc Nd Oe Pf
|
||||
// A N K H E B O L I F C P M J G D
|
||||
const uint8_t invshiftrows[] = {0,13,10, 7, 4, 1,14,11, 8, 5, 2,15,12, 9, 6, 3};
|
||||
const uint8_t invsubbytes[256] = {
|
||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
|
||||
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
|
||||
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
||||
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
|
||||
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
|
||||
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
||||
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
|
||||
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
|
||||
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
||||
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
||||
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
|
||||
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d,
|
||||
};
|
||||
|
||||
sse_regs_t eax1;
|
||||
for(int i=0; i<16; ++i)
|
||||
eax1.ub[i] = emu->xmm[xmm].ub[invshiftrows[i]];
|
||||
//STATE ← InvSubBytes( STATE );
|
||||
for(int i=0; i<16; ++i)
|
||||
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
|
||||
sse_regs_t eax1;
|
||||
for(int i=0; i<16; ++i)
|
||||
eax1.ub[i] = emu->xmm[xmm].ub[shiftrows[i]];
|
||||
//STATE ← SubBytes( STATE );
|
||||
for(int i=0; i<16; ++i)
|
||||
emu->xmm[xmm].ub[i] = subbytes[eax1.ub[i]];
|
||||
}
|
||||
void arm_aesd(x64emu_t* emu, int xmm)
|
||||
{
|
||||
arm_aesdlast(emu, xmm);
|
||||
arm_aesimc(emu, xmm);
|
||||
}
|
||||
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
|
||||
#define XMM8 16
|
||||
#define X870 8
|
||||
#define EMM0 8
|
||||
#define SCRATCH0 24
|
||||
|
||||
// Get a FPU scratch reg
|
||||
int fpu_get_scratch(dynarec_arm_t* dyn)
|
||||
{
|
||||
return SCRATCH0 + dyn->n.fpu_scratch++; // return an Sx
|
||||
}
|
||||
// Reset scratch regs counter
|
||||
void fpu_reset_scratch(dynarec_arm_t* dyn)
|
||||
{
|
||||
dyn->n.fpu_scratch = 0;
|
||||
}
|
||||
// Get a x87 double reg
|
||||
int fpu_get_reg_x87(dynarec_arm_t* dyn, int t, int n)
|
||||
{
|
||||
int i=X870;
|
||||
while (dyn->n.fpuused[i]) ++i;
|
||||
dyn->n.fpuused[i] = 1;
|
||||
dyn->n.neoncache[i].n = n;
|
||||
dyn->n.neoncache[i].t = t;
|
||||
dyn->n.news |= (1<<i);
|
||||
return i; // return a Dx
|
||||
}
|
||||
// Free a FPU double reg
|
||||
void fpu_free_reg(dynarec_arm_t* dyn, int reg)
|
||||
{
|
||||
// TODO: check upper limit?
|
||||
dyn->n.fpuused[reg] = 0;
|
||||
if(dyn->n.neoncache[reg].t!=NEON_CACHE_ST_F && dyn->n.neoncache[reg].t!=NEON_CACHE_ST_D)
|
||||
dyn->n.neoncache[reg].v = 0;
|
||||
}
|
||||
// Get an MMX double reg
|
||||
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
|
||||
int fpu_get_reg_xmm(dynarec_arm_t* dyn, int t, int xmm)
|
||||
{
|
||||
int i;
|
||||
if(xmm>7) {
|
||||
i = XMM8 + xmm - 8;
|
||||
} else {
|
||||
i = XMM0 + 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
|
||||
void fpu_reset_reg(dynarec_arm_t* dyn)
|
||||
{
|
||||
dyn->n.fpu_reg = 0;
|
||||
for (int i=0; i<24; ++i) {
|
||||
dyn->n.fpuused[i]=0;
|
||||
dyn->n.neoncache[i].v = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int neoncache_get_st(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
if (dyn->insts[ninst].n.swapped) {
|
||||
if(dyn->insts[ninst].n.combined1 == a)
|
||||
a = dyn->insts[ninst].n.combined2;
|
||||
else if(dyn->insts[ninst].n.combined2 == a)
|
||||
a = dyn->insts[ninst].n.combined1;
|
||||
}
|
||||
for(int i=0; i<24; ++i)
|
||||
if((dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F
|
||||
|| dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_D)
|
||||
&& dyn->insts[ninst].n.neoncache[i].n==a)
|
||||
return dyn->insts[ninst].n.neoncache[i].t;
|
||||
// not in the cache yet, so will be fetched...
|
||||
return NEON_CACHE_ST_D;
|
||||
}
|
||||
|
||||
int neoncache_get_current_st(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
(void)ninst;
|
||||
if(!dyn->insts)
|
||||
return NEON_CACHE_ST_D;
|
||||
for(int i=0; i<24; ++i)
|
||||
if((dyn->n.neoncache[i].t==NEON_CACHE_ST_F
|
||||
|| dyn->n.neoncache[i].t==NEON_CACHE_ST_D)
|
||||
&& dyn->n.neoncache[i].n==a)
|
||||
return dyn->n.neoncache[i].t;
|
||||
// not in the cache yet, so will be fetched...
|
||||
return NEON_CACHE_ST_D;
|
||||
}
|
||||
|
||||
int neoncache_get_st_f(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
/*if(a+dyn->insts[ninst].n.stack_next-st<0)
|
||||
// The STx has been pushed at the end of instructon, so stop going back
|
||||
return -1;*/
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F
|
||||
&& dyn->insts[ninst].n.neoncache[i].n==a)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
int neoncache_get_st_f_noback(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F
|
||||
&& dyn->insts[ninst].n.neoncache[i].n==a)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
int neoncache_get_current_st_f(dynarec_arm_t* dyn, int a)
|
||||
{
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->n.neoncache[i].t==NEON_CACHE_ST_F
|
||||
&& dyn->n.neoncache[i].n==a)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
static void neoncache_promote_double_forward(dynarec_arm_t* dyn, int ninst, int maxinst, int a);
|
||||
static void neoncache_promote_double_internal(dynarec_arm_t* dyn, int ninst, int maxinst, int a);
|
||||
static void neoncache_promote_double_combined(dynarec_arm_t* dyn, int ninst, int maxinst, int a)
|
||||
{
|
||||
if(a == dyn->insts[ninst].n.combined1 || a == dyn->insts[ninst].n.combined2) {
|
||||
if(a == dyn->insts[ninst].n.combined1) {
|
||||
a = dyn->insts[ninst].n.combined2;
|
||||
} else
|
||||
a = dyn->insts[ninst].n.combined1;
|
||||
int i = neoncache_get_st_f_noback(dyn, ninst, a);
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_combined, ninst=%d combined%c %d i=%d (stack:%d/%d)\n", ninst, (a == dyn->insts[ninst].n.combined2)?'2':'1', a ,i, dyn->insts[ninst].n.stack_push, -dyn->insts[ninst].n.stack_pop);
|
||||
if(i>=0) {
|
||||
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
if(!dyn->insts[ninst].n.barrier)
|
||||
neoncache_promote_double_internal(dyn, ninst-1, maxinst, a-dyn->insts[ninst].n.stack_push);
|
||||
// go forward is combined is not pop'd
|
||||
if(a-dyn->insts[ninst].n.stack_pop>=0)
|
||||
if(!dyn->insts[ninst+1].n.barrier)
|
||||
neoncache_promote_double_forward(dyn, ninst+1, maxinst, a-dyn->insts[ninst].n.stack_pop);
|
||||
}
|
||||
}
|
||||
}
|
||||
static void neoncache_promote_double_internal(dynarec_arm_t* dyn, int ninst, int maxinst, int a)
|
||||
{
|
||||
if(dyn->insts[ninst+1].n.barrier)
|
||||
return;
|
||||
while(ninst>=0) {
|
||||
a+=dyn->insts[ninst].n.stack_pop; // adjust Stack depth: add pop'd ST (going backward)
|
||||
int i = neoncache_get_st_f(dyn, ninst, a);
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d, a=%d st=%d:%d, i=%d\n", ninst, a, dyn->insts[ninst].n.stack, dyn->insts[ninst].n.stack_next, i);
|
||||
if(i<0) return;
|
||||
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
// check combined propagation too
|
||||
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) {
|
||||
if(dyn->insts[ninst].n.swapped) {
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d swapped %d/%d vs %d with st %d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, dyn->insts[ninst].n.stack);
|
||||
if (a==dyn->insts[ninst].n.combined1)
|
||||
a = dyn->insts[ninst].n.combined2;
|
||||
else if (a==dyn->insts[ninst].n.combined2)
|
||||
a = dyn->insts[ninst].n.combined1;
|
||||
} else {
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d combined %d/%d vs %d with st %d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, dyn->insts[ninst].n.stack);
|
||||
neoncache_promote_double_combined(dyn, ninst, maxinst, a);
|
||||
}
|
||||
}
|
||||
a-=dyn->insts[ninst].n.stack_push; // // adjust Stack depth: remove push'd ST (going backward)
|
||||
--ninst;
|
||||
if(ninst<0 || a<0 || dyn->insts[ninst].n.barrier)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void neoncache_promote_double_forward(dynarec_arm_t* dyn, int ninst, int maxinst, int a)
|
||||
{
|
||||
while((ninst!=-1) && (ninst<maxinst) && (a>=0)) {
|
||||
a+=dyn->insts[ninst].n.stack_push; // // adjust Stack depth: add push'd ST (going forward)
|
||||
if((dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) && dyn->insts[ninst].n.swapped) {
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_forward, ninst=%d swapped %d/%d vs %d with st %d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, dyn->insts[ninst].n.stack);
|
||||
if (a==dyn->insts[ninst].n.combined1)
|
||||
a = dyn->insts[ninst].n.combined2;
|
||||
else if (a==dyn->insts[ninst].n.combined2)
|
||||
a = dyn->insts[ninst].n.combined1;
|
||||
}
|
||||
int i = neoncache_get_st_f_noback(dyn, ninst, a);
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_forward, ninst=%d, a=%d st=%d:%d(%d/%d), i=%d\n", ninst, a, dyn->insts[ninst].n.stack, dyn->insts[ninst].n.stack_next, dyn->insts[ninst].n.stack_push, -dyn->insts[ninst].n.stack_pop, i);
|
||||
if(i<0) return;
|
||||
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
// check combined propagation too
|
||||
if((dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) && !dyn->insts[ninst].n.swapped) {
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_forward, ninst=%d combined %d/%d vs %d with st %d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, dyn->insts[ninst].n.stack);
|
||||
neoncache_promote_double_combined(dyn, ninst, maxinst, a);
|
||||
}
|
||||
a-=dyn->insts[ninst].n.stack_pop; // adjust Stack depth: remove pop'd ST (going forward)
|
||||
if(dyn->insts[ninst].x64.has_next && !dyn->insts[ninst].n.barrier)
|
||||
++ninst;
|
||||
else
|
||||
ninst=-1;
|
||||
}
|
||||
if(ninst==maxinst)
|
||||
neoncache_promote_double(dyn, ninst, a);
|
||||
}
|
||||
|
||||
void neoncache_promote_double(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
int i = neoncache_get_current_st_f(dyn, a);
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double, ninst=%d a=%d st=%d i=%d\n", ninst, a, dyn->n.stack, i);
|
||||
if(i<0) return;
|
||||
dyn->n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
// check combined propagation too
|
||||
if(dyn->n.combined1 || dyn->n.combined2) {
|
||||
if(dyn->n.swapped) {
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double, ninst=%d swapped! %d/%d vs %d\n", ninst, dyn->n.combined1 ,dyn->n.combined2, a);
|
||||
if(dyn->n.combined1 == a)
|
||||
a = dyn->n.combined2;
|
||||
else if(dyn->n.combined2 == a)
|
||||
a = dyn->n.combined1;
|
||||
} else {
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double, ninst=%d combined! %d/%d vs %d\n", ninst, dyn->n.combined1 ,dyn->n.combined2, a);
|
||||
if(dyn->n.combined1 == a)
|
||||
neoncache_promote_double(dyn, ninst, dyn->n.combined2);
|
||||
else if(dyn->n.combined2 == a)
|
||||
neoncache_promote_double(dyn, ninst, dyn->n.combined1);
|
||||
}
|
||||
}
|
||||
a-=dyn->insts[ninst].n.stack_push; // // adjust Stack depth: remove push'd ST (going backward)
|
||||
if(!ninst || a<0) return;
|
||||
neoncache_promote_double_internal(dyn, ninst-1, ninst, a);
|
||||
}
|
||||
|
||||
int neoncache_combine_st(dynarec_arm_t* dyn, int ninst, int a, int b)
|
||||
{
|
||||
dyn->n.combined1=a;
|
||||
dyn->n.combined2=b;
|
||||
if( neoncache_get_current_st(dyn, ninst, a)==NEON_CACHE_ST_F
|
||||
&& neoncache_get_current_st(dyn, ninst, b)==NEON_CACHE_ST_F )
|
||||
return NEON_CACHE_ST_F;
|
||||
return NEON_CACHE_ST_D;
|
||||
}
|
||||
|
||||
int isPred(dynarec_arm_t* dyn, int ninst, int pred) {
|
||||
for(int i=0; i<dyn->insts[ninst].pred_sz; ++i)
|
||||
if(dyn->insts[ninst].pred[i]==pred)
|
||||
return pred;
|
||||
return -1;
|
||||
}
|
||||
int getNominalPred(dynarec_arm_t* dyn, int ninst) {
|
||||
if((ninst<=0) || !dyn->insts[ninst].pred_sz)
|
||||
return -1;
|
||||
if(isPred(dyn, ninst, ninst-1)!=-1)
|
||||
return ninst-1;
|
||||
return dyn->insts[ninst].pred[0];
|
||||
}
|
||||
|
||||
int isCacheEmpty(dynarec_arm_t* dyn, int ninst) {
|
||||
if(dyn->insts[ninst].n.stack_next) {
|
||||
return 0;
|
||||
}
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->insts[ninst].n.neoncache[i].v) { // there is something at ninst for i
|
||||
if(!(
|
||||
(dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F || dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_D)
|
||||
&& dyn->insts[ninst].n.neoncache[i].n<dyn->insts[ninst].n.stack_pop))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
static int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|
||||
int i2 = dyn->insts[ninst].x64.jmp_insts;
|
||||
if(i2<0)
|
||||
return 1;
|
||||
if((dyn->insts[i2].x64.barrier&BARRIER_FLOAT))
|
||||
// if the barrier as already been apply, no transform needed
|
||||
return ((dyn->insts[ninst].x64.barrier&BARRIER_FLOAT))?0:(isCacheEmpty(dyn, ninst)?0:1);
|
||||
int ret = 0;
|
||||
if(!i2) { // just purge
|
||||
if(dyn->insts[ninst].n.stack_next) {
|
||||
return 1;
|
||||
}
|
||||
for(int i=0; i<24 && !ret; ++i)
|
||||
if(dyn->insts[ninst].n.neoncache[i].v) { // there is something at ninst for i
|
||||
if(!(
|
||||
(dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F || dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_D)
|
||||
&& dyn->insts[ninst].n.neoncache[i].n<dyn->insts[ninst].n.stack_pop))
|
||||
ret = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
// Check if ninst can be compatible to i2
|
||||
if(dyn->insts[ninst].n.stack_next != dyn->insts[i2].n.stack-dyn->insts[i2].n.stack_push) {
|
||||
return 1;
|
||||
}
|
||||
neoncache_t cache_i2 = dyn->insts[i2].n;
|
||||
neoncacheUnwind(&cache_i2);
|
||||
|
||||
for(int i=0; i<24; ++i) {
|
||||
if(dyn->insts[ninst].n.neoncache[i].v) { // there is something at ninst for i
|
||||
if(!cache_i2.neoncache[i].v) { // but there is nothing at i2 for i
|
||||
ret = 1;
|
||||
} else if(dyn->insts[ninst].n.neoncache[i].v!=cache_i2.neoncache[i].v) { // there is something different
|
||||
if(dyn->insts[ninst].n.neoncache[i].n!=cache_i2.neoncache[i].n) { // not the same x64 reg
|
||||
ret = 1;
|
||||
}
|
||||
else if(dyn->insts[ninst].n.neoncache[i].t == NEON_CACHE_XMMR && cache_i2.neoncache[i].t == NEON_CACHE_XMMW)
|
||||
{/* nothing */ }
|
||||
else
|
||||
ret = 1;
|
||||
}
|
||||
} else if(cache_i2.neoncache[i].v)
|
||||
ret = 1;
|
||||
}
|
||||
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) {
|
||||
// unswap
|
||||
int a = -1;
|
||||
int b = -1;
|
||||
for(int j=0; j<24 && ((a==-1) || (b==-1)); ++j)
|
||||
if((cache->neoncache[j].t == NEON_CACHE_ST_D || cache->neoncache[j].t == NEON_CACHE_ST_F)) {
|
||||
if(cache->neoncache[j].n == cache->combined1)
|
||||
a = j;
|
||||
else if(cache->neoncache[j].n == cache->combined2)
|
||||
b = j;
|
||||
}
|
||||
if(a!=-1 && b!=-1) {
|
||||
int tmp = cache->neoncache[a].n;
|
||||
cache->neoncache[a].n = cache->neoncache[b].n;
|
||||
cache->neoncache[b].n = tmp;
|
||||
}
|
||||
cache->swapped = 0;
|
||||
cache->combined1 = cache->combined2 = 0;
|
||||
}
|
||||
if(cache->news) {
|
||||
// reove the newly created neoncache
|
||||
for(int i=0; i<24; ++i)
|
||||
if(cache->news&(1<<i))
|
||||
cache->neoncache[i].v = 0;
|
||||
cache->news = 0;
|
||||
}
|
||||
if(cache->stack_push) {
|
||||
// unpush
|
||||
for(int j=0; j<24; ++j) {
|
||||
if((cache->neoncache[j].t == NEON_CACHE_ST_D || cache->neoncache[j].t == NEON_CACHE_ST_F)) {
|
||||
if(cache->neoncache[j].n<cache->stack_push)
|
||||
cache->neoncache[j].v = 0;
|
||||
else
|
||||
cache->neoncache[j].n-=cache->stack_push;
|
||||
}
|
||||
}
|
||||
cache->x87stack-=cache->stack_push;
|
||||
cache->stack-=cache->stack_push;
|
||||
cache->stack_push = 0;
|
||||
}
|
||||
cache->x87stack+=cache->stack_pop;
|
||||
cache->stack_next = cache->stack;
|
||||
cache->stack_pop = 0;
|
||||
cache->barrier = 0;
|
||||
// And now, rebuild the x87cache info with neoncache
|
||||
cache->mmxcount = 0;
|
||||
cache->fpu_scratch = 0;
|
||||
cache->fpu_extra_qscratch = 0;
|
||||
cache->fpu_reg = 0;
|
||||
for(int i=0; i<8; ++i) {
|
||||
cache->x87cache[i] = -1;
|
||||
cache->mmxcache[i] = -1;
|
||||
cache->x87reg[i] = 0;
|
||||
cache->ssecache[i*2].v = -1;
|
||||
cache->ssecache[i*2+1].v = -1;
|
||||
}
|
||||
int x87reg = 0;
|
||||
for(int i=0; i<24; ++i) {
|
||||
if(cache->neoncache[i].v) {
|
||||
cache->fpuused[i] = 1;
|
||||
switch (cache->neoncache[i].t) {
|
||||
case NEON_CACHE_MM:
|
||||
cache->mmxcache[cache->neoncache[i].n] = i;
|
||||
++cache->mmxcount;
|
||||
++cache->fpu_reg;
|
||||
break;
|
||||
case NEON_CACHE_XMMR:
|
||||
case NEON_CACHE_XMMW:
|
||||
cache->ssecache[cache->neoncache[i].n].reg = i;
|
||||
cache->ssecache[cache->neoncache[i].n].write = (cache->neoncache[i].t==NEON_CACHE_XMMW)?1:0;
|
||||
++cache->fpu_reg;
|
||||
break;
|
||||
case NEON_CACHE_ST_F:
|
||||
case NEON_CACHE_ST_D:
|
||||
cache->x87cache[x87reg] = cache->neoncache[i].n;
|
||||
cache->x87reg[x87reg] = i;
|
||||
++x87reg;
|
||||
++cache->fpu_reg;
|
||||
break;
|
||||
case NEON_CACHE_SCR:
|
||||
cache->fpuused[i] = 0;
|
||||
cache->neoncache[i].v = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
cache->fpuused[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define F8 *(uint8_t*)(addr++)
|
||||
#define F32 *(uint32_t*)(addr+=4, addr-4)
|
||||
#define F32S64 (uint64_t)(int64_t)*(int32_t*)(addr+=4, addr-4)
|
||||
// Get if ED will have the correct parity. Not emiting anything. Parity is 2 for DWORD or 3 for QWORD
|
||||
int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity, int delta)
|
||||
{
|
||||
(void)dyn; (void)ninst;
|
||||
|
||||
uint32_t tested = (1<<parity)-1;
|
||||
if((nextop&0xC0)==0xC0)
|
||||
return 0; // direct register, no parity...
|
||||
if(!(nextop&0xC0)) {
|
||||
if((nextop&7)==4) {
|
||||
uint8_t sib = F8;
|
||||
int sib_reg = (sib>>3)&7;
|
||||
if((sib&0x7)==5) {
|
||||
uint64_t tmp = F32S64;
|
||||
if (sib_reg!=4) {
|
||||
// if XXXXXX+reg<<N then check parity of XXXXX and N should be enough
|
||||
return ((tmp&tested)==0 && (sib>>6)>=parity)?1:0;
|
||||
} else {
|
||||
// just a constant...
|
||||
return (tmp&tested)?0:1;
|
||||
}
|
||||
} else {
|
||||
if(sib_reg==4 && parity<3)
|
||||
return 0; // simple [reg]
|
||||
// don't try [reg1 + reg2<<N], unless reg1 is ESP
|
||||
return ((sib&0x7)==4 && (sib>>6)>=parity)?1:0;
|
||||
}
|
||||
} else if((nextop&7)==5) {
|
||||
uint64_t tmp = F32S64;
|
||||
tmp+=addr+delta;
|
||||
return (tmp&tested)?0:1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0; //Form [reg1 + reg2<<N + XXXXXX]
|
||||
}
|
||||
}
|
||||
|
||||
// Do the GETED, but don't emit anything...
|
||||
uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop)
|
||||
{
|
||||
(void)dyn; (void)addr; (void)ninst;
|
||||
|
||||
if((nextop&0xC0)==0xC0)
|
||||
return addr;
|
||||
if(!(nextop&0xC0)) {
|
||||
if((nextop&7)==4) {
|
||||
uint8_t sib = F8;
|
||||
if((sib&0x7)==5) {
|
||||
addr+=4;
|
||||
}
|
||||
} else if((nextop&7)==5) {
|
||||
addr+=4;
|
||||
}
|
||||
} else {
|
||||
if((nextop&7)==4) {
|
||||
++addr;
|
||||
}
|
||||
if(nextop&0x80) {
|
||||
addr+=4;
|
||||
} else {
|
||||
++addr;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
#undef F8
|
||||
#undef F32
|
||||
|
||||
int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn)
|
||||
{
|
||||
(void)dyn;
|
||||
|
||||
#define PK(a) *(uint8_t*)(addr+a)
|
||||
#define PK32(a) *(int32_t*)(addr+a)
|
||||
|
||||
if(!addr || !getProtection(addr))
|
||||
return 0;
|
||||
if(PK(0)==0xff && PK(1)==0x25) { // "absolute" jump, maybe the GOT (well, RIP relative in fact)
|
||||
uintptr_t a1 = addr + 6 + (PK32(2)); // need to add a check to see if the address is from the GOT !
|
||||
addr = (uintptr_t)getAlternate(*(void**)a1);
|
||||
}
|
||||
if(!addr || !getProtection(addr))
|
||||
return 0;
|
||||
onebridge_t *b = (onebridge_t*)(addr);
|
||||
if(b->CC==0xCC && b->S=='S' && b->C=='C' && b->w!=(wrapper_t)0 && b->f!=(uintptr_t)PltResolver) {
|
||||
// found !
|
||||
if(retn) *retn = (b->C3==0xC2)?b->N:0;
|
||||
if(calladdress) *calladdress = addr+1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
#undef PK32
|
||||
#undef PK
|
||||
}
|
||||
|
||||
const char* getCacheName(int t, int n)
|
||||
{
|
||||
static char buff[20];
|
||||
switch(t) {
|
||||
case NEON_CACHE_ST_D: sprintf(buff, "ST%d", n); break;
|
||||
case NEON_CACHE_ST_F: sprintf(buff, "st%d", n); break;
|
||||
case NEON_CACHE_MM: sprintf(buff, "MM%d", n); break;
|
||||
case NEON_CACHE_XMMW: sprintf(buff, "XMM%d", n); break;
|
||||
case NEON_CACHE_XMMR: sprintf(buff, "xmm%d", n); break;
|
||||
case NEON_CACHE_SCR: sprintf(buff, "Scratch"); break;
|
||||
case NEON_CACHE_NONE: buff[0]='\0'; break;
|
||||
}
|
||||
return buff;
|
||||
}
|
||||
|
||||
// is inst clean for a son branch?
|
||||
int isInstClean(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
// check flags cache
|
||||
if(dyn->insts[ninst].f_entry.dfnone || dyn->insts[ninst].f_entry.pending)
|
||||
return 0;
|
||||
if(dyn->insts[ninst].x64.state_flags)
|
||||
return 0;
|
||||
// check neoncache
|
||||
neoncache_t* n = &dyn->insts[ninst].n;
|
||||
if(n->news || n->stack || n->stack_next)
|
||||
return 0;
|
||||
for(int i=0; i<24; ++i)
|
||||
if(n->neoncache[i].v)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
Executable
+97
@@ -0,0 +1,97 @@
|
||||
#ifndef __DYNAREC_ARM_FUNCTIONS_H__
|
||||
#define __DYNAREC_ARM_FUNCTIONS_H__
|
||||
|
||||
typedef struct x64emu_s x64emu_t;
|
||||
|
||||
void arm_fstp(x64emu_t* emu, void* p);
|
||||
|
||||
void arm_print_armreg(x64emu_t* emu, uintptr_t reg, uintptr_t n);
|
||||
|
||||
void arm_f2xm1(x64emu_t* emu);
|
||||
void arm_fyl2x(x64emu_t* emu);
|
||||
void arm_ftan(x64emu_t* emu);
|
||||
void arm_fpatan(x64emu_t* emu);
|
||||
void arm_fxtract(x64emu_t* emu);
|
||||
void arm_fprem(x64emu_t* emu);
|
||||
void arm_fyl2xp1(x64emu_t* emu);
|
||||
void arm_fsincos(x64emu_t* emu);
|
||||
void arm_frndint(x64emu_t* emu);
|
||||
void arm_fscale(x64emu_t* emu);
|
||||
void arm_fsin(x64emu_t* emu);
|
||||
void arm_fcos(x64emu_t* emu);
|
||||
void arm_fbld(x64emu_t* emu, uint8_t* ed);
|
||||
void arm_fild64(x64emu_t* emu, int64_t* ed);
|
||||
void arm_fbstp(x64emu_t* emu, uint8_t* ed);
|
||||
void arm_fistp64(x64emu_t* emu, int64_t* ed);
|
||||
void arm_fistt64(x64emu_t* emu, int64_t* ed);
|
||||
void arm_fld(x64emu_t* emu, uint8_t* ed);
|
||||
void arm_fsave(x64emu_t* emu, uint8_t* ed);
|
||||
void arm_frstor(x64emu_t* emu, uint8_t* ed);
|
||||
void arm_fprem1(x64emu_t* emu);
|
||||
|
||||
void arm_aesd(x64emu_t* emu, int xmm);
|
||||
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);
|
||||
// Reset scratch regs counter
|
||||
void fpu_reset_scratch(dynarec_arm_t* dyn);
|
||||
// Get an x87 double reg
|
||||
int fpu_get_reg_x87(dynarec_arm_t* dyn, int t, int n);
|
||||
// Get an MMX double reg
|
||||
int fpu_get_reg_emm(dynarec_arm_t* dyn, int emm);
|
||||
// Get an XMM quad reg
|
||||
int fpu_get_reg_xmm(dynarec_arm_t* dyn, int t, int xmm);
|
||||
// Free a FPU/MMX/XMM reg
|
||||
void fpu_free_reg(dynarec_arm_t* dyn, int reg);
|
||||
// Reset fpu regs counter
|
||||
void fpu_reset_reg(dynarec_arm_t* dyn);
|
||||
|
||||
// ---- Neon cache functions
|
||||
// Get type for STx
|
||||
int neoncache_get_st(dynarec_arm_t* dyn, int ninst, int a);
|
||||
// Get if STx is FLOAT or DOUBLE
|
||||
int neoncache_get_st_f(dynarec_arm_t* dyn, int ninst, int a);
|
||||
// Get actual type for STx
|
||||
int neoncache_get_current_st(dynarec_arm_t* dyn, int ninst, int a);
|
||||
// Get actual STx is FLOAT or DOUBLE
|
||||
int neoncache_get_current_st_f(dynarec_arm_t* dyn, int a);
|
||||
// Back-propagate a change float->double
|
||||
void neoncache_promote_double(dynarec_arm_t* dyn, int ninst, int a);
|
||||
// Combine and propagate if needed (pass 1 only)
|
||||
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 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);
|
||||
|
||||
// is inst clean for a son branch?
|
||||
int isInstClean(dynarec_arm_t* dyn, int ninst);
|
||||
|
||||
// predecessor access
|
||||
int isPred(dynarec_arm_t* dyn, int ninst, int pred);
|
||||
int getNominalPred(dynarec_arm_t* dyn, int ninst);
|
||||
|
||||
// Get if ED will have the correct parity. Not emiting anything. Parity is 2 for DWORD or 3 for QWORD
|
||||
int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity, int delta);
|
||||
// Do the GETED, but don't emit anything...
|
||||
uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop);
|
||||
|
||||
// Is what pointed at addr a native call? And if yes, to what function?
|
||||
int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn);
|
||||
|
||||
const char* getCacheName(int t, int n);
|
||||
|
||||
#endif //__DYNAREC_ARM_FUNCTIONS_H__
|
||||
Executable
+1755
File diff suppressed because it is too large.
Load diff
Executable
+1298
File diff suppressed because it is too large.
Load diff
@@ -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);
|
||||
}
|
||||
Executable
+53
@@ -0,0 +1,53 @@
|
||||
|
||||
#define INIT uintptr_t sav_addr=addr
|
||||
#define FINI \
|
||||
dyn->isize = addr-sav_addr; \
|
||||
dyn->insts[ninst].x64.addr = addr; \
|
||||
if(ninst) dyn->insts[ninst-1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst-1].x64.addr
|
||||
|
||||
#define MESSAGE(A, ...)
|
||||
#define 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; \
|
||||
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
|
||||
#define BARRIER_NEXT(A) dyn->insts[ninst+1].x64.barrier = A
|
||||
#define NEW_INST \
|
||||
++dyn->size; \
|
||||
if(dyn->size+3>=dyn->cap) { \
|
||||
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; \
|
||||
} \
|
||||
dyn->insts[ninst].x64.addr = ip; \
|
||||
dyn->n.combined1 = dyn->n.combined2 = 0;\
|
||||
dyn->n.swapped = 0; dyn->n.barrier = 0; \
|
||||
dyn->insts[ninst].f_entry = dyn->f; \
|
||||
if(ninst) {dyn->insts[ninst-1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst-1].x64.addr;}
|
||||
|
||||
#define INST_EPILOG \
|
||||
dyn->insts[ninst].f_exit = dyn->f; \
|
||||
dyn->insts[ninst].n = dyn->n; \
|
||||
dyn->insts[ninst].x64.has_next = (ok>0)?1:0;
|
||||
#define INST_NAME(name)
|
||||
#define DEFAULT \
|
||||
--dyn->size; \
|
||||
*ok = -1; \
|
||||
if(box64_dynarec_log>=LOG_INFO) {\
|
||||
dynarec_log(LOG_NONE, "%p: Dynarec stopped because of Opcode %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", \
|
||||
(void*)ip, PKip(0), \
|
||||
PKip(1), PKip(2), PKip(3), \
|
||||
PKip(4), PKip(5), PKip(6), \
|
||||
PKip(7), PKip(8), PKip(9), \
|
||||
PKip(10),PKip(11),PKip(12), \
|
||||
PKip(13),PKip(14)); \
|
||||
printFunctionAddr(ip, " => "); \
|
||||
dynarec_log(LOG_NONE, "\n"); \
|
||||
}
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
#define INIT
|
||||
#define FINI
|
||||
#define MESSAGE(A, ...)
|
||||
#define EMIT(A)
|
||||
#define NEW_INST \
|
||||
dyn->insts[ninst].f_entry = dyn->f; \
|
||||
dyn->n.combined1 = dyn->n.combined2 = 0;\
|
||||
dyn->n.swapped = 0; dyn->n.barrier = 0
|
||||
|
||||
#define INST_EPILOG \
|
||||
dyn->insts[ninst].n = dyn->n; \
|
||||
dyn->insts[ninst].f_exit = dyn->f
|
||||
|
||||
#define INST_NAME(name)
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#define INIT dyn->native_size = 0
|
||||
#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(isInstClean(dyn, ninst) && dyn->last_ip!=ip) \
|
||||
dyn->last_ip = 0; \
|
||||
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)
|
||||
#define TABLE64(A, V) {Table64(dyn, (V)); EMIT(0);}
|
||||
#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; Table64(dyn, v.q); EMIT(0);}
|
||||
Executable
+70
@@ -0,0 +1,70 @@
|
||||
#define INIT
|
||||
#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); \
|
||||
dyn->block += 4; dyn->native_size += 4; \
|
||||
dyn->insts[ninst].size2 += 4
|
||||
|
||||
#define MESSAGE(A, ...) if(box64_dynarec_dump) dynarec_log(LOG_NONE, __VA_ARGS__)
|
||||
#define NEW_INST \
|
||||
if(ninst && isInstClean(dyn, ninst)) { \
|
||||
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), %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, \
|
||||
ninst, \
|
||||
dyn->insts[ninst].x64.barrier, \
|
||||
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_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)\
|
||||
dynarec_log(LOG_NONE, "%s%d", ii?"/":"", dyn->insts[ninst].pred[ii]);\
|
||||
} \
|
||||
if(dyn->insts[ninst].x64.jmp && dyn->insts[ninst].x64.jmp_insts>=0)\
|
||||
dynarec_log(LOG_NONE, ", jmp=%d", dyn->insts[ninst].x64.jmp_insts);\
|
||||
if(dyn->insts[ninst].x64.jmp && dyn->insts[ninst].x64.jmp_insts==-1)\
|
||||
dynarec_log(LOG_NONE, ", jmp=out"); \
|
||||
if(dyn->last_ip) \
|
||||
dynarec_log(LOG_NONE, ", last_ip=%p", (void*)dyn->last_ip);\
|
||||
for(int ii=0; ii<24; ++ii) { \
|
||||
switch(dyn->insts[ninst].n.neoncache[ii].t) { \
|
||||
case NEON_CACHE_ST_D: dynarec_log(LOG_NONE, " D%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break; \
|
||||
case NEON_CACHE_ST_F: dynarec_log(LOG_NONE, " S%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break; \
|
||||
case NEON_CACHE_MM: dynarec_log(LOG_NONE, " D%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break; \
|
||||
case NEON_CACHE_XMMW: dynarec_log(LOG_NONE, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break; \
|
||||
case NEON_CACHE_XMMR: dynarec_log(LOG_NONE, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break; \
|
||||
case NEON_CACHE_SCR: dynarec_log(LOG_NONE, " D%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break; \
|
||||
case NEON_CACHE_NONE: \
|
||||
default: break; \
|
||||
} \
|
||||
} \
|
||||
if(dyn->n.stack || dyn->insts[ninst].n.stack_next || dyn->insts[ninst].n.x87stack) \
|
||||
dynarec_log(LOG_NONE, " X87:%d/%d(+%d/-%d)%d", dyn->n.stack, dyn->insts[ninst].n.stack_next, dyn->insts[ninst].n.stack_push, dyn->insts[ninst].n.stack_pop, dyn->insts[ninst].n.x87stack); \
|
||||
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) \
|
||||
dynarec_log(LOG_NONE, " %s:%d/%d", dyn->insts[ninst].n.swapped?"SWP":"CMB", dyn->insts[ninst].n.combined1, dyn->insts[ninst].n.combined2); \
|
||||
dynarec_log(LOG_NONE, "%s\n", (box64_dynarec_dump>1)?"\e[m":""); \
|
||||
}
|
||||
|
||||
#define TABLE64(A, V) {int val64offset = Table64(dyn, (V)); MESSAGE(LOG_DUMP, " Table64: 0x%lx\n", (V)); LDRx_literal(A, val64offset);}
|
||||
#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; int val64offset = Table64(dyn, v.q); MESSAGE(LOG_DUMP, " FTable64: %g\n", v.d); VLDR64_literal(A, val64offset);}
|
||||
Executable
+132
@@ -0,0 +1,132 @@
|
||||
#ifndef __DYNAREC_ARM_PRIVATE_H_
|
||||
#define __DYNAREC_ARM_PRIVATE_H_
|
||||
|
||||
#include "../dynarec_private.h"
|
||||
|
||||
typedef struct x64emu_s x64emu_t;
|
||||
typedef struct dynablock_s dynablock_t;
|
||||
typedef struct instsize_s instsize_t;
|
||||
|
||||
#define BARRIER_MAYBE 8
|
||||
|
||||
#define NEON_CACHE_NONE 0
|
||||
#define NEON_CACHE_ST_D 1
|
||||
#define NEON_CACHE_ST_F 2
|
||||
#define NEON_CACHE_MM 3
|
||||
#define NEON_CACHE_XMMW 4
|
||||
#define NEON_CACHE_XMMR 5
|
||||
#define NEON_CACHE_SCR 6
|
||||
typedef union neon_cache_s {
|
||||
int8_t v;
|
||||
struct {
|
||||
uint8_t t:4; // reg type
|
||||
uint8_t n:4; // reg number
|
||||
};
|
||||
} neon_cache_t;
|
||||
typedef union sse_cache_s {
|
||||
int8_t v;
|
||||
struct {
|
||||
uint8_t reg:7;
|
||||
uint8_t write:1;
|
||||
};
|
||||
} sse_cache_t;
|
||||
typedef struct neoncache_s {
|
||||
// Neon cache
|
||||
neon_cache_t neoncache[24];
|
||||
int8_t stack;
|
||||
int8_t stack_next;
|
||||
int8_t stack_pop;
|
||||
int8_t stack_push;
|
||||
uint8_t combined1;
|
||||
uint8_t combined2;
|
||||
uint8_t swapped; // the combined reg were swapped
|
||||
uint8_t barrier; // is there a barrier at instruction epilog?
|
||||
uint32_t news; // bitmask, wich neoncache are new for this opcode
|
||||
// fpu cache
|
||||
int8_t x87cache[8]; // cache status for the 8 x87 register behind the fpu stack
|
||||
int8_t x87reg[8]; // reg used for x87cache entry
|
||||
int8_t mmxcache[8]; // cache status for the 8 MMX registers
|
||||
sse_cache_t ssecache[16]; // cache status for the 16 SSE(2) registers
|
||||
int8_t fpuused[24]; // all 0..24 double reg from fpu, used by x87, sse and mmx
|
||||
int8_t x87stack; // cache stack counter
|
||||
int8_t mmxcount; // number of mmx register used (not both mmx and x87 at the same time)
|
||||
int8_t fpu_scratch; // scratch counter
|
||||
int8_t fpu_extra_qscratch; // some opcode need an extra quad scratch register
|
||||
int8_t fpu_reg; // x87/sse/mmx reg counter
|
||||
} neoncache_t;
|
||||
|
||||
typedef struct flagcache_s {
|
||||
int pending; // is there a pending flags here, or to check?
|
||||
int dfnone; // if defered flags is already set to df_none
|
||||
} flagcache_t;
|
||||
|
||||
typedef struct instruction_arm64_s {
|
||||
instruction_x64_t x64;
|
||||
uintptr_t address; // (start) address of the arm emited instruction
|
||||
uintptr_t epilog; // epilog of current instruction (can be start of next, or barrier stuff)
|
||||
int size; // size of the arm emited instruction
|
||||
int size2; // size of the arm emited instrucion after pass2
|
||||
int pred_sz; // size of predecessor list
|
||||
int *pred; // predecessor array
|
||||
uintptr_t mark, mark2, mark3;
|
||||
uintptr_t markf;
|
||||
uintptr_t markseg;
|
||||
uintptr_t marklock;
|
||||
int pass2choice;// value for choices that are fixed on pass2 for pass3
|
||||
uintptr_t natcall;
|
||||
int retn;
|
||||
int barrier_maybe;
|
||||
flagcache_t f_exit; // flags status at end of intruction
|
||||
neoncache_t n; // neoncache at end of intruction (but before poping)
|
||||
flagcache_t f_entry; // flags status before the instruction begin
|
||||
} instruction_arm64_t;
|
||||
|
||||
typedef struct dynarec_arm_s {
|
||||
instruction_arm64_t*insts;
|
||||
int32_t size;
|
||||
int32_t cap;
|
||||
uintptr_t start; // start of the block
|
||||
uint32_t isize; // size in byte of x64 instructions included
|
||||
void* block; // memory pointer where next instruction is emited
|
||||
uintptr_t 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
|
||||
int table64size;// size of table (will be appended at end of executable code)
|
||||
int table64cap;
|
||||
uintptr_t tablestart;
|
||||
flagcache_t f;
|
||||
neoncache_t n; // cache for the 8..31 double reg from fpu, plus x87 stack delta
|
||||
uintptr_t* next; // variable array of "next" jump address
|
||||
int next_sz;
|
||||
int next_cap;
|
||||
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);
|
||||
uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr);
|
||||
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n);
|
||||
int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n);
|
||||
|
||||
int Table64(dynarec_arm_t *dyn, uint64_t val); // add a value to etable64 (if needed) and gives back the imm19 to use in LDR_literal
|
||||
|
||||
void CreateJmpNext(void* addr, void* next);
|
||||
|
||||
#define GO_TRACE() \
|
||||
GETIP_(ip); \
|
||||
MOVx_REG(x1, xRIP); \
|
||||
STORE_XEMU_CALL(xRIP); \
|
||||
MOV32w(x2, 1); \
|
||||
CALL(PrintTrace, -1); \
|
||||
LOAD_XEMU_CALL(xRIP)
|
||||
|
||||
#endif //__DYNAREC_ARM_PRIVATE_H_
|
||||
Executable
+271
@@ -0,0 +1,271 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <setjmp.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "tools/bridge_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynablock.h"
|
||||
#include "dynablock_private.h"
|
||||
#include "dynarec_private.h"
|
||||
#include "elfloader.h"
|
||||
#include "bridge.h"
|
||||
|
||||
#include "dynarec_native.h"
|
||||
#include "native_lock.h"
|
||||
|
||||
#include "custommem.h"
|
||||
#include "khash.h"
|
||||
|
||||
uint32_t X31_hash_code(void* addr, int len)
|
||||
{
|
||||
if(!len) return 0;
|
||||
uint8_t* p = (uint8_t*)addr;
|
||||
int32_t h = *p;
|
||||
for (--len, ++p; len; --len, ++p) h = (h << 5) - h + (int32_t)*p;
|
||||
return (uint32_t)h;
|
||||
}
|
||||
|
||||
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 already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size-1, db->gone);
|
||||
if(need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
// remove jumptable
|
||||
setJumpTableDefault64(db->x64_addr);
|
||||
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)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
}
|
||||
|
||||
void MarkDynablock(dynablock_t* db)
|
||||
{
|
||||
if(db) {
|
||||
if(db->need_test)
|
||||
return; // already done
|
||||
dynarec_log(LOG_DEBUG, "MarkDynablock %p %p-%p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1);
|
||||
db->need_test = 1;
|
||||
setJumpTableIfRef64(db->x64_addr, db->jmpnext, db->block);
|
||||
}
|
||||
}
|
||||
|
||||
static int IntervalIntersects(uintptr_t start1, uintptr_t end1, uintptr_t start2, uintptr_t end2)
|
||||
{
|
||||
if(start1 > end2 || start2 > end1)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int MarkedDynablock(dynablock_t* db)
|
||||
{
|
||||
if(db) {
|
||||
if(db->need_test)
|
||||
return 1; // already done
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MarkRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
// 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
dynablock_t *AddNewDynablock(uintptr_t addr)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
#endif
|
||||
// create and add new block
|
||||
dynarec_log(LOG_VERBOSE, "Ask for DynaRec Block creation @%p\n", (void*)addr);
|
||||
block = (dynablock_t*)customCalloc(1, sizeof(dynablock_t));
|
||||
return block;
|
||||
}
|
||||
|
||||
//TODO: move this to dynrec_arm.c and track allocated structure to avoid memory leak
|
||||
static __thread struct __jmp_buf_tag dynarec_jmpbuf;
|
||||
|
||||
void cancelFillBlock()
|
||||
{
|
||||
longjmp(&dynarec_jmpbuf, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
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, int need_lock)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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(sigsetjmp(&dynarec_jmpbuf, 1)) {
|
||||
printf_log(LOG_INFO, "FillBlock at %p triggered a segfault, cancelling\n", (void*)addr);
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
return NULL;
|
||||
}
|
||||
void* ret = FillBlock64(block, filladdr);
|
||||
if(!ret) {
|
||||
dynarec_log(LOG_DEBUG, "Fillblock of block %p for %p returned an error\n", block, (void*)addr);
|
||||
customFree(block);
|
||||
block = NULL;
|
||||
}
|
||||
// check size
|
||||
if(block && (block->x64_size || (!block->x64_size && !block->done))) {
|
||||
int blocksz = block->x64_size;
|
||||
if(blocksz>my_context->max_db_size)
|
||||
my_context->max_db_size = blocksz;
|
||||
// fill-in jumptable
|
||||
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
|
||||
}
|
||||
}
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create)
|
||||
{
|
||||
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(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, 0);
|
||||
} else {
|
||||
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
|
||||
setJumpTableIfRef64(db->x64_addr, db->block, db->jmpnext);
|
||||
}
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
return db;
|
||||
}
|
||||
|
||||
dynablock_t* DBAlternateBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "Creating AlternateBlock at %p for %p\n", (void*)addr, (void*)filladdr);
|
||||
int create = 1;
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, 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(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, 0);
|
||||
} else {
|
||||
db->need_test = 0;
|
||||
protectDB((uintptr_t)db->x64_addr, db->x64_size);
|
||||
// fill back jumptable
|
||||
addJumpTableIfDefault64(db->x64_addr, db->block);
|
||||
}
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
return db;
|
||||
}
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
#ifndef __DYNABLOCK_PRIVATE_H_
|
||||
#define __DYNABLOCK_PRIVATE_H_
|
||||
|
||||
typedef struct instsize_s {
|
||||
unsigned char x64:4;
|
||||
unsigned char nat:4;
|
||||
} instsize_t;
|
||||
|
||||
typedef struct dynablock_s {
|
||||
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;
|
||||
uint32_t hash;
|
||||
uint8_t need_test;
|
||||
uint8_t done;
|
||||
uint8_t gone;
|
||||
uint8_t dummy;
|
||||
int isize;
|
||||
instsize_t* instsize;
|
||||
void* jmpnext; // a branch jmpnext code when block is marked
|
||||
} dynablock_t;
|
||||
|
||||
#endif //__DYNABLOCK_PRIVATE_H_
|
||||
+56
-48
@@ -19,51 +19,65 @@
|
||||
#ifdef DYNAREC
|
||||
#include "dynablock.h"
|
||||
#include "dynablock_private.h"
|
||||
#include "bridge.h"
|
||||
#include "dynarec_next.h"
|
||||
#endif
|
||||
|
||||
#ifdef DYNAREC
|
||||
#ifdef ARM
|
||||
void arm_prolog(x64emu_t* emu, void* addr) EXPORTDYN;
|
||||
void arm_epilog() EXPORTDYN;
|
||||
void arm_epilog_fast() EXPORTDYN;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef DYNAREC
|
||||
#ifdef HAVE_TRACE
|
||||
uintptr_t getX64Address(dynablock_t* db, uintptr_t arm_addr);
|
||||
#include "elfloader.h"
|
||||
#endif
|
||||
void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2)
|
||||
|
||||
#ifdef DYNAREC
|
||||
uintptr_t getX64Address(dynablock_t* db, uintptr_t arm_addr);
|
||||
|
||||
void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3)
|
||||
{
|
||||
#ifdef HAVE_TRACE
|
||||
if(!addr) {
|
||||
x2-=8; // actual PC is 2 instructions ahead
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2);
|
||||
printf_log(LOG_NONE, "Warning, jumping to NULL address from %p (db=%p, x86addr=%p)\n", x2, db, db?(void*)getX86Address(db, (uintptr_t)x2):NULL);
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
|
||||
printf_log(LOG_NONE, "Warning, jumping to NULL address from %p (db=%p, x64addr=%p/%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...
|
||||
//tableupdate(arm_epilog, addr, table);
|
||||
return arm_epilog;
|
||||
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);
|
||||
}
|
||||
if(!block) {
|
||||
#ifdef HAVE_TRACE
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
|
||||
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;
|
||||
}
|
||||
}
|
||||
if(!block->done) {
|
||||
// not finished yet... leave linker
|
||||
//tableupdate(arm_linker, addr, table);
|
||||
return arm_epilog;
|
||||
return native_epilog;
|
||||
}
|
||||
if(!(jblock=block->block)) {
|
||||
// null block, but done: go to epilog, no linker here
|
||||
return arm_epilog;
|
||||
return native_epilog;
|
||||
}
|
||||
//dynablock_t *father = block->father?block->father:block;
|
||||
return jblock;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
// Disable "clobbered" warnings
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wclobbered"
|
||||
#endif
|
||||
void DynaCall(x64emu_t* emu, uintptr_t addr)
|
||||
{
|
||||
// prepare setjump for signal handling
|
||||
@@ -75,14 +89,14 @@ void DynaCall(x64emu_t* emu, uintptr_t addr)
|
||||
ejb->emu = emu;
|
||||
ejb->jmpbuf_ok = 1;
|
||||
jmpbuf_reset = 1;
|
||||
if(setjmp((struct __jmp_buf_tag*)ejb->jmpbuf)) {
|
||||
if(sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1)) {
|
||||
printf_log(LOG_DEBUG, "Setjmp DynaCall, fs=0x%x\n", ejb->emu->segs[_FS]);
|
||||
addr = R_RIP; // not sure if it should still be inside DynaCall!
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef DYNAREC
|
||||
if(!box86_dynarec)
|
||||
if(!box64_dynarec)
|
||||
#endif
|
||||
EmuCall(emu, addr);
|
||||
#ifdef DYNAREC
|
||||
@@ -96,35 +110,30 @@ void DynaCall(x64emu_t* emu, uintptr_t addr)
|
||||
PushExit(emu);
|
||||
R_RIP = addr;
|
||||
emu->df = d_none;
|
||||
dynablock_t* block = NULL;
|
||||
dynablock_t* current = NULL;
|
||||
while(!emu->quit) {
|
||||
block = DBGetBlock(emu, R_RIP, 1, ¤t);
|
||||
current = block;
|
||||
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);
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling DynaRec Block @%p (%p) of %d x86 instructions (father=%p) emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize ,block->father, emu);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling DynaRec Block @%p (%p) of %d x64 instructions emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize ,emu);
|
||||
CHECK_FLAGS(emu);
|
||||
// block is here, let's run it!
|
||||
#ifdef ARM
|
||||
arm_prolog(emu, block->block);
|
||||
#endif
|
||||
native_prolog(emu, block->block);
|
||||
}
|
||||
if(emu->fork) {
|
||||
int forktype = emu->fork;
|
||||
emu->quit = 0;
|
||||
emu->fork = 0;
|
||||
emu = x86emu_fork(emu, forktype);
|
||||
emu = x64emu_fork(emu, forktype);
|
||||
if(emu->type == EMUTYPE_MAIN) {
|
||||
ejb = GetJmpBuf();
|
||||
ejb->emu = emu;
|
||||
ejb->jmpbuf_ok = 1;
|
||||
jmpbuf_reset = 1;
|
||||
if(setjmp((struct __jmp_buf_tag*)ejb->jmpbuf)) {
|
||||
if(sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1)) {
|
||||
printf_log(LOG_DEBUG, "Setjmp inner DynaCall, fs=0x%x\n", ejb->emu->segs[_FS]);
|
||||
addr = R_RIP;
|
||||
}
|
||||
@@ -134,7 +143,8 @@ void DynaCall(x64emu_t* emu, uintptr_t addr)
|
||||
emu->quit = 0; // reset Quit flags...
|
||||
emu->df = d_none;
|
||||
if(emu->quitonlongjmp && emu->longjmp) {
|
||||
emu->longjmp = 0; // don't change anything because of the longjmp
|
||||
if(emu->quitonlongjmp==1)
|
||||
emu->longjmp = 0; // don't change anything because of the longjmp
|
||||
} else {
|
||||
R_RBX = old_rbx;
|
||||
R_RDI = old_rdi;
|
||||
@@ -165,44 +175,39 @@ int DynaRun(x64emu_t* emu)
|
||||
#ifdef DYNAREC
|
||||
jmpbuf_reset = 1;
|
||||
#endif
|
||||
if(setjmp((struct __jmp_buf_tag*)ejb->jmpbuf))
|
||||
if(sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))
|
||||
printf_log(LOG_DEBUG, "Setjmp DynaRun, fs=0x%x\n", ejb->emu->segs[_FS]);
|
||||
}
|
||||
}
|
||||
#ifdef DYNAREC
|
||||
if(!box86_dynarec)
|
||||
if(!box64_dynarec)
|
||||
#endif
|
||||
return Run(emu, 0);
|
||||
#ifdef DYNAREC
|
||||
else {
|
||||
dynablock_t* block = NULL;
|
||||
dynablock_t* current = NULL;
|
||||
while(!emu->quit) {
|
||||
block = DBGetBlock(emu, R_RIP, 1, ¤t);
|
||||
current = block;
|
||||
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);
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x86 insts (father=%p) emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize, block->father, emu);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x64 insts emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize, emu);
|
||||
// block is here, let's run it!
|
||||
#ifdef ARM
|
||||
arm_prolog(emu, block->block);
|
||||
#endif
|
||||
native_prolog(emu, block->block);
|
||||
}
|
||||
if(emu->fork) {
|
||||
int forktype = emu->fork;
|
||||
emu->quit = 0;
|
||||
emu->fork = 0;
|
||||
emu = x86emu_fork(emu, forktype);
|
||||
emu = x64emu_fork(emu, forktype);
|
||||
if(emu->type == EMUTYPE_MAIN) {
|
||||
ejb = GetJmpBuf();
|
||||
ejb->emu = emu;
|
||||
ejb->jmpbuf_ok = 1;
|
||||
jmpbuf_reset = 1;
|
||||
if(setjmp((struct __jmp_buf_tag*)ejb->jmpbuf))
|
||||
if(sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))
|
||||
printf_log(LOG_DEBUG, "Setjmp inner DynaRun, fs=0x%x\n", ejb->emu->segs[_FS]);
|
||||
}
|
||||
}
|
||||
@@ -213,4 +218,7 @@ int DynaRun(x64emu_t* emu)
|
||||
ejb->jmpbuf_ok = 0;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
#ifndef __DYNAREC_ARCH__H_
|
||||
#define __DYNAREC_ARCH__H_
|
||||
|
||||
#ifdef ARM64
|
||||
#include "arm64/arm64_printer.h"
|
||||
#include "arm64/dynarec_arm64_private.h"
|
||||
#include "arm64/dynarec_arm64_functions.h"
|
||||
|
||||
#define instruction_native_t instruction_arm64_t
|
||||
#define dynarec_native_t dynarec_arm_t
|
||||
|
||||
#elif defined(LA464)
|
||||
#include "la464/la464_printer.h"
|
||||
#include "la464/dynarec_la464_private.h"
|
||||
#include "la464/dynarec_la464_functions.h"
|
||||
|
||||
#define instruction_native_t instruction_la464_t
|
||||
#define dynarec_native_t dynarec_la464_t
|
||||
|
||||
|
||||
#else
|
||||
#error Unsupported platform
|
||||
#endif
|
||||
|
||||
#endif //__DYNAREC_ARCH__H_
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#ifndef __DYNAREC_HELPER__H_
|
||||
#define __DYNAREC_HELPER__H_
|
||||
|
||||
#ifdef ARM64
|
||||
#include "arm64/dynarec_arm64_helper.h"
|
||||
#elif defined(LA464)
|
||||
#include "la464/dynarec_la464_helper.h"
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
|
||||
#endif //__DYNAREC_HELPER__H_
|
||||
Executable
+608
@@ -0,0 +1,608 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "custommem.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "tools/bridge_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynablock.h"
|
||||
#include "dynablock_private.h"
|
||||
#include "elfloader.h"
|
||||
|
||||
#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[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[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[01;33m":"", ip, DecodeX64Trace(dec, inst->addr));
|
||||
} else {
|
||||
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]);
|
||||
}
|
||||
dynarec_log(LOG_NONE, " %s", name);
|
||||
}
|
||||
// print Call function name if possible
|
||||
if(ip[0]==0xE8 || ip[0]==0xE9) { // Call / Jmp
|
||||
uintptr_t nextaddr = (uintptr_t)ip + 5 + *((int32_t*)(ip+1));
|
||||
printFunctionAddr(nextaddr, "=> ");
|
||||
} else if(ip[0]==0xFF) {
|
||||
if(ip[1]==0x25) {
|
||||
uintptr_t nextaddr = (uintptr_t)ip + 6 + *((int32_t*)(ip+2));
|
||||
printFunctionAddr(nextaddr, "=> ");
|
||||
}
|
||||
}
|
||||
// end of line and colors
|
||||
dynarec_log(LOG_NONE, "%s\n", (box64_dynarec_dump>1)?"\e[m":"");
|
||||
}
|
||||
}
|
||||
|
||||
void add_next(dynarec_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 += 64;
|
||||
dyn->next = (uintptr_t*)customRealloc(dyn->next, dyn->next_cap*sizeof(uintptr_t));
|
||||
}
|
||||
dyn->next[dyn->next_sz++] = addr;
|
||||
}
|
||||
uintptr_t get_closest_next(dynarec_native_t *dyn, uintptr_t addr) {
|
||||
// get closest, but no addresses befores
|
||||
uintptr_t best = 0;
|
||||
int i = 0;
|
||||
while((i<dyn->next_sz) && (best!=addr)) {
|
||||
if(dyn->next[i]<addr) { // remove the address, it's before current address
|
||||
dyn->next[i] = 0;
|
||||
} else {
|
||||
if((dyn->next[i]<best) || !best)
|
||||
best = dyn->next[i];
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return best;
|
||||
}
|
||||
#define PK(A) (*((uint8_t*)(addr+(A))))
|
||||
int is_nops(dynarec_native_t *dyn, uintptr_t addr, int n)
|
||||
{
|
||||
if(!n)
|
||||
return 1;
|
||||
if(PK(0)==0x90)
|
||||
return is_nops(dyn, addr+1, n-1);
|
||||
if(n>1 && PK(0)==0x66) // if opcode start with 0x66, and there is more after, than is *can* be a NOP
|
||||
return is_nops(dyn, addr+1, n-1);
|
||||
if(n>2 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x00)
|
||||
return is_nops(dyn, addr+3, n-3);
|
||||
if(n>2 && PK(0)==0x8d && PK(1)==0x76 && PK(2)==0x00) // lea esi, [esi]
|
||||
return is_nops(dyn, addr+3, n-3);
|
||||
if(n>3 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x40 && PK(3)==0x00)
|
||||
return is_nops(dyn, addr+4, n-4);
|
||||
if(n>3 && PK(0)==0x8d && PK(1)==0x74 && PK(2)==0x26 && PK(3)==0x00)
|
||||
return is_nops(dyn, addr+4, n-4);
|
||||
if(n>4 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x44 && PK(3)==0x00 && PK(4)==0x00)
|
||||
return is_nops(dyn, addr+5, n-5);
|
||||
if(n>5 && PK(0)==0x8d && PK(1)==0xb6 && PK(2)==0x00 && PK(3)==0x00 && PK(4)==0x00 && PK(5)==0x00)
|
||||
return is_nops(dyn, addr+6, n-6);
|
||||
if(n>6 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x80 && PK(3)==0x00 && PK(4)==0x00 && PK(5)==0x00 && PK(6)==0x00)
|
||||
return is_nops(dyn, addr+7, n-7);
|
||||
if(n>6 && PK(0)==0x8d && PK(1)==0xb4 && PK(2)==0x26 && PK(3)==0x00 && PK(4)==0x00 && PK(5)==0x00 && PK(6)==0x00) // lea esi, [esi+0]
|
||||
return is_nops(dyn, addr+7, n-7);
|
||||
if(n>7 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x84 && PK(3)==0x00 && PK(4)==0x00 && PK(5)==0x00 && PK(6)==0x00 && PK(7)==0x00)
|
||||
return is_nops(dyn, addr+8, n-8);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return size of next instuciton, -1 is unknown
|
||||
// not all instrction are setup
|
||||
int next_instruction(dynarec_native_t *dyn, uintptr_t addr)
|
||||
{
|
||||
uint8_t opcode = PK(0);
|
||||
uint8_t nextop;
|
||||
switch (opcode) {
|
||||
case 0x66:
|
||||
opcode = PK(1);
|
||||
switch(opcode) {
|
||||
case 0x90:
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
case 0x81:
|
||||
nextop = PK(1);
|
||||
return fakeed(dyn, addr+2, 0, nextop)-addr + 4;
|
||||
case 0x83:
|
||||
nextop = PK(1);
|
||||
return fakeed(dyn, addr+2, 0, nextop)-addr + 1;
|
||||
case 0x84:
|
||||
case 0x85:
|
||||
case 0x88:
|
||||
case 0x89:
|
||||
case 0x8A:
|
||||
case 0x8B:
|
||||
case 0x8C:
|
||||
case 0x8D:
|
||||
case 0x8E:
|
||||
case 0x8F:
|
||||
nextop = PK(1);
|
||||
return fakeed(dyn, addr+2, 0, nextop)-addr;
|
||||
case 0x50:
|
||||
case 0x51:
|
||||
case 0x52:
|
||||
case 0x53:
|
||||
case 0x54:
|
||||
case 0x55:
|
||||
case 0x56:
|
||||
case 0x57:
|
||||
case 0x58:
|
||||
case 0x59:
|
||||
case 0x5A:
|
||||
case 0x5B:
|
||||
case 0x5C:
|
||||
case 0x5D:
|
||||
case 0x5E:
|
||||
case 0x5F:
|
||||
case 0x90:
|
||||
case 0x91:
|
||||
case 0x92:
|
||||
case 0x93:
|
||||
case 0x94:
|
||||
case 0x95:
|
||||
case 0x96:
|
||||
case 0x97:
|
||||
case 0x98:
|
||||
case 0x99:
|
||||
case 0x9B:
|
||||
case 0x9C:
|
||||
case 0x9D:
|
||||
case 0x9E:
|
||||
case 0x9F:
|
||||
return 1;
|
||||
case 0xA0:
|
||||
case 0xA1:
|
||||
case 0xA2:
|
||||
case 0xA3:
|
||||
return 5;
|
||||
case 0xB0:
|
||||
case 0xB1:
|
||||
case 0xB2:
|
||||
case 0xB3:
|
||||
case 0xB4:
|
||||
case 0xB5:
|
||||
case 0xB6:
|
||||
case 0xB7:
|
||||
return 2;
|
||||
case 0xB8:
|
||||
case 0xB9:
|
||||
case 0xBA:
|
||||
case 0xBB:
|
||||
case 0xBC:
|
||||
case 0xBD:
|
||||
case 0xBE:
|
||||
case 0xBF:
|
||||
return 5;
|
||||
case 0xFF:
|
||||
nextop = PK(1);
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: // INC Ed
|
||||
case 1: //DEC Ed
|
||||
case 2: // CALL Ed
|
||||
case 4: // JMP Ed
|
||||
case 6: // Push Ed
|
||||
return fakeed(dyn, addr+2, 0, nextop)-addr;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#undef PK
|
||||
|
||||
int is_instructions(dynarec_native_t *dyn, uintptr_t addr, int n)
|
||||
{
|
||||
int i = 0;
|
||||
while(i<n) {
|
||||
int j=next_instruction(dyn, addr+i);
|
||||
if(j<=0) return 0;
|
||||
i+=j;
|
||||
}
|
||||
return (i==n)?1:0;
|
||||
}
|
||||
|
||||
void addInst(instsize_t* insts, size_t* size, int x64_size, int native_size)
|
||||
{
|
||||
// x64 instruction is <16 bytes
|
||||
int toadd;
|
||||
if(x64_size>native_size)
|
||||
toadd = 1 + x64_size/15;
|
||||
else
|
||||
toadd = 1 + native_size/15;
|
||||
while(toadd) {
|
||||
if(x64_size>15)
|
||||
insts[*size].x64 = 15;
|
||||
else
|
||||
insts[*size].x64 = x64_size;
|
||||
x64_size -= insts[*size].x64;
|
||||
if(native_size>15)
|
||||
insts[*size].nat = 15;
|
||||
else
|
||||
insts[*size].nat = native_size;
|
||||
native_size -= insts[*size].nat;
|
||||
++(*size);
|
||||
--toadd;
|
||||
}
|
||||
}
|
||||
|
||||
// add a value to table64 (if needed) and gives back the imm19 to use in LDR_literal
|
||||
int Table64(dynarec_native_t *dyn, uint64_t val)
|
||||
{
|
||||
// find the value if already present
|
||||
int idx = -1;
|
||||
for(int i=0; i<dyn->table64size && (idx==-1); ++i)
|
||||
if(dyn->table64[i] == val)
|
||||
idx = i;
|
||||
// not found, add it
|
||||
if(idx==-1) {
|
||||
if(dyn->table64size == dyn->table64cap) {
|
||||
dyn->table64cap+=16;
|
||||
dyn->table64 = (uint64_t*)customRealloc(dyn->table64, dyn->table64cap * sizeof(uint64_t));
|
||||
}
|
||||
idx = dyn->table64size++;
|
||||
dyn->table64[idx] = val;
|
||||
}
|
||||
// calculate offset
|
||||
int delta = dyn->tablestart + idx*sizeof(uint64_t) - (uintptr_t)dyn->block;
|
||||
return delta;
|
||||
}
|
||||
|
||||
static void fillPredecessors(dynarec_native_t* dyn)
|
||||
{
|
||||
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++;
|
||||
}
|
||||
}
|
||||
// second the "has_next"
|
||||
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*)customMalloc(pred_sz*sizeof(int));
|
||||
// fill pred pointer
|
||||
int* p = dyn->predecessor;
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
dyn->insts[i].pred = p;
|
||||
p += dyn->insts[i].pred_sz;
|
||||
dyn->insts[i].pred_sz=0; // reset size, it's reused to actually fill pred[]
|
||||
}
|
||||
// fill pred
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
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)) {
|
||||
int j = dyn->insts[i].x64.jmp_insts;
|
||||
dyn->insts[j].pred[dyn->insts[j].pred_sz++] = i;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
return ninst;
|
||||
}
|
||||
|
||||
void* current_helper = NULL;
|
||||
|
||||
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(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
return;
|
||||
}
|
||||
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);
|
||||
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) {
|
||||
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);
|
||||
// init the helper
|
||||
dynarec_native_t helper = {0};
|
||||
current_helper = &helper;
|
||||
helper.dynablock = block;
|
||||
helper.start = addr;
|
||||
uintptr_t start = addr;
|
||||
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
|
||||
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(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);
|
||||
AddHotPage(addr);
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
// protect the block of it goes over the 1st page
|
||||
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);
|
||||
// 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 || j==helper.insts[i].x64.addr) {
|
||||
helper.insts[i].x64.jmp_insts = -1;
|
||||
helper.insts[i].x64.need_after |= X_PEND;
|
||||
} else {
|
||||
// find jump address instruction
|
||||
int k=-1;
|
||||
for(int i2=0; i2<helper.size && k==-1; ++i2) {
|
||||
if(helper.insts[i2].x64.addr==j)
|
||||
k=i2;
|
||||
}
|
||||
if(k!=-1 && !helper.insts[i].barrier_maybe)
|
||||
helper.insts[k].x64.barrier |= BARRIER_FULL;
|
||||
helper.insts[i].x64.jmp_insts = k;
|
||||
}
|
||||
}
|
||||
// fill predecessors with the jump address
|
||||
fillPredecessors(&helper);
|
||||
|
||||
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 = 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(0);
|
||||
return NULL;
|
||||
}
|
||||
helper.block = p;
|
||||
helper.native_start = (uintptr_t)p;
|
||||
helper.tablestart = helper.native_start + helper.native_size;
|
||||
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);
|
||||
printFunctionAddr(helper.start, " => ");
|
||||
dynarec_log(LOG_NONE, "%s\n", (box64_dynarec_dump>1)?"\e[m":"");
|
||||
}
|
||||
int oldtable64size = helper.table64size;
|
||||
size_t oldnativesize = helper.native_size;
|
||||
helper.native_size = 0;
|
||||
helper.table64size = 0; // reset table64 (but not the cap)
|
||||
native_pass3(&helper, addr);
|
||||
if((oldnativesize!=helper.native_size) || (oldtable64size<helper.table64size)) {
|
||||
printf_log(LOG_NONE, "BOX64: Warning, size difference in block between pass2 (%zu) & pass3 (%zu)!\n", sz, helper.native_size+helper.table64size*8);
|
||||
uint8_t *dump = (uint8_t*)helper.start;
|
||||
printf_log(LOG_NONE, "Dump of %d x64 opcodes:\n", helper.size);
|
||||
for(int i=0; i<helper.size; ++i) {
|
||||
printf_log(LOG_NONE, "%p:", dump);
|
||||
for(; dump<(uint8_t*)helper.insts[i+1].x64.addr; ++dump)
|
||||
printf_log(LOG_NONE, " %02X", *dump);
|
||||
printf_log(LOG_NONE, "\t%d -> %d\n", helper.insts[i].size2, helper.insts[i].size);
|
||||
}
|
||||
printf_log(LOG_NONE, "Table64 \t%d -> %d\n", oldtable64size*8, helper.table64size*8);
|
||||
printf_log(LOG_NONE, " ------------\n");
|
||||
//TODO: Cancel block and return empty one
|
||||
}
|
||||
// add table64 if needed
|
||||
if(helper.table64size) {
|
||||
memcpy((void*)helper.tablestart, helper.table64, helper.table64size*8);
|
||||
}
|
||||
// keep size of instructions for signal handling
|
||||
block->instsize = instsize;
|
||||
// ok, free the helper now
|
||||
customFree(helper.insts);
|
||||
helper.insts = NULL;
|
||||
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_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_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);
|
||||
}
|
||||
current_helper = NULL;
|
||||
//block->done = 1;
|
||||
return (void*)block;
|
||||
}
|
||||
Executable
+287
@@ -0,0 +1,287 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynablock.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "custommem.h"
|
||||
#include "elfloader.h"
|
||||
|
||||
#include "dynarec_arch.h"
|
||||
#include "dynarec_helper.h"
|
||||
|
||||
#ifndef STEP
|
||||
#error No STEP defined
|
||||
#endif
|
||||
|
||||
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;
|
||||
// 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) {
|
||||
ip = addr;
|
||||
if (reset_n!=-1) {
|
||||
dyn->last_ip = 0;
|
||||
if(reset_n==-2) {
|
||||
MESSAGE(LOG_DEBUG, "Reset Caches to zero\n");
|
||||
dyn->f.dfnone = 0;
|
||||
dyn->f.pending = 0;
|
||||
fpu_reset(dyn);
|
||||
} else {
|
||||
MESSAGE(LOG_DEBUG, "Reset Caches with %d\n",reset_n);
|
||||
#if STEP > 1
|
||||
// for STEP 2 & 3, just need to refrest with current, and undo the changes (push & swap)
|
||||
dyn->n = dyn->insts[ninst].n;
|
||||
neoncacheUnwind(&dyn->n);
|
||||
#ifdef HAVE_TRACE
|
||||
if(box64_dynarec_dump)
|
||||
if(memcmp(&dyn->n, &dyn->insts[reset_n].n, sizeof(neon_cache_t))) {
|
||||
MESSAGE(LOG_DEBUG, "Warning, difference in neoncache: reset=");
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->insts[reset_n].n.neoncache[i].v)
|
||||
MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->insts[reset_n].n.neoncache[i].t, dyn->insts[reset_n].n.neoncache[i].n));
|
||||
if(dyn->insts[reset_n].n.combined1 || dyn->insts[reset_n].n.combined2)
|
||||
MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->insts[reset_n].n.swapped?"SWP":"CMB", dyn->insts[reset_n].n.combined1, dyn->insts[reset_n].n.combined2);
|
||||
if(dyn->insts[reset_n].n.stack_push || dyn->insts[reset_n].n.stack_pop)
|
||||
MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->insts[reset_n].n.stack_push, -dyn->insts[reset_n].n.stack_pop);
|
||||
MESSAGE(LOG_DEBUG, " ==> ");
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->insts[ninst].n.neoncache[i].v)
|
||||
MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->insts[ninst].n.neoncache[i].t, dyn->insts[ninst].n.neoncache[i].n));
|
||||
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2)
|
||||
MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->insts[ninst].n.swapped?"SWP":"CMB", dyn->insts[ninst].n.combined1, dyn->insts[ninst].n.combined2);
|
||||
if(dyn->insts[ninst].n.stack_push || dyn->insts[ninst].n.stack_pop)
|
||||
MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->insts[ninst].n.stack_push, -dyn->insts[ninst].n.stack_pop);
|
||||
MESSAGE(LOG_DEBUG, " -> ");
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->n.neoncache[i].v)
|
||||
MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->n.neoncache[i].t, dyn->n.neoncache[i].n));
|
||||
if(dyn->n.combined1 || dyn->n.combined2)
|
||||
MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->n.swapped?"SWP":"CMB", dyn->n.combined1, dyn->n.combined2);
|
||||
if(dyn->n.stack_push || dyn->n.stack_pop)
|
||||
MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->n.stack_push, -dyn->n.stack_pop);
|
||||
MESSAGE(LOG_DEBUG, "\n");
|
||||
}
|
||||
#endif //HAVE_TRACE
|
||||
#else
|
||||
dyn->n = dyn->insts[reset_n].n;
|
||||
#endif
|
||||
dyn->f = dyn->insts[reset_n].f_exit;
|
||||
if(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT) {
|
||||
MESSAGE(LOG_DEBUG, "Apply Barrier Float\n");
|
||||
fpu_reset(dyn);
|
||||
}
|
||||
if(dyn->insts[ninst].x64.barrier&BARRIER_FLAGS) {
|
||||
MESSAGE(LOG_DEBUG, "Apply Barrier Flags\n");
|
||||
dyn->f.dfnone = 0;
|
||||
dyn->f.pending = 0;
|
||||
}
|
||||
}
|
||||
reset_n = -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) {
|
||||
for(int j=0; j<24; ++j)
|
||||
if((dyn->n.neoncache[j].t == NEON_CACHE_ST_D || dyn->n.neoncache[j].t == NEON_CACHE_ST_F)) {
|
||||
if(dyn->n.neoncache[j].n<dyn->n.stack_pop)
|
||||
dyn->n.neoncache[j].v = 0;
|
||||
else
|
||||
dyn->n.neoncache[j].n-=dyn->n.stack_pop;
|
||||
}
|
||||
dyn->n.stack_pop = 0;
|
||||
}
|
||||
dyn->n.stack = dyn->n.stack_next;
|
||||
dyn->n.news = 0;
|
||||
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)
|
||||
|| ((ip >= trace_start) && (ip < trace_end))) {
|
||||
MESSAGE(LOG_DUMP, "TRACE ----\n");
|
||||
fpu_reflectcache(dyn, ninst, x1, x2, x3);
|
||||
GO_TRACE();
|
||||
MESSAGE(LOG_DUMP, "----------\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
rep = 0;
|
||||
uint8_t pk = PK(0);
|
||||
while((pk==0xF2) || (pk==0xF3)) {
|
||||
rep = pk-0xF1;
|
||||
++addr;
|
||||
pk = PK(0);
|
||||
}
|
||||
while(pk==0x3E || pk==0x26) { //Branch Taken Hint ignored, same for ES: prefix
|
||||
++addr;
|
||||
pk = PK(0);
|
||||
}
|
||||
rex.rex = 0;
|
||||
while(pk>=0x40 && pk<=0x4f) {
|
||||
rex.rex = pk;
|
||||
++addr;
|
||||
pk = PK(0);
|
||||
}
|
||||
|
||||
addr = dynarec64_00(dyn, addr, ip, ninst, rex, rep, &ok, &need_epilog);
|
||||
|
||||
INST_EPILOG;
|
||||
|
||||
int next = ninst+1;
|
||||
#if STEP > 0
|
||||
if(!dyn->insts[ninst].x64.has_next && dyn->insts[ninst].x64.jmp && dyn->insts[ninst].x64.jmp_insts!=-1)
|
||||
next = dyn->insts[ninst].x64.jmp_insts;
|
||||
#endif
|
||||
if(dyn->insts[ninst].x64.has_next && dyn->insts[next].x64.barrier) {
|
||||
if(dyn->insts[next].x64.barrier&BARRIER_FLOAT)
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
if(dyn->insts[next].x64.barrier&BARRIER_FLAGS) {
|
||||
dyn->f.pending = 0;
|
||||
dyn->f.dfnone = 0;
|
||||
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;
|
||||
// we use the 1st predecessor here
|
||||
int ii = ninst+1;
|
||||
while(ii<dyn->size && !dyn->insts[ii].pred_sz)
|
||||
++ii;
|
||||
if((dyn->insts[ii].x64.barrier&BARRIER_FULL)==BARRIER_FULL)
|
||||
reset_n = -2; // hack to say Barrier!
|
||||
else {
|
||||
reset_n = getNominalPred(dyn, ii); // may get -1 if no predecessor are availble
|
||||
if(reset_n==-1) {
|
||||
reset_n = -2;
|
||||
MESSAGE(LOG_DEBUG, "Warning, Reset Caches mark not found\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
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 && (
|
||||
(((next-addr)<15) && is_nops(dyn, addr, next-addr))
|
||||
/*||(((next-addr)<30) && is_instructions(dyn, addr, next-addr))*/ ))
|
||||
{
|
||||
ok = 1;
|
||||
// need to find back that instruction to copy the caches, as previous version cannot be used anymore
|
||||
reset_n = -2;
|
||||
for(int ii=0; ii<ninst; ++ii)
|
||||
if(dyn->insts[ii].x64.jmp == next) {
|
||||
reset_n = ii;
|
||||
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)<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 && (((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);
|
||||
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
|
||||
dyn->insts[ninst].x64.need_after |= X_PEND;
|
||||
#endif
|
||||
++ninst;
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
jump_to_next(dyn, addr, 0, ninst);
|
||||
ok=0; need_epilog=0;
|
||||
}
|
||||
}
|
||||
if(need_epilog) {
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
jump_to_epilog(dyn, ip, 0, ninst); // no linker here, it's an unknow instruction
|
||||
}
|
||||
FINI;
|
||||
MESSAGE(LOG_DUMP, "---- END OF BLOCK ---- (%d)\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__
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
#ifndef __DYNAREC_PRIVATE_H_
|
||||
#define __DYNAREC_PRIVATE_H_
|
||||
|
||||
#define BARRIER_NONE 0
|
||||
#define BARRIER_FLAGS 1
|
||||
#define BARRIER_FLOAT 2
|
||||
#define BARRIER_FULL 3
|
||||
|
||||
// all flags for the use_flags field
|
||||
#define X_CF (1<<0)
|
||||
#define X_PF (1<<1)
|
||||
#define X_AF (1<<2)
|
||||
#define X_ZF (1<<3)
|
||||
#define X_SF (1<<4)
|
||||
#define X_OF (1<<5)
|
||||
#define X_ALL ((1<<6)-1)
|
||||
#define X_PEND (0x80)
|
||||
|
||||
// all state flags
|
||||
#define SF_UNKNOWN 0
|
||||
#define SF_SET 1
|
||||
#define SF_PENDING 2
|
||||
#define SF_SET_PENDING (SF_SET|SF_PENDING)
|
||||
#define SF_SUB 4
|
||||
#define SF_SUBSET (SF_SUB|SF_SET)
|
||||
#define SF_SUBSET_PENDING (SF_SUBSET|SF_PENDING)
|
||||
|
||||
typedef struct instruction_x64_s {
|
||||
uintptr_t addr; //address of the instruction
|
||||
int32_t size; // size of the instruction
|
||||
uintptr_t jmp; // offset to jump to, even if conditionnal (0 if not), no relative offset here
|
||||
int jmp_insts; // instuction to jump to (-1 if out of the block)
|
||||
uint8_t jmp_cond; // 1 of conditionnal jump
|
||||
uint8_t has_next; // does this opcode can continue to the next?
|
||||
uint8_t barrier; // next instruction is a jump point, so no optim allowed
|
||||
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 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);
|
||||
|
||||
#endif //__DYNAREC_PRIVATE_H_
|
||||
Executable
+34
@@ -0,0 +1,34 @@
|
||||
#ifndef __NATIVE_LOCK__H__
|
||||
#define __NATIVE_LOCK__H__
|
||||
|
||||
#ifdef ARM64
|
||||
#include "arm64/arm64_lock.h"
|
||||
|
||||
#define native_lock_read_b(A) arm64_lock_read_b(A)
|
||||
#define native_lock_write_b(A, B) arm64_lock_write_b(A, B)
|
||||
#define native_lock_read_h(A) arm64_lock_read_h(A)
|
||||
#define native_lock_write_h(A, B) arm64_lock_write_h(A, B)
|
||||
#define native_lock_read_d(A) arm64_lock_read_d(A)
|
||||
#define native_lock_write_d(A, B) arm64_lock_write_d(A, B)
|
||||
#define native_lock_read_dd(A) arm64_lock_read_dd(A)
|
||||
#define native_lock_write_dd(A, B) arm64_lock_write_dd(A, B)
|
||||
#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
|
||||
#endif
|
||||
|
||||
#endif //#define __NATIVE_LOCK__H__
|
||||
@@ -0,0 +1,721 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "elfloader_private.h"
|
||||
#include "elfdwarf_private.h"
|
||||
|
||||
typedef struct dwarf_unwind_constr_s {
|
||||
uint8_t reg_count;
|
||||
uint64_t *table;
|
||||
uint8_t *statuses;
|
||||
#define GET_STATUS(n,i) (((n).statuses[(i) >> 1] >> (((i) & 1) << 2)) & 0xF)
|
||||
#define SET_STATUS(n,i,v) (n).statuses[(i) >> 1] = ((n).statuses[(i) >> 1] & (0xF0 >> (((i) & 1) << 2))) | (v << (((i) & 1) << 2))
|
||||
#define REGSTATUS_undefined 0b0000
|
||||
#define REGSTATUS_same_val 0b0101
|
||||
#define REGSTATUS_offset 0b0010
|
||||
#define REGSTATUS_val_offset 0b0011
|
||||
#define REGSTATUS_register 0b0100
|
||||
} dwarf_unwind_constr_t;
|
||||
|
||||
#define DW_EH_PE_uptr 0x00
|
||||
#define DW_EH_PE_uleb128 0x01
|
||||
#define DW_EH_PE_udata2 0x02
|
||||
#define DW_EH_PE_udata4 0x03
|
||||
#define DW_EH_PE_udata8 0x04
|
||||
#define DW_EH_PE_SIZE_MASK 0x07
|
||||
#define DW_EH_PE_signed 0x08
|
||||
#define DW_EH_PE_absptr 0x00
|
||||
#define DW_EH_PE_pcrel 0x10
|
||||
#define DW_EH_PE_textrel 0x20 // Unsupported
|
||||
#define DW_EH_PE_datarel 0x30 // Unsupported
|
||||
#define DW_EH_PE_indirect 0x80 // May crash
|
||||
#define DW_EH_PE_omit 0xff
|
||||
|
||||
#define READ_U1(var, ptr) do { (var) = *( uint8_t*)(ptr); (ptr) += 1; } while (0)
|
||||
#define READ_S1(var, ptr) do { (var) = *( int8_t*)(ptr); (ptr) += 1; } while (0)
|
||||
#define READ_U2(var, ptr) do { (var) = *(uint16_t*)(ptr); (ptr) += 2; } while (0)
|
||||
#define READ_S2(var, ptr) do { (var) = *( int16_t*)(ptr); (ptr) += 2; } while (0)
|
||||
#define READ_U4(var, ptr) do { (var) = *(uint32_t*)(ptr); (ptr) += 4; } while (0)
|
||||
#define READ_S4(var, ptr) do { (var) = *( int32_t*)(ptr); (ptr) += 4; } while (0)
|
||||
#define READ_U8(var, ptr) do { (var) = *(uint64_t*)(ptr); (ptr) += 8; } while (0)
|
||||
#define READ_S8(var, ptr) do { (var) = *( int64_t*)(ptr); (ptr) += 8; } while (0)
|
||||
#define READ_ULEB128(var, ptr) readULEB(&(var), &(ptr))
|
||||
#define READ_SLEB128(var, ptr) readSLEB((int64_t*)&(var), &(ptr))
|
||||
// Seems like DW_EH_PE_signed is actually an invalid encoding
|
||||
#define READ_ENCODED(var, ptr, enc, isptr) do { uintptr_t optr = (uintptr_t)(ptr); \
|
||||
if ((((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_uleb128) && ((enc) & DW_EH_PE_signed)) READ_SLEB128(var, ptr); \
|
||||
else if ((((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_uleb128) && !((enc) & DW_EH_PE_signed)) READ_ULEB128(var, ptr); \
|
||||
else if ((((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_udata2 ) && ((enc) & DW_EH_PE_signed)) READ_S2 (var, ptr); \
|
||||
else if ((((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_udata2 ) && !((enc) & DW_EH_PE_signed)) READ_U2 (var, ptr); \
|
||||
else if ((((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_udata4 ) && ((enc) & DW_EH_PE_signed)) READ_S4 (var, ptr); \
|
||||
else if ((((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_udata4 ) && !((enc) & DW_EH_PE_signed)) READ_U4 (var, ptr); \
|
||||
else if ((((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_udata8 ) && ((enc) & DW_EH_PE_signed)) READ_S8 (var, ptr); \
|
||||
else if ((((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_udata8 ) && !((enc) & DW_EH_PE_signed)) READ_U8 (var, ptr); \
|
||||
else if ((((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_uptr ) && ((enc) & DW_EH_PE_signed)) READ_S8 (var, ptr); \
|
||||
else if ((((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_uptr ) && !((enc) & DW_EH_PE_signed)) READ_U8 (var, ptr); \
|
||||
else { printf_log(LOG_DEBUG, "Invalid encoding 0x%02X\n", (enc)); (var) = 0; } \
|
||||
if (((enc) & DW_EH_PE_pcrel) && isptr) (var) += optr; \
|
||||
if ((enc) & DW_EH_PE_indirect) (var) = *(uint64_t*)(var); \
|
||||
} while (0)
|
||||
#define SKIP_1(ptr) (ptr) += 1
|
||||
#define SKIP_2(ptr) (ptr) += 2
|
||||
#define SKIP_4(ptr) (ptr) += 4
|
||||
#define SKIP_8(ptr) (ptr) += 8
|
||||
#define SKIP_LEB128(ptr) do { ++(ptr); } while (((*(((unsigned char*)(ptr))-1))) & (1 << 7))
|
||||
#define SKIP_ENCODED(ptr, enc) \
|
||||
do { if (((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_uleb128) SKIP_LEB128(ptr); \
|
||||
else if (((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_udata2 ) SKIP_2 (ptr); \
|
||||
else if (((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_udata4 ) SKIP_4 (ptr); \
|
||||
else if (((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_udata8 ) SKIP_8 (ptr); \
|
||||
else if (((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_uptr ) SKIP_8 (ptr); \
|
||||
else printf_log(LOG_DEBUG, "Invalid encoding 0x%02X\n", (enc)); \
|
||||
} while (0)
|
||||
|
||||
// LEB128 wil only work on 64 bits numbers (unsigned long, like the Linux kernel)
|
||||
void readULEB(uint64_t *var, unsigned char **ptr) {
|
||||
*var = 0;
|
||||
int shift = 0;
|
||||
while (1) {
|
||||
unsigned char byte = **ptr; ++*ptr;
|
||||
*var |= ((byte & 0x7F) << shift);
|
||||
if (!(byte & (1 << 7))) break;
|
||||
shift += 7;
|
||||
}
|
||||
}
|
||||
void readSLEB(int64_t *var, unsigned char **ptr) {
|
||||
uint64_t tmp = 0;
|
||||
int shift = 0;
|
||||
unsigned char byte;
|
||||
while (1) {
|
||||
byte = **ptr; ++*ptr;
|
||||
tmp |= ((byte & 0x7F) << shift);
|
||||
if (!(byte & (1 << 7))) break;
|
||||
shift += 7;
|
||||
}
|
||||
// Sign extend
|
||||
if (byte & (1 << 6)) {
|
||||
*(uint64_t*)var = tmp | (0xFFFFFFFFFFFFFFFFull << (shift + 7));
|
||||
} else {
|
||||
*var = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t get_parent_registers(dwarf_unwind_t *unwind, const elfheader_t *ehdr, uintptr_t addr, char *success) {
|
||||
if (!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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// printf_log(LOG_NONE, "Address: 0x%016lX\nEH frame address: 0x%016lX\n", addr, ehdr->ehframe);
|
||||
|
||||
// Not using the binary search table (for now)
|
||||
|
||||
unsigned char *cur_addr = (unsigned char*)ehdr->ehframe;
|
||||
unsigned char *end_addr = (unsigned char*)ehdr->ehframe_end;
|
||||
|
||||
#define AUG_EHDATA (1 << 0)
|
||||
#define AUG_AUGDATA (1 << 1)
|
||||
#define AUG_LSDA (1 << 2)
|
||||
#define AUG_PARG (1 << 3)
|
||||
#define AUG_FDEENC (1 << 4)
|
||||
#define AUG_SIGHDLER (1 << 5)
|
||||
unsigned short aug_fields = 0;
|
||||
unsigned char lsda_encoding = DW_EH_PE_omit;
|
||||
unsigned char fde_encoding = DW_EH_PE_omit;
|
||||
uint64_t eh_data = 0; // Note: these are never reset, so use aug_fields & AUG_EHDATA
|
||||
uint64_t code_alignment_factor = 0;
|
||||
int64_t data_alignment_factor = 0;
|
||||
uint64_t cie_aug_data_len = 0; // Note: these are never reset, so use aug_fields & AUG_AUGDATA
|
||||
unsigned char *cie_aug_data = NULL; // Note: these are never reset, so use aug_fields & AUG_AUGDATA
|
||||
unsigned char *initCIEinstr = NULL; // Never NULL if initialized
|
||||
unsigned char *endCIEinstr = NULL; // Never NULL if initialized
|
||||
uint64_t return_addr_reg = 0; // Description absent in the LSBCS 5.0, but still present
|
||||
while (cur_addr < end_addr) {
|
||||
// Length
|
||||
uint64_t len; int extended = 0;
|
||||
READ_U4(len, cur_addr);
|
||||
if (!len) {
|
||||
// Terminator, end parsing
|
||||
*success = 0;
|
||||
return 0;
|
||||
} else if (len == 0xFFFFFFFF) {
|
||||
// Extended Length (optional)
|
||||
extended = 1;
|
||||
READ_U8(len, cur_addr);
|
||||
}
|
||||
(void)extended;
|
||||
// printf_log(LOG_NONE, "[???] Length %02X\n", len);
|
||||
// printf_log(LOG_NONE, "[???] Extended %c\n", extended ? 'Y' : 'N');
|
||||
unsigned char *next_addr = cur_addr + len;
|
||||
|
||||
// CIE ID (always 0) or CIE Pointer (never 0)
|
||||
uint32_t cie_ptr;
|
||||
READ_U4(cie_ptr, cur_addr);
|
||||
if (cie_ptr == 0) {
|
||||
// Current block is a CIE
|
||||
// printf_log(LOG_NONE, "[CIE] ID %02X\n", cie_ptr);
|
||||
|
||||
// Version (always 1 or 3)
|
||||
uint8_t cie_version;
|
||||
READ_U1(cie_version, cur_addr);
|
||||
// printf_log(LOG_NONE, "[CIE] Version %01X\n", cie_version);
|
||||
if ((cie_version != 1) && (cie_version != 3)) { // Only 1 is in the LSBCS 5.0 but I found 3 exists as well
|
||||
// Invalid CIE version
|
||||
printf_log(LOG_DEBUG, "Invalid CIE version %d (should be 1 or 3), stopping parsing\n", cie_version);
|
||||
// Failed to process CIE
|
||||
*success = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Augmentation String
|
||||
char *aug_str = (char*)cur_addr; cur_addr += strlen(aug_str) + 1;
|
||||
// printf_log(LOG_NONE, "[CIE] Augmentation st %s\n", aug_str);
|
||||
aug_fields = (aug_str[0] == 'z') ? AUG_AUGDATA : 0;
|
||||
for (char *aug_str2 = aug_str + ((aug_fields & AUG_AUGDATA) ? 1 : 0); *aug_str2; ++aug_str2) {
|
||||
if ((aug_str2[0] == 'e') && (aug_str2[1] == 'h')) {
|
||||
// Use has also been left untold in the Linux Standard Base Core Specification 3.0RC1
|
||||
printf_log(LOG_DEBUG, "Warning: EH data detected but this was removed from the standard\n");
|
||||
aug_fields |= AUG_EHDATA; ++aug_str2;
|
||||
} else if (aug_fields & AUG_AUGDATA) {
|
||||
if (aug_str2[0] == 'L') {
|
||||
aug_fields |= AUG_LSDA;
|
||||
} else if (aug_str2[0] == 'P') {
|
||||
aug_fields |= AUG_PARG;
|
||||
printf_log(LOG_DEBUG, "Warning: augmentation string attribute 'P' unsupported\n");
|
||||
} else if (aug_str2[0] == 'S') {
|
||||
aug_fields |= AUG_SIGHDLER;
|
||||
printf_log(LOG_DEBUG, "Warning: augmentation string attribute 'S' ignored\n");
|
||||
} else if (aug_str2[0] == 'R') {
|
||||
aug_fields |= AUG_FDEENC;
|
||||
} else {
|
||||
printf_log(LOG_DEBUG, "Error: invalid augmentation string %s\n", aug_str);
|
||||
// Failed to process augmentation string
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
printf_log(LOG_DEBUG, "Error: invalid augmentation string %s\n", aug_str);
|
||||
// Failed to process augmentation string
|
||||
break;
|
||||
}
|
||||
}
|
||||
// printf_log(LOG_NONE, "[CIE] Augmentation fs %02x\n", aug_fields);
|
||||
|
||||
// Code Alignment Factor
|
||||
READ_ULEB128(code_alignment_factor, cur_addr);
|
||||
// printf_log(LOG_NONE, "[CIE] Code AF %d\n", code_alignment_factor);
|
||||
// Data Alignment Factor
|
||||
READ_SLEB128(data_alignment_factor, cur_addr);
|
||||
// printf_log(LOG_NONE, "[CIE] Data AF %d\n", data_alignment_factor);
|
||||
|
||||
if (cie_version == 1) {
|
||||
READ_U1(return_addr_reg, cur_addr);
|
||||
} else {
|
||||
READ_ULEB128(return_addr_reg, cur_addr);
|
||||
}
|
||||
// printf_log(LOG_NONE, "[CIE] Return addr reg %01X\n", return_addr_reg);
|
||||
|
||||
lsda_encoding = DW_EH_PE_omit;
|
||||
fde_encoding = DW_EH_PE_absptr;
|
||||
if (aug_fields & AUG_AUGDATA) {
|
||||
// Augmentation Data Length (optional)
|
||||
READ_ULEB128(cie_aug_data_len, cur_addr);
|
||||
// printf_log(LOG_NONE, "[CIE] Aug data len %01X\n", cie_aug_data_len);
|
||||
// Augmentation Data (optional)
|
||||
cie_aug_data = cur_addr; cur_addr += cie_aug_data_len;
|
||||
char *cie_aug_data2 = (char*)cie_aug_data;
|
||||
for (char *aug_str2 = aug_str + ((aug_fields & AUG_AUGDATA) ? 1 : 0); *aug_str2; ++aug_str2) {
|
||||
if ((aug_str2[0] == 'e') && (aug_str2[1] == 'h')) {
|
||||
break; // Unknown usage
|
||||
} else if (aug_fields & AUG_AUGDATA) {
|
||||
if (aug_str2[0] == 'L') {
|
||||
READ_U1(lsda_encoding, cie_aug_data2);
|
||||
if (lsda_encoding != DW_EH_PE_omit) printf_log(LOG_DEBUG, "Warning: LSDA unsupported\n");
|
||||
} else if (aug_str2[0] == 'P') {
|
||||
unsigned char pencoding;
|
||||
READ_U1(pencoding, cie_aug_data2);
|
||||
SKIP_ENCODED(cie_aug_data2, pencoding);
|
||||
} else if (aug_str2[0] == 'S') {
|
||||
} else if (aug_str2[0] == 'R') {
|
||||
READ_U1(fde_encoding, cie_aug_data2);
|
||||
// printf_log(LOG_NONE, "[CIE] FDE encoding %02X\n", fde_encoding);
|
||||
if (fde_encoding == DW_EH_PE_omit) printf_log(LOG_DEBUG, "Error: FDE encoding set to 'omit'\n");
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initial Instructions
|
||||
initCIEinstr = cur_addr;
|
||||
endCIEinstr = next_addr;
|
||||
} else if (initCIEinstr) {
|
||||
// Current block is a FDE
|
||||
// printf_log(LOG_NONE, "[FDE] Ptr %02X\n", cie_ptr);
|
||||
|
||||
// PC Begin
|
||||
uintptr_t pc_begin;
|
||||
READ_ENCODED(pc_begin, cur_addr, fde_encoding, 1);
|
||||
// printf_log(LOG_NONE, "[FDE] PC begin %016lX\n", pc_begin);
|
||||
// PC Range
|
||||
uint64_t pc_range;
|
||||
READ_ENCODED(pc_range, cur_addr, fde_encoding, 0);
|
||||
// printf_log(LOG_NONE, "[FDE] PC end %016lX\n", pc_begin + pc_range);
|
||||
|
||||
uint64_t aug_data_len;
|
||||
unsigned char *aug_data;
|
||||
if (aug_fields & AUG_AUGDATA) {
|
||||
// Augmentation Data Length (optional)
|
||||
READ_ULEB128(aug_data_len, cur_addr);
|
||||
// printf_log(LOG_NONE, "[FDE] Aug data len %01X\n", aug_data_len);
|
||||
// Augmentation Data (optional)
|
||||
aug_data = cur_addr; cur_addr += aug_data_len;
|
||||
(void)aug_data;
|
||||
}
|
||||
|
||||
if (lsda_encoding != DW_EH_PE_omit) {
|
||||
SKIP_ENCODED(cur_addr, lsda_encoding);
|
||||
}
|
||||
|
||||
// Call Frame Instructions
|
||||
if ((pc_begin <= addr) && (addr < pc_begin + pc_range)) {
|
||||
// Corresponding Frame Descriptor Entry found!
|
||||
|
||||
#define setmax(a, b) a = (a < (b) ? (b) : a)
|
||||
dwarf_unwind_constr_t unwind_constr;
|
||||
unwind_constr.reg_count = return_addr_reg;
|
||||
uint64_t maxstacksize = 0;
|
||||
uint64_t curstacksize = 0;
|
||||
unsigned char *cur_inst = initCIEinstr;
|
||||
uint64_t nreg;
|
||||
#define PARSE_INST \
|
||||
switch (inst >> 6) { \
|
||||
case 0b01: \
|
||||
break; \
|
||||
case 0b10: \
|
||||
setmax(unwind_constr.reg_count, inst & 0x3F); \
|
||||
SKIP_LEB128(cur_inst); \
|
||||
break; \
|
||||
case 0b11: \
|
||||
setmax(unwind_constr.reg_count, inst & 0x3F); \
|
||||
break; \
|
||||
case 0b00: \
|
||||
switch (inst & 0x3F) { \
|
||||
case 0b000000: \
|
||||
break; \
|
||||
case 0b001010: \
|
||||
++curstacksize; \
|
||||
setmax(maxstacksize, curstacksize); \
|
||||
break; \
|
||||
case 0b001011: \
|
||||
if (!curstacksize) { \
|
||||
printf_log(LOG_DEBUG, "Negative stack size during CFI execution\n"); \
|
||||
*success = 0; \
|
||||
return 0; \
|
||||
} \
|
||||
--curstacksize; \
|
||||
break; \
|
||||
case 0b000010: \
|
||||
SKIP_1(cur_inst); \
|
||||
break; \
|
||||
case 0b000011: \
|
||||
SKIP_2(cur_inst); \
|
||||
break; \
|
||||
case 0b000100: \
|
||||
SKIP_4(cur_inst); \
|
||||
break; \
|
||||
case 0b000001: \
|
||||
SKIP_8(cur_inst); \
|
||||
break; \
|
||||
case 0b001110: \
|
||||
case 0b010011: \
|
||||
SKIP_LEB128(cur_inst); \
|
||||
break; \
|
||||
case 0b000110: \
|
||||
case 0b000111: \
|
||||
case 0b001000: \
|
||||
case 0b001101: \
|
||||
READ_ULEB128(nreg, cur_inst); \
|
||||
setmax(unwind_constr.reg_count, nreg); \
|
||||
break; \
|
||||
case 0b000101: \
|
||||
case 0b001100: \
|
||||
case 0b010001: \
|
||||
case 0b010010: \
|
||||
case 0b010100: \
|
||||
case 0b010101: \
|
||||
READ_ULEB128(nreg, cur_inst); \
|
||||
setmax(unwind_constr.reg_count, nreg); \
|
||||
SKIP_LEB128(cur_inst); \
|
||||
break; \
|
||||
case 0b001001: \
|
||||
READ_ULEB128(nreg, cur_inst); \
|
||||
setmax(unwind_constr.reg_count, nreg); \
|
||||
READ_ULEB128(nreg, cur_inst); \
|
||||
setmax(unwind_constr.reg_count, nreg); \
|
||||
break; \
|
||||
default: \
|
||||
/* Contains undefined, user and expression CFIs */ \
|
||||
printf_log(LOG_DEBUG, "Unknown CFI 0x%02X\n", inst); \
|
||||
*success = 0; \
|
||||
return 0; \
|
||||
} \
|
||||
break; \
|
||||
}
|
||||
while (cur_inst < endCIEinstr) {
|
||||
unsigned char inst; READ_U1(inst, cur_inst);
|
||||
PARSE_INST
|
||||
}
|
||||
cur_inst = cur_addr;
|
||||
while (cur_inst < next_addr) {
|
||||
unsigned char inst; READ_U1(inst, cur_inst);
|
||||
PARSE_INST
|
||||
}
|
||||
#undef PARSE_INST
|
||||
|
||||
uint64_t cfa_reg = -1;
|
||||
unsigned char cfa_signed = 0;
|
||||
union { uint64_t uoff; int64_t soff; } cfa_offset = { .uoff = 0 };
|
||||
++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*)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**)box_malloc(maxstacksize * sizeof(uint64_t*));
|
||||
for (uint64_t i = 0; i < maxstacksize; ++i) {
|
||||
table_stack[i] = (uint64_t*)box_malloc(tablelen);
|
||||
}
|
||||
cur_inst = initCIEinstr;
|
||||
uintptr_t cur_pointed_addr = pc_begin;
|
||||
// Missing:
|
||||
/* DW_CFA_def_cfa_expression 0 0x0f BLOCK */
|
||||
/* DW_CFA_expression 0 0x10 ULEB128 register BLOCK */
|
||||
/* DW_CFA_val_expression 0 0x16 ULEB128 BLOCK */
|
||||
/* DW_CFA_lo_user 0 0x1c */
|
||||
/* DW_CFA_GNU_args_size 0 0x2e ULEB128 argsize */
|
||||
/* DW_CFA_GNU_negative_offset_extended 0 0x2f ULEB128 register ULEB128 offset (obsoleted by DW_CFA_offset_extended_sf) */
|
||||
/* DW_CFA_hi_user 0 0x3f */
|
||||
// Known "bug": DW_CFA_set_loc can go backwards, this is ignored
|
||||
uint64_t tmpreg;
|
||||
uint64_t tmpuval;
|
||||
int64_t tmpsval;
|
||||
#define PARSE_INST \
|
||||
switch (inst >> 6) { \
|
||||
case 0b01: /* DW_CFA_advance_loc 0x1 delta */ \
|
||||
cur_pointed_addr += (inst & 0x3F) * code_alignment_factor; \
|
||||
break; \
|
||||
case 0b10: /* DW_CFA_offset 0x2 register ULEB128 offset */ \
|
||||
READ_ULEB128(tmpuval, cur_inst); \
|
||||
SET_STATUS(unwind_constr, inst & 0x3F, REGSTATUS_offset); \
|
||||
unwind_constr.table[inst & 0x3F] = (int64_t)tmpuval * data_alignment_factor; \
|
||||
break; \
|
||||
case 0b11: /* DW_CFA_restore 0x3 register */ \
|
||||
RESTORE_REG(inst & 0x3F) \
|
||||
break; \
|
||||
case 0b00: \
|
||||
switch (inst & 0x3F) { \
|
||||
case 0b000001: /* DW_CFA_set_loc 0 0x01 address */ \
|
||||
READ_U8(cur_pointed_addr, cur_inst); \
|
||||
break; \
|
||||
case 0b000010: /* DW_CFA_advance_loc1 0 0x02 1-byte delta */ \
|
||||
READ_U1(tmpuval, cur_inst); \
|
||||
cur_pointed_addr += tmpuval * code_alignment_factor; \
|
||||
break; \
|
||||
case 0b000011: /* DW_CFA_advance_loc2 0 0x03 2-byte delta */ \
|
||||
READ_U2(tmpuval, cur_inst); \
|
||||
cur_pointed_addr += tmpuval * code_alignment_factor; \
|
||||
break; \
|
||||
case 0b000100: /* DW_CFA_advance_loc4 0 0x04 4-byte delta */ \
|
||||
READ_U4(tmpuval, cur_inst); \
|
||||
cur_pointed_addr += tmpuval * code_alignment_factor; \
|
||||
break; \
|
||||
\
|
||||
case 0b001100: /* DW_CFA_def_cfa 0 0x0c ULEB128 register ULEB128 offset */ \
|
||||
READ_ULEB128(cfa_reg, cur_inst); \
|
||||
cfa_signed = 0; \
|
||||
READ_ULEB128(cfa_offset.uoff, cur_inst); \
|
||||
break; \
|
||||
case 0b010010: /* DW_CFA_def_cfa_sf 0 0x12 ULEB128 register SLEB128 offset */ \
|
||||
READ_ULEB128(cfa_reg, cur_inst); \
|
||||
cfa_signed = 1; \
|
||||
READ_SLEB128(cfa_offset.soff, cur_inst); \
|
||||
cfa_offset.soff *= data_alignment_factor; \
|
||||
break; \
|
||||
case 0b001101: /* DW_CFA_def_cfa_register 0 0x0d ULEB128 register */ \
|
||||
READ_ULEB128(cfa_reg, cur_inst); \
|
||||
break; \
|
||||
case 0b001110: /* DW_CFA_def_cfa_offset 0 0x0e ULEB128 offset */ \
|
||||
cfa_signed = 0; \
|
||||
READ_ULEB128(cfa_offset.uoff, cur_inst); \
|
||||
break; \
|
||||
case 0b010011: /* DW_CFA_def_cfa_offset_sf 0 0x13 SLEB128 offset */ \
|
||||
READ_SLEB128(cfa_offset.soff, cur_inst); \
|
||||
cfa_offset.soff *= data_alignment_factor; \
|
||||
break; \
|
||||
/* DW_CFA_def_cfa_expression */ \
|
||||
\
|
||||
case 0b000111: /* DW_CFA_undefined 0 0x07 ULEB128 register */ \
|
||||
READ_ULEB128(tmpreg, cur_inst); \
|
||||
SET_STATUS(unwind_constr, tmpreg, REGSTATUS_undefined); \
|
||||
break; \
|
||||
case 0b001000: /* DW_CFA_same_value 0 0x08 ULEB128 register */ \
|
||||
READ_ULEB128(tmpreg, cur_inst); \
|
||||
SET_STATUS(unwind_constr, tmpreg, REGSTATUS_same_val); \
|
||||
break; \
|
||||
case 0b000101: /* DW_CFA_offset_extended 0 0x05 ULEB128 register ULEB128 offset */ \
|
||||
READ_ULEB128(tmpreg, cur_inst); \
|
||||
READ_ULEB128(tmpuval, cur_inst); \
|
||||
SET_STATUS(unwind_constr, tmpreg, REGSTATUS_offset); \
|
||||
unwind_constr.table[tmpreg] = (int64_t)tmpuval * data_alignment_factor; \
|
||||
break; \
|
||||
case 0b010001: /* DW_CFA_offset_extended_sf 0 0x11 ULEB128 register SLEB128 offset */ \
|
||||
READ_ULEB128(tmpreg, cur_inst); \
|
||||
READ_SLEB128(tmpsval, cur_inst); \
|
||||
SET_STATUS(unwind_constr, tmpreg, REGSTATUS_offset); \
|
||||
unwind_constr.table[tmpreg] = tmpsval * data_alignment_factor; \
|
||||
break; \
|
||||
case 0b010100: /* DW_CFA_val_offset 0 0x14 ULEB128 register ULEB128 offset */ \
|
||||
READ_ULEB128(tmpreg, cur_inst); \
|
||||
READ_ULEB128(tmpuval, cur_inst); \
|
||||
SET_STATUS(unwind_constr, tmpreg, REGSTATUS_val_offset); \
|
||||
unwind_constr.table[tmpreg] = (int64_t)tmpuval * data_alignment_factor; \
|
||||
break; \
|
||||
case 0b010101: /* DW_CFA_val_offset_sf 0 0x15 ULEB128 register SLEB128 offset */ \
|
||||
READ_ULEB128(tmpreg, cur_inst); \
|
||||
READ_SLEB128(tmpsval, cur_inst); \
|
||||
SET_STATUS(unwind_constr, tmpreg, REGSTATUS_val_offset); \
|
||||
unwind_constr.table[tmpreg] = tmpsval * data_alignment_factor; \
|
||||
break; \
|
||||
case 0b001001: /* DW_CFA_register 0 0x09 ULEB128 register ULEB128 register */ \
|
||||
READ_ULEB128(tmpreg, cur_inst); \
|
||||
READ_ULEB128(tmpuval, cur_inst); \
|
||||
SET_STATUS(unwind_constr, tmpreg, REGSTATUS_register); \
|
||||
unwind_constr.table[tmpreg] = tmpuval; \
|
||||
break; \
|
||||
/* DW_CFA_expression */ \
|
||||
/* DW_CFA_val_expression */ \
|
||||
case 0b000110: /* DW_CFA_restore_extended 0 0x06 ULEB128 register */ \
|
||||
READ_ULEB128(tmpreg, cur_inst); \
|
||||
RESTORE_REG(tmpreg) \
|
||||
break; \
|
||||
\
|
||||
case 0b001010: /* DW_CFA_remember_state 0 0x0a */ \
|
||||
memcpy(table_stack[curstacksize], unwind_constr.table, tablelen); \
|
||||
++curstacksize; \
|
||||
break; \
|
||||
case 0b001011: /* DW_CFA_restore_state 0 0x0b */ \
|
||||
--curstacksize; \
|
||||
memcpy(unwind_constr.table, table_stack[curstacksize], tablelen); \
|
||||
break; \
|
||||
\
|
||||
case 0b000000: /* DW_CFA_nop 0 0 */ \
|
||||
break; \
|
||||
default: \
|
||||
/* Contains undefined, user and expression CFIs */ \
|
||||
printf_log(LOG_DEBUG, "Unknown CFI 0x%02X\n", inst); \
|
||||
FAILED \
|
||||
} \
|
||||
break; \
|
||||
}
|
||||
#define RESTORE_REG(reg) \
|
||||
printf_log(LOG_DEBUG, "Trying to restore register 0x%02lX while in the intial CFIs\n", (uint64_t)reg); \
|
||||
FAILED
|
||||
#define FAILED \
|
||||
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);
|
||||
// printf_log(LOG_NONE, "Executing pre 0x%02X\n", inst);
|
||||
PARSE_INST
|
||||
}
|
||||
#undef FAILED
|
||||
#undef RESTORE_REG
|
||||
uint64_t *init_table = (uint64_t*)box_malloc(tablelen);
|
||||
memcpy(init_table, unwind_constr.table, tablelen);
|
||||
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 \
|
||||
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);
|
||||
// printf_log(LOG_NONE, "Executing post 0x%02X\n", inst);
|
||||
PARSE_INST
|
||||
}
|
||||
#undef FAILED
|
||||
#undef RESTORE_REG
|
||||
#undef PARSE_INST
|
||||
box_free(init_statuses);
|
||||
box_free(init_table);
|
||||
for (int i = 0; i < maxstacksize; ++i) {
|
||||
box_free(table_stack[i]);
|
||||
}
|
||||
box_free(table_stack);
|
||||
|
||||
dwarf_unwind_t new_unwind;
|
||||
new_unwind.reg_count = unwind_constr.reg_count;
|
||||
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;
|
||||
|
||||
// printf_log(LOG_NONE, "Done, rewriting registers (CFA at r%d(0x%016lX) + %lld (%c) -> 0x%016lX\n", cfa_reg, unwind->regs[cfa_reg], cfa_offset.soff, cfa_signed ? 's' : 'u', cfa);
|
||||
for (uint64_t i = 0; i < unwind_constr.reg_count; ++i) {
|
||||
switch (GET_STATUS(unwind_constr, i)) {
|
||||
case REGSTATUS_undefined:
|
||||
// printf_log(LOG_NONE, "Register %02lX: (undefined)\n", i);
|
||||
break;
|
||||
case REGSTATUS_same_val:
|
||||
if (i >= unwind->reg_count) {
|
||||
printf_log(LOG_DEBUG, "Invalid register status (value copied from register 0x%02lX)\n", i);
|
||||
box_free(unwind_constr.statuses);
|
||||
box_free(unwind_constr.table);
|
||||
box_free(new_unwind.regs);
|
||||
*success = 0;
|
||||
return 0;
|
||||
}
|
||||
new_unwind.regs[i] = unwind->regs[i];
|
||||
// printf_log(LOG_NONE, "Register %02lX: copy %016lX\n", i, new_unwind.regs[i]);
|
||||
break;
|
||||
case REGSTATUS_offset:
|
||||
new_unwind.regs[i] = *(uint64_t*)(cfa + (int64_t)unwind_constr.table[i]);
|
||||
// printf_log(LOG_NONE, "Register %02lX: offset %016lX [%016lX + %lld]\n", i, new_unwind.regs[i], cfa, (int64_t)unwind_constr.table[i]);
|
||||
break;
|
||||
case REGSTATUS_val_offset:
|
||||
new_unwind.regs[i] = (uint64_t)(cfa + (int64_t)unwind_constr.table[i]);
|
||||
// printf_log(LOG_NONE, "Register %02lX: voff %016lX\n", i, new_unwind.regs[i]);
|
||||
break;
|
||||
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]);
|
||||
box_free(unwind_constr.statuses);
|
||||
box_free(unwind_constr.table);
|
||||
box_free(new_unwind.regs);
|
||||
*success = 0;
|
||||
return 0;
|
||||
}
|
||||
new_unwind.regs[i] = unwind->regs[unwind_constr.table[i]];
|
||||
// printf_log(LOG_NONE, "Register %02lX: reg %016lX\n", i, new_unwind.regs[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
*success = (GET_STATUS(unwind_constr, return_addr_reg) == REGSTATUS_undefined) ? 0 : ((aug_fields & AUG_SIGHDLER) ? 2 : 1);
|
||||
box_free(unwind_constr.statuses);
|
||||
box_free(unwind_constr.table);
|
||||
|
||||
box_free(unwind->regs);
|
||||
unwind->reg_count = new_unwind.reg_count;
|
||||
unwind->regs = new_unwind.regs;
|
||||
|
||||
// Maybe?
|
||||
unwind->regs[cfa_reg] = cfa;
|
||||
|
||||
// printf_log(LOG_NONE, "Returning %016lX\n", unwind->regs[return_addr_reg]);
|
||||
return unwind->regs[return_addr_reg];
|
||||
}
|
||||
} else {
|
||||
// printf_log(LOG_NONE, "[FDE] Ptr %02X\n", cie_ptr);
|
||||
printf_log(LOG_DEBUG, "Unexpected FDE, corresponding CIE missing\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
cur_addr = next_addr;
|
||||
}
|
||||
*success = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dwarf_unwind_t *init_dwarf_unwind_registers(x64emu_t *emu) {
|
||||
dwarf_unwind_t *unwind_struct = (dwarf_unwind_t*)box_malloc(sizeof(dwarf_unwind_t));
|
||||
unwind_struct->reg_count = 17;
|
||||
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
|
||||
* General Purpose Register RDX | 1 | %rdx
|
||||
* General Purpose Register RCX | 2 | %rcx
|
||||
* General Purpose Register RBX | 3 | %rbx
|
||||
* General Purpose Register RSI | 4 | %rsi
|
||||
* General Purpose Register RDI | 5 | %rdi
|
||||
* Frame Pointer Register RBP | 6 | %rbp
|
||||
* Stack Pointer Register RSP | 7 | %rsp
|
||||
* Extended Integer Registers 8-15 | 8-15 | %r8-%r15
|
||||
* Return Address RA | 16 |
|
||||
* Vector Registers 0-7 | 17-24 | %xmm0-%xmm7
|
||||
* Extended Vector Registers 8-15 | 25-32 | %xmm8-%xmm15
|
||||
* Floating Point Registers 0-7 | 33-40 | %st0-%st7
|
||||
* MMX Registers 0-7 | 41-48 | %mm0-%mm7
|
||||
* Flag Register | 49 | %rFLAGS
|
||||
* Segment Register ES | 50 | %es
|
||||
* Segment Register CS | 51 | %cs
|
||||
* Segment Register SS | 52 | %ss
|
||||
* Segment Register DS | 53 | %ds
|
||||
* Segment Register FS | 54 | %fs
|
||||
* Segment Register GS | 55 | %gs
|
||||
* Reserved | 56-57 |
|
||||
* FS Base address | 58 | %fs.base
|
||||
* GS Base address | 59 | %gs.base
|
||||
* Reserved | 60-61 |
|
||||
* Task Register | 62 | %tr
|
||||
* LDT Register | 63 | %ldtr
|
||||
* 128-bit Media Control and Status | 64 | %mxcsr
|
||||
* x87 Control Word | 65 | %fcw
|
||||
* x87 Status Word | 66 | %fsw
|
||||
*/
|
||||
unwind_struct->regs[ 0] = emu->regs[_RAX].q[0];
|
||||
unwind_struct->regs[ 1] = emu->regs[_RDX].q[0];
|
||||
unwind_struct->regs[ 2] = emu->regs[_RCX].q[0];
|
||||
unwind_struct->regs[ 3] = emu->regs[_RBX].q[0];
|
||||
unwind_struct->regs[ 4] = emu->regs[_RSI].q[0];
|
||||
unwind_struct->regs[ 5] = emu->regs[_RDI].q[0];
|
||||
unwind_struct->regs[ 6] = emu->regs[_RBP].q[0];
|
||||
unwind_struct->regs[ 7] = emu->regs[_RSP].q[0] + 8;
|
||||
unwind_struct->regs[ 8] = emu->regs[_R8 ].q[0];
|
||||
unwind_struct->regs[ 9] = emu->regs[_R9 ].q[0];
|
||||
unwind_struct->regs[10] = emu->regs[_R10].q[0];
|
||||
unwind_struct->regs[11] = emu->regs[_R11].q[0];
|
||||
unwind_struct->regs[12] = emu->regs[_R12].q[0];
|
||||
unwind_struct->regs[13] = emu->regs[_R13].q[0];
|
||||
unwind_struct->regs[14] = emu->regs[_R14].q[0];
|
||||
unwind_struct->regs[15] = emu->regs[_R15].q[0];
|
||||
unwind_struct->regs[16] = emu->ip.q[0];
|
||||
return unwind_struct;
|
||||
}
|
||||
|
||||
void free_dwarf_unwind_registers(dwarf_unwind_t **unwind_struct) {
|
||||
box_free((*unwind_struct)->regs);
|
||||
box_free(*unwind_struct);
|
||||
*unwind_struct = NULL;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef __ELFDWARF_PRIVATE_H_
|
||||
#define __ELFDWARF_PRIVATE_H_
|
||||
|
||||
#include "emu/x64emu_private.h"
|
||||
|
||||
typedef struct dwarf_unwind_s {
|
||||
uint8_t reg_count;
|
||||
uint64_t *regs;
|
||||
} dwarf_unwind_t;
|
||||
typedef struct elfheader_s elfheader_t;
|
||||
|
||||
dwarf_unwind_t *init_dwarf_unwind_registers(x64emu_t *emu);
|
||||
void free_dwarf_unwind_registers(dwarf_unwind_t **unwind_struct);
|
||||
|
||||
// Returns the callee's address on success or NULL on failure (may be NULL regardless).
|
||||
// If success equals 2, the frame is a signal frame.
|
||||
uintptr_t get_parent_registers(dwarf_unwind_t *emu, const elfheader_t *ehdr, uintptr_t addr, char *success);
|
||||
|
||||
#endif // __ELFDWARF_PRIVATE_H_
|
||||
+68
-65
@@ -225,13 +225,14 @@ const char* DumpRelType(int t)
|
||||
return buff;
|
||||
}
|
||||
|
||||
const char* DumpSym(elfheader_t *h, Elf64_Sym* sym)
|
||||
const char* DumpSym(elfheader_t *h, Elf64_Sym* sym, int version)
|
||||
{
|
||||
static char buff[4096];
|
||||
const char* vername = (version==-1)?"(none)":((version==0)?"*local*":((version==1)?"*global*":GetSymbolVersion(h, version)));
|
||||
memset(buff, 0, sizeof(buff));
|
||||
sprintf(buff, "\"%s\", value=%p, size=%ld, info/other=%d/%d index=%d",
|
||||
sprintf(buff, "\"%s\", value=%p, size=%ld, info/other=%d/%d index=%d (ver=%d/%s)",
|
||||
h->DynStr+sym->st_name, (void*)sym->st_value, sym->st_size,
|
||||
sym->st_info, sym->st_other, sym->st_shndx);
|
||||
sym->st_info, sym->st_other, sym->st_shndx, version, vername);
|
||||
return buff;
|
||||
}
|
||||
|
||||
@@ -246,116 +247,118 @@ const char* IdxSymName(elfheader_t *h, int sym)
|
||||
|
||||
void DumpMainHeader(Elf64_Ehdr *header, elfheader_t *h)
|
||||
{
|
||||
if(box64_log>=LOG_DUMP) {
|
||||
printf_log(LOG_DUMP, "ELF Dump main header\n");
|
||||
printf_log(LOG_DUMP, " Entry point = %p\n", (void*)header->e_entry);
|
||||
printf_log(LOG_DUMP, " Program Header table offset = %p\n", (void*)header->e_phoff);
|
||||
printf_log(LOG_DUMP, " Section Header table offset = %p\n", (void*)header->e_shoff);
|
||||
printf_log(LOG_DUMP, " Flags = 0x%X\n", header->e_flags);
|
||||
printf_log(LOG_DUMP, " ELF Header size = %d\n", header->e_ehsize);
|
||||
printf_log(LOG_DUMP, " Program Header Entry num/size = %d(%d)/%d\n", h->numPHEntries, header->e_phnum, header->e_phentsize);
|
||||
printf_log(LOG_DUMP, " Section Header Entry num/size = %d(%d)/%d\n", h->numSHEntries, header->e_shnum, header->e_shentsize);
|
||||
printf_log(LOG_DUMP, " Section Header index num = %d(%d)\n", h->SHIdx, header->e_shstrndx);
|
||||
printf_log(LOG_DUMP, "ELF Dump ==========\n");
|
||||
if(box64_dump) {
|
||||
printf_dump(LOG_NEVER, "ELF Dump main header\n");
|
||||
printf_dump(LOG_NEVER, " Entry point = %p\n", (void*)header->e_entry);
|
||||
printf_dump(LOG_NEVER, " Program Header table offset = %p\n", (void*)header->e_phoff);
|
||||
printf_dump(LOG_NEVER, " Section Header table offset = %p\n", (void*)header->e_shoff);
|
||||
printf_dump(LOG_NEVER, " Flags = 0x%X\n", header->e_flags);
|
||||
printf_dump(LOG_NEVER, " ELF Header size = %d\n", header->e_ehsize);
|
||||
printf_dump(LOG_NEVER, " Program Header Entry num/size = %zu(%d)/%d\n", h->numPHEntries, header->e_phnum, header->e_phentsize);
|
||||
printf_dump(LOG_NEVER, " Section Header Entry num/size = %zu(%d)/%d\n", h->numSHEntries, header->e_shnum, header->e_shentsize);
|
||||
printf_dump(LOG_NEVER, " Section Header index num = %zu(%d)\n", h->SHIdx, header->e_shstrndx);
|
||||
printf_dump(LOG_NEVER, "ELF Dump ==========\n");
|
||||
|
||||
printf_log(LOG_DUMP, "ELF Dump PEntries (%d)\n", h->numSHEntries);
|
||||
for (int i=0; i<h->numPHEntries; ++i)
|
||||
printf_log(LOG_DUMP, " PHEntry %04d : %s\n", i, DumpPHEntry(h->PHEntries+i));
|
||||
printf_log(LOG_DUMP, "ELF Dump PEntries ====\n");
|
||||
printf_dump(LOG_NEVER, "ELF Dump PEntries (%zu)\n", h->numPHEntries);
|
||||
for (size_t i=0; i<h->numPHEntries; ++i)
|
||||
printf_dump(LOG_NEVER, " PHEntry %04zu : %s\n", i, DumpPHEntry(h->PHEntries+i));
|
||||
printf_dump(LOG_NEVER, "ELF Dump PEntries ====\n");
|
||||
|
||||
printf_log(LOG_DUMP, "ELF Dump Sections (%d)\n", h->numSHEntries);
|
||||
for (int i=0; i<h->numSHEntries; ++i)
|
||||
printf_log(LOG_DUMP, " Section %04d : %s\n", i, DumpSection(h->SHEntries+i, h->SHStrTab));
|
||||
printf_log(LOG_DUMP, "ELF Dump Sections ====\n");
|
||||
printf_dump(LOG_NEVER, "ELF Dump Sections (%zu)\n", h->numSHEntries);
|
||||
for (size_t i=0; i<h->numSHEntries; ++i)
|
||||
printf_dump(LOG_NEVER, " Section %04zu : %s\n", i, DumpSection(h->SHEntries+i, h->SHStrTab));
|
||||
printf_dump(LOG_NEVER, "ELF Dump Sections ====\n");
|
||||
}
|
||||
}
|
||||
|
||||
void DumpSymTab(elfheader_t *h)
|
||||
{
|
||||
if(box64_log>=LOG_DUMP && h->SymTab) {
|
||||
if(box64_dump && h->SymTab) {
|
||||
const char* name = ElfName(h);
|
||||
printf_log(LOG_DUMP, "ELF Dump SymTab(%d)=\n", h->numSymTab);
|
||||
for (int i=0; i<h->numSymTab; ++i)
|
||||
printf_log(LOG_DUMP, " %s:SymTab[%d] = \"%s\", value=%p, size=%ld, info/other=%d/%d index=%d\n", name,
|
||||
printf_dump(LOG_NEVER, "ELF Dump SymTab(%zu)=\n", h->numSymTab);
|
||||
for (size_t i=0; i<h->numSymTab; ++i)
|
||||
printf_dump(LOG_NEVER, " %s:SymTab[%zu] = \"%s\", value=%p, size=%ld, info/other=%d/%d index=%d\n", name,
|
||||
i, h->StrTab+h->SymTab[i].st_name, (void*)h->SymTab[i].st_value, h->SymTab[i].st_size,
|
||||
h->SymTab[i].st_info, h->SymTab[i].st_other, h->SymTab[i].st_shndx);
|
||||
printf_log(LOG_DUMP, "ELF Dump SymTab=====\n");
|
||||
printf_dump(LOG_NEVER, "ELF Dump SymTab=====\n");
|
||||
}
|
||||
}
|
||||
|
||||
void DumpDynamicSections(elfheader_t *h)
|
||||
{
|
||||
if(box64_log>=LOG_DUMP && h->Dynamic) {
|
||||
printf_log(LOG_DUMP, "ELF Dump Dynamic(%d)=\n", h->numDynamic);
|
||||
for (int i=0; i<h->numDynamic; ++i)
|
||||
printf_log(LOG_DUMP, " Dynamic %04d : %s\n", i, DumpDynamic(h->Dynamic+i));
|
||||
printf_log(LOG_DUMP, "ELF Dump Dynamic=====\n");
|
||||
if(box64_dump && h->Dynamic) {
|
||||
printf_dump(LOG_NEVER, "ELF Dump Dynamic(%zu)=\n", h->numDynamic);
|
||||
for (size_t i=0; i<h->numDynamic; ++i)
|
||||
printf_dump(LOG_NEVER, " Dynamic %04zu : %s\n", i, DumpDynamic(h->Dynamic+i));
|
||||
printf_dump(LOG_NEVER, "ELF Dump Dynamic=====\n");
|
||||
}
|
||||
}
|
||||
|
||||
void DumpDynSym(elfheader_t *h)
|
||||
{
|
||||
if(box64_log>=LOG_DUMP && h->DynSym) {
|
||||
if(box64_dump && h->DynSym) {
|
||||
const char* name = ElfName(h);
|
||||
printf_log(LOG_DUMP, "ELF Dump DynSym(%d)=\n", h->numDynSym);
|
||||
for (int i=0; i<h->numDynSym; ++i)
|
||||
printf_log(LOG_DUMP, " %s:DynSym[%d] = %s\n", name, i, DumpSym(h, h->DynSym+i));
|
||||
printf_log(LOG_DUMP, "ELF Dump DynSym=====\n");
|
||||
printf_dump(LOG_NEVER, "ELF Dump DynSym(%zu)=\n", h->numDynSym);
|
||||
for (size_t i=0; i<h->numDynSym; ++i) {
|
||||
int version = h->VerSym?((Elf64_Half*)((uintptr_t)h->VerSym+h->delta))[i]:-1;
|
||||
printf_dump(LOG_NEVER, " %s:DynSym[%zu] = %s\n", name, i, DumpSym(h, h->DynSym+i, version));
|
||||
}
|
||||
printf_dump(LOG_NEVER, "ELF Dump DynSym=====\n");
|
||||
}
|
||||
}
|
||||
|
||||
void DumpDynamicNeeded(elfheader_t *h)
|
||||
{
|
||||
if(box64_log>=LOG_DUMP && h->DynStrTab) {
|
||||
printf_log(LOG_DUMP, "ELF Dump DT_NEEDED=====\n");
|
||||
for (int i=0; i<h->numDynamic; ++i)
|
||||
if(box64_dump && h->DynStrTab) {
|
||||
printf_dump(LOG_NEVER, "ELF Dump DT_NEEDED=====\n");
|
||||
for (size_t i=0; i<h->numDynamic; ++i)
|
||||
if(h->Dynamic[i].d_tag==DT_NEEDED) {
|
||||
printf_log(LOG_DUMP, " Needed : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
|
||||
printf_dump(LOG_NEVER, " Needed : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
|
||||
}
|
||||
printf_log(LOG_DUMP, "ELF Dump DT_NEEDED=====\n");
|
||||
printf_dump(LOG_NEVER, "ELF Dump DT_NEEDED=====\n");
|
||||
}
|
||||
}
|
||||
|
||||
void DumpDynamicRPath(elfheader_t *h)
|
||||
{
|
||||
if(box64_log>=LOG_DUMP && h->DynStrTab) {
|
||||
printf_log(LOG_DUMP, "ELF Dump DT_RPATH/DT_RUNPATH=====\n");
|
||||
for (int i=0; i<h->numDynamic; ++i) {
|
||||
if(box64_dump && h->DynStrTab) {
|
||||
printf_dump(LOG_NEVER, "ELF Dump DT_RPATH/DT_RUNPATH=====\n");
|
||||
for (size_t i=0; i<h->numDynamic; ++i) {
|
||||
if(h->Dynamic[i].d_tag==DT_RPATH) {
|
||||
printf_log(LOG_DUMP, " RPATH : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
|
||||
printf_dump(LOG_NEVER, " RPATH : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
|
||||
}
|
||||
if(h->Dynamic[i].d_tag==DT_RUNPATH) {
|
||||
printf_log(LOG_DUMP, " RUNPATH : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
|
||||
printf_dump(LOG_NEVER, " RUNPATH : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
|
||||
}
|
||||
}
|
||||
printf_log(LOG_DUMP, "=====ELF Dump DT_RPATH/DT_RUNPATH\n");
|
||||
printf_dump(LOG_NEVER, "=====ELF Dump DT_RPATH/DT_RUNPATH\n");
|
||||
}
|
||||
}
|
||||
|
||||
void DumpRelTable(elfheader_t *h, int cnt, Elf64_Rel *rel, const char* name)
|
||||
{
|
||||
if(box64_log>=LOG_DUMP) {
|
||||
if(box64_dump) {
|
||||
const char* elfname = ElfName(h);
|
||||
printf_log(LOG_DUMP, "ELF Dump %s Table(%d) @%p\n", name, cnt, rel);
|
||||
printf_dump(LOG_NEVER, "ELF Dump %s Table(%d) @%p\n", name, cnt, rel);
|
||||
for (int i = 0; i<cnt; ++i)
|
||||
printf_log(LOG_DUMP, " %s:Rel[%d] = %p (0x%lX: %s, sym=0x%0lX/%s)\n", elfname,
|
||||
printf_dump(LOG_NEVER, " %s:Rel[%d] = %p (0x%lX: %s, sym=0x%0lX/%s)\n", elfname,
|
||||
i, (void*)rel[i].r_offset, rel[i].r_info, DumpRelType(ELF64_R_TYPE(rel[i].r_info)),
|
||||
ELF64_R_SYM(rel[i].r_info), IdxSymName(h, ELF64_R_SYM(rel[i].r_info)));
|
||||
printf_log(LOG_DUMP, "ELF Dump Rel Table=====\n");
|
||||
printf_dump(LOG_NEVER, "ELF Dump Rel Table=====\n");
|
||||
}
|
||||
}
|
||||
|
||||
void DumpRelATable(elfheader_t *h, int cnt, Elf64_Rela *rela, const char* name)
|
||||
{
|
||||
if(box64_log>=LOG_DUMP && h->rela) {
|
||||
if(box64_dump && h->rela) {
|
||||
const char* elfname = ElfName(h);
|
||||
printf_log(LOG_DUMP, "ELF Dump %s Table(%d) @%p\n", name, cnt, rela);
|
||||
printf_dump(LOG_NEVER, "ELF Dump %s Table(%d) @%p\n", name, cnt, rela);
|
||||
for (int i = 0; i<cnt; ++i)
|
||||
printf_log(LOG_DUMP, " %s:RelA[%d] = %p (0x%lX: %s, sym=0x%lX/%s) Addend=%ld\n", elfname,
|
||||
printf_dump(LOG_NEVER, " %s:%s[%d] = %p (0x%lX: %s, sym=0x%lX/%s) Addend=0x%lx\n", elfname, name,
|
||||
i, (void*)rela[i].r_offset, rela[i].r_info, DumpRelType(ELF64_R_TYPE(rela[i].r_info)),
|
||||
ELF64_R_SYM(rela[i].r_info), IdxSymName(h, ELF64_R_SYM(rela[i].r_info)),
|
||||
rela[i].r_addend);
|
||||
printf_log(LOG_DUMP, "ELF Dump RelA Table=====\n");
|
||||
printf_dump(LOG_NEVER, "ELF Dump %s Table=====\n", name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,24 +369,24 @@ void DumpBinary(char* p, int sz)
|
||||
unsigned char* d = (unsigned char*)p;
|
||||
int delta = ((uintptr_t)p)&0xf;
|
||||
for (int i = 0; sz; ++i) {
|
||||
printf_log(LOG_DUMP, "%p ", (void*)(((uintptr_t)d)&~0xf));
|
||||
printf_dump(LOG_NEVER, "%p ", (void*)(((uintptr_t)d)&~0xf));
|
||||
int n = 16 - delta;
|
||||
if (n>sz) n = sz;
|
||||
int fill = 16-sz;
|
||||
for (int j = 0; j<delta; ++j)
|
||||
printf_log(LOG_DUMP, " ");
|
||||
printf_dump(LOG_NEVER, " ");
|
||||
for (int j = 0; j<n; ++j)
|
||||
printf_log(LOG_DUMP, "%02X ", d[j]);
|
||||
printf_dump(LOG_NEVER, "%02X ", d[j]);
|
||||
for (int j = 0; j<fill; ++j)
|
||||
printf_log(LOG_DUMP, " ");
|
||||
printf_log(LOG_DUMP, " | ");
|
||||
printf_dump(LOG_NEVER, " ");
|
||||
printf_dump(LOG_NEVER, " | ");
|
||||
for (int j = 0; j<delta; ++j)
|
||||
printf_log(LOG_DUMP, " ");
|
||||
printf_dump(LOG_NEVER, " ");
|
||||
for (int j = 0; j<n; ++j)
|
||||
printf_log(LOG_DUMP, "%c", (d[j]<32 || d[j]>127)?'.':d[j]);
|
||||
printf_dump(LOG_NEVER, "%c", (d[j]<32 || d[j]>127)?'.':d[j]);
|
||||
for (int j = 0; j<fill; ++j)
|
||||
printf_log(LOG_DUMP, " ");
|
||||
printf_log(LOG_DUMP, "\n");
|
||||
printf_dump(LOG_NEVER, " ");
|
||||
printf_dump(LOG_NEVER, "\n");
|
||||
d+=n;
|
||||
sz-=n;
|
||||
delta=0;
|
||||
|
||||
Loaded 100 of 1148 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user