mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-03 08:20:28 +00:00
Compare commits
679 commits
Author | SHA1 | Date | |
---|---|---|---|
|
f1e83d5240 | ||
|
2fe8338f92 | ||
|
4ca513cba2 | ||
|
455910e8f2 | ||
|
9c68bc19b5 | ||
|
66d1050af6 | ||
|
fbc4fcbb71 | ||
|
afc986f741 | ||
|
5eb7cd6643 | ||
|
a8ed4fdd09 | ||
|
7b69652854 | ||
|
b235492e71 | ||
|
fc81fd8d16 | ||
|
38930de8e0 | ||
|
0e557d041d | ||
|
1d676b36e6 | ||
|
10a92cee94 | ||
|
42a9ed0131 | ||
|
12cb0669fb | ||
|
7f6a7d6fff | ||
|
9f6bf6ea71 | ||
|
102edf4ea2 | ||
|
21968acf99 | ||
|
98861b23fc | ||
|
dab6d7a345 | ||
|
90119c422c | ||
|
5907304049 | ||
|
035b0e2a62 | ||
|
7b67b20dae | ||
|
f0b0f926bf | ||
|
29eb7e67bb | ||
|
f71f61cd40 | ||
|
53c6edfd18 | ||
|
42a3bb729a | ||
|
c97a858470 | ||
|
4acd12a514 | ||
|
b734eec836 | ||
|
fe01642a20 | ||
|
e939659b70 | ||
|
ed6d133a27 | ||
|
97fc2aab41 | ||
|
662e7b217f | ||
|
27f2777cc6 | ||
|
538ce338f4 | ||
|
a15958edc6 | ||
|
8db646f6b2 | ||
|
fde03f8487 | ||
|
f24c854b28 | ||
|
0b3c81dd4e | ||
|
98c5847727 | ||
|
fd7da586b5 | ||
|
a51ccc8fb1 | ||
|
c7e3d9f7ff | ||
|
9ba5b227d9 | ||
|
aca4214ff6 | ||
|
379cd77078 | ||
|
36e5861b0c | ||
|
cc8a9eb93c | ||
|
0158579493 | ||
|
2de3845b25 | ||
|
93e22c581f | ||
|
ec2db4e40e | ||
|
55b7aa1632 | ||
|
4705705548 | ||
|
c8e10eef30 | ||
|
624573207e | ||
|
906bd06a5a | ||
|
c8c81af0c7 | ||
|
af7bd80430 | ||
|
26c051c297 | ||
|
9cc1bd04b2 | ||
|
69402f4d78 | ||
|
838b54f906 | ||
|
2d43d400c6 | ||
|
c22b413ac4 | ||
|
22094ae9ca | ||
|
bda2a4d55e | ||
|
b490e23d63 | ||
|
b40140e6c5 | ||
|
3142758675 | ||
|
cf9252f429 | ||
|
5fae582e82 | ||
|
ef00a7d0c2 | ||
|
746660066f | ||
|
fd15b2d7a3 | ||
|
e228aa3e14 | ||
|
9ddbfd921e | ||
|
729f7045e3 | ||
|
e47d67ba9b | ||
|
2477677c85 | ||
|
abdf6c9c26 | ||
|
5c3f854acb | ||
|
ad0a7c67c4 | ||
|
1312f60245 | ||
|
cafdb456ed | ||
|
4e9566cd33 | ||
|
5ce5fb6f2a | ||
|
d3279d3c0d | ||
|
e62ff3e19c | ||
|
913b573661 | ||
|
9add248c9b | ||
|
beb090b83f | ||
|
107d335c0d | ||
|
bd6630d62d | ||
|
a120bc7149 | ||
|
baad1df71d | ||
|
4e44517c9c | ||
|
26663dea9c | ||
|
23da0d75a5 | ||
|
4b2a00fd4a | ||
|
2f4e6e8d77 | ||
|
dd249ff5d4 | ||
|
4abcba8d8f | ||
|
dc1afc968b | ||
|
5edc0819c0 | ||
|
706cb66310 | ||
|
a8bc7ac119 | ||
|
d8fac40f55 | ||
|
000d6dbb0f | ||
|
17a85e4790 | ||
|
ad11fc32ad | ||
|
dcf9596620 | ||
|
85c58be942 | ||
|
e4d6eb382a | ||
|
fef24d622a | ||
|
12cc2de22e | ||
|
70603fa6ea | ||
|
9255113011 | ||
|
333c3d1f0a | ||
|
518eabadf5 | ||
|
556a294363 | ||
|
80804ccfff | ||
|
4a7dd31567 | ||
|
d730fc668c | ||
|
e975245102 | ||
|
126a44dc49 | ||
|
476926790a | ||
|
dd8c4dbd7d | ||
|
0e59afb403 | ||
|
f68fc1f815 | ||
|
6107eb38f9 | ||
|
d50f4c02f6 | ||
|
0d74673213 | ||
|
8527462b95 | ||
|
8313dca982 | ||
|
87a6669900 | ||
|
ce2fbf9325 | ||
|
1bfb348403 | ||
|
aaed879ec7 | ||
|
8201ef2b3d | ||
|
b1c9801897 | ||
|
f7754ab608 | ||
|
96abe91c29 | ||
|
bb7942e557 | ||
|
b14dddcc18 | ||
|
65e425fbca | ||
|
774c67fcd3 | ||
|
3c58ecd00c | ||
|
5aa970bc4e | ||
|
56ca00b022 | ||
|
ecbf453464 | ||
|
c3482af66d | ||
|
b73673e984 | ||
|
e260d90096 | ||
|
81bc8d0963 | ||
|
ef62730ae4 | ||
|
6397999fca | ||
|
b55e4d61a9 | ||
|
e65fe614b7 | ||
|
949c398327 | ||
|
baf70af780 | ||
|
c260144843 | ||
|
37e2660c7f | ||
|
675abfa029 | ||
|
e3d28de8a6 | ||
|
7f21547122 | ||
|
19563d37c1 | ||
|
ed1f992cb7 | ||
|
7d2c363963 | ||
|
462ba6909e | ||
|
b5fcb59a85 | ||
|
6b10f4d0b6 | ||
|
1260f9d0ed | ||
|
e142124730 | ||
|
5469202ea8 | ||
|
acd6c32184 | ||
|
6f868fe1de | ||
|
0f3457c172 | ||
|
a5c0189bf6 | ||
|
deb5e07b5a | ||
|
4d05060aac | ||
|
51c0f44d1c | ||
|
fbdf9d028c | ||
|
cceddd21b2 | ||
|
a0a404a431 | ||
|
2f48a02b44 | ||
|
58d252f3db | ||
|
95fee8614d | ||
|
d50d954a3c | ||
|
d99f066114 | ||
|
4754f200ee | ||
|
f882887178 | ||
|
dc579b79cd | ||
|
c66abd7260 | ||
|
d1157d471f | ||
|
5d3b91d8b9 | ||
|
07fde68d52 | ||
|
41fc76c2b8 | ||
|
1e9902af8b | ||
|
df04ab846a | ||
|
0d6ff04b87 | ||
|
03875beadb | ||
|
dd8544c3bd | ||
|
8f8145105c | ||
|
3c61a541bd | ||
|
79516bf08e | ||
|
90460ceb3c | ||
|
2ec413b5a9 | ||
|
39e7f24947 | ||
|
a089c07ddc | ||
|
ae57fa2c4e | ||
|
48b703b3f6 | ||
|
389d565d46 | ||
|
75e161b27b | ||
|
cca0edd62b | ||
|
7c83f4abc8 | ||
|
e1528a71e2 | ||
|
a6fe62cf13 | ||
|
c9152b6f14 | ||
|
5b9862907c | ||
|
c2420860e6 | ||
|
6baf6cdb10 | ||
|
06a1193b4d | ||
|
884d89235f | ||
|
610c951f71 | ||
|
12ecaf8650 | ||
|
185e957696 | ||
|
ebe1cbb1e3 | ||
|
e7b586e7f8 | ||
|
111ec9a989 | ||
|
f3ce684aef | ||
|
908b7a82ca | ||
|
bb06230f1e | ||
|
38cc4b3c68 | ||
|
37ca1badaf | ||
|
1a9f82bc9f | ||
|
df1aee7ce5 | ||
|
2d44142444 | ||
|
4bbc16e2cc | ||
|
863c704684 | ||
|
60e697f7b2 | ||
|
4389f4709a | ||
|
ca2c30c977 | ||
|
eb6e96f036 | ||
|
77be460290 | ||
|
8e14b27749 | ||
|
1d532ba3f8 | ||
|
b2a1811c01 | ||
|
2eda50929b | ||
|
098638cc6c | ||
|
732554ce3a | ||
|
914d521090 | ||
|
11d9fb521d | ||
|
de0cde8def | ||
|
5bd22aef12 | ||
|
1671283f1a | ||
|
0a79c6961f | ||
|
3fd275f59f | ||
|
2045e87b7c | ||
|
24666e121d | ||
|
ff1a0d1c40 | ||
|
7f0db3e3b9 | ||
|
31194165d2 | ||
|
c265c17d54 | ||
|
7499367060 | ||
|
3f26dfbb31 | ||
|
761c6ad615 | ||
|
a80ab3f8fe | ||
|
9ebacb7892 | ||
|
6ac3d3b804 | ||
|
f8cfc89eba | ||
|
4ed4a1095a | ||
|
8d8aecb6d9 | ||
|
1fba310e22 | ||
|
bb815eafaf | ||
|
d0360bf4bd | ||
|
8cdb3e136b | ||
|
3dab207351 | ||
|
1092d9b7e8 | ||
|
d40acc60b1 | ||
|
cf1559c448 | ||
|
01b09bc817 | ||
|
c1a0b017e9 | ||
|
77d3a07ff2 | ||
|
0d7c272d3f | ||
|
18964e5d76 | ||
|
e18fe1e112 | ||
|
8621034d42 | ||
|
32292aee84 | ||
|
81dd9639ed | ||
|
f147d3dde9 | ||
|
fb54604b31 | ||
|
cdfcee51ca | ||
|
18a620cc1a | ||
|
690d3df66e | ||
|
efb3a34608 | ||
|
642e9cb91a | ||
|
59692b0882 | ||
|
02e1cbcd00 | ||
|
0679cfeb41 | ||
|
edd5e2c8e3 | ||
|
c8e25d811c | ||
|
a31d5ea399 | ||
|
7d88343973 | ||
|
3915ca0f71 | ||
|
2c4b88753b | ||
|
0f486a13c8 | ||
|
1020dd41cc | ||
|
d3a13e8d70 | ||
|
7ba9a73840 | ||
|
4a1ae86124 | ||
|
5dd7ddb9ea | ||
|
f25fbbaaeb | ||
|
fbc4b03d4c | ||
|
e398f3887c | ||
|
2187d6d2dd | ||
|
0602ff6bab | ||
|
5660ec4741 | ||
|
62ace3623a | ||
|
6e809ee49b | ||
|
61c36c1dd6 | ||
|
0a9a6f86bb | ||
|
3de6632be6 | ||
|
c83ec5fdd9 | ||
|
23611cd854 | ||
|
62a97c919f | ||
|
16d244614e | ||
|
41cc053419 | ||
|
5d2d9e9640 | ||
|
e08a4cd99e | ||
|
7ebaff34c6 | ||
|
e7be5a5e2b | ||
|
30afd6ddbb | ||
|
d3167126aa | ||
|
d3f87f4c64 | ||
|
29ce25c767 | ||
|
7996bf67b5 | ||
|
626a5d02ee | ||
|
527aaa41eb | ||
|
421a819d88 | ||
|
3374cbba73 | ||
|
2018cac11f | ||
|
6a5d4ed65b | ||
|
493ffc9b7f | ||
|
101fb3d9b3 | ||
|
f6ba270ff3 | ||
|
86d884cce2 | ||
|
0ed916ad5c | ||
|
1029dcc597 | ||
|
c697133a2d | ||
|
1ff037df3c | ||
|
567d8fe32d | ||
|
23dfb79d33 | ||
|
76cea6c687 | ||
|
63065cdd70 | ||
|
3f2a1b696e | ||
|
f590e96abd | ||
|
f7780de24b | ||
|
196942084b | ||
|
6be030cd7c | ||
|
8c645fa1ee | ||
|
3756870635 | ||
|
fc65422660 | ||
|
01587de761 | ||
|
5a9a08d1cf | ||
|
bd6d9ff99a | ||
|
15ea0524b3 | ||
|
fdab49b30e | ||
|
135d538b1d | ||
|
6dbc3fba18 | ||
|
70f77aad33 | ||
|
d0cd719375 | ||
|
61370983e1 | ||
|
72511ff0ac | ||
|
c1f8d0678c | ||
|
e627bfa359 | ||
|
acbabedf27 | ||
|
239f8ce76e | ||
|
ca4cf67eb8 | ||
|
78d3b86ec7 | ||
|
44191b3f50 | ||
|
e437bed006 | ||
|
76957983cf | ||
|
387310c659 | ||
|
4cb5e21ba8 | ||
|
1bf2d8e308 | ||
|
98e684622b | ||
|
617ddfee93 | ||
|
464858dbb4 | ||
|
6de12c1032 | ||
|
a16eb76f5e | ||
|
021c53ba32 | ||
|
38921dc46b | ||
|
054da021d0 | ||
|
199662071a | ||
|
572ac7d100 | ||
|
d461c6f47d | ||
|
67b19ae733 | ||
|
c4c812c154 | ||
|
388e236360 | ||
|
f2c8ddbbe3 | ||
|
d1d4388201 | ||
|
6ffed14b9c | ||
|
7f6d0b8709 | ||
|
d7b1919b29 | ||
|
f86e6f8eb0 | ||
|
7e780e57d4 | ||
|
9a5a13854d | ||
|
a795017416 | ||
|
8e3b361aeb | ||
|
f9dd5683a4 | ||
|
e38a6e7996 | ||
|
ddfaf3fee0 | ||
|
0dbf01bf1d | ||
|
3a599bfbe1 | ||
|
89fc95fefd | ||
|
8e37ee2598 | ||
|
d9b4f647d8 | ||
|
0dde3a0e70 | ||
|
32643e9fa7 | ||
|
0a92c78035 | ||
|
118db71121 | ||
|
a0410f0170 | ||
|
d44a7dc603 | ||
|
2ba6b0158f | ||
|
f3effcb703 | ||
|
03b476f943 | ||
|
8b3e368e9a | ||
|
df6b384e31 | ||
|
280bdec817 | ||
|
2c5e7ec547 | ||
|
fdcb8b2f7e | ||
|
04c6bc478e | ||
|
cc2c1893c5 | ||
|
3093f0e467 | ||
|
3609f65de3 | ||
|
9906f299bb | ||
|
1d8f37a2f0 | ||
|
e677460d14 | ||
|
4937843f70 | ||
|
b003888696 | ||
|
2ca491dc56 | ||
|
9aa353d88b | ||
|
c67faf61df | ||
|
165c6b37e2 | ||
|
dcd626edf8 | ||
|
f032b5570b | ||
|
ea081b262c | ||
|
fae1c32267 | ||
|
9b6718ac99 | ||
|
cd672e251f | ||
|
500a47bc2f | ||
|
e4d25d68e4 | ||
|
f31a98d50a | ||
|
2816df59b2 | ||
|
a05ce3ad9d | ||
|
7c8df05042 | ||
|
4c77acdfcf | ||
|
b74b974cfd | ||
|
07cef612c3 | ||
|
deaef81463 | ||
|
c638eabfe0 | ||
|
8e68384e15 | ||
|
2f4ca71f26 | ||
|
07004ebf04 | ||
|
086d7006da | ||
|
0a51241f7a | ||
|
c68f6599e5 | ||
|
af3f62a71a | ||
|
6cf9b9e0fc | ||
|
1d4b452839 | ||
|
c2db3b703a | ||
|
edb03b89d8 | ||
|
7724664b13 | ||
|
1df4296208 | ||
|
ce9aeb2aed | ||
|
ed93fc3dd7 | ||
|
5f61d273e4 | ||
|
bf3531de81 | ||
|
3b0ea2db4d | ||
|
f029375d39 | ||
|
9b87dd2b87 | ||
|
787b04f752 | ||
|
0768807935 | ||
|
0b59f01b43 | ||
|
cf70a44756 | ||
|
a52792c59f | ||
|
65c9b28e99 | ||
|
4292348707 | ||
|
2ec20b6c4c | ||
|
47183551d6 | ||
|
42891e82bb | ||
|
624119ea38 | ||
|
2f3c6e7cc3 | ||
|
13b9ecd537 | ||
|
6659981457 | ||
|
ae2a7ac844 | ||
|
793393a341 | ||
|
952b9009e8 | ||
|
8f18b3ad65 | ||
|
56e0fd9d1d | ||
|
df68a6362b | ||
|
19c81863a3 | ||
|
7d31fc311a | ||
|
57c0b065c8 | ||
|
a6ecbb747d | ||
|
3bf95ae7ec | ||
|
5fd7b07fac | ||
|
317c8bc312 | ||
|
2a1f352622 | ||
|
06d916b449 | ||
|
9ea64725b6 | ||
|
f9fc7eb49f | ||
|
b0df6c1fce | ||
|
d5ebb1fa5b | ||
|
130fd66f9e | ||
|
8a44f913ae | ||
|
5488f0b2ca | ||
|
deff138e7e | ||
|
b6e40a3a58 | ||
|
8f6bc9dabc | ||
|
181cd4cbe8 | ||
|
5c6877b02b | ||
|
403bc25412 | ||
|
3bcd40be12 | ||
|
fcfdd26b72 | ||
|
2b00ee8723 | ||
|
ff2b6fc0b0 | ||
|
0eef971494 | ||
|
2bfd6b37c1 | ||
|
69db501c68 | ||
|
6e6fc38935 | ||
|
342d0c81e5 | ||
|
cec4c04aa1 | ||
|
f8c0186221 | ||
|
6992d8c195 | ||
|
1a6b4ab627 | ||
|
9e848abad9 | ||
|
223eb358c4 | ||
|
ea3cc4ea0b | ||
|
01267ea0f5 | ||
|
bc6c18368f | ||
|
06839ab301 | ||
|
39dde41516 | ||
|
3e16e59f72 | ||
|
cf9a1f7f33 | ||
|
49a32136f8 | ||
|
b9d6e6e348 | ||
|
b431ca4449 | ||
|
98d06b23cc | ||
|
9ff65cff63 | ||
|
bef2cb05ff | ||
|
43885a76e4 | ||
|
74a85087de | ||
|
045632a743 | ||
|
9a10adac35 | ||
|
0c12c26e1d | ||
|
40b7da8422 | ||
|
640668931d | ||
|
1c34088ba0 | ||
|
bb92347158 | ||
|
8bfd56b59e | ||
|
a6baba1b07 | ||
|
c8383f25b4 | ||
|
64a9e6fe56 | ||
|
0ef36489c8 | ||
|
7c7bf4bb90 | ||
|
592f6ebc20 | ||
|
af8f2bd19f | ||
|
38bceaeb8f | ||
|
99f0491f04 | ||
|
e72a88ea70 | ||
|
9b4701b3bc | ||
|
f7ff515961 | ||
|
3afe3a3646 | ||
|
b4faaa7c57 | ||
|
c4991e53ac | ||
|
ad3944a3b6 | ||
|
29eac8e2a2 | ||
|
a5a3e78fcf | ||
|
e9a756e78b | ||
|
38af54a2dd | ||
|
77a92f517b | ||
|
3eb405e0e2 | ||
|
68b9479f0c | ||
|
d9df41c4d5 | ||
|
fc3c536ec2 | ||
|
77ddf4cb07 | ||
|
4d018306b3 | ||
|
b3bb93d1d9 | ||
|
980af27bbf | ||
|
957c61cbbf | ||
|
d3ff48c63f | ||
|
2ab9e9f7fd | ||
|
d5225a693b | ||
|
c72904b2f6 | ||
|
616717fa82 | ||
|
369aebfc48 | ||
|
5f8e9f14c1 | ||
|
c1e18e7903 | ||
|
f27808c4d2 | ||
|
2719080986 | ||
|
33418f6742 | ||
|
83a8686c06 | ||
|
8ab3a545c6 | ||
|
8ebe2e9020 | ||
|
51cd83f674 | ||
|
39b0a9c03e | ||
|
d50064a779 | ||
|
1226eb7a5e | ||
|
8834dde0c2 | ||
|
1ef63eb206 | ||
|
08793aa143 | ||
|
6db1200a7e | ||
|
a2753de7fd | ||
|
6715b670b1 | ||
|
fd75fd1467 | ||
|
5d80e8dbf6 | ||
|
eeb20775d2 | ||
|
cb19e172da | ||
|
df648fb174 | ||
|
9a6af92bed | ||
|
6ab01716ce | ||
|
21093044c0 | ||
|
b8a9fbbd01 | ||
|
81ce2e4cbc | ||
|
07db3004d6 | ||
|
b0566348b2 | ||
|
8fb24a8f88 | ||
|
a4b455185b | ||
|
6cb0354e19 | ||
|
b580080af1 | ||
|
8b33204f37 | ||
|
94bab1618d | ||
|
cafea9a0a5 | ||
|
16099801cc | ||
|
4cd02c29ed | ||
|
5ae2554c10 | ||
|
531ac85923 | ||
|
8d9fcb5e5a | ||
|
aa37a327ea | ||
|
c4205f8305 | ||
|
b3fb6cff43 | ||
|
2e5f662dfe | ||
|
5e7137097d | ||
|
f224a55d57 | ||
|
0c51995b2b | ||
|
a9f23ccd17 | ||
|
57d1bf7a9c | ||
|
ce17ed60df | ||
|
d27a47b0e2 | ||
|
390335eb45 | ||
|
492a8f4f53 | ||
|
636bc4007b | ||
|
b09096691a | ||
|
91de6f1f5d | ||
|
fad1279c61 | ||
|
c0eacf2eb1 | ||
|
c60b150fcf | ||
|
80ec6c9283 | ||
|
2d93788ce3 | ||
|
15548b523c | ||
|
412a200ae4 | ||
|
44a463e4d2 | ||
|
0de6a08988 | ||
|
a334f9cc33 | ||
|
3315b6ef11 | ||
|
e93c8c4f8f | ||
|
0e49bed660 |
7602 changed files with 855037 additions and 463908 deletions
|
@ -6,6 +6,8 @@ AlignConsecutiveMacros: true
|
|||
AlignConsecutiveDeclarations: false
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
IncludeBlocks: Merge
|
||||
|
|
31
.git-blame-ignore-revs
Normal file
31
.git-blame-ignore-revs
Normal file
|
@ -0,0 +1,31 @@
|
|||
# Run this command to always ignore formatting commits in git blame
|
||||
# git config blame.ignoreRevsFile .git-blame-ignore-revs
|
||||
|
||||
# Upgraded clang-format to 19.0.0git
|
||||
89fc95fefd40413706ff1bdaac2e8d98b328dbf1
|
||||
# vim c++ filetype in modelines
|
||||
04c6bc478e082263d67c41bedbd033dde2d429eb
|
||||
# Ran clang-format
|
||||
f032b5570b4cd87c6bb4abb54c0b98e69c939955
|
||||
# Applied clang-format update to repo
|
||||
6e6fc38935054db0534d5af4fb99c6193305b946
|
||||
# revert retabbing
|
||||
2b315626f3af765cdfbc61114647412cdb798b3a
|
||||
# more modeline errata
|
||||
3a8e01a77a7c97af0b16fb1651b230cee7f7d4c6
|
||||
# fix more vi modelines
|
||||
2fc507c98f53a76718f61f9a36602f86b5ac0cc9
|
||||
# flip et/noet in modelines
|
||||
e16a7d8f3b8f906c3ef76e79f57f3adfc7f25186
|
||||
# fix vi modelines
|
||||
394d998315f613a888cc6b6c051d4163bdf5cd6f
|
||||
# clang-format
|
||||
c0eacf2eb1e1c0b3bd4f71f12fef258f5b249c3f
|
||||
# ape-m1 formatting cleanup
|
||||
da8baf2aa5ce93b958aca90a0ae69f537806324b
|
||||
# Run clang-format on most sources
|
||||
369f9740de4534c28d0e81ab2afc99decbb9a3e6
|
||||
# Get rid of .internal.h convention in LIBC_INTRIN
|
||||
86d884cce24d773e298a2714c1e3d91ecab9be45
|
||||
# Remove .internal from more header filenames
|
||||
31194165d2afca36c2315a6e7ca2f0797dde09e3
|
8
.gitattributes
vendored
8
.gitattributes
vendored
|
@ -1,4 +1,10 @@
|
|||
# -*- conf -*-
|
||||
*.gz binary
|
||||
/build/bootstrap/*.com binary
|
||||
*.so binary
|
||||
*.dll binary
|
||||
*.dylib binary
|
||||
/build/bootstrap/* binary
|
||||
/usr/share/terminfo/* binary
|
||||
/usr/share/terminfo/*/* binary
|
||||
/usr/share/zoneinfo/* binary
|
||||
/usr/share/zoneinfo/*/* binary
|
||||
|
|
59
.github/ISSUE_TEMPLATE/01-bug-low.yml
vendored
Normal file
59
.github/ISSUE_TEMPLATE/01-bug-low.yml
vendored
Normal file
|
@ -0,0 +1,59 @@
|
|||
name: Low Severity Bugs
|
||||
description: Used to report low severity bugs in cosmopolitan (e.g. cosmetic issues, non critical UI glitches)
|
||||
title: "Bug: "
|
||||
labels: ["bug", "low severity"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
Please include information about your system, the steps to reproduce the bug,
|
||||
and the version of cosmopolitan that you are using.
|
||||
If possible, please provide a minimal code example that reproduces the bug.
|
||||
You may also consider using function call tracing `--ftrace` or the lighter system call tracing `--strace`
|
||||
for additional technical logging that may allow us to narrow down where the fault occurred.
|
||||
- type: input
|
||||
id: contact
|
||||
attributes:
|
||||
label: Contact Details
|
||||
description: How can we get in touch with you if we need more info?
|
||||
placeholder: ex. email@example.com
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: Also tell us, what did you expect to happen?
|
||||
placeholder: Tell us what you see!
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: version
|
||||
attributes:
|
||||
label: Version
|
||||
description: What version of our software are you running? (use `--version` to get a version string)
|
||||
placeholder: "cosmocc (GCC) 12.3.0"
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: operating-system
|
||||
attributes:
|
||||
label: What operating system are you seeing the problem on?
|
||||
multiple: true
|
||||
options:
|
||||
- Linux
|
||||
- Mac
|
||||
- Windows
|
||||
- FreeBSD
|
||||
- OpenBSD
|
||||
- NetBSD
|
||||
- BIOS
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant log output
|
||||
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
||||
render: shell
|
59
.github/ISSUE_TEMPLATE/02-bug-medium.yml
vendored
Normal file
59
.github/ISSUE_TEMPLATE/02-bug-medium.yml
vendored
Normal file
|
@ -0,0 +1,59 @@
|
|||
name: Medium Severity Bug
|
||||
description: Used to report medium severity bugs in cosmopolitan (e.g. Malfunctioning Features but generally still useable)
|
||||
title: "Bug: "
|
||||
labels: ["bug", "medium severity"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
Please include information about your system, the steps to reproduce the bug,
|
||||
and the version of cosmopolitan that you are using.
|
||||
If possible, please provide a minimal code example that reproduces the bug.
|
||||
You may also consider using function call tracing `--ftrace` or the lighter system call tracing `--strace`
|
||||
for additional technical logging that may allow us to narrow down where the fault occurred.
|
||||
- type: input
|
||||
id: contact
|
||||
attributes:
|
||||
label: Contact Details
|
||||
description: How can we get in touch with you if we need more info?
|
||||
placeholder: ex. email@example.com
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: Also tell us, what did you expect to happen?
|
||||
placeholder: Tell us what you see!
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: version
|
||||
attributes:
|
||||
label: Version
|
||||
description: What version of our software are you running? (use `--version` to get a version string)
|
||||
placeholder: "cosmocc (GCC) 12.3.0"
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: operating-system
|
||||
attributes:
|
||||
label: What operating system are you seeing the problem on?
|
||||
multiple: true
|
||||
options:
|
||||
- Linux
|
||||
- Mac
|
||||
- Windows
|
||||
- FreeBSD
|
||||
- OpenBSD
|
||||
- NetBSD
|
||||
- BIOS
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant log output
|
||||
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
||||
render: shell
|
59
.github/ISSUE_TEMPLATE/03-bug-high.yml
vendored
Normal file
59
.github/ISSUE_TEMPLATE/03-bug-high.yml
vendored
Normal file
|
@ -0,0 +1,59 @@
|
|||
name: High Severity Bug
|
||||
description: Used to report high severity bugs in cosmopolitan (e.g. Malfunctioning features hindering important common workflow)
|
||||
title: "Bug: "
|
||||
labels: ["bug", "high severity"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
Please include information about your system, the steps to reproduce the bug,
|
||||
and the version of cosmopolitan that you are using.
|
||||
If possible, please provide a minimal code example that reproduces the bug.
|
||||
You may also consider using function call tracing `--ftrace` or the lighter system call tracing `--strace`
|
||||
for additional technical logging that may allow us to narrow down where the fault occurred.
|
||||
- type: input
|
||||
id: contact
|
||||
attributes:
|
||||
label: Contact Details
|
||||
description: How can we get in touch with you if we need more info?
|
||||
placeholder: ex. email@example.com
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: Also tell us, what did you expect to happen?
|
||||
placeholder: Tell us what you see!
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: version
|
||||
attributes:
|
||||
label: Version
|
||||
description: What version of our software are you running? (use `--version` to get a version string)
|
||||
placeholder: "cosmocc (GCC) 12.3.0"
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: operating-system
|
||||
attributes:
|
||||
label: What operating system are you seeing the problem on?
|
||||
multiple: true
|
||||
options:
|
||||
- Linux
|
||||
- Mac
|
||||
- Windows
|
||||
- FreeBSD
|
||||
- OpenBSD
|
||||
- NetBSD
|
||||
- BIOS
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant log output
|
||||
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
||||
render: shell
|
59
.github/ISSUE_TEMPLATE/04-bug-critical.yml
vendored
Normal file
59
.github/ISSUE_TEMPLATE/04-bug-critical.yml
vendored
Normal file
|
@ -0,0 +1,59 @@
|
|||
name: Critical Severity Bug
|
||||
description: Used to report critical severity bugs in cosmopolitan (e.g. Crashing, Corrupted, Dataloss)
|
||||
title: "Bug: "
|
||||
labels: ["bug", "critical severity"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
Please include information about your system, the steps to reproduce the bug,
|
||||
and the version of cosmopolitan that you are using.
|
||||
If possible, please provide a minimal code example that reproduces the bug.
|
||||
You may also consider using function call tracing `--ftrace` or the lighter system call tracing `--strace`
|
||||
for additional technical logging that may allow us to narrow down where the fault occurred.
|
||||
- type: input
|
||||
id: contact
|
||||
attributes:
|
||||
label: Contact Details
|
||||
description: How can we get in touch with you if we need more info?
|
||||
placeholder: ex. email@example.com
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: Also tell us, what did you expect to happen?
|
||||
placeholder: Tell us what you see!
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: version
|
||||
attributes:
|
||||
label: Version
|
||||
description: What version of our software are you running? (use `--version` to get a version string)
|
||||
placeholder: "cosmocc (GCC) 12.3.0"
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: operating-system
|
||||
attributes:
|
||||
label: What operating system are you seeing the problem on?
|
||||
multiple: true
|
||||
options:
|
||||
- Linux
|
||||
- Mac
|
||||
- Windows
|
||||
- FreeBSD
|
||||
- OpenBSD
|
||||
- NetBSD
|
||||
- BIOS
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant log output
|
||||
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
||||
render: shell
|
51
.github/ISSUE_TEMPLATE/05-enhancement.yml
vendored
Normal file
51
.github/ISSUE_TEMPLATE/05-enhancement.yml
vendored
Normal file
|
@ -0,0 +1,51 @@
|
|||
name: Enhancement template
|
||||
description: Used to request enhancements for cosmopolitan
|
||||
title: "Feature Request: "
|
||||
labels: ["enhancement"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
[Please post your idea first in Discussion if there is not yet a consensus for this enhancement request. This will help to keep this issue tracker focused on enhancements that the community has agreed needs to be implemented.](https://github.com/jart/cosmopolitan/discussions/categories/ideas)
|
||||
|
||||
- type: checkboxes
|
||||
id: prerequisites
|
||||
attributes:
|
||||
label: Prerequisites
|
||||
description: Please confirm the following before submitting your enhancement request.
|
||||
options:
|
||||
- label: I am running the latest code. Mention the version if possible as well.
|
||||
required: true
|
||||
- label: I carefully followed the [README.md](https://github.com/jart/cosmopolitan/blob/master/README.md).
|
||||
required: true
|
||||
- label: I searched using keywords relevant to my issue to make sure that I am creating a new issue that is not already open (or closed).
|
||||
required: true
|
||||
- label: I reviewed the [Discussions](https://github.com/jart/cosmopolitan/discussions), and have a new and useful enhancement to share.
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: feature-description
|
||||
attributes:
|
||||
label: Feature Description
|
||||
description: Please provide a detailed written description of what you were trying to do, and what you expected `cosmopolitan` to do as an enhancement.
|
||||
placeholder: Detailed description of the enhancement
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: motivation
|
||||
attributes:
|
||||
label: Motivation
|
||||
description: Please provide a detailed written description of reasons why this feature is necessary and how it is useful to `cosmopolitan` users.
|
||||
placeholder: Explanation of why this feature is needed and its benefits
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: possible-implementation
|
||||
attributes:
|
||||
label: Possible Implementation
|
||||
description: If you have an idea as to how it can be implemented, please write a detailed description. Feel free to give links to external sources or share visuals that might be helpful to understand the details better.
|
||||
placeholder: Detailed description of potential implementation
|
||||
validations:
|
||||
required: false
|
52
.github/ISSUE_TEMPLATE/06-research.yml
vendored
Normal file
52
.github/ISSUE_TEMPLATE/06-research.yml
vendored
Normal file
|
@ -0,0 +1,52 @@
|
|||
name: Research
|
||||
description: Track new technical research area
|
||||
title: "Research: "
|
||||
labels: ["research"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Don't forget to check for any [duplicate research issue tickets](https://github.com/jart/cosmopolitan/issues?q=is%3Aopen+is%3Aissue+label%3A%22research+%F0%9F%94%AC%22)
|
||||
|
||||
- type: checkboxes
|
||||
id: research-stage
|
||||
attributes:
|
||||
label: Research Stage
|
||||
description: Track general state of this research ticket
|
||||
options:
|
||||
- label: Background Research (Let's try to avoid reinventing the wheel)
|
||||
- label: Hypothesis Formed (How do you think this will work and it's effect?)
|
||||
- label: Strategy / Implementation Forming
|
||||
- label: Analysis of results
|
||||
- label: Debrief / Documentation (So people in the future can learn from us)
|
||||
|
||||
- type: textarea
|
||||
id: background
|
||||
attributes:
|
||||
label: Previous existing literature and research
|
||||
description: Whats the current state of the art and whats the motivation for this research?
|
||||
|
||||
- type: textarea
|
||||
id: hypothesis
|
||||
attributes:
|
||||
label: Hypothesis
|
||||
description: How do you think this will work and it's effect?
|
||||
|
||||
- type: textarea
|
||||
id: implementation
|
||||
attributes:
|
||||
label: Implementation
|
||||
description: Got an approach? e.g. a PR ready to go?
|
||||
|
||||
- type: textarea
|
||||
id: analysis
|
||||
attributes:
|
||||
label: Analysis
|
||||
description: How does the proposed implementation behave?
|
||||
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant log output
|
||||
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
||||
render: shell
|
28
.github/ISSUE_TEMPLATE/07-refactor.yml
vendored
Normal file
28
.github/ISSUE_TEMPLATE/07-refactor.yml
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
name: Refactor (Maintainers)
|
||||
description: Used to track refactoring opportunities
|
||||
title: "Refactor: "
|
||||
labels: ["refactor"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Don't forget to [check for existing refactor issue tickets](https://github.com/jart/cosmopolitan/issues?q=is%3Aopen+is%3Aissue+label%3Arefactoring) in case it's already covered.
|
||||
Also you may want to check [Pull request refactor label as well](https://github.com/jart/cosmopolitan/pulls?q=is%3Aopen+is%3Apr+label%3Arefactoring) for duplicates too.
|
||||
|
||||
- type: textarea
|
||||
id: background-description
|
||||
attributes:
|
||||
label: Background Description
|
||||
description: Please provide a detailed written description of the pain points you are trying to solve.
|
||||
placeholder: Detailed description behind your motivation to request refactor
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: possible-approaches
|
||||
attributes:
|
||||
label: Possible Refactor Approaches
|
||||
description: If you have some idea of possible approaches to solve this problem. You may want to make it a todo list.
|
||||
placeholder: Your idea of possible refactoring opportunity/approaches
|
||||
validations:
|
||||
required: false
|
15
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
15
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: FAQ
|
||||
url: https://github.com/jart/cosmopolitan/wiki/FAQ
|
||||
about: Is your question a common one? You may want to check here first.
|
||||
- name: Got an idea?
|
||||
url: https://github.com/jart/cosmopolitan/discussions/categories/ideas
|
||||
about: Pop it there. It may then become an enhancement ticket.
|
||||
- name: Got a question?
|
||||
url: https://github.com/jart/cosmopolitan/discussions/categories/q-a
|
||||
about: Ask a question there!
|
||||
- name: Want to contribute?
|
||||
url: https://github.com/jart/cosmopolitan/wiki/contribute
|
||||
about: Head to the contribution guide page of the wiki for areas you can help with
|
||||
|
49
.github/labeler.yml
vendored
Normal file
49
.github/labeler.yml
vendored
Normal file
|
@ -0,0 +1,49 @@
|
|||
# https://github.com/actions/labeler
|
||||
|
||||
documentation:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- README.md
|
||||
- LICENSE
|
||||
- CONTRIBUTING.md
|
||||
- libc/README.md
|
||||
- tool/cosmocc/README.md
|
||||
- third_party/getopt/README.txt
|
||||
build:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- build/**
|
||||
- Makefile
|
||||
- '*/*.mk'
|
||||
examples:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: examples/**
|
||||
devops:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- .github/**
|
||||
- .clang-format
|
||||
dsp:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- dsp/**
|
||||
ape:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- ape/**
|
||||
libc:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- libc/**
|
||||
net:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- net/**
|
||||
third_party:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- third_party/**
|
||||
tool:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- tool/**
|
42
.github/workflows/build.yml
vendored
42
.github/workflows/build.yml
vendored
|
@ -1,5 +1,8 @@
|
|||
name: build
|
||||
|
||||
env:
|
||||
COSMOCC_VERSION: 3.9.2
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
|
@ -19,13 +22,48 @@ jobs:
|
|||
matrix:
|
||||
mode: ["", tiny, rel, tinylinux, optlinux]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
# Full checkout needed for git-restore-mtime-bare.
|
||||
fetch-depth: 0
|
||||
|
||||
# TODO(jart): fork this action.
|
||||
- uses: chetan/git-restore-mtime-action@v2
|
||||
|
||||
- uses: actions/cache/restore@v4
|
||||
id: cache
|
||||
with:
|
||||
path: |
|
||||
.cosmocc
|
||||
o
|
||||
key: ${{ env.COSMOCC_VERSION }}-${{ matrix.mode }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ env.COSMOCC_VERSION }}-${{ matrix.mode }}-
|
||||
${{ env.COSMOCC_VERSION }}-
|
||||
|
||||
- name: Restore mtimes
|
||||
if: steps.cache.outputs.cache-hit == 'true'
|
||||
run: |
|
||||
while read mtime file; do
|
||||
[ -f "$file" ] && touch -d "@$mtime" "$file"
|
||||
done < o/.mtimes
|
||||
|
||||
- name: support ape bins 1
|
||||
run: sudo cp build/bootstrap/ape.elf /usr/bin/ape
|
||||
run: sudo cp -a build/bootstrap/ape.elf /usr/bin/ape
|
||||
|
||||
- name: support ape bins 2
|
||||
run: sudo sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register"
|
||||
|
||||
- name: make matrix
|
||||
run: V=0 make -j2 MODE=${{ matrix.mode }}
|
||||
|
||||
- name: Save mtimes
|
||||
run: |
|
||||
find o -type f -exec stat -c "%Y %n" {} \; > o/.mtimes
|
||||
|
||||
- uses: actions/cache/save@v4
|
||||
with:
|
||||
path: |
|
||||
.cosmocc
|
||||
o
|
||||
key: ${{ env.COSMOCC_VERSION }}-${{ matrix.mode }}-${{ github.sha }}
|
||||
|
|
17
.github/workflows/labeler.yml
vendored
Normal file
17
.github/workflows/labeler.yml
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
name: "Pull Request Labeler"
|
||||
on:
|
||||
- pull_request_target
|
||||
|
||||
jobs:
|
||||
labeler:
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: "jart/cosmopolitan"
|
||||
- uses: actions/labeler@v5
|
||||
with:
|
||||
configuration-path: '.github/labeler.yml'
|
24
.github/workflows/nightly-cosmocc.yml
vendored
Normal file
24
.github/workflows/nightly-cosmocc.yml
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
name: Nightly cosmocc
|
||||
on:
|
||||
schedule:
|
||||
# https://crontab.guru/#37_4_*_*_*
|
||||
- cron: "37 4 * * *"
|
||||
workflow_dispatch:
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}
|
||||
cancel-in-progress: true
|
||||
jobs:
|
||||
build-cosmocc:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: |
|
||||
sudo cp build/bootstrap/ape.elf /usr/bin/ape
|
||||
sudo sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register"
|
||||
- run: tool/cosmocc/package.sh
|
||||
# https://github.com/actions/upload-artifact/issues/590
|
||||
- uses: actions/upload-artifact@v4.3.5
|
||||
with:
|
||||
name: cosmocc
|
||||
path: cosmocc
|
||||
compression-level: 9
|
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -1,7 +1,8 @@
|
|||
# -*- conf -*-
|
||||
|
||||
/o
|
||||
/.prompt.jtlp
|
||||
/cosmocc
|
||||
/.cosmocc
|
||||
|
||||
# TODO: Find some way to have Python write to o/
|
||||
__pycache__
|
||||
|
@ -14,3 +15,4 @@ __pycache__
|
|||
/tool/emacs/*.elc
|
||||
/perf.data
|
||||
/perf.data.old
|
||||
/qemu*core
|
||||
|
|
109
.vscode/c_cpp_properties.json
vendored
109
.vscode/c_cpp_properties.json
vendored
|
@ -1,109 +0,0 @@
|
|||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Win32",
|
||||
"includePath": [
|
||||
"${workspaceFolder}"
|
||||
],
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++11",
|
||||
"forcedInclude": ["${workspaceFolder}/.vscode/vscode.h"],
|
||||
"defines": [
|
||||
"libcesque=",
|
||||
"pureconst=",
|
||||
"paramsnonnull(x)=",
|
||||
"alignas(x)",
|
||||
"alignof(x)",
|
||||
"artificial=",
|
||||
"__wur=",
|
||||
"mayalias=",
|
||||
"forceinline=",
|
||||
"forcealign(x)=",
|
||||
"scanfesque(x)=",
|
||||
"strftimeesque(x)=",
|
||||
"wontreturn=",
|
||||
"textreal=",
|
||||
"mallocesque=",
|
||||
"callocesque=",
|
||||
"vallocesque=",
|
||||
"reallocesque=",
|
||||
"strlenesque=",
|
||||
"memcpyesque=",
|
||||
"hasatleast=",
|
||||
"noinline=",
|
||||
"textexit=",
|
||||
"returnstwice=",
|
||||
"textwindows=",
|
||||
"privileged=",
|
||||
"dontinstrument=",
|
||||
"nodebuginfo=",
|
||||
"interruptfn=",
|
||||
"optimizespeed=",
|
||||
"forcealignargpointer=",
|
||||
"dontasan=",
|
||||
"dontubsan=",
|
||||
"donothing=",
|
||||
"nosideeffect=",
|
||||
"unreachable=",,
|
||||
"notpossible=",
|
||||
"thatispacked=",
|
||||
"dontthrow=",
|
||||
"nocallback=",
|
||||
"relegated=",
|
||||
"hidden=",
|
||||
"textstartup=",
|
||||
"initarray=",
|
||||
"returnsnonnull=",
|
||||
"returnspointerwithnoaliases=",
|
||||
"printfesque(x)=",
|
||||
"attributeallocsize(x)=",
|
||||
"returnsaligned(x)=",
|
||||
"attributeallocalign(x)=",
|
||||
"nullterminated(x)="
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}"
|
||||
],
|
||||
"cStandard": "gnu17",
|
||||
"compilerPath": "${workspaceFolder}/o/third_party/gcc/bin/x86_64-linux-musl-gcc",
|
||||
"compilerArgs": [
|
||||
"-Wall",
|
||||
"-Werror",
|
||||
"-fdebug-prefix-map=${workspaceFolder}=",
|
||||
"-frecord-gcc-switches",
|
||||
"-Wa,-W",
|
||||
"-Wa,-I.",
|
||||
"-Wa,--noexecstack",
|
||||
"-Og",
|
||||
"-g",
|
||||
"-gdescribe-dies",
|
||||
"-msse3",
|
||||
"-mno-red-zone",
|
||||
"-fno-math-errno",
|
||||
"-fno-trapping-math",
|
||||
"-fno-fp-int-builtin-inexact",
|
||||
"-fno-ident",
|
||||
"-fno-common",
|
||||
"-fno-gnu-unique",
|
||||
"-fstrict-aliasing",
|
||||
"-fstrict-overflow",
|
||||
"-fno-semantic-interposition",
|
||||
"-mno-omit-leaf-frame-pointer",
|
||||
"-fno-jump-tables",
|
||||
"-nostdinc",
|
||||
"-iquote."
|
||||
],
|
||||
"forcedInclude": [
|
||||
"libc/integral/normalize.inc"
|
||||
],
|
||||
"defines": [
|
||||
"COSMO",
|
||||
"MODE="
|
||||
]
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
36
.vscode/settings.json
vendored
Normal file
36
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"C_Cpp.default.compilerPath": ".cosmocc/3.9.2/bin/aarch64-linux-cosmo-c++",
|
||||
"C_Cpp.default.compilerArgs": [
|
||||
"-nostdinc",
|
||||
"-nostdlib",
|
||||
"-iquote.",
|
||||
"-isystemlibc/isystem",
|
||||
"-isystemthird_party/libcxx",
|
||||
"-includelibc/integral/normalize.inc",
|
||||
"-D_COSMO_SOURCE",
|
||||
"-D__aarch64__"
|
||||
],
|
||||
"[c]": {
|
||||
"editor.tabSize": 2,
|
||||
"editor.insertSpaces": true
|
||||
},
|
||||
"[cpp]": {
|
||||
"editor.tabSize": 2,
|
||||
"editor.insertSpaces": true
|
||||
},
|
||||
"[makefile]": {
|
||||
"editor.tabSize": 8,
|
||||
"editor.insertSpaces": false
|
||||
},
|
||||
"[make]": {
|
||||
"editor.tabSize": 8,
|
||||
"editor.insertSpaces": false
|
||||
},
|
||||
"[assembly]": {
|
||||
"editor.tabSize": 8,
|
||||
"editor.insertSpaces": true
|
||||
},
|
||||
"files.associations": {
|
||||
"log.h": "c"
|
||||
}
|
||||
}
|
2
.vscode/vscode.h
vendored
2
.vscode/vscode.h
vendored
|
@ -1,2 +0,0 @@
|
|||
#define __VSCODE_INTELLISENSE__ 1
|
||||
#include "libc/integral/normalize.inc"
|
114
CONTRIBUTING.md
114
CONTRIBUTING.md
|
@ -2,23 +2,77 @@
|
|||
|
||||
We'd love to accept your patches! Please read this guide first.
|
||||
|
||||
## Identity Disclosure
|
||||
|
||||
This project does not accept anonymous contributions. Justine Tunney
|
||||
won't merge pull requests from strangers. In order to change the Cosmo
|
||||
codebase, and have your changes be upstreamed, she has to know who you
|
||||
are. You're encouraged to disclose your full name and email address to
|
||||
the public too, by including them in your git commit messages; however
|
||||
that's not a requirement; as we're happy to respect the wishes of
|
||||
contributors who prefer to remain anonymous to the public.
|
||||
|
||||
## Copyright Assignment
|
||||
|
||||
Please send an email to Justine Tunney <jtunney@gmail.com> stating that
|
||||
you intend to assign her the copyright to the changes you contribute to
|
||||
Cosmopolitan. Please use the same email address you use for git commits
|
||||
which should only contain original source code from you or other people
|
||||
who are also assigning copyright. Please note that, if you're employed,
|
||||
you may need to get your employer's approval beforehand. If you can not
|
||||
assign copyright due to local laws, then you may alternatively consider
|
||||
disclaiming it using the language in [Unlicense](https://unlicense.org)
|
||||
or [CC-0](http://creativecommons.org/share-your-work/public-domain/cc0)
|
||||
The first time you send a pull request, you need to send an email to
|
||||
Justine Tunney <jtunney@gmail.com> stating that you intend to assign her
|
||||
the copyright to the changes you contribute to Cosmopolitan. It only
|
||||
needs to happen once. This only applies to the code you *choose* to
|
||||
contribute. The email should be sent from an email address associated
|
||||
with your identity. Your email should link to your pull request.
|
||||
|
||||
This is important because we can't produce 12kb single-file executables
|
||||
that comply with license requirements if we have to embed lots of them.
|
||||
Although that's less of an issue depending on the purpose of the files.
|
||||
For example, ownership is much less of a concern in the unit test files
|
||||
so you're encouraged to put your copyright on those, provided it's ISC.
|
||||
To make things easy, here's an example of a good email you can use:
|
||||
|
||||
> **From**: YOUR NAME (yname@gmail.com)
|
||||
> **To**: Justine Tunney (jtunney@gmail.com)
|
||||
> **Subject**: Cosmopolitan Copyright Assignment for YOUR NAME
|
||||
>
|
||||
> Hi Justine,
|
||||
>
|
||||
> I made my first contribution to Cosmopolitan in
|
||||
> https://github.com/jart/cosmopolitan/pull/XXXX could you please take a
|
||||
> look? I intend to assign you the copyright to the changes I contribute
|
||||
> to Cosmopolitan.
|
||||
>
|
||||
> Thanks!
|
||||
|
||||
Please note that in order to give Justine the copyright, it has to be
|
||||
yours to give in the first place. If you're employed, then you should
|
||||
get your employer's approval to do this beforehand. Even with big
|
||||
companies like Google, this process is quick and painless. Usually we
|
||||
see employers granting authorization in less than one day.
|
||||
|
||||
If you live in a country that doesn't recognize one's ability to assign
|
||||
copyright, then you may alternatively consider disclaiming it using the
|
||||
language in [Unlicense](https://unlicense.org) or
|
||||
[CC-0](http://creativecommons.org/share-your-work/public-domain/cc0).
|
||||
|
||||
If you're checking-in third party code, then you need to have headers at
|
||||
the top of each source file (but never header files) documenting its
|
||||
owners and the code should go in the `third_party/` folder. Every third
|
||||
party project should have a `README.cosmo` file that documents its
|
||||
provenance as well as any local changes you've made.
|
||||
|
||||
## Copyright Policy Exceptions
|
||||
|
||||
### Tests
|
||||
|
||||
You're encoraged to claim ownership of your test code. If you add a new
|
||||
file under the `test/` directory, then you should put your name in the
|
||||
ISC license header at the top of the file. If you add new test cases to
|
||||
an existing unit test file, then you're encouraged to append a line with
|
||||
your name to the existing copyright header of that file.
|
||||
|
||||
### Exceptional Features
|
||||
|
||||
Let's say you discovered a faster better way to implement `log10()` and
|
||||
you want to give it to Cosmopolitan. In cases like this, it really isn't
|
||||
appropriate for Justine to own your code. What you could do instead, is
|
||||
write your own new and improved `log10.c` from scratch, put your name on
|
||||
the top with the ISC license, and then add a `__notice()` directive so
|
||||
that your name will be embedded inside every executable that links the
|
||||
`log10()` function. This will help you get your name out there. Please
|
||||
note you need get approval from Justine each time you want to do this.
|
||||
|
||||
## Style Guide
|
||||
|
||||
|
@ -29,34 +83,4 @@ clang-format -i -style=file tool/net/redbean.c
|
|||
```
|
||||
|
||||
If you use Emacs this can be automated on save for Cosmopolitan using
|
||||
[tool/emacs/cosmo-format.el]([tool/emacs/cosmo-format.el]).
|
||||
|
||||
### Source Files
|
||||
|
||||
- Must use include paths relative to the root of the repository
|
||||
- Must have comment at top of file documenting copyright and license
|
||||
- Must have notice embedding if not owned by Justine (exception: tests)
|
||||
- May use language extensions that are supported by both GCC and Clang
|
||||
- Should use Google indentation (otherwise use `/* clang-format off */`)
|
||||
- Should use asm() instead of compiler APIs (exception: ctz, clz, memcpy)
|
||||
|
||||
### Header Files
|
||||
|
||||
- Must not have copyright or license comments
|
||||
- Must have once guards (otherwise change `.h` to `.inc`)
|
||||
- Must be ANSI C89 compatible to be included in the amalgamation header
|
||||
- Must include its dependencies (exception: libc/integral/normalize.inc)
|
||||
- Must not define objects (i.e. `cc -c -xc foo.h` will produce empty `.o`)
|
||||
- Should not use typedefs
|
||||
- Should not use forward declarations
|
||||
- Should not include documentation comments
|
||||
- Should not include parameter names in prototypes
|
||||
- Should not pose problems if included by C++ or Assembly sources
|
||||
- Should not declare non-ANSI code, at all, when the user requests ANSI
|
||||
|
||||
### Build Config
|
||||
|
||||
- Must not write files outside `o/`
|
||||
- Must not communicate with Internet
|
||||
- Must not depend on system libraries
|
||||
- Must not depend on system commands (exception: sh, make, gzip, zip)
|
||||
[tool/emacs/cosmo-format.el](tool/emacs/cosmo-format.el).
|
||||
|
|
304
Makefile
304
Makefile
|
@ -21,23 +21,23 @@
|
|||
# make -j8 -O MODE=tiny
|
||||
#
|
||||
# # build individual target
|
||||
# make -j8 -O o//examples/hello.com
|
||||
# o//examples/hello.com
|
||||
# make -j8 -O o//examples/hello
|
||||
# o//examples/hello
|
||||
#
|
||||
# # view source
|
||||
# less examples/hello.c
|
||||
#
|
||||
# # view binary
|
||||
# o//tool/viz/bing.com o//examples/hello.com |
|
||||
# o//tool/viz/fold.com
|
||||
# o//tool/viz/bing o//examples/hello |
|
||||
# o//tool/viz/fold
|
||||
#
|
||||
# # view transitive closure of legalese
|
||||
# o//tool/viz/bing.com -n o//examples/hello.com |
|
||||
# o//tool/viz/fold.com
|
||||
# o//tool/viz/bing -n o//examples/hello |
|
||||
# o//tool/viz/fold
|
||||
#
|
||||
# # basic debugging
|
||||
# make -j8 -O MODE=dbg o/dbg/examples/crashreport.com
|
||||
# o/examples/crashreport.com
|
||||
# make -j8 -O MODE=dbg o/dbg/examples/crashreport
|
||||
# o/examples/crashreport
|
||||
# less examples/crashreport.c
|
||||
#
|
||||
# # extremely tiny binaries
|
||||
|
@ -51,7 +51,7 @@
|
|||
#
|
||||
# TROUBLESHOOTING
|
||||
#
|
||||
# make -j8 -O V=1 o//examples/hello.com
|
||||
# make -j8 -O V=1 o//examples/hello
|
||||
# make o//examples/life.elf -pn |& less
|
||||
# etc.
|
||||
#
|
||||
|
@ -59,7 +59,7 @@
|
|||
#
|
||||
# build/config.mk
|
||||
|
||||
SHELL = build/bootstrap/cocmd.com
|
||||
SHELL = build/bootstrap/cocmd
|
||||
MAKEFLAGS += --no-builtin-rules
|
||||
|
||||
.SUFFIXES:
|
||||
|
@ -73,10 +73,14 @@ MODE := $(m)
|
|||
endif
|
||||
endif
|
||||
|
||||
COMMA := ,
|
||||
PWD := $(shell pwd)
|
||||
|
||||
# detect wsl2 running cosmopolitan binaries on the host by checking whether:
|
||||
# - user ran build/bootstrap/make.com, in which case make's working directory is in wsl
|
||||
# - user ran make, in which case cocmd.com's working directory is in wsl
|
||||
ifneq ($(findstring //wsl.localhost/,$(CURDIR) $(shell pwd)),)
|
||||
# - user ran .cosmocc/current/bin/make, in which case make's working directory
|
||||
# is in wsl
|
||||
# - user ran make, in which case cocmd's working directory is in wsl
|
||||
ifneq ($(findstring //wsl.localhost/,$(CURDIR) $(PWD)),)
|
||||
$(warning wsl2 interop is enabled)
|
||||
$(error you need to run sudo sh -c 'echo -1 > /proc/sys/fs/binfmt_misc/WSLInterop')
|
||||
endif
|
||||
|
@ -86,17 +90,34 @@ UNAME_S := $(shell uname -s)
|
|||
|
||||
# apple still distributes a 17 year old version of gnu make
|
||||
ifeq ($(MAKE_VERSION), 3.81)
|
||||
$(error please use build/bootstrap/make.com)
|
||||
$(error please use https://cosmo.zip/pub/cosmos/bin/make)
|
||||
endif
|
||||
|
||||
# provide instructions to non-linux users on unbundling gcc
|
||||
ifeq ($(TOOLCHAIN),) # if TOOLCHAIN isn't defined
|
||||
ifeq ("$(wildcard o/third_party/gcc/bin/x86_64-linux-cosmo-*)","") # if our gcc isn't unbundled
|
||||
ifneq ($(UNAME_M)-$(UNAME_S), x86_64-Linux) # if this is not amd64 linux
|
||||
$(error please run tool/cosmocc/fetch.sh)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
LC_ALL = C
|
||||
SOURCE_DATE_EPOCH = 0
|
||||
|
||||
ARFLAGS = rcsD
|
||||
ZFLAGS ?=
|
||||
XARGS ?= xargs -P4 -rs8000
|
||||
DOT ?= dot
|
||||
CLANG = clang
|
||||
TMPDIR = o/tmp
|
||||
AR = $(BOOTSTRAP)/ar.ape
|
||||
CP = $(BOOTSTRAP)/cp.ape
|
||||
RM = $(BOOTSTRAP)/rm.ape -f
|
||||
GZIP = $(BOOTSTRAP)/gzip.ape
|
||||
ECHO = $(BOOTSTRAP)/echo.ape
|
||||
CHMOD = $(BOOTSTRAP)/chmod.ape
|
||||
TOUCH = $(BOOTSTRAP)/touch.ape
|
||||
PKG = $(BOOTSTRAP)/package.ape
|
||||
MKDEPS = $(BOOTSTRAP)/mkdeps
|
||||
ZIPOBJ = $(BOOTSTRAP)/zipobj
|
||||
ZIPCOPY = $(BOOTSTRAP)/zipcopy
|
||||
PECHECK = $(BOOTSTRAP)/pecheck
|
||||
FIXUPOBJ = $(BOOTSTRAP)/fixupobj
|
||||
OBJBINCOPY = $(BOOTSTRAP)/objbincopy
|
||||
MKDIR = $(BOOTSTRAP)/mkdir.ape -p
|
||||
COMPILE = $(BOOTSTRAP)/compile.ape -V9 -M2048m -P8192 $(QUOTA)
|
||||
|
||||
# the default build modes is empty string
|
||||
# on x86_64 hosts, MODE= is the same as MODE=x86_64
|
||||
|
@ -110,11 +131,52 @@ MODE := aarch64
|
|||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(findstring aarch64,$(MODE)),)
|
||||
ARCH = aarch64
|
||||
HOSTS ?= pi pi5 studio freebsdarm
|
||||
else
|
||||
ARCH = x86_64
|
||||
HOSTS ?= freebsd rhel7 xnu openbsd netbsd win10 luna
|
||||
endif
|
||||
|
||||
ZIPOBJ_FLAGS += -a$(ARCH)
|
||||
|
||||
export ADDR2LINE
|
||||
export LC_ALL
|
||||
export MKDIR
|
||||
export MODE
|
||||
export SOURCE_DATE_EPOCH
|
||||
export TMPDIR
|
||||
|
||||
COSMOCC = .cosmocc/3.9.2
|
||||
BOOTSTRAP = $(COSMOCC)/bin
|
||||
TOOLCHAIN = $(COSMOCC)/bin/$(ARCH)-linux-cosmo-
|
||||
DOWNLOAD := $(shell build/download-cosmocc.sh $(COSMOCC) 3.9.2 f4ff13af65fcd309f3f1cfd04275996fb7f72a4897726628a8c9cf732e850193)
|
||||
|
||||
IGNORE := $(shell $(MKDIR) $(TMPDIR))
|
||||
|
||||
AS = $(TOOLCHAIN)as
|
||||
CC = $(TOOLCHAIN)gcc
|
||||
CXX = $(TOOLCHAIN)g++
|
||||
CXXFILT = $(TOOLCHAIN)c++filt
|
||||
LD = $(TOOLCHAIN)ld.bfd
|
||||
NM = $(TOOLCHAIN)nm
|
||||
GCC = $(TOOLCHAIN)gcc
|
||||
STRIP = $(TOOLCHAIN)strip
|
||||
OBJCOPY = $(TOOLCHAIN)objcopy
|
||||
OBJDUMP = $(TOOLCHAIN)objdump
|
||||
ifneq ($(wildcard $(PWD)/$(TOOLCHAIN)addr2line),)
|
||||
ADDR2LINE = $(PWD)/$(TOOLCHAIN)addr2line
|
||||
else
|
||||
ADDR2LINE = $(TOOLCHAIN)addr2line
|
||||
endif
|
||||
|
||||
# primary build rules
|
||||
all: o
|
||||
o: o/$(MODE)
|
||||
o/$(MODE): \
|
||||
o/$(MODE)/ape \
|
||||
o/$(MODE)/ctl \
|
||||
o/$(MODE)/dsp \
|
||||
o/$(MODE)/net \
|
||||
o/$(MODE)/libc \
|
||||
|
@ -128,7 +190,7 @@ o/$(MODE): \
|
|||
o/$(MODE)/: o/$(MODE)
|
||||
o/$(MODE)/.: o/$(MODE)
|
||||
|
||||
# check if we're using o//third_party/make/make.com
|
||||
# check if we're using o//third_party/make/make
|
||||
# we added sandboxing to guarantee cosmo's makefile is hermetic
|
||||
# it also shaves away 200ms of startup latency with native $(uniq)
|
||||
ifneq ($(LANDLOCKMAKE_VERSION),)
|
||||
|
@ -138,7 +200,7 @@ $(warning please run ape/apeinstall.sh if you intend to use landlock make)
|
|||
$(shell sleep .5)
|
||||
endif
|
||||
endif
|
||||
ifeq ($(USE_SYSTEM_TOOLCHAIN),)
|
||||
ifneq ($(TOOLCHAIN),)
|
||||
.STRICT = 1
|
||||
endif
|
||||
endif
|
||||
|
@ -147,10 +209,9 @@ endif
|
|||
.UNVEIL += \
|
||||
libc/integral \
|
||||
libc/stdbool.h \
|
||||
libc/disclaimer.inc \
|
||||
rwc:/dev/shm \
|
||||
rx:.cosmocc \
|
||||
rx:build/bootstrap \
|
||||
rx:o/third_party/gcc \
|
||||
r:build/portcosmo.h \
|
||||
/proc/stat \
|
||||
rw:/dev/null \
|
||||
|
@ -189,7 +250,6 @@ include libc/calls/BUILD.mk #─┐
|
|||
include libc/irq/BUILD.mk # ├──SYSTEMS RUNTIME
|
||||
include third_party/nsync/BUILD.mk # │ You can issue system calls
|
||||
include libc/runtime/BUILD.mk # │
|
||||
include third_party/double-conversion/BUILD.mk # │
|
||||
include libc/crt/BUILD.mk # │
|
||||
include third_party/dlmalloc/BUILD.mk #─┘
|
||||
include libc/mem/BUILD.mk #─┐
|
||||
|
@ -201,7 +261,7 @@ include libc/thread/BUILD.mk # │ You can finally call malloc()
|
|||
include third_party/zlib/BUILD.mk # │
|
||||
include libc/stdio/BUILD.mk # │
|
||||
include tool/hello/BUILD.mk # │
|
||||
include libc/time/BUILD.mk # │
|
||||
include third_party/tz/BUILD.mk # │
|
||||
include net/BUILD.mk # │
|
||||
include third_party/vqsort/BUILD.mk # │
|
||||
include libc/log/BUILD.mk # │
|
||||
|
@ -215,28 +275,40 @@ include libc/BUILD.mk #─┘
|
|||
include libc/sock/BUILD.mk #─┐
|
||||
include net/http/BUILD.mk # ├──ONLINE RUNTIME
|
||||
include third_party/musl/BUILD.mk # │ You can communicate with the network
|
||||
include third_party/regex/BUILD.mk # │
|
||||
include third_party/tr/BUILD.mk # │
|
||||
include third_party/sed/BUILD.mk # │
|
||||
include libc/system/BUILD.mk # │
|
||||
include libc/x/BUILD.mk # │
|
||||
include dsp/scale/BUILD.mk # │
|
||||
include dsp/mpeg/BUILD.mk # │
|
||||
include dsp/tty/BUILD.mk # │
|
||||
include dsp/audio/BUILD.mk # │
|
||||
include dsp/prog/BUILD.mk # │
|
||||
include dsp/BUILD.mk # │
|
||||
include third_party/stb/BUILD.mk # │
|
||||
include third_party/mbedtls/BUILD.mk # │
|
||||
include third_party/ncurses/BUILD.mk # │
|
||||
include third_party/readline/BUILD.mk # │
|
||||
include third_party/libunwind/BUILD.mk # |
|
||||
include third_party/libcxxabi/BUILD.mk # |
|
||||
include third_party/double-conversion/BUILD.mk # │
|
||||
include ctl/BUILD.mk # │
|
||||
include third_party/libcxx/BUILD.mk # │
|
||||
include third_party/openmp/BUILD.mk # │
|
||||
include third_party/pcre/BUILD.mk # │
|
||||
include third_party/less/BUILD.mk # │
|
||||
include net/https/BUILD.mk # │
|
||||
include third_party/regex/BUILD.mk # │
|
||||
include third_party/bash/BUILD.mk #─┘
|
||||
include net/https/BUILD.mk #─┘
|
||||
include third_party/tidy/BUILD.mk
|
||||
include third_party/BUILD.mk
|
||||
include third_party/nsync/testing/BUILD.mk
|
||||
include libc/testlib/BUILD.mk
|
||||
include tool/viz/lib/BUILD.mk
|
||||
include tool/args/BUILD.mk
|
||||
include test/math/BUILD.mk
|
||||
include test/posix/BUILD.mk
|
||||
include test/ctl/BUILD.mk
|
||||
include test/libcxx/BUILD.mk
|
||||
include test/tool/args/BUILD.mk
|
||||
include third_party/linenoise/BUILD.mk
|
||||
include third_party/maxmind/BUILD.mk
|
||||
|
@ -245,8 +317,6 @@ include third_party/double-conversion/test/BUILD.mk
|
|||
include third_party/lua/BUILD.mk
|
||||
include third_party/tree/BUILD.mk
|
||||
include third_party/zstd/BUILD.mk
|
||||
include third_party/tr/BUILD.mk
|
||||
include third_party/sed/BUILD.mk
|
||||
include third_party/awk/BUILD.mk
|
||||
include third_party/hiredis/BUILD.mk
|
||||
include third_party/make/BUILD.mk
|
||||
|
@ -256,7 +326,6 @@ include third_party/argon2/BUILD.mk
|
|||
include third_party/smallz4/BUILD.mk
|
||||
include third_party/sqlite3/BUILD.mk
|
||||
include third_party/mbedtls/test/BUILD.mk
|
||||
include third_party/quickjs/BUILD.mk
|
||||
include third_party/lz4cli/BUILD.mk
|
||||
include third_party/zip/BUILD.mk
|
||||
include third_party/xxhash/BUILD.mk
|
||||
|
@ -268,6 +337,7 @@ include third_party/python/BUILD.mk
|
|||
include tool/build/BUILD.mk
|
||||
include tool/curl/BUILD.mk
|
||||
include third_party/qemu/BUILD.mk
|
||||
include third_party/libcxxabi/test/BUILD.mk
|
||||
include examples/BUILD.mk
|
||||
include examples/pyapp/BUILD.mk
|
||||
include examples/pylife/BUILD.mk
|
||||
|
@ -299,7 +369,7 @@ include test/libc/fmt/BUILD.mk
|
|||
include test/libc/time/BUILD.mk
|
||||
include test/libc/proc/BUILD.mk
|
||||
include test/libc/stdio/BUILD.mk
|
||||
include test/libc/release/BUILD.mk
|
||||
include test/libc/system/BUILD.mk
|
||||
include test/libc/BUILD.mk
|
||||
include test/net/http/BUILD.mk
|
||||
include test/net/https/BUILD.mk
|
||||
|
@ -352,73 +422,82 @@ o/$(MODE)/hdrs-old.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS
|
|||
$(file >$@) $(foreach x,$(HDRS) $(INCS),$(file >>$@,$(x)))
|
||||
|
||||
TAGS: private .UNSANDBOXED = 1
|
||||
TAGS: o/$(MODE)/srcs-old.txt $(SRCS) #o/$(MODE)/third_party/ctags/ctags.com
|
||||
TAGS: o/$(MODE)/srcs-old.txt $(SRCS) #o/$(MODE)/third_party/ctags/ctags
|
||||
@$(RM) $@
|
||||
@o/$(MODE)/third_party/ctags/ctags.com $(TAGSFLAGS) -L $< -o $@
|
||||
@o/$(MODE)/third_party/ctags/ctags $(TAGSFLAGS) -L $< -o $@
|
||||
|
||||
HTAGS: private .UNSANDBOXED = 1
|
||||
HTAGS: o/$(MODE)/hdrs-old.txt $(filter-out third_party/libcxx/%,$(HDRS)) #o/$(MODE)/third_party/ctags/ctags.com
|
||||
HTAGS: o/$(MODE)/hdrs-old.txt $(filter-out third_party/libcxx/%,$(HDRS)) #o/$(MODE)/third_party/ctags/ctags
|
||||
@$(RM) $@
|
||||
@build/htags o/$(MODE)/third_party/ctags/ctags.com -L $< -o $@
|
||||
@build/htags o/$(MODE)/third_party/ctags/ctags -L $< -o $@
|
||||
|
||||
loc: private .UNSANDBOXED = 1
|
||||
loc: o/$(MODE)/tool/build/summy.com
|
||||
find -name \*.h -or -name \*.c -or -name \*.S | \
|
||||
loc: o/$(MODE)/tool/build/summy
|
||||
find -name \*.h -or -name \*.hpp -or -name \*.c -or -name \*.cc -or -name \*.cpp -or -name \*.S -or -name \*.mk | \
|
||||
$(XARGS) wc -l | grep total | awk '{print $$1}' | $<
|
||||
|
||||
# PLEASE: MAINTAIN TOPOLOGICAL ORDER
|
||||
# FROM HIGHEST LEVEL TO LOWEST LEVEL
|
||||
COSMOPOLITAN_OBJECTS = \
|
||||
TOOL_ARGS \
|
||||
NET_HTTP \
|
||||
LIBC_SOCK \
|
||||
LIBC_NT_WS2_32 \
|
||||
LIBC_NT_IPHLPAPI \
|
||||
LIBC_X \
|
||||
THIRD_PARTY_GETOPT \
|
||||
LIBC_LOG \
|
||||
LIBC_TIME \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_ZLIB_GZ \
|
||||
LIBC_STDIO \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_REGEX \
|
||||
LIBC_THREAD \
|
||||
LIBC_PROC \
|
||||
THIRD_PARTY_NSYNC_MEM \
|
||||
LIBC_MEM \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
LIBC_DLOPEN \
|
||||
LIBC_RUNTIME \
|
||||
THIRD_PARTY_NSYNC \
|
||||
LIBC_ELF \
|
||||
LIBC_IRQ \
|
||||
COSMOPOLITAN = \
|
||||
CTL \
|
||||
DSP_AUDIO \
|
||||
LIBC_CALLS \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_VGA \
|
||||
LIBC_NT_PSAPI \
|
||||
LIBC_NT_POWRPROF \
|
||||
LIBC_NT_PDH \
|
||||
LIBC_NT_GDI32 \
|
||||
LIBC_NT_COMDLG32 \
|
||||
LIBC_NT_USER32 \
|
||||
LIBC_NT_NTDLL \
|
||||
LIBC_NT_ADVAPI32 \
|
||||
LIBC_NT_SYNCHRONIZATION \
|
||||
LIBC_DLOPEN \
|
||||
LIBC_ELF \
|
||||
LIBC_FMT \
|
||||
THIRD_PARTY_ZLIB \
|
||||
THIRD_PARTY_PUFF \
|
||||
THIRD_PARTY_COMPILER_RT \
|
||||
LIBC_TINYMATH \
|
||||
THIRD_PARTY_XED \
|
||||
LIBC_STR \
|
||||
LIBC_SYSV \
|
||||
LIBC_INTRIN \
|
||||
LIBC_IRQ \
|
||||
LIBC_LOG \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_NT_ADVAPI32 \
|
||||
LIBC_NT_BCRYPTPRIMITIVES \
|
||||
LIBC_NT_COMDLG32 \
|
||||
LIBC_NT_GDI32 \
|
||||
LIBC_NT_IPHLPAPI \
|
||||
LIBC_NT_KERNEL32 \
|
||||
LIBC_NEXGEN32E
|
||||
LIBC_NT_NTDLL \
|
||||
LIBC_NT_PDH \
|
||||
LIBC_NT_POWRPROF \
|
||||
LIBC_NT_PSAPI \
|
||||
LIBC_NT_REALTIME \
|
||||
LIBC_NT_SHELL32 \
|
||||
LIBC_NT_SYNCHRONIZATION \
|
||||
LIBC_NT_USER32 \
|
||||
LIBC_NT_WS2_32 \
|
||||
LIBC_PROC \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_SOCK \
|
||||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
LIBC_SYSTEM \
|
||||
LIBC_SYSV \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_THREAD \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_VGA \
|
||||
LIBC_X \
|
||||
NET_HTTP \
|
||||
THIRD_PARTY_COMPILER_RT \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
THIRD_PARTY_DOUBLECONVERSION \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_LIBCXXABI \
|
||||
THIRD_PARTY_LIBUNWIND \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_NSYNC \
|
||||
THIRD_PARTY_NSYNC_MEM \
|
||||
THIRD_PARTY_OPENMP \
|
||||
THIRD_PARTY_PUFF \
|
||||
THIRD_PARTY_REGEX \
|
||||
THIRD_PARTY_TZ \
|
||||
THIRD_PARTY_XED \
|
||||
THIRD_PARTY_ZLIB \
|
||||
THIRD_PARTY_ZLIB_GZ \
|
||||
TOOL_ARGS \
|
||||
|
||||
COSMOPOLITAN_H_PKGS = \
|
||||
APE \
|
||||
DSP_AUDIO \
|
||||
LIBC \
|
||||
LIBC_CALLS \
|
||||
LIBC_ELF \
|
||||
|
@ -438,7 +517,6 @@ COSMOPOLITAN_H_PKGS = \
|
|||
LIBC_STR \
|
||||
LIBC_SYSV \
|
||||
LIBC_THREAD \
|
||||
LIBC_TIME \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_X \
|
||||
LIBC_VGA \
|
||||
|
@ -449,49 +527,42 @@ COSMOPOLITAN_H_PKGS = \
|
|||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_ZLIB \
|
||||
THIRD_PARTY_ZLIB_GZ \
|
||||
THIRD_PARTY_REGEX
|
||||
|
||||
COSMOCC_PKGS = \
|
||||
$(COSMOPOLITAN_H_PKGS) \
|
||||
CTL \
|
||||
THIRD_PARTY_AARCH64 \
|
||||
THIRD_PARTY_LIBCXX \
|
||||
THIRD_PARTY_LIBCXXABI \
|
||||
THIRD_PARTY_LIBUNWIND \
|
||||
THIRD_PARTY_OPENMP \
|
||||
THIRD_PARTY_INTEL
|
||||
|
||||
o/$(MODE)/cosmopolitan.a: \
|
||||
$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_A_OBJS))
|
||||
$(call reverse,$(call uniq,$(foreach x,$(COSMOPOLITAN),$($(x)))))
|
||||
|
||||
COSMOCC_HDRS = \
|
||||
$(wildcard libc/integral/*) \
|
||||
$(foreach x,$(COSMOCC_PKGS),$($(x)_HDRS)) \
|
||||
$(foreach x,$(COSMOCC_PKGS),$($(x)_INCS))
|
||||
|
||||
o/cosmocc.h.txt: Makefile
|
||||
o/cosmocc.h.txt: Makefile libc $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x)))) $(HDRS) $(INCS)
|
||||
$(file >$@, $(call uniq,$(COSMOCC_HDRS)))
|
||||
|
||||
COSMOPOLITAN_H_ROOT_HDRS = \
|
||||
libc/integral/normalize.inc \
|
||||
$(foreach x,$(COSMOPOLITAN_H_PKGS),$($(x)_HDRS))
|
||||
|
||||
o/cosmopolitan.h.txt: Makefile
|
||||
$(file >$@, $(call uniq,$(COSMOPOLITAN_H_ROOT_HDRS)))
|
||||
|
||||
o/cosmopolitan.h: o/cosmopolitan.h.txt \
|
||||
$(wildcard libc/integral/*) \
|
||||
$(foreach x,$(COSMOPOLITAN_H_PKGS),$($(x)_HDRS)) \
|
||||
$(foreach x,$(COSMOPOLITAN_H_PKGS),$($(x)_INCS))
|
||||
@$(ECHO) '#ifndef __STRICT_ANSI__' >$@
|
||||
@$(ECHO) '#define _COSMO_SOURCE' >>$@
|
||||
@$(ECHO) '#endif' >>$@
|
||||
@$(COMPILE) -AROLLUP -T$@ build/bootstrap/rollup.com @$< >>$@
|
||||
|
||||
o/cosmopolitan.html: private .UNSANDBOXED = 1
|
||||
o/cosmopolitan.html: \
|
||||
o/$(MODE)/third_party/chibicc/chibicc.com.dbg \
|
||||
o/$(MODE)/third_party/chibicc/chibicc.dbg \
|
||||
$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))) \
|
||||
$(SRCS) \
|
||||
$(filter-out %.cpp,$(filter-out %.cc,$(SRCS))) \
|
||||
$(HDRS)
|
||||
$(file >$(TMPDIR)/$(subst /,_,$@),$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))))
|
||||
o/$(MODE)/third_party/chibicc/chibicc.com.dbg -J \
|
||||
$(file >$(TMPDIR)/$(subst /,_,$@),$(filter-out %.cpp,$(filter-out %.cc,$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))))))
|
||||
o/$(MODE)/third_party/chibicc/chibicc.dbg -J \
|
||||
-fno-common -include libc/integral/normalize.inc -o $@ \
|
||||
-DCOSMO @$(TMPDIR)/$(subst /,_,$@)
|
||||
|
||||
|
@ -505,7 +576,6 @@ $(SRCS): \
|
|||
|
||||
ifeq ($(ARCH), x86_64)
|
||||
TOOLCHAIN_ARTIFACTS = \
|
||||
o/cosmopolitan.h \
|
||||
o/$(MODE)/ape/ape.lds \
|
||||
o/$(MODE)/libc/crt/crt.o \
|
||||
o/$(MODE)/ape/ape.elf \
|
||||
|
@ -514,13 +584,13 @@ TOOLCHAIN_ARTIFACTS = \
|
|||
o/$(MODE)/ape/ape-no-modify-self.o \
|
||||
o/$(MODE)/cosmopolitan.a \
|
||||
o/$(MODE)/third_party/libcxx/libcxx.a \
|
||||
o/$(MODE)/tool/build/march-native.com \
|
||||
o/$(MODE)/tool/build/ar.com \
|
||||
o/$(MODE)/tool/build/mktemper.com \
|
||||
o/$(MODE)/tool/build/fixupobj.com \
|
||||
o/$(MODE)/tool/build/zipcopy.com \
|
||||
o/$(MODE)/tool/build/apelink.com \
|
||||
o/$(MODE)/tool/build/pecheck.com
|
||||
o/$(MODE)/tool/build/march-native \
|
||||
o/$(MODE)/tool/build/ar \
|
||||
o/$(MODE)/tool/build/mktemper \
|
||||
o/$(MODE)/tool/build/fixupobj \
|
||||
o/$(MODE)/tool/build/zipcopy \
|
||||
o/$(MODE)/tool/build/apelink \
|
||||
o/$(MODE)/tool/build/pecheck
|
||||
else
|
||||
TOOLCHAIN_ARTIFACTS = \
|
||||
o/$(MODE)/ape/ape.elf \
|
||||
|
@ -528,9 +598,9 @@ TOOLCHAIN_ARTIFACTS = \
|
|||
o/$(MODE)/libc/crt/crt.o \
|
||||
o/$(MODE)/cosmopolitan.a \
|
||||
o/$(MODE)/third_party/libcxx/libcxx.a \
|
||||
o/$(MODE)/tool/build/march-native.com \
|
||||
o/$(MODE)/tool/build/fixupobj.com \
|
||||
o/$(MODE)/tool/build/zipcopy.com
|
||||
o/$(MODE)/tool/build/march-native \
|
||||
o/$(MODE)/tool/build/fixupobj \
|
||||
o/$(MODE)/tool/build/zipcopy
|
||||
endif
|
||||
|
||||
.PHONY: toolchain
|
||||
|
|
58
README.md
58
README.md
|
@ -3,12 +3,12 @@
|
|||
[](https://github.com/jart/cosmopolitan/actions/workflows/build.yml)
|
||||
# Cosmopolitan
|
||||
|
||||
[Cosmopolitan Libc](https://justine.lol/cosmopolitan/index.html) makes C
|
||||
[Cosmopolitan Libc](https://justine.lol/cosmopolitan/index.html) makes C/C++
|
||||
a build-once run-anywhere language, like Java, except it doesn't need an
|
||||
interpreter or virtual machine. Instead, it reconfigures stock GCC and
|
||||
Clang to output a POSIX-approved polyglot format that runs natively on
|
||||
Linux + Mac + Windows + FreeBSD + OpenBSD + NetBSD + BIOS with the best
|
||||
possible performance and the tiniest footprint imaginable.
|
||||
Linux + Mac + Windows + FreeBSD + OpenBSD 7.3 + NetBSD + BIOS with the
|
||||
best possible performance and the tiniest footprint imaginable.
|
||||
|
||||
## Background
|
||||
|
||||
|
@ -76,18 +76,7 @@ make install
|
|||
## Cosmopolitan Source Builds
|
||||
|
||||
Cosmopolitan can be compiled from source on any of our supported
|
||||
platforms. First, you need to download or clone the repository. If
|
||||
you're not using x86-64 Linux then you'll need cosmocc too.
|
||||
|
||||
```sh
|
||||
git clone https://github.com/jart/cosmopolitan cosmo
|
||||
cd cosmo
|
||||
mkdir -p o/third_party/gcc
|
||||
pushd o/third_party/gcc
|
||||
wget https://cosmo.zip/pub/cosmocc/cosmocc.zip
|
||||
unzip cosmocc.zip
|
||||
popd
|
||||
```
|
||||
platforms. The Makefile will download cosmocc automatically.
|
||||
|
||||
It's recommended that you install a systemwide APE Loader. This command
|
||||
requires `sudo` access to copy the `ape` command to a system folder and
|
||||
|
@ -98,15 +87,22 @@ ape/apeinstall.sh
|
|||
```
|
||||
|
||||
You can now build the mono repo with any modern version of GNU Make. To
|
||||
make life easier, we've included one in the cosmocc toolchain, which is
|
||||
guaranteed to be compatible and furthermore includes our extensions for
|
||||
doing build system sandboxing.
|
||||
bootstrap your build, you can install Cosmopolitan Make from this site:
|
||||
|
||||
https://cosmo.zip/pub/cosmos/bin/make
|
||||
|
||||
E.g.:
|
||||
|
||||
```sh
|
||||
o//third_party/gcc/bin/make -j8
|
||||
o//examples/hello.com
|
||||
curl -LO https://cosmo.zip/pub/cosmos/bin/make
|
||||
./make -j8
|
||||
o//examples/hello
|
||||
```
|
||||
|
||||
After you've built the repo once, you can also use the make from your
|
||||
cosmocc at `.cosmocc/current/bin/make`. You might even prefer to alias
|
||||
make to `$COSMO/.cosmocc/current/bin/make`.
|
||||
|
||||
Since the Cosmopolitan repository is very large, you might only want to
|
||||
build one particular thing. Here's an example of a target that can be
|
||||
compiled relatively quickly, which is a simple POSIX test that only
|
||||
|
@ -114,8 +110,8 @@ depends on core LIBC packages.
|
|||
|
||||
```sh
|
||||
rm -rf o//libc o//test
|
||||
o//third_party/gcc/bin/make o//test/posix/signal_test.com
|
||||
o//test/posix/signal_test.com
|
||||
.cosmocc/current/bin/make o//test/posix/signal_test
|
||||
o//test/posix/signal_test
|
||||
```
|
||||
|
||||
Sometimes it's desirable to build a subset of targets, without having to
|
||||
|
@ -123,21 +119,21 @@ list out each individual one. For example if you wanted to build and run
|
|||
all the unit tests in the `TEST_POSIX` package, you could say:
|
||||
|
||||
```sh
|
||||
o//third_party/gcc/bin/make o//test/posix
|
||||
.cosmocc/current/bin/make o//test/posix
|
||||
```
|
||||
|
||||
Cosmopolitan provides a variety of build modes. For example, if you want
|
||||
really tiny binaries (as small as 12kb in size) then you'd say:
|
||||
|
||||
```sh
|
||||
o//third_party/gcc/bin/make m=tiny
|
||||
.cosmocc/current/bin/make m=tiny
|
||||
```
|
||||
|
||||
You can furthermore cut out the bloat of other operating systems, and
|
||||
have Cosmopolitan become much more similar to Musl Libc.
|
||||
|
||||
```sh
|
||||
o//third_party/gcc/bin/make m=tinylinux
|
||||
.cosmocc/current/bin/make m=tinylinux
|
||||
```
|
||||
|
||||
For further details, see [//build/config.mk](build/config.mk).
|
||||
|
@ -190,11 +186,11 @@ end
|
|||
src
|
||||
```
|
||||
|
||||
You normally run the `.com.dbg` file under gdb. If you need to debug the
|
||||
`.com` file itself, then you can load the debug symbols independently as
|
||||
You normally run the `.dbg` file under gdb. If you need to debug the
|
||||
`` file itself, then you can load the debug symbols independently as
|
||||
|
||||
```sh
|
||||
gdb foo.com -ex 'add-symbol-file foo.com.dbg 0x401000'
|
||||
gdb foo -ex 'add-symbol-file foo.dbg 0x401000'
|
||||
```
|
||||
|
||||
## Platform Notes
|
||||
|
@ -255,12 +251,12 @@ server. You're welcome to join us! <https://discord.gg/FwAVVu7eJ4>
|
|||
|
||||
| Platform | Min Version | Circa |
|
||||
| :--- | ---: | ---: |
|
||||
| AMD | K8 Venus | 2005 |
|
||||
| AMD | K8 | 2003 |
|
||||
| Intel | Core | 2006 |
|
||||
| Linux | 2.6.18 | 2007 |
|
||||
| Windows | 8 [1] | 2012 |
|
||||
| Mac OS X | 15.6 | 2018 |
|
||||
| OpenBSD | 7 | 2021 |
|
||||
| Darwin (macOS) | 23.1.0+ | 2023 |
|
||||
| OpenBSD | 7.3 or earlier | 2023 |
|
||||
| FreeBSD | 13 | 2020 |
|
||||
| NetBSD | 9.2 | 2021 |
|
||||
|
||||
|
|
55
ape/BUILD.mk
55
ape/BUILD.mk
|
@ -45,10 +45,10 @@ o/$(MODE)/ape: $(APE)
|
|||
|
||||
o/$(MODE)/ape/aarch64.lds: \
|
||||
ape/aarch64.lds \
|
||||
libc/zip.internal.h \
|
||||
libc/zip.h \
|
||||
libc/thread/tls.h \
|
||||
libc/calls/struct/timespec.h \
|
||||
libc/macros.internal.h \
|
||||
libc/macros.h \
|
||||
libc/str/str.h
|
||||
|
||||
APE_LOADER_LDFLAGS = \
|
||||
|
@ -157,15 +157,13 @@ o/$(MODE)/ape/ape-no-modify-self.o: \
|
|||
ape/ape.S \
|
||||
ape/ape.h \
|
||||
ape/macros.internal.h \
|
||||
ape/notice.inc \
|
||||
ape/relocations.h \
|
||||
ape/ape.internal.h \
|
||||
libc/dce.h \
|
||||
libc/elf/def.h \
|
||||
libc/thread/tls.h \
|
||||
libc/intrin/asancodes.h \
|
||||
libc/macho.internal.h \
|
||||
libc/macros.internal.h \
|
||||
libc/macho.h \
|
||||
libc/macros.h \
|
||||
libc/nexgen32e/uart.internal.h \
|
||||
libc/calls/metalfile.internal.h \
|
||||
libc/nt/pedef.internal.h \
|
||||
|
@ -173,8 +171,6 @@ o/$(MODE)/ape/ape-no-modify-self.o: \
|
|||
libc/runtime/mman.internal.h \
|
||||
libc/runtime/pc.internal.h \
|
||||
libc/sysv/consts/prot.h \
|
||||
ape/blink-linux-aarch64.gz \
|
||||
ape/blink-xnu-aarch64.gz \
|
||||
o/$(MODE)/ape/ape.elf
|
||||
@$(COMPILE) \
|
||||
-AOBJECTIFY.S \
|
||||
|
@ -187,24 +183,20 @@ o/$(MODE)/ape/ape-copy-self.o: \
|
|||
ape/ape.S \
|
||||
ape/ape.h \
|
||||
ape/macros.internal.h \
|
||||
ape/notice.inc \
|
||||
ape/relocations.h \
|
||||
ape/ape.internal.h \
|
||||
libc/dce.h \
|
||||
libc/elf/def.h \
|
||||
libc/thread/tls.h \
|
||||
libc/intrin/asancodes.h \
|
||||
libc/macho.internal.h \
|
||||
libc/macros.internal.h \
|
||||
libc/macho.h \
|
||||
libc/macros.h \
|
||||
libc/nexgen32e/uart.internal.h \
|
||||
libc/calls/metalfile.internal.h \
|
||||
libc/nt/pedef.internal.h \
|
||||
libc/runtime/e820.internal.h \
|
||||
libc/runtime/mman.internal.h \
|
||||
libc/runtime/pc.internal.h \
|
||||
libc/sysv/consts/prot.h \
|
||||
ape/blink-linux-aarch64.gz \
|
||||
ape/blink-xnu-aarch64.gz
|
||||
libc/sysv/consts/prot.h
|
||||
@$(COMPILE) \
|
||||
-AOBJECTIFY.S \
|
||||
$(OBJECTIFY.S) \
|
||||
|
@ -226,10 +218,10 @@ o/$(MODE)/ape/loader-xnu-clang.asm: ape/loader.c
|
|||
@$(COMPILE) -AOBJECTIFY.c $(CLANG) -DSUPPORT_VECTOR=8 -S -g0 $(APE_LOADER_FLAGS)
|
||||
|
||||
o/$(MODE)/ape/ape.elf: o/$(MODE)/ape/ape.elf.dbg
|
||||
@$(COMPILE) -AOBJBINCOPY -w build/bootstrap/objbincopy.com -f -o $@ $<
|
||||
@$(COMPILE) -AOBJBINCOPY -w $(OBJBINCOPY) -f -o $@ $<
|
||||
|
||||
o/$(MODE)/ape/ape.macho: o/$(MODE)/ape/ape.elf.dbg
|
||||
@$(COMPILE) -AOBJBINCOPY -w build/bootstrap/objbincopy.com -fm -o $@ $<
|
||||
@$(COMPILE) -AOBJBINCOPY -w $(OBJBINCOPY) -fm -o $@ $<
|
||||
|
||||
APE_LOADER_LDFLAGS = \
|
||||
-static \
|
||||
|
@ -254,18 +246,29 @@ o/$(MODE)/ape: $(APE_CHECKS) \
|
|||
o/$(MODE)/ape/ape.lds \
|
||||
o/$(MODE)/ape/ape.elf \
|
||||
o/$(MODE)/ape/ape.macho \
|
||||
o/$(MODE)/ape/ape-copy-self.o \
|
||||
o/$(MODE)/ape/ape-no-modify-self.o
|
||||
|
||||
endif
|
||||
|
||||
# these assembly files are safe to build on aarch64
|
||||
o/$(MODE)/ape/ape.o: ape/ape.S
|
||||
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
|
||||
|
||||
o/$(MODE)/ape/ape.o: \
|
||||
ape/blink-linux-aarch64.gz \
|
||||
ape/blink-xnu-aarch64.gz
|
||||
ape/ape.S \
|
||||
ape/ape.h \
|
||||
libc/dce.h \
|
||||
libc/elf/def.h \
|
||||
ape/relocations.h \
|
||||
libc/thread/tls.h \
|
||||
ape/ape.internal.h \
|
||||
ape/macros.internal.h \
|
||||
libc/macho.h \
|
||||
libc/macros.h \
|
||||
libc/sysv/consts/prot.h \
|
||||
libc/nt/pedef.internal.h \
|
||||
libc/runtime/pc.internal.h \
|
||||
libc/runtime/e820.internal.h \
|
||||
libc/runtime/mman.internal.h \
|
||||
libc/nexgen32e/uart.internal.h \
|
||||
libc/calls/metalfile.internal.h
|
||||
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
|
||||
|
||||
o/$(MODE)/ape/ape.lds: \
|
||||
ape/ape.lds \
|
||||
|
@ -278,7 +281,7 @@ o/$(MODE)/ape/ape.lds: \
|
|||
libc/dce.h \
|
||||
libc/elf/def.h \
|
||||
libc/elf/pf2prot.internal.h \
|
||||
libc/macros.internal.h \
|
||||
libc/macros.h \
|
||||
libc/nt/pedef.internal.h \
|
||||
libc/str/str.h \
|
||||
libc/zip.internal.h
|
||||
libc/zip.h
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*-*- mode: ld-script; indent-tabs-mode: nil; tab-width: 2; coding: utf-8 -*-│
|
||||
│ vi: set et sts=2 sw=2 fenc=utf-8 :vi │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
ENTRY(_start)
|
||||
|
@ -11,7 +12,7 @@ OUTPUT_FORMAT("elf64-littleaarch64",
|
|||
|
||||
SECTIONS {
|
||||
|
||||
. = SEGMENT_START("text-segment", 0x010000000000);
|
||||
. = SEGMENT_START("text-segment", 0x000800000000);
|
||||
__executable_start = .;
|
||||
. += SIZEOF_HEADERS;
|
||||
|
||||
|
@ -89,10 +90,12 @@ SECTIONS {
|
|||
*(.ubsan.data)
|
||||
}
|
||||
|
||||
.comment : {
|
||||
__comment_start = .;
|
||||
KEEP(*(.comment))
|
||||
.notice : {
|
||||
__notices = .;
|
||||
KEEP(*(.notice))
|
||||
BYTE(0);
|
||||
BYTE(10);
|
||||
BYTE(10);
|
||||
}
|
||||
|
||||
.eh_frame_hdr : {
|
||||
|
@ -100,10 +103,8 @@ SECTIONS {
|
|||
*(.eh_frame_entry .eh_frame_entry.*)
|
||||
}
|
||||
|
||||
.eh_frame : ONLY_IF_RO {
|
||||
KEEP(*(.eh_frame))
|
||||
*(.eh_frame.*)
|
||||
}
|
||||
__eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0;
|
||||
__eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0;
|
||||
|
||||
.gcc_except_table : ONLY_IF_RO {
|
||||
*(.gcc_except_table .gcc_except_table.*)
|
||||
|
@ -124,9 +125,11 @@ SECTIONS {
|
|||
. += CONSTANT(MAXPAGESIZE);
|
||||
. = DATA_SEGMENT_ALIGN(CONSTANT(MAXPAGESIZE), CONSTANT(COMMONPAGESIZE));
|
||||
|
||||
.eh_frame : ONLY_IF_RW {
|
||||
.eh_frame : {
|
||||
__eh_frame_start = .;
|
||||
KEEP(*(.eh_frame))
|
||||
*(.eh_frame.*)
|
||||
__eh_frame_end = .;
|
||||
}
|
||||
|
||||
.gnu_extab : ONLY_IF_RW {
|
||||
|
@ -157,8 +160,11 @@ SECTIONS {
|
|||
|
||||
.init_array : {
|
||||
__init_array_start = .;
|
||||
KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
|
||||
KEEP(*(.init_array EXCLUDE_FILE(*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
|
||||
KEEP(*(.preinit_array))
|
||||
KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*)
|
||||
SORT_BY_INIT_PRIORITY(.ctors.*)))
|
||||
KEEP(*(.init_array))
|
||||
KEEP(*(.ctors))
|
||||
__init_array_end = .;
|
||||
}
|
||||
|
||||
|
@ -253,6 +259,9 @@ SECTIONS {
|
|||
.debug_ranges 0 : { *(.debug_ranges) }
|
||||
.debug_macro 0 : { *(.debug_macro) }
|
||||
.debug_addr 0 : { *(.debug_addr) }
|
||||
.debug_names 0 : { *(.debug_names) }
|
||||
.debug_loclists 0 : { *(.debug_loclists) }
|
||||
.debug_str_offsets 0 : { *(.debug_str_offsets) }
|
||||
.ARM.attributes 0 : { KEEP(*(.ARM.attributes)) KEEP(*(.gnu.attributes)) }
|
||||
.note.gnu.arm.ident 0 : { KEEP(*(.note.gnu.arm.ident)) }
|
||||
|
||||
|
@ -280,15 +289,13 @@ SECTIONS {
|
|||
|
||||
ape_stack_vaddr = DEFINED(ape_stack_vaddr) ? ape_stack_vaddr : 0x700000000000;
|
||||
ape_stack_memsz = DEFINED(ape_stack_memsz) ? ape_stack_memsz : 8 * 1024 * 1024;
|
||||
ape_stack_align = DEFINED(ape_stack_align) ? ape_stack_align : 16;
|
||||
ape_stack_round = -ape_stack_align;
|
||||
ape_stack_prot = PROT_READ | PROT_WRITE;
|
||||
|
||||
_tls_size = _tbss_end - _tdata_start;
|
||||
_tdata_size = _tdata_end - _tdata_start;
|
||||
_tbss_size = _tbss_end - _tbss_start;
|
||||
_tbss_offset = _tbss_start - _tdata_start;
|
||||
_tls_content = (_tdata_end - _tdata_start) + (_tbss_end - _tbss_start);
|
||||
_tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss));
|
||||
|
||||
ASSERT(ALIGNOF(.tdata) <= TLS_ALIGNMENT && ALIGNOF(.tbss) <= TLS_ALIGNMENT,
|
||||
"_Thread_local _Alignof can't exceed TLS_ALIGNMENT");
|
||||
_tdata_align = ALIGNOF(.tdata);
|
||||
_tbss_align = ALIGNOF(.tbss);
|
||||
_tls_align = MAX(TLS_ALIGNMENT, MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)));
|
||||
|
|
245
ape/ape-m1.c
245
ape/ape-m1.c
|
@ -16,6 +16,12 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#ifndef __APPLE__
|
||||
#error "ape/ape-m1.c is for apple silicon. chances you want ape/loader.c"
|
||||
#endif
|
||||
#ifndef __aarch64__
|
||||
#error "ape/ape-m1.c is for apple silicon; you want: make o//ape/ape.macho"
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
#include <dlfcn.h>
|
||||
|
@ -31,6 +37,8 @@
|
|||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/random.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
@ -39,7 +47,7 @@
|
|||
/* maximum path size that cosmo can take */
|
||||
#define PATHSIZE (PATH_MAX < 1024 ? PATH_MAX : 1024)
|
||||
#define SYSLIB_MAGIC ('s' | 'l' << 8 | 'i' << 16 | 'b' << 24)
|
||||
#define SYSLIB_VERSION 8
|
||||
#define SYSLIB_VERSION 10 /* sync with libc/runtime/syslib.internal.h */
|
||||
|
||||
struct Syslib {
|
||||
int magic;
|
||||
|
@ -96,11 +104,20 @@ struct Syslib {
|
|||
long (*sem_trywait)(int *);
|
||||
long (*getrlimit)(int, struct rlimit *);
|
||||
long (*setrlimit)(int, const struct rlimit *);
|
||||
// v6 (2023-11-03)
|
||||
/* v6 (2023-11-03) */
|
||||
void *(*dlopen)(const char *, int);
|
||||
void *(*dlsym)(void *, const char *);
|
||||
int (*dlclose)(void *);
|
||||
char *(*dlerror)(void);
|
||||
/* MANDATORY (cosmo runtime won't load if version < 8)
|
||||
---------------------------------------------------
|
||||
OPTIONAL (cosmo lib should check __syslib->version) */
|
||||
/* v9 (2024-01-31) */
|
||||
int (*pthread_cpu_number_np)(size_t *);
|
||||
/* v10 (2024-05-02) */
|
||||
long (*sysctl)(int *, u_int, void *, size_t *, void *, size_t);
|
||||
long (*sysctlbyname)(const char *, void *, size_t *, void *, size_t);
|
||||
long (*sysctlnametomib)(const char *, int *, size_t *);
|
||||
};
|
||||
|
||||
#define ELFCLASS32 1
|
||||
|
@ -121,6 +138,9 @@ struct Syslib {
|
|||
#define AT_PHNUM 5
|
||||
#define AT_PAGESZ 6
|
||||
#define AT_BASE 7
|
||||
#define AT_FLAGS 8
|
||||
#define AT_FLAGS_PRESERVE_ARGV0_BIT 0
|
||||
#define AT_FLAGS_PRESERVE_ARGV0 (1 << AT_FLAGS_PRESERVE_ARGV0_BIT)
|
||||
#define AT_ENTRY 9
|
||||
#define AT_UID 11
|
||||
#define AT_EUID 12
|
||||
|
@ -132,7 +152,10 @@ struct Syslib {
|
|||
#define AT_RANDOM 25
|
||||
#define AT_EXECFN 31
|
||||
|
||||
#define AUXV_WORDS 29
|
||||
#define EF_APE_MODERN 0x101ca75
|
||||
#define EF_APE_MODERN_MASK 0x1ffffff
|
||||
|
||||
#define AUXV_WORDS 31
|
||||
|
||||
/* from the xnu codebase */
|
||||
#define _COMM_PAGE_START_ADDRESS 0x0000000FFFFFC000ul
|
||||
|
@ -140,8 +163,8 @@ struct Syslib {
|
|||
#define _COMM_PAGE_APRR_WRITE_ENABLE (_COMM_PAGE_START_ADDRESS + 0x110)
|
||||
#define _COMM_PAGE_APRR_WRITE_DISABLE (_COMM_PAGE_START_ADDRESS + 0x118)
|
||||
|
||||
#define MIN(X, Y) ((Y) > (X) ? (X) : (Y))
|
||||
#define MAX(X, Y) ((Y) < (X) ? (X) : (Y))
|
||||
#define Min(X, Y) ((Y) > (X) ? (X) : (Y))
|
||||
#define Max(X, Y) ((Y) < (X) ? (X) : (Y))
|
||||
|
||||
#define READ32(S) \
|
||||
((unsigned)(255 & (S)[3]) << 030 | (unsigned)(255 & (S)[2]) << 020 | \
|
||||
|
@ -213,13 +236,15 @@ struct ApeLoader {
|
|||
|
||||
static unsigned long StrLen(const char *s) {
|
||||
unsigned long n = 0;
|
||||
while (*s++) ++n;
|
||||
while (*s++)
|
||||
++n;
|
||||
return n;
|
||||
}
|
||||
|
||||
static int StrCmp(const char *l, const char *r) {
|
||||
unsigned long i = 0;
|
||||
while (l[i] == r[i] && r[i]) ++i;
|
||||
while (l[i] == r[i] && r[i])
|
||||
++i;
|
||||
return (l[i] & 255) - (r[i] & 255);
|
||||
}
|
||||
|
||||
|
@ -268,7 +293,8 @@ static char *Utoa(char p[21], unsigned long x) {
|
|||
}
|
||||
|
||||
static char *Itoa(char p[21], long x) {
|
||||
if (x < 0) *p++ = '-', x = -(unsigned long)x;
|
||||
if (x < 0)
|
||||
*p++ = '-', x = -(unsigned long)x;
|
||||
return Utoa(p, x);
|
||||
}
|
||||
|
||||
|
@ -304,7 +330,8 @@ static int GetIndirectOffset(const char *arg0) {
|
|||
static void Perror(const char *thing, long rc, const char *reason) {
|
||||
char ibuf[21];
|
||||
ibuf[0] = 0;
|
||||
if (rc) Itoa(ibuf, -rc);
|
||||
if (rc)
|
||||
Itoa(ibuf, -rc);
|
||||
Print(2, "ape error: ", thing, ": ", reason, rc ? " failed w/ errno " : "",
|
||||
ibuf, "\n", 0l);
|
||||
}
|
||||
|
@ -319,20 +346,11 @@ static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) {
|
|||
if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path)) {
|
||||
return 0;
|
||||
}
|
||||
if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/';
|
||||
if (pathlen && ps->path[pathlen - 1] != '/')
|
||||
ps->path[pathlen++] = '/';
|
||||
memmove(ps->path + pathlen, ps->name, ps->namelen);
|
||||
ps->path[pathlen + ps->namelen] = 0;
|
||||
if (!access(ps->path, X_OK)) {
|
||||
if (ps->indirect) {
|
||||
ps->namelen -= 4;
|
||||
ps->path[pathlen + ps->namelen] = 0;
|
||||
if (access(ps->path, X_OK) < 0) {
|
||||
Pexit(ps->path, -errno, "access(X_OK)");
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
return !access(ps->path, X_OK);
|
||||
}
|
||||
|
||||
static char SearchPath(struct PathSearcher *ps) {
|
||||
|
@ -358,12 +376,8 @@ static char FindCommand(struct PathSearcher *ps) {
|
|||
ps->path[0] = 0;
|
||||
|
||||
/* paths are always 100% taken literally when a slash exists
|
||||
$ ape foo/bar.com arg1 arg2 */
|
||||
if (memchr(ps->name, '/', ps->namelen)) {
|
||||
return AccessCommand(ps, 0);
|
||||
}
|
||||
|
||||
/* we don't run files in the current directory
|
||||
$ ape foo/bar.com arg1 arg2
|
||||
we don't run files in the current directory
|
||||
$ ape foo.com arg1 arg2
|
||||
unless $PATH has an empty string entry, e.g.
|
||||
$ expert PATH=":/bin"
|
||||
|
@ -371,8 +385,8 @@ static char FindCommand(struct PathSearcher *ps) {
|
|||
however we will execute this
|
||||
$ ape - foo.com foo.com arg1 arg2
|
||||
because cosmo's execve needs it */
|
||||
if (ps->literally && AccessCommand(ps, 0)) {
|
||||
return 1;
|
||||
if (ps->literally || memchr(ps->name, '/', ps->namelen)) {
|
||||
return AccessCommand(ps, 0);
|
||||
}
|
||||
|
||||
/* otherwise search for name on $PATH */
|
||||
|
@ -382,8 +396,11 @@ static char FindCommand(struct PathSearcher *ps) {
|
|||
static char *Commandv(struct PathSearcher *ps, const char *name,
|
||||
const char *syspath) {
|
||||
ps->syspath = syspath ? syspath : "/bin:/usr/local/bin:/usr/bin";
|
||||
if (!(ps->namelen = StrLen((ps->name = name)))) return 0;
|
||||
if (ps->namelen + 1 > sizeof(ps->path)) return 0;
|
||||
ps->name = name;
|
||||
if (!(ps->namelen = ps->indirect ? ps->indirect : StrLen(ps->name)))
|
||||
return 0;
|
||||
if (ps->namelen + 1 > sizeof(ps->path))
|
||||
return 0;
|
||||
if (FindCommand(ps)) {
|
||||
return ps->path;
|
||||
} else {
|
||||
|
@ -550,6 +567,20 @@ static long sys_pselect(int nfds, fd_set *readfds, fd_set *writefds,
|
|||
return sysret(pselect(nfds, readfds, writefds, errorfds, timeout, sigmask));
|
||||
}
|
||||
|
||||
static long sys_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
|
||||
void *newp, size_t newlen) {
|
||||
return sysret(sysctl(name, namelen, oldp, oldlenp, newp, newlen));
|
||||
}
|
||||
|
||||
static long sys_sysctlbyname(const char *name, void *oldp, size_t *oldlenp,
|
||||
void *newp, size_t newlen) {
|
||||
return sysret(sysctlbyname(name, oldp, oldlenp, newp, newlen));
|
||||
}
|
||||
|
||||
static long sys_sysctlnametomib(const char *name, int *mibp, size_t *sizep) {
|
||||
return sysret(sysctlnametomib(name, mibp, sizep));
|
||||
}
|
||||
|
||||
__attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
||||
long *sp, struct ElfEhdr *e,
|
||||
struct ElfPhdr *p,
|
||||
|
@ -590,10 +621,11 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
|||
a = p[i].p_vaddr & -pagesz;
|
||||
b = (p[i].p_vaddr + p[i].p_memsz + (pagesz - 1)) & -pagesz;
|
||||
for (j = i + 1; j < e->e_phnum; ++j) {
|
||||
if (p[j].p_type != PT_LOAD) continue;
|
||||
if (p[j].p_type != PT_LOAD)
|
||||
continue;
|
||||
c = p[j].p_vaddr & -pagesz;
|
||||
d = (p[j].p_vaddr + p[j].p_memsz + (pagesz - 1)) & -pagesz;
|
||||
if (MAX(a, c) < MIN(b, d)) {
|
||||
if (Max(a, c) < Min(b, d)) {
|
||||
Pexit(exe, 0, "ELF segments overlap each others virtual memory");
|
||||
}
|
||||
}
|
||||
|
@ -619,7 +651,8 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
|||
if (e->e_type == ET_DYN) {
|
||||
rc = sys_mmap(0, virtmax - virtmin, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
if (rc < 0) Pexit(exe, rc, "pie mmap");
|
||||
if (rc < 0)
|
||||
Pexit(exe, rc, "pie mmap");
|
||||
dynbase = rc;
|
||||
if (dynbase & (pagesz - 1)) {
|
||||
Pexit(exe, 0, "OS mmap incongruent w/ AT_PAGESZ");
|
||||
|
@ -635,14 +668,18 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
|||
for (i = 0; i < e->e_phnum; ++i) {
|
||||
void *addr;
|
||||
unsigned long size;
|
||||
if (p[i].p_type != PT_LOAD) continue;
|
||||
if (p[i].p_type != PT_LOAD)
|
||||
continue;
|
||||
|
||||
/* configure mapping */
|
||||
prot = 0;
|
||||
flags = MAP_FIXED | MAP_PRIVATE;
|
||||
if (p[i].p_flags & PF_R) prot |= PROT_READ;
|
||||
if (p[i].p_flags & PF_W) prot |= PROT_WRITE;
|
||||
if (p[i].p_flags & PF_X) prot |= PROT_EXEC;
|
||||
if (p[i].p_flags & PF_R)
|
||||
prot |= PROT_READ;
|
||||
if (p[i].p_flags & PF_W)
|
||||
prot |= PROT_WRITE;
|
||||
if (p[i].p_flags & PF_X)
|
||||
prot |= PROT_EXEC;
|
||||
|
||||
/* load from file */
|
||||
if (p[i].p_filesz) {
|
||||
|
@ -662,7 +699,7 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
|||
a = p[i].p_vaddr + p[i].p_filesz; /* end of file content */
|
||||
b = (a + (pagesz - 1)) & -pagesz; /* first pure bss page */
|
||||
c = p[i].p_vaddr + p[i].p_memsz; /* end of segment data */
|
||||
wipe = MIN(b - a, c - a);
|
||||
wipe = Min(b - a, c - a);
|
||||
if (wipe && (~prot1 & PROT_WRITE)) {
|
||||
prot1 = PROT_READ | PROT_WRITE;
|
||||
}
|
||||
|
@ -670,9 +707,9 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
|||
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_filesz;
|
||||
if (prot1 & PROT_EXEC) {
|
||||
#ifdef SIP_DISABLED
|
||||
// if sip is disabled then we can load the executable segments
|
||||
// off the binary into memory without needing to copy anything
|
||||
// which provides considerably better performance for building
|
||||
/* if sip is disabled then we can load the executable segments
|
||||
off the binary into memory without needing to copy anything
|
||||
which provides considerably better performance for building */
|
||||
rc = sys_mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz);
|
||||
if (rc < 0) {
|
||||
if (rc == -EPERM) {
|
||||
|
@ -684,32 +721,38 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
|||
}
|
||||
}
|
||||
#else
|
||||
// the issue is that if sip is enabled then, attempting to map
|
||||
// it with exec permission will cause xnu to phone home a hash
|
||||
// of the entire file to apple intelligence as a one time cost
|
||||
// which is literally minutes for executables holding big data
|
||||
// since there's no public apple api for detecting sip we read
|
||||
// as the default strategy which is slow but it works for both
|
||||
/* the issue is that if sip is enabled then, attempting to map
|
||||
it with exec permission will cause xnu to phone home a hash
|
||||
of the entire file to apple intelligence as a one time cost
|
||||
which is literally minutes for executables holding big data
|
||||
since there's no public apple api for detecting sip we read
|
||||
as the default strategy which is slow but it works for both */
|
||||
rc = sys_mmap(addr, size, (prot1 = PROT_READ | PROT_WRITE),
|
||||
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
|
||||
if (rc < 0) Pexit(exe, rc, "prog mmap anon");
|
||||
if (rc < 0)
|
||||
Pexit(exe, rc, "prog mmap anon");
|
||||
rc = pread(fd, addr, p[i].p_filesz, p[i].p_offset & -pagesz);
|
||||
if (rc != p[i].p_filesz) Pexit(exe, -errno, "prog pread");
|
||||
if (rc != p[i].p_filesz)
|
||||
Pexit(exe, -errno, "prog pread");
|
||||
#endif
|
||||
} else {
|
||||
rc = sys_mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz);
|
||||
if (rc < 0) Pexit(exe, rc, "prog mmap");
|
||||
if (rc < 0)
|
||||
Pexit(exe, rc, "prog mmap");
|
||||
}
|
||||
if (wipe) memset((void *)(dynbase + a), 0, wipe);
|
||||
if (wipe)
|
||||
memset((void *)(dynbase + a), 0, wipe);
|
||||
if (prot2 != prot1) {
|
||||
rc = sys_mprotect(addr, size, prot2);
|
||||
if (rc < 0) Pexit(exe, rc, "prog mprotect");
|
||||
if (rc < 0)
|
||||
Pexit(exe, rc, "prog mprotect");
|
||||
}
|
||||
/* allocate extra bss */
|
||||
if (c > b) {
|
||||
flags |= MAP_ANONYMOUS;
|
||||
rc = sys_mmap((void *)(dynbase + b), c - b, prot, flags, -1, 0);
|
||||
if (rc < 0) Pexit(exe, rc, "extra bss mmap");
|
||||
if (rc < 0)
|
||||
Pexit(exe, rc, "extra bss mmap");
|
||||
}
|
||||
} else {
|
||||
/* allocate pure bss */
|
||||
|
@ -717,7 +760,8 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
|||
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_memsz;
|
||||
flags |= MAP_ANONYMOUS;
|
||||
rc = sys_mmap(addr, size, prot, flags, -1, 0);
|
||||
if (rc < 0) Pexit(exe, rc, "bss mmap");
|
||||
if (rc < 0)
|
||||
Pexit(exe, rc, "bss mmap");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -764,7 +808,7 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
|||
}
|
||||
|
||||
static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
||||
const char *exe, int fd, long *sp, long *auxv,
|
||||
char *exe, int fd, long *sp, long *auxv,
|
||||
char *execfn) {
|
||||
long i, rc;
|
||||
unsigned size;
|
||||
|
@ -785,6 +829,10 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
|||
if (e->e_machine != EM_AARCH64) {
|
||||
return "couldn't find ELF header with ARM64 machine type";
|
||||
}
|
||||
if ((e->e_flags & EF_APE_MODERN_MASK) != EF_APE_MODERN && sp[0] > 0) {
|
||||
/* change argv[0] to resolved path for older binaries */
|
||||
((char **)(sp + 1))[0] = exe;
|
||||
}
|
||||
if (e->e_phentsize != sizeof(struct ElfPhdr)) {
|
||||
Pexit(exe, 0, "e_phentsize is wrong");
|
||||
}
|
||||
|
@ -795,8 +843,10 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
|||
|
||||
/* read program headers */
|
||||
rc = pread(fd, M->phdr.buf, size, ebuf->ehdr.e_phoff);
|
||||
if (rc < 0) return "failed to read ELF program headers";
|
||||
if (rc != size) return "truncated read of ELF program headers";
|
||||
if (rc < 0)
|
||||
return "failed to read ELF program headers";
|
||||
if (rc != size)
|
||||
return "truncated read of ELF program headers";
|
||||
|
||||
/* bail on recoverable program header errors */
|
||||
p = &M->phdr.phdr;
|
||||
|
@ -822,12 +872,10 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* merge adjacent loads that are contiguous with equal protection,
|
||||
* which prevents our program header overlap check from needlessly
|
||||
* failing later on; it also shaves away a microsecond of latency,
|
||||
* since every program header requires invoking at least 1 syscall
|
||||
*/
|
||||
/* merge adjacent loads that are contiguous with equal protection,
|
||||
which prevents our program header overlap check from needlessly
|
||||
failing later on; it also shaves away a microsecond of latency,
|
||||
since every program header requires invoking at least 1 syscall */
|
||||
for (i = 0; i + 1 < e->e_phnum;) {
|
||||
if (p[i].p_type == PT_LOAD && p[i + 1].p_type == PT_LOAD &&
|
||||
((p[i].p_flags & (PF_R | PF_W | PF_X)) ==
|
||||
|
@ -861,25 +909,27 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
|||
auxv[7] = ebuf->ehdr.e_entry;
|
||||
auxv[8] = AT_PAGESZ;
|
||||
auxv[9] = pagesz;
|
||||
auxv[10] = AT_UID;
|
||||
auxv[11] = getuid();
|
||||
auxv[12] = AT_EUID;
|
||||
auxv[13] = geteuid();
|
||||
auxv[14] = AT_GID;
|
||||
auxv[15] = getgid();
|
||||
auxv[16] = AT_EGID;
|
||||
auxv[17] = getegid();
|
||||
auxv[18] = AT_HWCAP;
|
||||
auxv[19] = 0xffb3ffffu;
|
||||
auxv[20] = AT_HWCAP2;
|
||||
auxv[21] = 0x181;
|
||||
auxv[22] = AT_SECURE;
|
||||
auxv[23] = issetugid();
|
||||
auxv[24] = AT_RANDOM;
|
||||
auxv[25] = (long)M->rando;
|
||||
auxv[26] = AT_EXECFN;
|
||||
auxv[27] = (long)execfn;
|
||||
auxv[28] = 0;
|
||||
auxv[10] = AT_FLAGS;
|
||||
auxv[11] = M->ps.literally ? AT_FLAGS_PRESERVE_ARGV0 : 0;
|
||||
auxv[12] = AT_UID;
|
||||
auxv[13] = getuid();
|
||||
auxv[14] = AT_EUID;
|
||||
auxv[15] = geteuid();
|
||||
auxv[16] = AT_GID;
|
||||
auxv[17] = getgid();
|
||||
auxv[18] = AT_EGID;
|
||||
auxv[19] = getegid();
|
||||
auxv[20] = AT_HWCAP;
|
||||
auxv[21] = 0xffb3ffffu;
|
||||
auxv[22] = AT_HWCAP2;
|
||||
auxv[23] = 0x181;
|
||||
auxv[24] = AT_SECURE;
|
||||
auxv[25] = issetugid();
|
||||
auxv[26] = AT_RANDOM;
|
||||
auxv[27] = (long)M->rando;
|
||||
auxv[28] = AT_EXECFN;
|
||||
auxv[29] = (long)execfn;
|
||||
auxv[30] = 0;
|
||||
|
||||
/* we're now ready to load */
|
||||
Spawn(exe, fd, sp, e, p, &M->lib, M->ps.path);
|
||||
|
@ -891,7 +941,7 @@ int main(int argc, char **argv, char **envp) {
|
|||
struct ApeLoader *M;
|
||||
long *sp, *sp2, *auxv;
|
||||
union ElfEhdrBuf *ebuf;
|
||||
char *p, *pe, *exe, *prog, *execfn, *shell;
|
||||
char *p, *pe, *exe, *prog, *execfn;
|
||||
|
||||
/* allocate loader memory in program's arg block */
|
||||
n = sizeof(struct ApeLoader);
|
||||
|
@ -952,14 +1002,22 @@ int main(int argc, char **argv, char **envp) {
|
|||
M->lib.dlsym = dlsym;
|
||||
M->lib.dlclose = dlclose;
|
||||
M->lib.dlerror = dlerror;
|
||||
M->lib.pthread_cpu_number_np = pthread_cpu_number_np;
|
||||
M->lib.sysctl = sys_sysctl;
|
||||
M->lib.sysctlbyname = sys_sysctlbyname;
|
||||
M->lib.sysctlnametomib = sys_sysctlnametomib;
|
||||
|
||||
/* getenv("_") is close enough to at_execfn */
|
||||
execfn = argc > 0 ? argv[0] : 0;
|
||||
execfn = 0;
|
||||
for (i = 0; envp[i]; ++i) {
|
||||
if (envp[i][0] == '_' && envp[i][1] == '=') {
|
||||
execfn = envp[i] + 2;
|
||||
}
|
||||
}
|
||||
prog = GetEnv(envp + i + 1, "executable_path");
|
||||
if (!execfn) {
|
||||
execfn = prog;
|
||||
}
|
||||
|
||||
/* sneak the system five abi back out of args */
|
||||
sp = (long *)(argv - 1);
|
||||
|
@ -970,7 +1028,8 @@ int main(int argc, char **argv, char **envp) {
|
|||
grows down the alloc by poking the guard pages */
|
||||
n = (auxv - sp + AUXV_WORDS + 1) * sizeof(long);
|
||||
sp2 = (long *)__builtin_alloca(n);
|
||||
if ((long)sp2 & 15) ++sp2;
|
||||
if ((long)sp2 & 15)
|
||||
++sp2;
|
||||
for (; n > 0; n -= pagesz) {
|
||||
((char *)sp2)[n - 1] = 0;
|
||||
}
|
||||
|
@ -981,8 +1040,8 @@ int main(int argc, char **argv, char **envp) {
|
|||
sp = sp2;
|
||||
|
||||
/* interpret command line arguments */
|
||||
if ((M->ps.indirect = argc > 0 ? GetIndirectOffset(argv[0]) : 0)) {
|
||||
/* if argv[0] is $prog.ape, then we strip off the .ape and run
|
||||
if ((M->ps.indirect = GetIndirectOffset(prog))) {
|
||||
/* if called as $prog.ape, then strip off the .ape and run the
|
||||
$prog. This allows you to use symlinks to trick the OS when
|
||||
a native executable is required. For example, let's say you
|
||||
want to use the APE binary /opt/cosmos/bin/bash as a system
|
||||
|
@ -991,13 +1050,7 @@ int main(int argc, char **argv, char **envp) {
|
|||
but it will if you say:
|
||||
ln -sf /usr/local/bin/ape /opt/cosmos/bin/bash.ape
|
||||
and then use #!/opt/cosmos/bin/bash.ape instead. */
|
||||
M->ps.literally = 0;
|
||||
if (*argv[0] == '-' && (shell = GetEnv(envp, "SHELL")) &&
|
||||
!StrCmp(argv[0] + 1, BaseName(shell))) {
|
||||
execfn = prog = shell;
|
||||
} else {
|
||||
prog = (char *)sp[1];
|
||||
}
|
||||
M->ps.literally = 1;
|
||||
argc = sp[0];
|
||||
argv = (char **)(sp + 1);
|
||||
} else if ((M->ps.literally = argc >= 3 && !StrCmp(argv[1], "-"))) {
|
||||
|
@ -1011,7 +1064,7 @@ int main(int argc, char **argv, char **envp) {
|
|||
} else if (argc < 2) {
|
||||
Emit("usage: ape PROG [ARGV1,ARGV2,...]\n"
|
||||
" ape - PROG [ARGV0,ARGV1,...]\n"
|
||||
" ($0 = PROG.ape) [ARGV1,ARGV2,...]\n"
|
||||
" PROG.ape [ARGV1,ARGV2,...]\n"
|
||||
"actually portable executable loader silicon 1.10\n"
|
||||
"copyrights 2023 justine alexandra roberts tunney\n"
|
||||
"https://justine.lol/ape.html\n");
|
||||
|
|
85
ape/ape.S
85
ape/ape.S
|
@ -1,5 +1,5 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│ vi: set noet ft=asm ts=8 sw=8 fenc=utf-8 :vi │
|
||||
│ vi: set noet ft=asm ts=8 sw=8 fenc=utf-8 nofixeol :vi │
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
|
@ -33,12 +33,11 @@
|
|||
│ αcτµαlly pδrταblε εxεcµταblε § program header │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "ape/macros.internal.h"
|
||||
#include "ape/notice.inc"
|
||||
#include "ape/relocations.h"
|
||||
#include "libc/calls/metalfile.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/elf/def.h"
|
||||
#include "libc/macho.internal.h"
|
||||
#include "libc/macho.h"
|
||||
#include "libc/nexgen32e/uart.internal.h"
|
||||
#include "libc/nt/pedef.internal.h"
|
||||
#include "libc/runtime/pc.internal.h"
|
||||
|
@ -197,7 +196,7 @@ ape_mz:
|
|||
.quad ape_elf_entry // 18: e_entry
|
||||
.quad ape_elf_phoff // 20: e_phoff
|
||||
.quad ape_elf_shoff // 28: e_shoff
|
||||
.long 0 // 30: e_flags
|
||||
.long 0x101ca75 // 30: ape e_flags
|
||||
.short 64 // 34: e_ehsize
|
||||
.short 56 // 36: e_phentsize
|
||||
.short ape_elf_phnum // 38: e_phnum
|
||||
|
@ -670,7 +669,7 @@ apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang
|
|||
.shstub ape_elf_entry,8 // 18: e_entry
|
||||
.shstub ape_elf_phoff,8 // 20: e_phoff
|
||||
.shstub ape_elf_shoff,8 // 28: e_shoff
|
||||
.ascii "\\0\\0\\0\\0" // 30: e_flags
|
||||
.ascii "\\165\\312\\1\\1" // 30: ape e_flags
|
||||
.ascii "\\100\\0" // 34: e_ehsize
|
||||
.ascii "\\070\\0" // 36: e_phentsize
|
||||
.shstub ape_elf_phnum,2 // 38: e_phnum
|
||||
|
@ -700,36 +699,9 @@ apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang
|
|||
#endif /* APE_NO_MODIFY_SELF */
|
||||
.ascii "exit $?\n"
|
||||
.ascii "fi\n" // x86_64
|
||||
// ...
|
||||
// decentralized section (.apesh)
|
||||
// ...
|
||||
.ascii "PHDRS='' <<'@'\n"
|
||||
.endobj apesh
|
||||
|
||||
// elf program headers get inserted here
|
||||
// because they need to be in the first 4096 bytes
|
||||
.section .emushprologue,"a",@progbits
|
||||
emush: .ascii "\n@\n#'\"\n"
|
||||
.ascii "s=$(uname -s 2>/dev/null) || s=Darwin\n"
|
||||
// our script is running on a non-x86_64 architecture
|
||||
// 1. `dd` out the appropriate blink vm blob
|
||||
// 2. gunzip the blink virtual machine executable
|
||||
// 3. relaunch this program inside the blink vm
|
||||
.ascii "o=\"$(command -v \"$0\")\"\n"
|
||||
.ascii "e=\"${TMPDIR:-${HOME:-.}}/.ape-blink-1.0.0\"\n"
|
||||
.previous
|
||||
// ...
|
||||
// decentralized section (.emush)
|
||||
// - __static_yoink("blink_linux_aarch64"); // for raspberry pi
|
||||
// - __static_yoink("blink_xnu_aarch64"); // is apple silicon
|
||||
// ...
|
||||
.section .emushepilogue,"a",@progbits
|
||||
.ascii "echo \"$0: this ape binary lacks $m support\" >&2\n"
|
||||
.rept 16
|
||||
.ascii "exit 127\n"
|
||||
.endr
|
||||
.ascii "echo error: this ape binary only supports x86_64 >&2\n"
|
||||
.ascii "exit 1\n"
|
||||
.previous
|
||||
.endobj apesh
|
||||
|
||||
#ifdef APE_LOADER
|
||||
.section .ape.loader,"a",@progbits
|
||||
|
@ -789,7 +761,7 @@ ape_phdrs:
|
|||
.quad 0
|
||||
.quad 0
|
||||
.quad 0
|
||||
.stub ape_stack_align,quad
|
||||
.quad 16
|
||||
|
||||
#if SupportsOpenbsd() || SupportsNetbsd()
|
||||
.long PT_NOTE
|
||||
|
@ -1064,7 +1036,7 @@ ape_pe: .ascin "PE",4
|
|||
.quad ape_pe_base // ImageBase
|
||||
.long ape_pe_sectionalignment // SectionAlignment
|
||||
.long ape_pe_filealignment // FileAlignment
|
||||
.short v_ntversion // MajorOperatingSystemVersion
|
||||
.short 10 // MajorOperatingSystemVersion
|
||||
.short 0 // MinorOperatingSystemVersion
|
||||
.short 0 // MajorImageVersion
|
||||
.short 0 // MinorImageVersion
|
||||
|
@ -1799,49 +1771,31 @@ kernel: movabs $ape_stack_vaddr,%rsp
|
|||
.type ape_text_nops,@object
|
||||
.type __test_end,@object
|
||||
|
||||
.section .commentprologue,"a",@progbits
|
||||
.globl __comment_start
|
||||
.type __comment_start,@object
|
||||
.hidden __comment_start
|
||||
__comment_start:/*
|
||||
...
|
||||
decentralized content
|
||||
...
|
||||
*/.previous
|
||||
.section .commentepilogue,"a",@progbits
|
||||
.byte 0
|
||||
.previous
|
||||
|
||||
.section .ape.pad.head,"a",@progbits
|
||||
.type ape_pad_head,@object
|
||||
.hidden ape_pad_head
|
||||
ape_pad_head:
|
||||
.previous
|
||||
|
||||
.section .ape.pad.text,"a",@progbits
|
||||
.type ape_pad_text,@object
|
||||
.hidden ape_pad_text
|
||||
ape_pad_text:
|
||||
.previous
|
||||
|
||||
.section .ape.pad.privileged,"a",@progbits
|
||||
.type ape_pad_privileged,@object
|
||||
.hidden ape_pad_privileged
|
||||
ape_pad_privileged:
|
||||
.previous
|
||||
|
||||
.section .ape.pad.data,"a",@progbits
|
||||
.type ape_pad_data,@object
|
||||
.hidden ape_pad_data
|
||||
ape_pad_data:
|
||||
.previous
|
||||
|
||||
#if SupportsWindows()
|
||||
.section .idata.ro,"a",@progbits
|
||||
.type ape_idata_ro,@object
|
||||
.hidden ape_idata_ro
|
||||
ape_idata_ro:
|
||||
.previous
|
||||
#endif /* SupportsWindows() */
|
||||
|
||||
.section .dataprologue,"aw",@progbits
|
||||
|
@ -1849,32 +1803,45 @@ ape_idata_ro:
|
|||
.globl __data_start
|
||||
.hidden __data_start
|
||||
__data_start:
|
||||
.previous
|
||||
|
||||
.section .dataepilogue,"aw",@progbits
|
||||
.type __data_end,@object
|
||||
.globl __data_end
|
||||
.hidden __data_end
|
||||
__data_end:
|
||||
.previous
|
||||
|
||||
.section .bssprologue,"aw",@nobits
|
||||
.type __bss_start,@object
|
||||
.globl __bss_start
|
||||
.hidden __bss_start
|
||||
__bss_start:
|
||||
.previous
|
||||
|
||||
.section .bssepilogue,"aw",@nobits
|
||||
.type __bss_end,@object
|
||||
.globl __bss_end
|
||||
.hidden __bss_end
|
||||
__bss_end:
|
||||
.previous
|
||||
|
||||
.section .fstls,"awT",@nobits
|
||||
.align TLS_ALIGNMENT
|
||||
.previous
|
||||
|
||||
.section .notice,"aR",@progbits
|
||||
.asciz "\n\n\
|
||||
Cosmopolitan\n\
|
||||
Copyright 2024 Justine Alexandra Roberts Tunney\n\
|
||||
\n\
|
||||
Permission to use, copy, modify, and/or distribute this software for\n\
|
||||
any purpose with or without fee is hereby granted, provided that the\n\
|
||||
above copyright notice and this permission notice appear in all copies.\n\
|
||||
\n\
|
||||
THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL\n\
|
||||
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED\n\
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE\n\
|
||||
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL\n\
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR\n\
|
||||
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER\n\
|
||||
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\n\
|
||||
PERFORMANCE OF THIS SOFTWARE."
|
||||
|
||||
.end
|
||||
|
99
ape/ape.lds
99
ape/ape.lds
|
@ -229,7 +229,6 @@ SECTIONS {
|
|||
|
||||
/* Real Mode */
|
||||
KEEP(*(.head))
|
||||
KEEP(*(.apesh))
|
||||
KEEP(*(.text.head))
|
||||
|
||||
/* Executable & Linkable Format */
|
||||
|
@ -238,10 +237,6 @@ SECTIONS {
|
|||
KEEP(*(.elf.phdrs))
|
||||
ape_phdrs_end = .;
|
||||
|
||||
KEEP(*(.emushprologue))
|
||||
KEEP(*(.emush))
|
||||
KEEP(*(.emushepilogue))
|
||||
|
||||
/* OpenBSD */
|
||||
. = ALIGN(. != 0 ? __SIZEOF_POINTER__ : 0);
|
||||
ape_note = .;
|
||||
|
@ -287,12 +282,9 @@ SECTIONS {
|
|||
KEEP(*(SORT_BY_NAME(.init.*)))
|
||||
KEEP(*(.init))
|
||||
KEEP(*(.initepilogue))
|
||||
KEEP(*(.pltprologue))
|
||||
*(.plt)
|
||||
KEEP(*(.pltepilogue))
|
||||
KEEP(*(.pltgotprologue))
|
||||
*(.plt.got)
|
||||
KEEP(*(.pltgotepilogue))
|
||||
*(.iplt)
|
||||
*(.text.startup .text.startup.*)
|
||||
*(.text.exit .text.exit.*)
|
||||
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
|
||||
|
@ -301,7 +293,6 @@ SECTIONS {
|
|||
KEEP(*(.textwindowsprologue))
|
||||
*(.text.windows)
|
||||
KEEP(*(.textwindowsepilogue))
|
||||
KEEP(*(.blink))
|
||||
*(SORT_BY_ALIGNMENT(.text.modernity))
|
||||
*(SORT_BY_ALIGNMENT(.text.modernity.*))
|
||||
*(SORT_BY_ALIGNMENT(.text.hot))
|
||||
|
@ -319,7 +310,7 @@ SECTIONS {
|
|||
. = ALIGN(__privileged_end > __privileged_start ? CONSTANT(COMMONPAGESIZE) : 0);
|
||||
/*END: morphable code */
|
||||
__privileged_start = .;
|
||||
*(.privileged)
|
||||
*(.privileged .privileged.*)
|
||||
__privileged_end = .;
|
||||
|
||||
KEEP(*(.ape.pad.text))
|
||||
|
@ -329,7 +320,7 @@ SECTIONS {
|
|||
|
||||
/*BEGIN: Read Only Data */
|
||||
|
||||
.rodata . : {
|
||||
.rodata ALIGN(CONSTANT(COMMONPAGESIZE)) : {
|
||||
KEEP(*(.rodata.pytab.0));
|
||||
KEEP(*(.rodata.pytab.1));
|
||||
KEEP(*(.rodata.pytab.2));
|
||||
|
@ -338,12 +329,16 @@ SECTIONS {
|
|||
*(.ubsan.types)
|
||||
*(.ubsan.data)
|
||||
|
||||
__eh_frame_hdr_start_actual = .;
|
||||
*(.eh_frame_hdr)
|
||||
__eh_frame_hdr_end_actual = .;
|
||||
|
||||
/* Legal Notices */
|
||||
#if !defined(IM_FEELING_NAUGHTY) || defined(EMBED_NOTICES)
|
||||
KEEP(*(.commentprologue))
|
||||
KEEP(*(.comment))
|
||||
KEEP(*(.commentepilogue))
|
||||
#endif
|
||||
__notices = .;
|
||||
KEEP(*(.notice))
|
||||
BYTE(0);
|
||||
BYTE(10);
|
||||
BYTE(10);
|
||||
|
||||
/*BEGIN: read-only data that's only needed for initialization */
|
||||
|
||||
|
@ -391,6 +386,13 @@ SECTIONS {
|
|||
_tbss_end = .;
|
||||
} :Tls
|
||||
|
||||
.eh_frame : {
|
||||
__eh_frame_start = .;
|
||||
KEEP(*(.eh_frame))
|
||||
*(.eh_frame.*)
|
||||
__eh_frame_end = .;
|
||||
} :Ram
|
||||
|
||||
.data . : {
|
||||
/*BEGIN: Read/Write Data */
|
||||
#if SupportsWindows()
|
||||
|
@ -399,26 +401,28 @@ SECTIONS {
|
|||
/*BEGIN: NT FORK COPYING */
|
||||
KEEP(*(.dataprologue))
|
||||
*(.data .data.*)
|
||||
*(.gnu_extab)
|
||||
*(.gcc_except_table .gcc_except_table.*)
|
||||
*(.exception_ranges*)
|
||||
*(.PyRuntime) /* for python */
|
||||
*(.subrs) /* for emacs */
|
||||
KEEP(*(SORT_BY_NAME(.sort.data.*)))
|
||||
. += . > 0 ? CODE_GRANULE : 0;
|
||||
|
||||
KEEP(*(.gotprologue))
|
||||
. = ALIGN(. != 0 ? __SIZEOF_POINTER__ : 0);
|
||||
__got_start = .;
|
||||
*(.got)
|
||||
KEEP(*(.gotepilogue))
|
||||
__got_end = .;
|
||||
|
||||
KEEP(*(.gotpltprologue))
|
||||
*(.got.plt)
|
||||
KEEP(*(.gotpltepilogue))
|
||||
|
||||
. = ALIGN(. != 0 ? __SIZEOF_POINTER__ : 0);
|
||||
__init_array_start = .;
|
||||
KEEP(*(.preinit_array))
|
||||
KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*)
|
||||
SORT_BY_INIT_PRIORITY(.ctors.*)))
|
||||
KEEP(*(.ctors))
|
||||
KEEP(*(.init_array))
|
||||
KEEP(*(.preinit_array))
|
||||
KEEP(*(.ctors))
|
||||
__init_array_end = .;
|
||||
|
||||
. = ALIGN(. != 0 ? __SIZEOF_POINTER__ : 0);
|
||||
|
@ -435,6 +439,7 @@ SECTIONS {
|
|||
. = ALIGN(. != 0 ? __SIZEOF_POINTER__ : 0);
|
||||
KEEP(*(SORT_BY_NAME(.piro.data.sort.*)))
|
||||
KEEP(*(.piro.pad.data))
|
||||
*(.igot.plt)
|
||||
KEEP(*(.dataepilogue))
|
||||
. = ALIGN(. != 0 ? CONSTANT(COMMONPAGESIZE) : 0);
|
||||
/*END: NT FORK COPYING */
|
||||
|
@ -515,6 +520,9 @@ SECTIONS {
|
|||
.debug_rnglists 0 : { *(.debug_rnglists) }
|
||||
.debug_macro 0 : { *(.debug_macro) }
|
||||
.debug_addr 0 : { *(.debug_addr) }
|
||||
.debug_names 0 : { *(.debug_names) }
|
||||
.debug_loclists 0 : { *(.debug_loclists) }
|
||||
.debug_str_offsets 0 : { *(.debug_str_offsets) }
|
||||
.gnu.attributes 0 : { KEEP(*(.gnu.attributes)) }
|
||||
.GCC.command.line 0 : { *(.GCC.command.line) }
|
||||
|
||||
|
@ -533,7 +541,9 @@ SECTIONS {
|
|||
*(.piro.data.sort.iat.*)
|
||||
#endif
|
||||
*(__patchable_function_entries)
|
||||
*(.note.gnu.property)
|
||||
*(__mcount_loc)
|
||||
*(.rela.dyn)
|
||||
*(.discard)
|
||||
*(.yoink)
|
||||
}
|
||||
|
@ -556,7 +566,9 @@ _tdata_size = _tdata_end - _tdata_start;
|
|||
_tbss_size = _tbss_end - _tbss_start;
|
||||
_tbss_offset = _tbss_start - _tdata_start;
|
||||
_tls_content = (_tdata_end - _tdata_start) + (_tbss_end - _tbss_start);
|
||||
_tls_align = 1;
|
||||
_tdata_align = ALIGNOF(.tdata);
|
||||
_tbss_align = ALIGNOF(.tbss);
|
||||
_tls_align = MAX(TLS_ALIGNMENT, MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)));
|
||||
|
||||
ape_cod_offset = 0;
|
||||
ape_cod_vaddr = ADDR(.head);
|
||||
|
@ -574,11 +586,11 @@ ape_rom_memsz = ape_rom_filesz;
|
|||
ape_rom_align = CONSTANT(COMMONPAGESIZE);
|
||||
ape_rom_rva = RVA(ape_rom_vaddr);
|
||||
|
||||
ape_ram_vaddr = ADDR(.data);
|
||||
ape_ram_vaddr = ADDR(.eh_frame);
|
||||
ape_ram_offset = ape_ram_vaddr - __executable_start;
|
||||
ape_ram_paddr = LOADADDR(.data);
|
||||
ape_ram_filesz = ADDR(.bss) - ADDR(.data);
|
||||
ape_ram_memsz = _end - ADDR(.data);
|
||||
ape_ram_paddr = LOADADDR(.eh_frame);
|
||||
ape_ram_filesz = ADDR(.bss) - ADDR(.eh_frame);
|
||||
ape_ram_memsz = _end - ADDR(.eh_frame);
|
||||
ape_ram_align = CONSTANT(COMMONPAGESIZE);
|
||||
ape_ram_rva = RVA(ape_ram_vaddr);
|
||||
|
||||
|
@ -588,9 +600,7 @@ ape_stack_offset = 0;
|
|||
ape_stack_vaddr = DEFINED(ape_stack_vaddr) ? ape_stack_vaddr : 0x700000000000;
|
||||
ape_stack_paddr = ape_ram_paddr + ape_ram_filesz;
|
||||
ape_stack_filesz = 0;
|
||||
ape_stack_memsz = DEFINED(ape_stack_memsz) ? ape_stack_memsz : 8 * 1024 * 1024;
|
||||
ape_stack_align = DEFINED(ape_stack_align) ? ape_stack_align : 16;
|
||||
ape_stack_round = -ape_stack_align;
|
||||
ape_stack_memsz = DEFINED(ape_stack_memsz) ? ape_stack_memsz : 4 * 1024 * 1024;
|
||||
|
||||
ape_note_offset = ape_cod_offset + (ape_note - ape_cod_vaddr);
|
||||
ape_note_filesz = ape_note_end - ape_note;
|
||||
|
@ -604,6 +614,9 @@ ape_text_memsz = ape_text_filesz;
|
|||
ape_text_align = CONSTANT(COMMONPAGESIZE);
|
||||
ape_text_rva = RVA(ape_text_vaddr);
|
||||
|
||||
__eh_frame_hdr_start = __eh_frame_hdr_end_actual > __eh_frame_hdr_start_actual ? __eh_frame_hdr_start_actual : 0;
|
||||
__eh_frame_hdr_end = __eh_frame_hdr_end_actual > __eh_frame_hdr_start_actual ? __eh_frame_hdr_end_actual : 0;
|
||||
|
||||
/* we roundup here because xnu wants the file load segments page-aligned */
|
||||
/* but we don't want to add the nop padding to the ape program, so we'll */
|
||||
/* let ape.S dd read past the end of the file into the wrapping binaries */
|
||||
|
@ -613,29 +626,6 @@ SHSTUB2(ape_loader_dd_count,
|
|||
? ROUNDUP(ape_loader_end - ape_loader, CONSTANT(COMMONPAGESIZE)) / 64
|
||||
: 0);
|
||||
|
||||
#if defined(APE_IS_SHELL_SCRIPT) && !IsTiny()
|
||||
|
||||
#define IDENTITY(X) X
|
||||
|
||||
#define APE_DECLARE_FIXED_DECIMAL(F, X) \
|
||||
X##_quad = DEFINED(X) ? ((F(X) < 1000000000 ? 32 : F(X) / 1000000000 % 10 + 48) << 000 | \
|
||||
(F(X) < 100000000 ? 32 : F(X) / 100000000 % 10 + 48) << 010 | \
|
||||
(F(X) < 10000000 ? 32 : F(X) / 10000000 % 10 + 48) << 020 | \
|
||||
(F(X) < 1000000 ? 32 : F(X) / 1000000 % 10 + 48) << 030 | \
|
||||
(F(X) < 100000 ? 32 : F(X) / 100000 % 10 + 48) << 040 | \
|
||||
(F(X) < 10000 ? 32 : F(X) / 10000 % 10 + 48) << 050 | \
|
||||
(F(X) < 1000 ? 32 : F(X) / 1000 % 10 + 48) << 060 | \
|
||||
(F(X) < 100 ? 32 : F(X) / 100 % 10 + 48) << 070) : 0; \
|
||||
X##_short = DEFINED(X) ? ((F(X) < 10 ? 32 : F(X) / 10 % 10 + 48) << 000 | \
|
||||
(F(X) % 10 + 48) << 010) : 0
|
||||
|
||||
APE_DECLARE_FIXED_DECIMAL(RVA, blink_linux_aarch64);
|
||||
APE_DECLARE_FIXED_DECIMAL(IDENTITY, blink_linux_aarch64_size);
|
||||
APE_DECLARE_FIXED_DECIMAL(RVA, blink_xnu_aarch64);
|
||||
APE_DECLARE_FIXED_DECIMAL(IDENTITY, blink_xnu_aarch64_size);
|
||||
|
||||
#endif /* APE_IS_SHELL_SCRIPT */
|
||||
|
||||
#if SupportsMetal()
|
||||
v_ape_realsectors = MIN(0x70000 - IMAGE_BASE_REAL, ROUNDUP(RVA(_ezip), 512)) / 512;
|
||||
v_ape_realbytes = v_ape_realsectors * 512;
|
||||
|
@ -739,7 +729,6 @@ ape_idataz = LINK_WINDOWS ? RVA(ape_idata_iat) : 0;
|
|||
ape_idata_iatsize = LINK_WINDOWS ? ape_idata_iatend - ape_idata_iat : 0;
|
||||
ape_idata = LINK_WINDOWS ? RVA(ape_idata_idt) : 0;
|
||||
ape_idata_idtsize = LINK_WINDOWS ? ape_idata_idtend - ape_idata_idt : 0;
|
||||
v_ntversion = LINK_WINDOWS ? 6 : 1;
|
||||
v_ntdllchar = LINK_WINDOWS ? 288 : 0;
|
||||
v_ntsubversion = LINK_WINDOWS ? 6 : 5;
|
||||
v_ntsubsystem = (LINK_WINDOWS
|
||||
|
|
|
@ -10,73 +10,98 @@ if [ ! -f ape/loader.c ]; then
|
|||
cd "$COSMO" || exit
|
||||
fi
|
||||
|
||||
if [ -x .cosmocc/current/bin/make ]; then
|
||||
MAKE=.cosmocc/current/bin/make
|
||||
else
|
||||
MAKE=make
|
||||
fi
|
||||
|
||||
if [ "$(id -u)" -eq 0 ]; then
|
||||
SUDO=
|
||||
else
|
||||
elif command -v sudo >/dev/null 2>&1; then
|
||||
SUDO=sudo
|
||||
elif command -v doas >/dev/null 2>&1; then
|
||||
SUDO=doas
|
||||
else
|
||||
echo "need root or sudo" >&2
|
||||
exit
|
||||
fi
|
||||
|
||||
if command -v install >/dev/null 2>&1; then
|
||||
if [ x"$(uname -s)" = xLinux ]; then
|
||||
INSTALL="install -o root -g root -m 755"
|
||||
else
|
||||
INSTALL="install -o root -g wheel -m 755"
|
||||
fi
|
||||
else
|
||||
INSTALL="cp -f"
|
||||
fi
|
||||
|
||||
echo "Actually Portable Executable (APE) Installer" >&2
|
||||
echo "Author: Justine Tunney <jtunney@gmail.com>" >&2
|
||||
|
||||
# special installation process for apple silicon
|
||||
if [ "$(uname -s)" = "Darwin" ] && [ "$(uname -m)" = "arm64" ]; then
|
||||
if [ x"$(uname -s)" = xDarwin ] && [ x"$(uname -m)" = xarm64 ]; then
|
||||
echo "cc -O -o $TMPDIR/ape.$$ ape/ape-m1.c" >&2
|
||||
cc -O -o "$TMPDIR/ape.$$" ape/ape-m1.c || exit
|
||||
trap 'rm "$TMPDIR/ape.$$"' EXIT
|
||||
if [ ! -d /usr/local/bin ]; then
|
||||
echo "$SUDO mkdir -p /usr/local/bin" >&2
|
||||
$SUDO mkdir -p /usr/local/bin || exit
|
||||
fi
|
||||
echo "$SUDO mv -f $TMPDIR/ape.$$ /usr/local/bin/ape" >&2
|
||||
$SUDO mv -f "$TMPDIR/ape.$$" /usr/local/bin/ape || exit
|
||||
echo "$SUDO $INSTALL $TMPDIR/ape.$$ /usr/local/bin/ape" >&2
|
||||
$SUDO $INSTALL "$TMPDIR/ape.$$" /usr/local/bin/ape || exit
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ x"$(uname -m)" = xarm64 ] || [ x"$(uname -m)" = xaarch64 ]; then
|
||||
MODE=aarch64
|
||||
EXT=elf
|
||||
BEXT=aarch64
|
||||
elif [ x"$(uname -m)" = xx86_64 ]; then
|
||||
MODE=
|
||||
if [ x"$(uname -s)" = xDarwin ]; then
|
||||
EXT=macho
|
||||
else
|
||||
EXT=elf
|
||||
fi
|
||||
BEXT=$EXT
|
||||
else
|
||||
echo "unsupported architecture $(uname -m)" >&2
|
||||
exit
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
# INSTALL APE LOADER SYSTEMWIDE
|
||||
|
||||
if [ -f o/depend ] && make -j8 o//ape; then
|
||||
if [ -f o/$MODE/depend ] && $MAKE -j8 o/$MODE/ape; then
|
||||
echo "successfully recompiled ape loader" >&2
|
||||
elif [ -x o//ape/ape.elf ] && [ -x o//ape/ape.macho ]; then
|
||||
elif [ -x o/$MODE/ape/ape.$EXT ]; then
|
||||
echo "using ape loader you compiled earlier" >&2
|
||||
elif [ -d build/bootstrap ]; then
|
||||
# if make isn't being used then it's unlikely the user changed the sources
|
||||
# in that case the prebuilt binaries should be completely up-to-date
|
||||
echo "using prebuilt ape loader from cosmo repo" >&2
|
||||
mkdir -p o//ape || exit
|
||||
cp -af build/bootstrap/ape.elf o//ape/ape.elf || exit
|
||||
cp -af build/bootstrap/ape.macho o//ape/ape.macho || exit
|
||||
mkdir -p o/$MODE/ape || exit
|
||||
cp -af build/bootstrap/ape.$BEXT o/$MODE/ape/ape.$EXT || exit
|
||||
else
|
||||
echo "no cosmopolitan libc repository here" >&2
|
||||
echo "fetching ape loader from justine.lol" >&2
|
||||
mkdir -p o//ape || exit
|
||||
mkdir -p o/$MODE/ape || exit
|
||||
if command -v wget >/dev/null 2>&1; then
|
||||
wget -qO o//ape/ape.elf https://justine.lol/ape.elf || exit
|
||||
wget -qO o//ape/ape.macho https://justine.lol/ape.macho || exit
|
||||
wget -qO o/$MODE/ape/ape.$EXT https://justine.lol/ape.$BEXT || exit
|
||||
else
|
||||
curl -Rso o//ape/ape.elf https://justine.lol/ape.elf || exit
|
||||
curl -Rso o//ape/ape.macho https://justine.lol/ape.macho || exit
|
||||
curl -Rso o/$MODE/ape/ape.$EXT https://justine.lol/ape.$BEXT || exit
|
||||
fi
|
||||
chmod +x o//ape/ape.elf || exit
|
||||
chmod +x o//ape/ape.macho || exit
|
||||
chmod +x o/$MODE/ape/ape.$EXT || exit
|
||||
fi
|
||||
|
||||
if [ "$(uname -s)" = "Darwin" ]; then
|
||||
if ! [ /usr/bin/ape -nt o//ape/ape.macho ]; then
|
||||
if ! [ /usr/bin/ape -nt o/$MODE/ape/ape.$EXT ]; then
|
||||
echo >&2
|
||||
echo "installing o//ape/ape.macho to /usr/bin/ape" >&2
|
||||
echo "$SUDO cp -f o//ape/ape.macho /usr/bin/ape" >&2
|
||||
$SUDO cp -f o//ape/ape.macho /usr/bin/ape || exit
|
||||
echo "installing o/$MODE/ape/ape.$EXT to /usr/bin/ape" >&2
|
||||
echo "$SUDO $INSTALL o/$MODE/ape/ape.$EXT /usr/bin/ape" >&2
|
||||
$SUDO $INSTALL o/$MODE/ape/ape.$EXT /usr/bin/ape || exit
|
||||
echo "done" >&2
|
||||
fi
|
||||
else
|
||||
if ! [ /usr/bin/ape -nt o//ape/ape.elf ]; then
|
||||
echo >&2
|
||||
echo "installing o//ape/ape.elf to /usr/bin/ape" >&2
|
||||
echo "$SUDO mv -f o//ape/ape.elf /usr/bin/ape" >&2
|
||||
$SUDO cp -f o//ape/ape.elf /usr/bin/ape || exit
|
||||
echo "done" >&2
|
||||
fi
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
|
@ -112,13 +137,20 @@ if [ x"$(uname -s)" = xLinux ]; then
|
|||
echo done >&2
|
||||
fi
|
||||
|
||||
uname_r="$(uname -r)"
|
||||
if printf '%s\n%s\n' 5.12 "$uname_r" | sort -CV; then
|
||||
FLAGS=FP
|
||||
else
|
||||
FLAGS=F
|
||||
fi
|
||||
|
||||
echo >&2
|
||||
echo registering APE with binfmt_misc >&2
|
||||
echo you may need to edit configs to persist across reboot >&2
|
||||
echo '$SUDO sh -c "echo '"'"':APE:M::MZqFpD::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
|
||||
$SUDO sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
|
||||
echo '$SUDO sh -c "echo '"'"':APE-jart:M::jartsr::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
|
||||
$SUDO sh -c "echo ':APE-jart:M::jartsr::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
|
||||
echo '$SUDO sh -c "echo '"'"':APE:M::MZqFpD::/usr/bin/ape:'"$FLAGS'"' >/proc/sys/fs/binfmt_misc/register"' >&2
|
||||
$SUDO sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:$FLAGS' >/proc/sys/fs/binfmt_misc/register" || exit
|
||||
echo '$SUDO sh -c "echo '"'"':APE-jart:M::jartsr::/usr/bin/ape:'"$FLAGS'"' >/proc/sys/fs/binfmt_misc/register"' >&2
|
||||
$SUDO sh -c "echo ':APE-jart:M::jartsr::/usr/bin/ape:$FLAGS' >/proc/sys/fs/binfmt_misc/register" || exit
|
||||
echo done >&2
|
||||
|
||||
if [ x"$(cat /proc/sys/fs/binfmt_misc/status)" = xdisabled ]; then
|
||||
|
|
|
@ -11,8 +11,13 @@ fi
|
|||
|
||||
if [ "$UID" = "0" ]; then
|
||||
SUDO=
|
||||
else
|
||||
elif command -v sudo >/dev/null 2>&1; then
|
||||
SUDO=sudo
|
||||
elif command -v doas >/dev/null 2>&1; then
|
||||
SUDO=doas
|
||||
else
|
||||
echo "need root or sudo" >&2
|
||||
exit
|
||||
fi
|
||||
|
||||
{
|
||||
|
@ -54,9 +59,7 @@ for x in .ape \
|
|||
.ape-1.7 \
|
||||
.ape-1.8 \
|
||||
.ape-1.9 \
|
||||
.ape-1.10 \
|
||||
.ape-blink-0.9.2 \
|
||||
.ape-blink-1.0.0; do
|
||||
.ape-1.10; do
|
||||
rm -f \
|
||||
~/$x \
|
||||
/tmp/$x \
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -16,7 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/macros.h"
|
||||
|
||||
// Calls _start() function of loaded program.
|
||||
//
|
||||
|
|
|
@ -16,13 +16,13 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macho.internal.h"
|
||||
#include "libc/macho.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/macros.h"
|
||||
|
||||
// Apple Mach-O Executable Headers
|
||||
// Fixups are applied by objbincopy.com
|
||||
// Fixups are applied by objbincopy
|
||||
// There must exist a MAC_LC_SEGMENT_64 for every PT_LOAD
|
||||
|
||||
.section .macho,"a",@progbits
|
||||
|
|
218
ape/loader.c
218
ape/loader.c
|
@ -141,6 +141,9 @@
|
|||
#define AT_PHENT 4
|
||||
#define AT_PHNUM 5
|
||||
#define AT_PAGESZ 6
|
||||
#define AT_FLAGS 8
|
||||
#define AT_FLAGS_PRESERVE_ARGV0_BIT 0
|
||||
#define AT_FLAGS_PRESERVE_ARGV0 (1 << AT_FLAGS_PRESERVE_ARGV0_BIT)
|
||||
#define AT_EXECFN_LINUX 31
|
||||
#define AT_EXECFN_NETBSD 2014
|
||||
#define X_OK 1
|
||||
|
@ -149,6 +152,9 @@
|
|||
#define PR_SET_MM 35
|
||||
#define PR_SET_MM_EXE_FILE 13
|
||||
|
||||
#define EF_APE_MODERN 0x101ca75
|
||||
#define EF_APE_MODERN_MASK 0x1ffffff
|
||||
|
||||
#define READ32(S) \
|
||||
((unsigned)(255 & (S)[3]) << 030 | (unsigned)(255 & (S)[2]) << 020 | \
|
||||
(unsigned)(255 & (S)[1]) << 010 | (unsigned)(255 & (S)[0]) << 000)
|
||||
|
@ -163,13 +169,6 @@
|
|||
(unsigned long)(255 & (S)[1]) << 010 | \
|
||||
(unsigned long)(255 & (S)[0]) << 000)
|
||||
|
||||
#define DEBUG(VAR) \
|
||||
{ \
|
||||
char ibuf[19] = {0}; \
|
||||
Utox(ibuf, VAR); \
|
||||
Print(os, 2, ibuf, " " #VAR, "\n", 0l); \
|
||||
}
|
||||
|
||||
struct ElfEhdr {
|
||||
unsigned char e_ident[16];
|
||||
unsigned short e_type;
|
||||
|
@ -232,13 +231,15 @@ extern char _end[];
|
|||
|
||||
static unsigned long StrLen(const char *s) {
|
||||
unsigned long n = 0;
|
||||
while (*s++) ++n;
|
||||
while (*s++)
|
||||
++n;
|
||||
return n;
|
||||
}
|
||||
|
||||
static int StrCmp(const char *l, const char *r) {
|
||||
unsigned long i = 0;
|
||||
while (l[i] == r[i] && r[i]) ++i;
|
||||
while (l[i] == r[i] && r[i])
|
||||
++i;
|
||||
return (l[i] & 255) - (r[i] & 255);
|
||||
}
|
||||
|
||||
|
@ -337,23 +338,6 @@ static char *GetEnv(char **p, const char *s) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static char *Utox(char p[19], unsigned long x) {
|
||||
int i;
|
||||
if (x) {
|
||||
*p++ = '0';
|
||||
*p++ = 'x';
|
||||
i = (__builtin_clzl(x) ^ (sizeof(long) * 8 - 1)) + 1;
|
||||
i = (i + 3) & -4;
|
||||
do {
|
||||
*p++ = "0123456789abcdef"[(x >> (i -= 4)) & 15];
|
||||
} while (i);
|
||||
} else {
|
||||
*p++ = '0';
|
||||
}
|
||||
*p = 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *Utoa(char p[20], unsigned long x) {
|
||||
char t;
|
||||
unsigned long i, a, b;
|
||||
|
@ -374,7 +358,8 @@ static char *Utoa(char p[20], unsigned long x) {
|
|||
}
|
||||
|
||||
static char *Itoa(char p[21], long x) {
|
||||
if (x < 0) *p++ = '-', x = -(unsigned long)x;
|
||||
if (x < 0)
|
||||
*p++ = '-', x = -(unsigned long)x;
|
||||
return Utoa(p, x);
|
||||
}
|
||||
|
||||
|
@ -383,7 +368,8 @@ __attribute__((__noinline__)) static long CallSystem(long arg1, long arg2,
|
|||
long arg5, long arg6,
|
||||
long arg7, int numba,
|
||||
char os) {
|
||||
if (IsXnu()) numba |= 0x2000000;
|
||||
if (IsXnu())
|
||||
numba |= 0x2000000;
|
||||
return SystemCall(arg1, arg2, arg3, arg4, arg5, arg6, arg7, numba);
|
||||
}
|
||||
|
||||
|
@ -531,10 +517,62 @@ static long Print(int os, int fd, const char *s, ...) {
|
|||
return Write(fd, b, n, os);
|
||||
}
|
||||
|
||||
static long Printf(int os, int fd, const char *fmt, ...) {
|
||||
int i;
|
||||
char c;
|
||||
int k = 0;
|
||||
unsigned u;
|
||||
char b[512];
|
||||
const char *s;
|
||||
unsigned long d;
|
||||
__builtin_va_list va;
|
||||
__builtin_va_start(va, fmt);
|
||||
for (;;) {
|
||||
switch ((c = *fmt++)) {
|
||||
case '\0':
|
||||
__builtin_va_end(va);
|
||||
return Write(fd, b, k, os);
|
||||
case '%':
|
||||
switch ((c = *fmt++)) {
|
||||
case 's':
|
||||
for (s = __builtin_va_arg(va, const char *); s && *s; ++s) {
|
||||
if (k < 512)
|
||||
b[k++] = *s;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
d = __builtin_va_arg(va, unsigned long);
|
||||
for (i = 16; i--;) {
|
||||
u = (d >> (i * 4)) & 15;
|
||||
if (u < 10) {
|
||||
c = '0' + u;
|
||||
} else {
|
||||
u -= 10;
|
||||
c = 'a' + u;
|
||||
}
|
||||
if (k < 512)
|
||||
b[k++] = c;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (k < 512)
|
||||
b[k++] = c;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (k < 512)
|
||||
b[k++] = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Perror(int os, const char *thing, long rc, const char *reason) {
|
||||
char ibuf[21];
|
||||
ibuf[0] = 0;
|
||||
if (rc) Itoa(ibuf, -rc);
|
||||
if (rc)
|
||||
Itoa(ibuf, -rc);
|
||||
Print(os, 2, "ape error: ", thing, ": ", reason,
|
||||
rc ? " failed w/ errno " : "", ibuf, "\n", 0l);
|
||||
}
|
||||
|
@ -546,8 +584,10 @@ __attribute__((__noreturn__)) static void Pexit(int os, const char *c, int rc,
|
|||
}
|
||||
|
||||
static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) {
|
||||
if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path)) return 0;
|
||||
if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/';
|
||||
if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path))
|
||||
return 0;
|
||||
if (pathlen && ps->path[pathlen - 1] != '/')
|
||||
ps->path[pathlen++] = '/';
|
||||
MemMove(ps->path + pathlen, ps->name, ps->namelen);
|
||||
ps->path[pathlen + ps->namelen] = 0;
|
||||
return !Access(ps->path, X_OK, ps->os);
|
||||
|
@ -572,39 +612,18 @@ static char SearchPath(struct PathSearcher *ps) {
|
|||
}
|
||||
}
|
||||
|
||||
static char FindCommand(struct PathSearcher *ps) {
|
||||
ps->path[0] = 0;
|
||||
|
||||
/* paths are always 100% taken literally when a slash exists
|
||||
$ ape foo/bar.com arg1 arg2 */
|
||||
if (MemChr(ps->name, '/', ps->namelen)) {
|
||||
return AccessCommand(ps, 0);
|
||||
}
|
||||
|
||||
/* we don't run files in the current directory
|
||||
$ ape foo.com arg1 arg2
|
||||
unless $PATH has an empty string entry, e.g.
|
||||
$ expert PATH=":/bin"
|
||||
$ ape foo.com arg1 arg2
|
||||
however we will execute this
|
||||
$ ape - foo.com foo.com arg1 arg2
|
||||
because cosmo's execve needs it */
|
||||
if (ps->literally && AccessCommand(ps, 0)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* otherwise search for name on $PATH */
|
||||
return SearchPath(ps);
|
||||
}
|
||||
|
||||
static char *Commandv(struct PathSearcher *ps, int os, char *name,
|
||||
const char *syspath, int may_path_search) {
|
||||
if (!may_path_search) return name;
|
||||
const char *syspath) {
|
||||
if (!(ps->namelen = StrLen((ps->name = name))))
|
||||
return 0;
|
||||
if (ps->literally || MemChr(ps->name, '/', ps->namelen))
|
||||
return name;
|
||||
ps->os = os;
|
||||
ps->syspath = syspath ? syspath : "/bin:/usr/local/bin:/usr/bin";
|
||||
if (!(ps->namelen = StrLen((ps->name = name)))) return 0;
|
||||
if (ps->namelen + 1 > sizeof(ps->path)) return 0;
|
||||
if (FindCommand(ps)) {
|
||||
if (ps->namelen + 1 > sizeof(ps->path))
|
||||
return 0;
|
||||
ps->path[0] = 0;
|
||||
if (SearchPath(ps)) {
|
||||
return ps->path;
|
||||
} else {
|
||||
return 0;
|
||||
|
@ -659,7 +678,8 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
|
|||
Pexit(os, exe, 0, "ELF segments overlap your APE loader");
|
||||
}
|
||||
for (j = i + 1; j < e->e_phnum; ++j) {
|
||||
if (p[j].p_type != PT_LOAD) continue;
|
||||
if (p[j].p_type != PT_LOAD)
|
||||
continue;
|
||||
c = p[j].p_vaddr & -pagesz;
|
||||
d = (p[j].p_vaddr + p[j].p_memsz + (pagesz - 1)) & -pagesz;
|
||||
if (MAX(a, c) < MIN(b, d)) {
|
||||
|
@ -692,7 +712,8 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
|
|||
if (e->e_type == ET_DYN) {
|
||||
rc = Mmap(0, virtmax - virtmin, PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0, os);
|
||||
if (rc < 0) Pexit(os, exe, rc, "pie mmap");
|
||||
if (rc < 0)
|
||||
Pexit(os, exe, rc, "pie mmap");
|
||||
dynbase = rc;
|
||||
if (dynbase & (pagesz - 1)) {
|
||||
Pexit(os, exe, 0, "OS mmap incongruent w/ AT_PAGESZ");
|
||||
|
@ -708,14 +729,18 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
|
|||
for (i = 0; i < e->e_phnum; ++i) {
|
||||
void *addr;
|
||||
unsigned long size;
|
||||
if (p[i].p_type != PT_LOAD) continue;
|
||||
if (p[i].p_type != PT_LOAD)
|
||||
continue;
|
||||
|
||||
/* configure mapping */
|
||||
prot = 0;
|
||||
flags = MAP_FIXED | MAP_PRIVATE;
|
||||
if (p[i].p_flags & PF_R) prot |= PROT_READ;
|
||||
if (p[i].p_flags & PF_W) prot |= PROT_WRITE;
|
||||
if (p[i].p_flags & PF_X) prot |= PROT_EXEC;
|
||||
if (p[i].p_flags & PF_R)
|
||||
prot |= PROT_READ;
|
||||
if (p[i].p_flags & PF_W)
|
||||
prot |= PROT_WRITE;
|
||||
if (p[i].p_flags & PF_X)
|
||||
prot |= PROT_EXEC;
|
||||
|
||||
if (p[i].p_filesz) {
|
||||
/* load from file */
|
||||
|
@ -742,17 +767,21 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
|
|||
addr = (void *)(dynbase + (p[i].p_vaddr & -pagesz));
|
||||
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_filesz;
|
||||
rc = Mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz, os);
|
||||
if (rc < 0) Pexit(os, exe, rc, "prog mmap");
|
||||
if (wipe) Bzero((void *)(dynbase + a), wipe);
|
||||
if (rc < 0)
|
||||
Pexit(os, exe, rc, "prog mmap");
|
||||
if (wipe)
|
||||
Bzero((void *)(dynbase + a), wipe);
|
||||
if (prot2 != prot1) {
|
||||
rc = Mprotect(addr, size, prot2, os);
|
||||
if (rc < 0) Pexit(os, exe, rc, "prog mprotect");
|
||||
if (rc < 0)
|
||||
Pexit(os, exe, rc, "prog mprotect");
|
||||
}
|
||||
/* allocate extra bss */
|
||||
if (c > b) {
|
||||
flags |= MAP_ANONYMOUS;
|
||||
rc = Mmap((void *)(dynbase + b), c - b, prot, flags, -1, 0, os);
|
||||
if (rc < 0) Pexit(os, exe, rc, "extra bss mmap");
|
||||
if (rc < 0)
|
||||
Pexit(os, exe, rc, "extra bss mmap");
|
||||
}
|
||||
} else {
|
||||
/* allocate pure bss */
|
||||
|
@ -760,7 +789,8 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
|
|||
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_memsz;
|
||||
flags |= MAP_ANONYMOUS;
|
||||
rc = Mmap(addr, size, prot, flags, -1, 0, os);
|
||||
if (rc < 0) Pexit(os, exe, rc, "bss mmap");
|
||||
if (rc < 0)
|
||||
Pexit(os, exe, rc, "bss mmap");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -781,7 +811,8 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
|||
struct ElfPhdr *p;
|
||||
|
||||
/* validate page size */
|
||||
if (!pagesz) pagesz = 4096;
|
||||
if (!pagesz)
|
||||
pagesz = 4096;
|
||||
if (pagesz & (pagesz - 1)) {
|
||||
Pexit(os, exe, 0, "AT_PAGESZ isn't two power");
|
||||
}
|
||||
|
@ -806,6 +837,10 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
|||
return "couldn't find ELF header with x86-64 machine type";
|
||||
}
|
||||
#endif
|
||||
if ((e->e_flags & EF_APE_MODERN_MASK) != EF_APE_MODERN && sp[0] > 0) {
|
||||
/* change argv[0] to resolved path for older binaries */
|
||||
((char **)(sp + 1))[0] = exe;
|
||||
}
|
||||
if (e->e_phentsize != sizeof(struct ElfPhdr)) {
|
||||
Pexit(os, exe, 0, "e_phentsize is wrong");
|
||||
}
|
||||
|
@ -816,8 +851,10 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
|||
|
||||
/* read program headers */
|
||||
rc = Pread(fd, M->phdr.buf, size, e->e_phoff, os);
|
||||
if (rc < 0) return "failed to read ELF program headers";
|
||||
if (rc != size) return "truncated read of ELF program headers";
|
||||
if (rc < 0)
|
||||
return "failed to read ELF program headers";
|
||||
if (rc != size)
|
||||
return "truncated read of ELF program headers";
|
||||
|
||||
/* bail on recoverable program header errors */
|
||||
p = &M->phdr.phdr;
|
||||
|
@ -897,7 +934,7 @@ __attribute__((__noreturn__)) static void ShowUsage(int os, int fd, int rc) {
|
|||
"NAME\n"
|
||||
"\n"
|
||||
" actually portable executable loader version " APE_VERSION_STR "\n"
|
||||
" copyright 2023 justine alexandra roberts tunney\n"
|
||||
" copyrights 2024 justine alexandra roberts tunney\n"
|
||||
" https://justine.lol/ape.html\n"
|
||||
"\n"
|
||||
"USAGE\n"
|
||||
|
@ -913,16 +950,16 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
|
|||
char dl) {
|
||||
int rc, n;
|
||||
unsigned i;
|
||||
char literally;
|
||||
const char *ape;
|
||||
int c, fd, os, argc;
|
||||
struct ApeLoader *M;
|
||||
char arg0, literally;
|
||||
unsigned long pagesz;
|
||||
union ElfEhdrBuf *ebuf;
|
||||
long *auxv, *ap, *endp, *sp2;
|
||||
char *p, *pe, *exe, *prog, **argv, **envp;
|
||||
|
||||
(void)Utox;
|
||||
(void)Printf;
|
||||
|
||||
/* detect freebsd */
|
||||
if (SupportsXnu() && dl == XNU) {
|
||||
|
@ -947,7 +984,8 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
|
|||
|
||||
/* determine ape loader program name */
|
||||
ape = argv[0];
|
||||
if (!ape) ape = "ape";
|
||||
if (!ape)
|
||||
ape = "ape";
|
||||
|
||||
/* detect openbsd */
|
||||
if (SupportsOpenbsd() && !os && !auxv[0]) {
|
||||
|
@ -961,11 +999,15 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
|
|||
|
||||
/* detect netbsd and find end of words */
|
||||
pagesz = 0;
|
||||
arg0 = 0;
|
||||
for (ap = auxv; ap[0]; ap += 2) {
|
||||
if (ap[0] == AT_PAGESZ) {
|
||||
pagesz = ap[1];
|
||||
} else if (SupportsNetbsd() && !os && ap[0] == AT_EXECFN_NETBSD) {
|
||||
os = NETBSD;
|
||||
} else if (SupportsLinux() && ap[0] == AT_FLAGS) {
|
||||
// TODO(mrdomino): maybe set/insert this when we are called as "ape -".
|
||||
arg0 = !!(ap[1] & AT_FLAGS_PRESERVE_ARGV0);
|
||||
}
|
||||
}
|
||||
if (!pagesz) {
|
||||
|
@ -979,8 +1021,12 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
|
|||
}
|
||||
|
||||
/* we can load via shell, shebang, or binfmt_misc */
|
||||
int may_path_search = 1;
|
||||
if ((literally = argc >= 3 && !StrCmp(argv[1], "-"))) {
|
||||
if (arg0) {
|
||||
literally = 1;
|
||||
prog = (char *)sp[2];
|
||||
argc = sp[2] = sp[0] - 2;
|
||||
argv = (char **)((sp += 2) + 1);
|
||||
} else if ((literally = argc >= 3 && !StrCmp(argv[1], "-"))) {
|
||||
/* if the first argument is a hyphen then we give the user the
|
||||
power to change argv[0] or omit it entirely. most operating
|
||||
systems don't permit the omission of argv[0] but we do, b/c
|
||||
|
@ -988,12 +1034,12 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
|
|||
prog = (char *)sp[3];
|
||||
argc = sp[3] = sp[0] - 3;
|
||||
argv = (char **)((sp += 3) + 1);
|
||||
may_path_search = 0;
|
||||
} else if (argc < 2) {
|
||||
ShowUsage(os, 2, 1);
|
||||
} else {
|
||||
if (argv[1][0] == '-') {
|
||||
rc = !(argv[1][1] == 'h' && !argv[1][2]) || !StrCmp(argv[1] + 1, "-help");
|
||||
rc = !((argv[1][1] == 'h' && !argv[1][2]) ||
|
||||
!StrCmp(argv[1] + 1, "-help"));
|
||||
ShowUsage(os, 1 + rc, rc);
|
||||
}
|
||||
prog = (char *)sp[2];
|
||||
|
@ -1011,7 +1057,8 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
|
|||
grows down the alloc by poking the guard pages */
|
||||
n = (endp - sp + 1) * sizeof(long);
|
||||
sp2 = (long *)__builtin_alloca(n);
|
||||
if ((long)sp2 & 15) ++sp2;
|
||||
if ((long)sp2 & 15)
|
||||
++sp2;
|
||||
for (; n > 0; n -= pagesz) {
|
||||
((char *)sp2)[n - 1] = 0;
|
||||
}
|
||||
|
@ -1029,8 +1076,7 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
|
|||
}
|
||||
|
||||
/* resolve path of executable and read its first page */
|
||||
if (!(exe = Commandv(&M->ps, os, prog, GetEnv(envp, "PATH"),
|
||||
may_path_search))) {
|
||||
if (!(exe = Commandv(&M->ps, os, prog, GetEnv(envp, "PATH")))) {
|
||||
Pexit(os, prog, 0, "not found (maybe chmod +x or ./ needed)");
|
||||
} else if ((fd = Open(exe, O_RDONLY, 0, os)) < 0) {
|
||||
Pexit(os, exe, fd, "open");
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#ifndef APE_MACROS_H_
|
||||
#define APE_MACROS_H_
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/macros.h"
|
||||
#ifdef __ASSEMBLER__
|
||||
/* clang-format off */
|
||||
|
||||
|
@ -84,7 +84,8 @@
|
|||
/* clang-format on */
|
||||
#elif defined(__LINKER__)
|
||||
|
||||
#define BCX_NIBBLE(X) ((((X)&0xf) > 0x9) ? ((X)&0xf) + 0x37 : ((X)&0xf) + 0x30)
|
||||
#define BCX_NIBBLE(X) \
|
||||
((((X) & 0xf) > 0x9) ? ((X) & 0xf) + 0x37 : ((X) & 0xf) + 0x30)
|
||||
#define BCX_OCTET(X) ((BCX_NIBBLE((X) >> 4) << 8) | (BCX_NIBBLE((X) >> 0) << 0))
|
||||
#define BCX_INT16(X) ((BCX_OCTET((X) >> 8) << 16) | (BCX_OCTET((X) >> 0) << 0))
|
||||
#define BCXSTUB(SYM, X) \
|
||||
|
@ -98,12 +99,12 @@
|
|||
*
|
||||
* <p>This allows linker scripts to generate printf commands.
|
||||
*/
|
||||
#define BCO_OCTET(X) (((X)&0x7) + 0x30)
|
||||
#define BCO_OCTET(X) (((X) & 0x7) + 0x30)
|
||||
#define BCOB_UNIT(X) \
|
||||
((BCO_OCTET((X) >> 0) << 24) | (BCO_OCTET((X) >> 3) << 16) | \
|
||||
(BCO_OCTET(((X)&0xff) >> 6) << 8) | 0x5c)
|
||||
(BCO_OCTET(((X) & 0xff) >> 6) << 8) | 0x5c)
|
||||
|
||||
#define PFBYTE(SYM, X, I) HIDDEN(SYM##_bcs##I = BCOB_UNIT((X) >> ((I)*8)))
|
||||
#define PFBYTE(SYM, X, I) HIDDEN(SYM##_bcs##I = BCOB_UNIT((X) >> ((I) * 8)))
|
||||
#define PFSTUB2(SYM, X) \
|
||||
HIDDEN(SYM = (X)); \
|
||||
PFBYTE(SYM, X, 0); \
|
||||
|
@ -142,20 +143,13 @@
|
|||
: 0xffffffffffffffff)
|
||||
#define BCD_RIGHT(X) \
|
||||
(((X)) < 10000 ? 0x20202020 \
|
||||
: (X) < 100000 ? 0x20202030 + \
|
||||
(X) % 10 \
|
||||
: (X) < 1000000 ? 0x20203030 + \
|
||||
((X) / 10) % 10 + \
|
||||
(X) % 10 * 0x100 \
|
||||
: (X) < 10000000 ? 0x20303030 + \
|
||||
((X) / 100) % 10 + \
|
||||
((X) / 10) % 10 * 0x100 + \
|
||||
(X) % 10 * 0x10000 \
|
||||
: (X) < 100000000 ? 0x30303030 + \
|
||||
((X) / 1000) % 10 + \
|
||||
((X) / 100) % 10 * 0x100 + \
|
||||
((X) / 10) % 10 * 0x10000 + \
|
||||
(X) % 10 * 0x1000000 \
|
||||
: (X) < 100000 ? 0x20202030 + (X) % 10 \
|
||||
: (X) < 1000000 ? 0x20203030 + ((X) / 10) % 10 + (X) % 10 * 0x100 \
|
||||
: (X) < 10000000 ? 0x20303030 + ((X) / 100) % 10 + \
|
||||
((X) / 10) % 10 * 0x100 + (X) % 10 * 0x10000 \
|
||||
: (X) < 100000000 \
|
||||
? 0x30303030 + ((X) / 1000) % 10 + ((X) / 100) % 10 * 0x100 + \
|
||||
((X) / 10) % 10 * 0x10000 + (X) % 10 * 0x1000000 \
|
||||
: 0xffffffffffffffff)
|
||||
|
||||
/**
|
||||
|
@ -166,14 +160,10 @@
|
|||
HIDDEN(SYM##_desc_ent1 = TSSDESC_ENT1(BASE)); \
|
||||
ASSERT((LIM) >= 0 && (LIM) <= 0xffff, "bare metal TSS is suspiciously fat")
|
||||
#define TSSDESC_ENT0(BASE, LIM) \
|
||||
(((LIM) << 0 & 0x000000000000ffff) | \
|
||||
((BASE) << 16 & 0x000000ffffff0000) | \
|
||||
0x89 << 40 | \
|
||||
((LIM) >> 16 << 48 & 0x000f000000000000) | \
|
||||
0x2 << 52 | \
|
||||
(((LIM) << 0 & 0x000000000000ffff) | ((BASE) << 16 & 0x000000ffffff0000) | \
|
||||
0x89 << 40 | ((LIM) >> 16 << 48 & 0x000f000000000000) | 0x2 << 52 | \
|
||||
((BASE) >> 24 << 56 & 0xff00000000000000))
|
||||
#define TSSDESC_ENT1(BASE) \
|
||||
((BASE) >> 32 << 0 & 0x00000000ffffffff)
|
||||
#define TSSDESC_ENT1(BASE) ((BASE) >> 32 << 0 & 0x00000000ffffffff)
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
#endif /* APE_MACROS_H_ */
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#define COSMOPOLITAN_APE_SECTIONS_INTERNAL_H_
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern const char __comment_start[] __attribute__((__weak__));
|
||||
extern const char __notices[] __attribute__((__weak__));
|
||||
extern unsigned char __executable_start[] __attribute__((__weak__));
|
||||
extern unsigned char __privileged_start[] __attribute__((__weak__));
|
||||
extern unsigned char _ehead[] __attribute__((__weak__));
|
||||
|
@ -16,12 +16,16 @@ extern unsigned char _tdata_end[] __attribute__((__weak__));
|
|||
extern unsigned char _tbss_start[] __attribute__((__weak__));
|
||||
extern unsigned char _tbss_end[] __attribute__((__weak__));
|
||||
extern unsigned char _tls_align[] __attribute__((__weak__));
|
||||
extern unsigned char _tdata_align[] __attribute__((__weak__));
|
||||
extern unsigned char _tbss_align[] __attribute__((__weak__));
|
||||
extern unsigned char __test_start[] __attribute__((__weak__));
|
||||
extern unsigned char __ro[] __attribute__((__weak__));
|
||||
extern uint8_t __data_start[] __attribute__((__weak__));
|
||||
extern uint8_t __data_end[] __attribute__((__weak__));
|
||||
extern uint8_t __bss_start[] __attribute__((__weak__));
|
||||
extern uint8_t __bss_end[] __attribute__((__weak__));
|
||||
extern unsigned char __data_start[] __attribute__((__weak__));
|
||||
extern unsigned char __data_end[] __attribute__((__weak__));
|
||||
extern unsigned char __bss_start[] __attribute__((__weak__));
|
||||
extern unsigned char __bss_end[] __attribute__((__weak__));
|
||||
extern unsigned long __got_start[] __attribute__((__weak__));
|
||||
extern unsigned long __got_end[] __attribute__((__weak__));
|
||||
extern unsigned char ape_phdrs[] __attribute__((__weak__));
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
703
ape/specification.md
Normal file
703
ape/specification.md
Normal file
|
@ -0,0 +1,703 @@
|
|||
# Actually Portable Executable Specification v0.1
|
||||
|
||||
Actually Portable Executable (APE) is an executable file format that
|
||||
polyglots the Windows Portable Executable (PE) format with a UNIX Sixth
|
||||
Edition style shell script that doesn't have a shebang. This makes it
|
||||
possible to produce a single file binary that executes on the stock
|
||||
installations of the many OSes and architectures.
|
||||
|
||||
## Supported OSes and Architectures
|
||||
|
||||
- AMD64
|
||||
- Linux
|
||||
- MacOS
|
||||
- Windows
|
||||
- FreeBSD
|
||||
- OpenBSD
|
||||
- NetBSD
|
||||
- BIOS
|
||||
|
||||
- ARM64
|
||||
- Linux
|
||||
- MacOS
|
||||
- FreeBSD
|
||||
- Windows (non-native)
|
||||
|
||||
## File Header
|
||||
|
||||
APE defines three separate file magics, all of which are 8 characters
|
||||
long. Any file that starts with one of these magic values can be
|
||||
considered an APE program.
|
||||
|
||||
### (1) APE MZ Magic
|
||||
|
||||
- ASCII: `MZqFpD='`
|
||||
- Hex: 4d 5a 71 46 70 44 3d 27
|
||||
|
||||
This is the canonical magic used by almost all APE programs. It enables
|
||||
maximum portability between OSes. When interpreted as a shell script, it
|
||||
is assigning a single quoted string to an unused variable. The shell
|
||||
will then ignore subsequent binary content that's placed inside the
|
||||
string.
|
||||
|
||||
It is strongly recommended that this magic value be immediately followed
|
||||
by a newline (\n or hex 0a) character. Some shells, e.g. FreeBSD SH and
|
||||
Zsh impose a binary safety check before handing off files that don't
|
||||
have a shebang to `/bin/sh`. That check applies to the first line, which
|
||||
can't contain NUL characters.
|
||||
|
||||
The letters were carefully chosen so as to be valid x86 instructions in
|
||||
all operating modes. This makes it possible to store a BIOS bootloader
|
||||
disk image inside an APE binary. For example, simple CLI programs built
|
||||
with Cosmopolitan Libc will boot from BIOS into long mode if they're
|
||||
treated as a floppy disk image.
|
||||
|
||||
The letters also allow for the possibility of being treated on x86-64 as
|
||||
a flat executable, where the PE / ELF / Mach-O executable structures are
|
||||
ignored, and execution simply begins at the beginning of the file,
|
||||
similar to how MS-DOS .COM binaries work.
|
||||
|
||||
The 0x4a relative offset of the magic causes execution to jump into the
|
||||
MS-DOS stub defined by Portable Executable. APE binaries built by Cosmo
|
||||
Libc use tricks in the MS-DOS stub to check the operating mode and then
|
||||
jump to the appropriate entrypoint, e.g. `_start()`.
|
||||
|
||||
#### Decoded as i8086
|
||||
|
||||
```asm
|
||||
dec %bp
|
||||
pop %dx
|
||||
jno 0x4a
|
||||
jo 0x4a
|
||||
```
|
||||
|
||||
#### Decoded as i386
|
||||
|
||||
```asm
|
||||
push %ebp
|
||||
pop %edx
|
||||
jno 0x4a
|
||||
jo 0x4a
|
||||
```
|
||||
|
||||
#### Decoded as x86-64
|
||||
|
||||
```asm
|
||||
rex.WRB
|
||||
pop %r10
|
||||
jno 0x4a
|
||||
jo 0x4a
|
||||
```
|
||||
|
||||
### (2) APE UNIX-Only Magic
|
||||
|
||||
- ASCII: `jartsr='`
|
||||
- Hex: 6a 61 72 74 73 72 3d 27
|
||||
|
||||
Being a novel executable format that was first published in 2020, the
|
||||
APE file format is less understood by industry tools compared to the PE,
|
||||
ELF, and Mach-O executable file formats, which have been around for
|
||||
decades. For this reason, APE programs that use the MZ magic above can
|
||||
attract attention from Windows AV software, which may be unwanted by
|
||||
developers who aren't interested in targeting the Windows platform.
|
||||
Therefore the `jartsr='` magic is defined which enables the creation of
|
||||
APE binaries that can safely target all non-Windows platforms. Even
|
||||
though this magic is less common, APE interpreters and binfmt-misc
|
||||
installations MUST support this.
|
||||
|
||||
It is strongly recommended that this magic value be immediately followed
|
||||
by a newline (\n or hex 0a) character. Some shells, e.g. FreeBSD SH and
|
||||
Zsh impose a binary safety check before handing off files that don't
|
||||
have a shebang to `/bin/sh`. That check applies to the first line, which
|
||||
can't contain NUL characters.
|
||||
|
||||
The letters were carefully chosen so as to be valid x86 instructions in
|
||||
all operating modes. This makes it possible to store a BIOS bootloader
|
||||
disk image inside an APE binary. For example, simple CLI programs built
|
||||
with Cosmopolitan Libc will boot from BIOS into long mode if they're
|
||||
treated as a floppy disk image.
|
||||
|
||||
The letters also allow for the possibility of being treated on x86-64 as
|
||||
a flat executable, where the PE / ELF / Mach-O executable structures are
|
||||
ignored, and execution simply begins at the beginning of the file,
|
||||
similar to how MS-DOS .COM binaries work.
|
||||
|
||||
The 0x78 relative offset of the magic causes execution to jump into the
|
||||
MS-DOS stub defined by Portable Executable. APE binaries built by Cosmo
|
||||
Libc use tricks in the MS-DOS stub to check the operating mode and then
|
||||
jump to the appropriate entrypoint, e.g. `_start()`.
|
||||
|
||||
#### Decoded as i8086 / i386 / x86-64
|
||||
|
||||
```asm
|
||||
push $0x61
|
||||
jb 0x78
|
||||
jae 0x78
|
||||
```
|
||||
|
||||
### (3) APE Debug Magic
|
||||
|
||||
- ASCII: `APEDBG='`
|
||||
- Hex: 41 50 45 44 42 47 3d 27
|
||||
|
||||
While APE files must be valid shell scripts, in practice, UNIX systems
|
||||
will oftentimes be configured to provide a faster safer alternative to
|
||||
loading an APE binary through `/bin/sh`. The Linux Kernel can be patched
|
||||
to have execve() recognize the APE format and directly load its embedded
|
||||
ELF header. Linux systems can also use binfmt-misc to recognize APE's MZ
|
||||
and jartsr magic, and pass them to a userspace program named `ape` that
|
||||
acts as an interpreter. In such environments, the need sometimes arises
|
||||
to be able to test that the `/bin/sh` is working correctly, in which
|
||||
case the `APEDBG='` magic is RECOMMENDED.
|
||||
|
||||
APE interpreters, execve() implementations, and binfmt-misc installs
|
||||
MUST ignore this magic. If necessary, steps can be taken to help files
|
||||
with this magic be passed to `/bin/sh` like a normal shebang-less shell
|
||||
script for execution.
|
||||
|
||||
## Embedded ELF Header
|
||||
|
||||
APE binaries MAY embed an ELF header inside them. Unlike conventional
|
||||
executable file formats, this header is not stored at a fixed offset.
|
||||
It's instead encoded as octal escape codes in a shell script `printf`
|
||||
statement. For example:
|
||||
|
||||
```
|
||||
printf '\177ELF\2\1\1\011\0\0\0\0\0\0\0\0\2\0\076\0\1\0\0\0\166\105\100\000\000\000\000\000\060\013\000\000\000\000\000\000\000\000\000\000\000\000\000\000\165\312\1\1\100\0\070\0\005\000\0\0\000\000\000\000'
|
||||
```
|
||||
|
||||
This `printf` statement MUST appear in the first 8192 bytes of the APE
|
||||
executable, so as to limit how much of the initial portion of a file an
|
||||
interpreter must load.
|
||||
|
||||
Multiple such `printf` statements MAY appear in the first 8192 bytes, in
|
||||
order to specify multiple architectures. For example, fat binaries built
|
||||
by the `apelink` program (provided by Cosmo Libc) will have two encoded
|
||||
ELF headers, for AMD64 and ARM64, each of which point into the proper
|
||||
file offsets for their respective native code. Therefore, kernels and
|
||||
interpreters which load the APE format directly MUST check the
|
||||
`e_machine` field of the `Elf64_Ehdr` that's decoded from the octal
|
||||
codes, before accepting a `printf` shell statement as valid.
|
||||
|
||||
These printf statements MUST always use only unescaped ASCII characters
|
||||
or octal escape codes. These printf statements MUST NOT use space saving
|
||||
escape codes such as `\n`. For example, rather than saying `\n` it would
|
||||
be valid to say `\012` instead. It's also valid to say `\12` but only if
|
||||
the encoded characters that follow aren't an octal digit.
|
||||
|
||||
For example, the following algorithm may be used for parsing octal:
|
||||
|
||||
```c
|
||||
static int ape_parse_octal(const unsigned char page[8192], int i, int *pc)
|
||||
{
|
||||
int c;
|
||||
if ('0' <= page[i] && page[i] <= '7') {
|
||||
c = page[i++] - '0';
|
||||
if ('0' <= page[i] && page[i] <= '7') {
|
||||
c *= 8;
|
||||
c += page[i++] - '0';
|
||||
if ('0' <= page[i] && page[i] <= '7') {
|
||||
c *= 8;
|
||||
c += page[i++] - '0';
|
||||
}
|
||||
}
|
||||
*pc = c;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
```
|
||||
|
||||
APE aware interpreters SHOULD only take `e_machine` into consideration.
|
||||
It is the responsibility of the `_start()` function to detect the OS.
|
||||
Therefore, multiple `printf` statements are only embedded in the shell
|
||||
script for different CPU architectures.
|
||||
|
||||
The OS ABI field of an APE embedded `Elf64_Ehdr` SHOULD be set to
|
||||
`ELFOSABI_FREEBSD`, since it's the only UNIX OS APE supports that
|
||||
actually checks the field. However different values MAY be chosen for
|
||||
binaries that don't intend to have FreeBSD in their support vector.
|
||||
|
||||
Counter-intuitively, the ARM64 ELF header is used on the MacOS ARM64
|
||||
platform when loading from fat binaries.
|
||||
|
||||
## Embedded Mach-O Header (x86-64 only)
|
||||
|
||||
APE shell scripts that support MacOS on AMD64 must use the `dd` command
|
||||
in a very specific way to specify how the embedded binary Macho-O header
|
||||
is copied backward to the start of the file. For example:
|
||||
|
||||
```
|
||||
dd if="$o" of="$o" bs=8 skip=433 count=66 conv=notrunc
|
||||
```
|
||||
|
||||
These `dd` statements have traditionally been generated by the GNU as
|
||||
and ld.bfd programs by encoding ASCII into 64-bit linker relocations,
|
||||
which necessitated a fixed width for integer values. It took several
|
||||
iterations over APE's history before we eventually got it right:
|
||||
|
||||
- `arg=" 9293"` is how we originally had ape do it
|
||||
- `arg=$(( 9293))` b/c busybox sh disliked quoted space
|
||||
- `arg=9293 ` is generated by modern apelink program
|
||||
|
||||
Software that parses the APE file format, which needs to extract the
|
||||
Macho-O x86-64 header SHOULD support the old binaries that use the
|
||||
previous encodings. To make backwards compatibility simple the following
|
||||
regular expression may be used, which generalizes to all defined
|
||||
formats:
|
||||
|
||||
```c
|
||||
regcomp(&rx,
|
||||
"bs=" // dd block size arg
|
||||
"(['\"] *)?" // #1 optional quote w/ space
|
||||
"(\\$\\(\\( *)?" // #2 optional math w/ space
|
||||
"([[:digit:]]+)" // #3
|
||||
"( *\\)\\))?" // #4 optional math w/ space
|
||||
"( *['\"])?" // #5 optional quote w/ space
|
||||
" +" //
|
||||
"skip=" // dd skip arg
|
||||
"(['\"] *)?" // #6 optional quote w/ space
|
||||
"(\\$\\(\\( *)?" // #7 optional math w/ space
|
||||
"([[:digit:]]+)" // #8
|
||||
"( *\\)\\))?" // #9 optional math w/ space
|
||||
"( *['\"])?" // #10 optional quote w/ space
|
||||
" +" //
|
||||
"count=" // dd count arg
|
||||
"(['\"] *)?" // #11 optional quote w/ space
|
||||
"(\\$\\(\\( *)?" // #12 optional math w/ space
|
||||
"([[:digit:]]+)", // #13
|
||||
REG_EXTENDED);
|
||||
```
|
||||
|
||||
For further details, see the canonical implementation in
|
||||
`cosmopolitan/tool/build/assimilate.c`.
|
||||
|
||||
## Static Linking
|
||||
|
||||
Actually Portable Executables are always statically linked. This
|
||||
revision of the specification does not define any facility for storing
|
||||
code in dynamic shared objects.
|
||||
|
||||
Cosmopolitan Libc provides a solution that enables APE binaries have
|
||||
limited access to dlopen(). By manually loading a platform-specific
|
||||
executable and asking the OS-specific libc's dlopen() to load
|
||||
OS-specific libraries, it becomes possible to use GPUs and GUIs. This
|
||||
has worked great for AI projects like llamafile.
|
||||
|
||||
There is no way for an Actually Portable Executable to interact with
|
||||
OS-specific dynamic shared object extension modules to programming
|
||||
languages. For example, a Lua interpreter compiled as an Actually
|
||||
Portable Executable would have no way of linking extension libraries
|
||||
downloaded from the Lua Rocks package manager. This is primarily because
|
||||
different OSes define incompatible ABIs.
|
||||
|
||||
While it was possible to polyglot PE+ELF+MachO to create multi-OS
|
||||
executables, it simply isn't possible to do that same thing for
|
||||
DLL+DYLIB+SO. Therefore, in order to have DSOs, APE would need to either
|
||||
choose one of the existing formats or invent one of its own, and then
|
||||
develop its own parallel ecosystem of extension software. In the future,
|
||||
the APE specification may expand to encompass this. However the focus to
|
||||
date has been exclusively on executables with limited dlopen() support.
|
||||
|
||||
## Application Binary Interface (ABI)
|
||||
|
||||
APE binaries use the System V ABI, as defined by:
|
||||
|
||||
- [System V ABI - AMD64 Architecture Processor Supplement](https://gitlab.com/x86-psABIs/x86-64-ABI)
|
||||
- AARCH64 has a uniform consensus defined by ARM Limited
|
||||
|
||||
There are however a few changes we've had to make.
|
||||
|
||||
### No Red Zone
|
||||
|
||||
Actually Portable Executables that have Windows and/or bare metal in
|
||||
their support vector MUST be compiled using `-mno-red-zone`. This is
|
||||
because, on Windows, DLLs and other software lurking in the va-space
|
||||
might use tricks like SetThreadContext() to take control of a thread
|
||||
whereas on bare metal, it's also generally accepted that kernel-mode
|
||||
code cannot assume a red zone either due to hardware interrupts that
|
||||
pull the exact same kinds of stunts.
|
||||
|
||||
APE software that only has truly System V ABI conformant OSes (e.g.
|
||||
Linux) in their support vector MAY use the red zone optimization.
|
||||
|
||||
### Thread Local Storage
|
||||
|
||||
#### aarch64
|
||||
|
||||
Here's the TLS memory layout on aarch64:
|
||||
|
||||
```
|
||||
x28
|
||||
%tpidr_el0
|
||||
│
|
||||
│ _Thread_local
|
||||
┌───┼───┬──────────┬──────────┐
|
||||
│tib│dtv│ .tdata │ .tbss │
|
||||
├───┴───┴──────────┴──────────┘
|
||||
│
|
||||
__get_tls()
|
||||
```
|
||||
|
||||
The ARM64 code in actually portable executables use the `x28` register
|
||||
to store the address of the thread information block. All aarch64 code
|
||||
linked into these executables SHOULD be compiled with `-ffixed-x28`
|
||||
which is supported by both Clang and GCC.
|
||||
|
||||
The runtime library for an actually portable executables MAY choose to
|
||||
use `tpidr_el0` instead, if OSes like MacOS aren't being targeted. For
|
||||
example, if the goal is to create a Linux-only fat binary linker program
|
||||
for Musl Libc, then choosing to use the existing `tpidr_el0` convention
|
||||
would be friction-free alternative.
|
||||
|
||||
It's not possible for an APE runtime that targets the full range of OSes
|
||||
to use the `tpidr_el0` register for TLS because Apple won't allow it. On
|
||||
MacOS ARM64 systems, this register can only be used by a runtime to
|
||||
implement the `sched_getcpu()` system call. It's reserved by MacOS.
|
||||
|
||||
#### x86-64
|
||||
|
||||
Here's the TLS memory layout on x86_64:
|
||||
|
||||
```
|
||||
__get_tls()
|
||||
│
|
||||
%fs OpenBSD/NetBSD
|
||||
_Thread_local │
|
||||
┌───┬──────────┬──────────┼───┐
|
||||
│pad│ .tdata │ .tbss │tib│
|
||||
└───┴──────────┴──────────┼───┘
|
||||
│
|
||||
Linux/FreeBSD/Windows/Mac %gs
|
||||
```
|
||||
|
||||
Quite possibly the greatest challenge in Actually Portable Executable
|
||||
working, has been overcoming the incompatibilities between OSes in how
|
||||
thread-local storage works on x86-64. The AMD64 architecture defines two
|
||||
special segment registers. Every OS uses one of these segment registers
|
||||
to implement TLS support. However not all OSes agree on which register
|
||||
to use. Some OSes grant userspace the power to define either of these
|
||||
registers to hold any value that is desired. Some OSes only effectively
|
||||
allow a single one of them to be changed. Lastly, some OSes, e.g.
|
||||
Windows, claim ownership of the memory layout these registers point
|
||||
towards too.
|
||||
|
||||
Here's a breakdown on how much power is granted to userspace runtimes by
|
||||
each OS when it comes to changing amd64 segment registers.
|
||||
|
||||
| | %fs | %gs |
|
||||
|---------|--------------|--------------|
|
||||
| Linux | unrestricted | unrestricted |
|
||||
| MacOS | inaccessible | unrestricted |
|
||||
| Windows | inaccessible | restricted |
|
||||
| FreeBSD | unrestricted | unrestricted |
|
||||
| NetBSD | unrestricted | broken |
|
||||
| OpenBSD | unrestricted | inaccessible |
|
||||
|
||||
Therefore, regardless of which register one we choose, some OSes are
|
||||
going to be incompatible.
|
||||
|
||||
APE binaries are always built with a Linux compiler. So another issue
|
||||
arises in the fact that our Linux-flavored GCC and Clang toolchains
|
||||
(which are used to produce cross-OS binaries) are also only capable of
|
||||
producing TLS instructions that use the %fs convention.
|
||||
|
||||
To solve these challenges, the `cosmocc` compiler will rewrite binary
|
||||
objects after they've been compiled by GCC, so that the `%gs` register
|
||||
is used, rather than `%fs`. Morphing x86-64 binaries after they've been
|
||||
compiled is normally difficult, due to the complexity of the machine
|
||||
instruction language. However GCC provides `-mno-tls-direct-seg-refs`
|
||||
which greatly reduces the complexity of this task. This flag forgoes
|
||||
some optimizations to make the generated code simpler. Rather than doing
|
||||
clever arithmetic with `%fs` prefixes, the compiler will always generate
|
||||
the thread information block address load as a separate instruction.
|
||||
|
||||
```c
|
||||
// Change AMD code to use %gs:0x30 instead of %fs:0
|
||||
// We assume -mno-tls-direct-seg-refs has been used
|
||||
static void ChangeTlsFsToGs(unsigned char *p, size_t n) {
|
||||
unsigned char *e = p + n - 9;
|
||||
while (p <= e) {
|
||||
// we're checking for the following expression:
|
||||
// 0144 == p[0] && // %fs
|
||||
// 0110 == (p[1] & 0373) && // rex.w (and ignore rex.r)
|
||||
// (0213 == p[2] || // mov reg/mem → reg (word-sized)
|
||||
// 0003 == p[2]) && // add reg/mem → reg (word-sized)
|
||||
// 0004 == (p[3] & 0307) && // mod/rm (4,reg,0) means sib → reg
|
||||
// 0045 == p[4] && // sib (5,4,0) → (rbp,rsp,0) → disp32
|
||||
// 0000 == p[5] && // displacement (von Neumann endian)
|
||||
// 0000 == p[6] && // displacement
|
||||
// 0000 == p[7] && // displacement
|
||||
// 0000 == p[8] // displacement
|
||||
uint64_t w = READ64LE(p) & READ64LE("\377\373\377\307\377\377\377\377");
|
||||
if ((w == READ64LE("\144\110\213\004\045\000\000\000") ||
|
||||
w == READ64LE("\144\110\003\004\045\000\000\000")) &&
|
||||
!p[8]) {
|
||||
p[0] = 0145; // change %fs to %gs
|
||||
p[5] = 0x30; // change 0 to 0x30
|
||||
p += 9;
|
||||
} else {
|
||||
++p;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
By favoring `%gs` we've now ensured friction-free compatibility for the
|
||||
APE runtime on MacOS, Linux, and FreeBSD which are all able to conform
|
||||
easily to this convention. However additional work needs to be done at
|
||||
runtime when an APE program is started on Windows, OpenBSD, and NetBSD.
|
||||
On these platforms, all executable pages must be faulted and morphed to
|
||||
fixup the TLS instructions.
|
||||
|
||||
On OpenBSD and NetBSD, this is as simple as undoing the example
|
||||
operation above. Earlier at compile-time we turned `%fs` into `%gs`.
|
||||
Now, at runtime, `%gs` must be turned back into `%fs`. Since the
|
||||
executable is morphing itself, this is easier said than done.
|
||||
|
||||
OpenBSD for example enforces a `W^X` invariant. Code that's executing
|
||||
can't modify itself at the same time. The way Cosmopolitan solves this
|
||||
is by defining a special part of the binary called `.text.privileged`.
|
||||
This section is aligned to page boundaries. A GNU ld linker script is
|
||||
used to ensure that code which morphs code is placed into this section,
|
||||
through the use of a header-defined cosmo-specific keyword `privileged`.
|
||||
Additionally, the `fixupobj` program is used by the Cosmo build system
|
||||
to ensure that compiled objects don't contain privileged functions that
|
||||
call non-privileged functions. Needless to say, `mprotect()` needs to be
|
||||
a privileged function, so that it can be used to disable the execute bit
|
||||
on all other parts of the executable except for the privileged section,
|
||||
thereby making it writable. Once this has been done, code can change.
|
||||
|
||||
On Windows the displacement bytes of the TLS instruction are changed to
|
||||
use the `%gs:0x1480+i*8` ABI where `i` is a number assigned by the WIN32
|
||||
`TlsAlloc()` API. This avoids the need to call `TlsGetValue()` which is
|
||||
implemented this exact same way under the hood. Even though 0x1480 isn't
|
||||
explicitly documented by MSDN, this ABI is believed to be stable because
|
||||
MSVC generates binaries that use this offset directly. The only caveat
|
||||
is that `TlsAlloc()` must be called as early in the runtime init as
|
||||
possible, to ensure an index less than 64 is returned.
|
||||
|
||||
### Thread Information Block (TIB)
|
||||
|
||||
The Actually Portable Executable Thread Information Block (TIB) is
|
||||
defined by this version of the specification as follows:
|
||||
|
||||
- The 64-bit TIB self-pointer is stored at offset 0x00.
|
||||
- The 64-bit TIB self-pointer is also stored at offset 0x30.
|
||||
- The 32-bit `errno` value is stored at offset 0x3c.
|
||||
|
||||
All other parts of the thread information block should be considered
|
||||
unspecified and therefore reserved for future specifications.
|
||||
|
||||
The APE thread information block is aligned on a 64-byte boundary.
|
||||
|
||||
Cosmopolitan Libc v3.5.8 (c. 2024-07-21) currently implements a thread
|
||||
information block that's 512 bytes in size.
|
||||
|
||||
### Foreign Function Calls
|
||||
|
||||
Even though APE programs always use the System V ABI, there arises the
|
||||
occasional need to interface with foreign functions, e.g. WIN32. The
|
||||
`__attribute__((__ms_abi__))` annotation introduced by GCC v6 is used
|
||||
for this purpose.
|
||||
|
||||
The ability to change a function's ABI on a case-by-case basis is
|
||||
surprisingly enough supported by GCC, Clang, NVCC, and even the AMD HIP
|
||||
compilers for both UNIX systems and Windows. All of these compilers
|
||||
support both the System V ABI and the Microsoft x64 ABI.
|
||||
|
||||
APE binaries will actually favor the Microsoft ABI even when running on
|
||||
UNIX OSes for certain dlopen() use-cases. For example, if we control the
|
||||
code to a CUDA module, which we compile on each OS separately from our
|
||||
main APE binary, then any function that's inside the APE binary whose
|
||||
pointer may be passed into a foreign module SHOULD be compiled to use
|
||||
the Microsoft ABI. This is because in practice the OS-specific module
|
||||
may need to be compiled by MSVC, where MS ABI is the *only* ABI, which
|
||||
forces our UNIX programs to partially conform. Thankfully, all UNIX
|
||||
compilers support doing it on a case-by-case basis.
|
||||
|
||||
### Char Signedness
|
||||
|
||||
Actually Portable Executable defines `char` as signed.
|
||||
|
||||
Therefore conformant APE software MUST use `-fsigned-char` when building
|
||||
code for aarch64, as well as any other architecture that (unlike x86-64)
|
||||
would otherwise define `char` as being `unsigned char` by default.
|
||||
|
||||
This decision was one of the cases where it made sense to offer a more
|
||||
consistent runtime experience for fat multi-arch binaries. However you
|
||||
SHOULD still write code to assume `char` can go either way. But if all
|
||||
you care about is using APE, then you CAN assume `char` is signed.
|
||||
|
||||
### Long Double
|
||||
|
||||
On AMD64 platforms, APE binaries define `long double` as 80-bit.
|
||||
|
||||
On ARM64 platforms, APE binaries define `long double` as 128-bit.
|
||||
|
||||
We accept inconsistency in this case, because hardware acceleration is
|
||||
far more valuable than stylistic consistency in the case of mathematics.
|
||||
|
||||
One challenge arises on AMD64 for supporting `long double` across OSes.
|
||||
Unlike UNIX systems, the Windows Executive on x86-64 initializes the x87
|
||||
FPU to have double (64-bit) precision rather than 80-bit. That's because
|
||||
code compiled by MSVC treats `long double` as though it were `double` to
|
||||
prefer always using the more modern SSE instructions. However System V
|
||||
requires genuine 80-bit `long double` support on AMD64.
|
||||
|
||||
Therefore, if an APE program detects that it's been started on a Windows
|
||||
x86-64 system, then it SHOULD use the following assembly to initialize
|
||||
the x87 FPU in System V ABI mode.
|
||||
|
||||
```asm
|
||||
fldcw 1f(%rip)
|
||||
.rodata
|
||||
.balign 2
|
||||
// 8087 FPU Control Word
|
||||
// IM: Invalid Operation ───────────────┐
|
||||
// DM: Denormal Operand ───────────────┐│
|
||||
// ZM: Zero Divide ───────────────────┐││
|
||||
// OM: Overflow ─────────────────────┐│││
|
||||
// UM: Underflow ───────────────────┐││││
|
||||
// PM: Precision ──────────────────┐│││││
|
||||
// PC: Precision Control ───────┐ ││││││
|
||||
// {float,∅,double,long double}│ ││││││
|
||||
// RC: Rounding Control ──────┐ │ ││││││
|
||||
// {even, →-∞, →+∞, →0} │┌┤ ││││││
|
||||
// ┌┤││ ││││││
|
||||
// d││││rr││││││
|
||||
1: .short 0b00000000000000000001101111111
|
||||
.previous
|
||||
```
|
||||
|
||||
## Executable File Alignment
|
||||
|
||||
Actually Portable Executable is a statically-linked flat executable file
|
||||
format that is, as a thing in itself, agnostic to file alignments. For
|
||||
example, the shell script payload at the beginning of the file and its
|
||||
statements have no such requirements. Alignment requirements are however
|
||||
imposed by the executable formats that APE wraps.
|
||||
|
||||
1. ELF requires that file offsets be congruent with virtual addresses
|
||||
modulo the CPU page size. So when we add a shell script to the start
|
||||
of an executable, we need to round up to the page size in order to
|
||||
maintain ELF's invariant. Although no such roundup is required on the
|
||||
program segments once the invariant is restored. ELF loaders will
|
||||
happily map program headers from arbitrary file intervals (which may
|
||||
overlap) onto arbitrarily virtual intervals (which don't need to be
|
||||
contiguous). In order to do that, the loaders will generally use
|
||||
UNIX's mmap() function which is more restrictive and only accepts
|
||||
addresses and offsets that are page aligned. To make it possible to
|
||||
map an unaligned ELF program header that could potentially start and
|
||||
stop at any byte, ELF loaders round-out the intervals, which means
|
||||
adjacent unrelated data might also get mapped, which may need to be
|
||||
explicitly zero'd. Thanks to the cleverness of ELF, it's possible to
|
||||
have an executable file be very tiny, without needing any alignment
|
||||
bytes, and it'll be loaded into a properly aligned virtual space
|
||||
where segments can be as sparse as we want them to be.
|
||||
|
||||
2. PE doesn't care about congruence and instead defines two separate
|
||||
kinds of alignment. First, PE requires that the layout of segment
|
||||
memory inside the file be aligned on at minimum the classic 512 byte
|
||||
MS-DOS page size. This means that, unlike ELF, some alignment padding
|
||||
may need to be encoded into the file, making it slightly larger. Next
|
||||
PE imposes an alignment restriction on segments once they've been
|
||||
mapped into the virtual address space, which must be rounded to the
|
||||
system page size. Like ELF, PE segments need to be properly ordered
|
||||
but they're allowed to drift apart once mapped in a non-contiguous
|
||||
sparsely mapped way. When inserting shell script content at the start
|
||||
of a PE file, the most problematic thing is the need to round up to
|
||||
the 64kb system granularity, which results in a lot of needless bytes
|
||||
of padding being inserted by a naive second-pass linker.
|
||||
|
||||
3. Apple's Mach-O format is the strictest of them all. While both ELF
|
||||
and PE are defined in such a way that invites great creativity, XNU
|
||||
will simply refuse to an executable that does anything creative with
|
||||
alignment. All loaded segments need to both start and end on a page
|
||||
aligned address. XNU also wants segments to be contiguous similar to
|
||||
portable executable, except it applies to both the file and virtual
|
||||
spaces, which must follow the same structure.
|
||||
|
||||
Actually Portable Executables must conform to the strictest requirements
|
||||
demanded by the support vector. Therefore an APE binary that has headers
|
||||
for all three of the above executable formats MUST conform to the Apple
|
||||
way of doing things. GNU ld linker scripts aren't very good at producing
|
||||
ELF binaries that rigidly conform to this simple naive layout. There are
|
||||
so many ways things can go wrong, where third party code might slip its
|
||||
own custom section name in-between the linker script sections that are
|
||||
explicitly defined, thereby causing ELF's powerful features to manifest
|
||||
and the resulting content overlapping. The best `ld` flag that helps is
|
||||
`--orphan-handling=error` which can help with explaining such mysteries.
|
||||
|
||||
While Cosmopolitan was originally defined to just use stock GNU tools,
|
||||
this proved intractable over time, and the project has been evolving in
|
||||
the direction of building its own. Inventing the `apelink` program was
|
||||
what enabled the project to achieve multi-architecture binaries whereas
|
||||
previously it was only possible to do multi-OS binaries. In the future,
|
||||
our hope is that a fast power linker like Mold can be adapted to produce
|
||||
fat APE binaries directly from object files in one pass.
|
||||
|
||||
## Position Independent Code
|
||||
|
||||
APE doesn't currently support position independent executable formats.
|
||||
This is because APE was originally written for the GNU linker, where PIC
|
||||
and PIE were after-thoughts and never fully incorporated with the older
|
||||
more powerful linker script techniques upon which APE relies. Future
|
||||
iterations of this specification are intended to converge on modern
|
||||
standards, as our tooling becomes developed enough to support it.
|
||||
|
||||
However this only applies to the wrapped executable formats themselves.
|
||||
While our convention to date has been to always load ELF programs at the
|
||||
4mb mark, this is not guaranteed across OSes and architectures. Programs
|
||||
should have no expectations that a program will be loaded to any given
|
||||
address. For example, Cosmo currently implements APE on AARCH64 as
|
||||
loading executables to a starting address of 0x000800000000. This
|
||||
address occupies a sweet spot of requirements.
|
||||
|
||||
## Address Space
|
||||
|
||||
In order to create a single binary that supports as many platforms as
|
||||
possible without needing to be recompiled, there's a very narrow range
|
||||
of addresses that can be used. That range is somewhere between 32 bits
|
||||
and 39 bits.
|
||||
|
||||
- Embedded devices that claim to be 64-bit will oftentimes only support
|
||||
a virtual address space that's 39 bits in size.
|
||||
|
||||
- We can't load executable images on AARCH64 beneath 0x100000000 (4gb)
|
||||
because Apple forbids doing that, possibly in an effort to enforce a
|
||||
best practice for spotting 32-bit to 64-bit transition bugs. Please
|
||||
note that this restriction only applies to Apple ARM64 systems. The
|
||||
x86-64 version of XNU will happily load APE binaries to 0x00400000.
|
||||
|
||||
- The AMD64 architecture on desktops and servers can usually be counted
|
||||
upon to provide a 47-bit address space. The Linux Kernel for instance
|
||||
grants each userspace program full dominion over addresses 0x00200000
|
||||
through 0x00007fffffffffff provided the hardware supports this. On
|
||||
modern workstations supporting Intel and AMD's new PML5T feature which
|
||||
virtualizes memory using a radix trie that's five layers deep, Linux
|
||||
is able to offer userspace its choice of fixed addresses from
|
||||
0x00200000 through 0x00ffffffffffffff. The only exception to this rule
|
||||
we've encountered so far is that Windows 7 and Windows Vista behaved
|
||||
similar to embedded devices in reducing the number of va bits.
|
||||
|
||||
## Page Size
|
||||
|
||||
APE software MUST be page size agnostic. For many years the industry had
|
||||
converged on a strong consensus of having a page size that's 4096 bytes.
|
||||
However this convention was never guaranteed. New computers have become
|
||||
extremely popular, such as Apple Silicon, that use a 16kb page size.
|
||||
|
||||
By convention, Cosmopolitan Libc currently generates ELF headers for
|
||||
x86-64 that are strictly aligned on a 4096-byte page size. On ARM64
|
||||
Cosmopolitan is currently implemented to always generate ELF headers
|
||||
aligned on a 16kb page size.
|
||||
|
||||
In addition to being page size agnostic, APE software that cares about
|
||||
working correctly on Windows needs to be aware of the concept of
|
||||
allocation granularity. While the page size on Windows is generally 4kb
|
||||
in size, memory mappings can only be created on addresses that aligned
|
||||
to the system allocation granularity, which is generally 64kb. If you
|
||||
use a function like mmap() with Cosmopolitan Libc, then the `addr` and
|
||||
`offset` parameters need to be aligned to `sysconf(_SC_GRANSIZE)` or
|
||||
else your software won't work on Windows. Windows has other limitations
|
||||
too, such as lacking the ability to carve or punch holes in mappings.
|
|
@ -18,7 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "ape/ape.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/macros.h"
|
||||
|
||||
#ifdef __aarch64__
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/macros.h"
|
||||
|
||||
// Invokes system call.
|
||||
//
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
build/bootstrap/cocmd
Executable file
BIN
build/bootstrap/cocmd
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
58
build/bootstrap/gcc-only-flags.txt
Normal file
58
build/bootstrap/gcc-only-flags.txt
Normal file
|
@ -0,0 +1,58 @@
|
|||
--nocompress-debug-sections
|
||||
--noexecstack
|
||||
-Wa,--nocompress-debug-sections
|
||||
-Wa,--noexecstack
|
||||
-Wa,-msse2avx
|
||||
-Werror=maybe-uninitialized
|
||||
-Wno-literal-suffix
|
||||
-Wno-unused-but-set-variable
|
||||
-Wunsafe-loop-optimizations
|
||||
-fbranch-target-load-optimize
|
||||
-fcx-limited-range
|
||||
-fdelete-dead-exceptions
|
||||
-femit-struct-debug-baseonly
|
||||
-ffp-int-builtin-inexact
|
||||
-finline-functions-called-once
|
||||
-fipa-pta
|
||||
-fivopts
|
||||
-flimit-function-alignment
|
||||
-fmerge-constants
|
||||
-fmodulo-sched
|
||||
-fmodulo-sched-allow-regmoves
|
||||
-fno-align-jumps
|
||||
-fno-align-labels
|
||||
-fno-align-loops
|
||||
-fno-code-hoisting
|
||||
-fno-cx-limited-range
|
||||
-fno-fp-int-builtin-inexact
|
||||
-fno-gnu-unique
|
||||
-fno-inline-functions-called-once
|
||||
-fno-instrument-functions
|
||||
-fno-schedule-insns2
|
||||
-fno-whole-program
|
||||
-fopt-info-vec
|
||||
-fopt-info-vec-missed
|
||||
-freg-struct-return
|
||||
-freschedule-modulo-scheduled-loops
|
||||
-frounding-math
|
||||
-fsched2-use-superblocks
|
||||
-fschedule-insns
|
||||
-fschedule-insns2
|
||||
-fshrink-wrap
|
||||
-fshrink-wrap-separate
|
||||
-fsignaling-nans
|
||||
-fstack-clash-protection
|
||||
-ftracer
|
||||
-ftrapv
|
||||
-ftree-loop-im
|
||||
-ftree-loop-vectorize
|
||||
-funsafe-loop-optimizations
|
||||
-fversion-loops-for-strides
|
||||
-fwhole-program
|
||||
-gdescribe-dies
|
||||
-gstabs
|
||||
-mcall-ms2sysv-xlogues
|
||||
-mdispatch-scheduler
|
||||
-mfpmath=sse+387
|
||||
-mmitigate-rop
|
||||
-mno-fentry
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
106
build/config.mk
106
build/config.mk
|
@ -11,20 +11,19 @@
|
|||
#
|
||||
ifeq ($(MODE),)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CCFLAGS += -O2 $(BACKTRACES)
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG
|
||||
TARGET_ARCH ?= -msse3
|
||||
endif
|
||||
ifeq ($(MODE), x86_64)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CCFLAGS += -O2 $(BACKTRACES)
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG
|
||||
endif
|
||||
ifeq ($(MODE), aarch64)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CCFLAGS += -O2 $(BACKTRACES)
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG
|
||||
endif
|
||||
|
@ -38,13 +37,13 @@ endif
|
|||
#
|
||||
ifeq ($(MODE), zero)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
OVERRIDE_CFLAGS += -O0
|
||||
OVERRIDE_CXXFLAGS += -O0
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG
|
||||
endif
|
||||
ifeq ($(MODE), aarch64-zero)
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
OVERRIDE_CFLAGS += -O0 -fdce
|
||||
OVERRIDE_CXXFLAGS += -O0 -fdce
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG
|
||||
|
@ -64,7 +63,6 @@ ENABLE_FTRACE = 1
|
|||
CONFIG_CCFLAGS += $(BACKTRACES) -O
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG -DDWARFLESS
|
||||
CONFIG_LDFLAGS += -S
|
||||
TARGET_ARCH ?= -msse3
|
||||
endif
|
||||
|
||||
# Optimized Mode
|
||||
|
@ -81,10 +79,10 @@ endif
|
|||
#
|
||||
ifeq ($(MODE), opt)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -O3 -fmerge-all-constants
|
||||
TARGET_ARCH ?= -march=native
|
||||
CONFIG_TARGET_ARCH ?= -march=native
|
||||
endif
|
||||
|
||||
# Optimized Linux Mode
|
||||
|
@ -98,11 +96,24 @@ endif
|
|||
# - Turns off support for other operating systems
|
||||
#
|
||||
ifeq ($(MODE), optlinux)
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG -DSUPPORT_VECTOR=1
|
||||
CONFIG_CCFLAGS += -O3 -fmerge-all-constants
|
||||
CONFIG_COPTS += -mred-zone
|
||||
CONFIG_TARGET_ARCH ?= -march=native
|
||||
endif
|
||||
ifeq ($(MODE), x86_64-optlinux)
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG -DSUPPORT_VECTOR=1
|
||||
CONFIG_CCFLAGS += -O3 -fmerge-all-constants
|
||||
CONFIG_COPTS += -mred-zone
|
||||
CONFIG_TARGET_ARCH ?= -march=native
|
||||
endif
|
||||
ifeq ($(MODE), aarch64-optlinux)
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG -DSUPPORT_VECTOR=1
|
||||
CONFIG_CCFLAGS += -O3 -fmerge-all-constants
|
||||
CONFIG_COPTS += -mred-zone
|
||||
TARGET_ARCH ?= -march=native
|
||||
endif
|
||||
|
||||
# Release Mode
|
||||
|
@ -123,36 +134,13 @@ endif
|
|||
ifeq ($(MODE), rel)
|
||||
CONFIG_CPPFLAGS += -DNDEBUG -DDWARFLESS
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -O2
|
||||
TARGET_ARCH ?= -msse3
|
||||
PYFLAGS += -O1
|
||||
endif
|
||||
|
||||
# Asan Mode
|
||||
#
|
||||
# Safer binaries good for backend production serving.
|
||||
#
|
||||
# - `make MODE=asan`
|
||||
# - Memory safety
|
||||
# - Production worthy
|
||||
# - Backtraces
|
||||
# - Debuggability
|
||||
# - Larger binaries
|
||||
#
|
||||
ifeq ($(MODE), asan)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_CPPFLAGS += -D__SANITIZE_ADDRESS__
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -O2 -DSYSDEBUG
|
||||
CONFIG_COPTS += -fsanitize=address
|
||||
TARGET_ARCH ?= -msse3
|
||||
QUOTA ?= -C64 -L300
|
||||
endif
|
||||
|
||||
# Debug Mode
|
||||
#
|
||||
# - `make MODE=dbg`
|
||||
# - Backtraces
|
||||
# - Enables asan
|
||||
# - Enables ubsan
|
||||
# - Stack canaries
|
||||
# - No optimization
|
||||
|
@ -160,19 +148,33 @@ endif
|
|||
#
|
||||
ifeq ($(MODE), dbg)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_ADDRESS__ -D__SANITIZE_UNDEFINED__
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG -O0 -fno-inline
|
||||
CONFIG_COPTS += -fsanitize=address -fsanitize=undefined
|
||||
TARGET_ARCH ?= -msse3
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
OVERRIDE_CFLAGS += -O0
|
||||
OVERRIDE_CXXFLAGS += -O0
|
||||
CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_UNDEFINED__ -Wno-unused-variable -Wno-unused-but-set-variable
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG
|
||||
CONFIG_COPTS += -fsanitize=undefined
|
||||
OVERRIDE_CCFLAGS += -fno-pie
|
||||
QUOTA ?= -C64 -L300
|
||||
endif
|
||||
ifeq ($(MODE), x86_64-dbg)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
OVERRIDE_CFLAGS += -O0
|
||||
OVERRIDE_CXXFLAGS += -O0
|
||||
CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_UNDEFINED__ -Wno-unused-variable -Wno-unused-but-set-variable
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG
|
||||
CONFIG_COPTS += -fsanitize=undefined
|
||||
OVERRIDE_CCFLAGS += -fno-pie
|
||||
QUOTA ?= -C64 -L300
|
||||
endif
|
||||
ifeq ($(MODE), aarch64-dbg)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_UNDEFINED__
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG -O0 -fno-inline -fdce
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
OVERRIDE_CFLAGS += -O0 -fdce
|
||||
OVERRIDE_CXXFLAGS += -O0 -fdce
|
||||
CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_UNDEFINED__ -Wno-unused-variable -Wno-unused-but-set-variable
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG
|
||||
CONFIG_COPTS += -fsanitize=undefined
|
||||
QUOTA ?= -C64 -L300
|
||||
endif
|
||||
|
@ -189,10 +191,9 @@ endif
|
|||
#
|
||||
ifeq ($(MODE), sysv)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -O2
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG -DSUPPORT_VECTOR=121
|
||||
TARGET_ARCH ?= -msse3
|
||||
endif
|
||||
|
||||
# Tiny Mode
|
||||
|
@ -222,8 +223,6 @@ CONFIG_CCFLAGS += \
|
|||
-momit-leaf-frame-pointer \
|
||||
-foptimize-sibling-calls \
|
||||
-DDWARFLESS
|
||||
TARGET_ARCH ?= \
|
||||
-msse3
|
||||
PYFLAGS += \
|
||||
-O2 \
|
||||
-B
|
||||
|
@ -243,8 +242,6 @@ CONFIG_CCFLAGS += \
|
|||
-momit-leaf-frame-pointer \
|
||||
-foptimize-sibling-calls \
|
||||
-DDWARFLESS
|
||||
TARGET_ARCH ?= \
|
||||
-msse3
|
||||
PYFLAGS += \
|
||||
-O2 \
|
||||
-B
|
||||
|
@ -296,8 +293,6 @@ CONFIG_CCFLAGS += \
|
|||
-fno-align-jumps \
|
||||
-fno-align-labels \
|
||||
-fno-align-loops
|
||||
TARGET_ARCH ?= \
|
||||
-msse3
|
||||
endif
|
||||
|
||||
# Linux+BSD Tiny Mode
|
||||
|
@ -327,8 +322,6 @@ CONFIG_CCFLAGS += \
|
|||
-fno-align-jumps \
|
||||
-fno-align-labels \
|
||||
-fno-align-loops
|
||||
TARGET_ARCH ?= \
|
||||
-msse3
|
||||
endif
|
||||
|
||||
# Unix Tiny Mode
|
||||
|
@ -357,8 +350,6 @@ CONFIG_CCFLAGS += \
|
|||
-fno-align-jumps \
|
||||
-fno-align-labels \
|
||||
-fno-align-loops
|
||||
TARGET_ARCH ?= \
|
||||
-msse3
|
||||
endif
|
||||
|
||||
# Tiny Metallic Unix Mode
|
||||
|
@ -387,8 +378,6 @@ CONFIG_CCFLAGS += \
|
|||
-fno-align-jumps \
|
||||
-fno-align-labels \
|
||||
-fno-align-loops
|
||||
TARGET_ARCH ?= \
|
||||
-msse3
|
||||
endif
|
||||
|
||||
# no x87 instructions mode
|
||||
|
@ -410,7 +399,6 @@ ENABLE_FTRACE = 1
|
|||
CONFIG_COPTS += -mlong-double-64
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -O2
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG -DNOX87
|
||||
TARGET_ARCH ?= -msse3
|
||||
endif
|
||||
|
||||
# LLVM Mode
|
||||
|
@ -423,7 +411,6 @@ endif
|
|||
#
|
||||
ifeq ($(MODE), llvm)
|
||||
.STRICT = 0
|
||||
TARGET_ARCH ?= -msse3
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG -O2
|
||||
AS = clang
|
||||
CC = clang
|
||||
|
@ -466,7 +453,6 @@ ifeq ($(MODE), ansi)
|
|||
CONFIG_CFLAGS += -std=c11
|
||||
#CONFIG_CPPFLAGS += -ansi
|
||||
CONFIG_CXXFLAGS += -std=c++11
|
||||
TARGET_ARCH ?= -msse3
|
||||
endif
|
||||
|
||||
ifneq ($(ENABLE_FTRACE),)
|
||||
|
@ -524,3 +510,5 @@ ifeq ($(ARCH), aarch64)
|
|||
CONFIG_CCFLAGS += -fpatchable-function-entry=7,6
|
||||
endif
|
||||
endif
|
||||
|
||||
TARGET_ARCH ?= $(CONFIG_TARGET_ARCH)
|
||||
|
|
|
@ -53,108 +53,17 @@
|
|||
# OVERRIDE_FOO set ~/.cosmo.mk and target-specific (use rarely)
|
||||
#
|
||||
|
||||
LC_ALL = C
|
||||
SOURCE_DATE_EPOCH = 0
|
||||
|
||||
ARFLAGS = rcsD
|
||||
ZFLAGS ?=
|
||||
XARGS ?= xargs -P4 -rs8000
|
||||
DOT ?= dot
|
||||
CLANG = clang
|
||||
TMPDIR = o/tmp
|
||||
|
||||
AR = build/bootstrap/ar.com
|
||||
CP = build/bootstrap/cp.com
|
||||
RM = build/bootstrap/rm.com -f
|
||||
GZIP = build/bootstrap/gzip.com
|
||||
ECHO = build/bootstrap/echo.com
|
||||
CHMOD = build/bootstrap/chmod.com
|
||||
TOUCH = build/bootstrap/touch.com
|
||||
PKG = build/bootstrap/package.com
|
||||
MKDEPS = build/bootstrap/mkdeps.com
|
||||
ZIPOBJ = build/bootstrap/zipobj.com
|
||||
ZIPCOPY = build/bootstrap/zipcopy.com
|
||||
PECHECK = build/bootstrap/pecheck.com
|
||||
FIXUPOBJ = build/bootstrap/fixupobj.com
|
||||
MKDIR = build/bootstrap/mkdir.com -p
|
||||
COMPILE = build/bootstrap/compile.com -V9 -P4096 $(QUOTA)
|
||||
|
||||
COMMA := ,
|
||||
PWD := $(shell build/bootstrap/pwd.com)
|
||||
|
||||
IGNORE := $(shell $(MKDIR) $(TMPDIR))
|
||||
|
||||
ifneq ($(findstring aarch64,$(MODE)),)
|
||||
ARCH = aarch64
|
||||
HOSTS ?= pi studio freebsdarm
|
||||
else
|
||||
ARCH = x86_64
|
||||
HOSTS ?= freebsd rhel7 xnu win10 openbsd netbsd
|
||||
endif
|
||||
|
||||
ZIPOBJ_FLAGS += -a$(ARCH)
|
||||
|
||||
ifeq ($(PREFIX),)
|
||||
ifeq ($(USE_SYSTEM_TOOLCHAIN),)
|
||||
ifeq ($(ARCH),x86_64)
|
||||
ifneq ("$(wildcard o/third_party/gcc/bin/x86_64-linux-cosmo-*)","")
|
||||
PREFIX = o/third_party/gcc/bin/x86_64-linux-cosmo-
|
||||
else
|
||||
IGNORE := $(shell build/bootstrap/unbundle.com)
|
||||
PREFIX = o/third_party/gcc/bin/x86_64-linux-musl-
|
||||
endif
|
||||
endif # ($(ARCH),x86_64))
|
||||
ifeq ($(ARCH),aarch64)
|
||||
ifneq ("$(wildcard o/third_party/gcc/bin/aarch64-linux-cosmo-*)","")
|
||||
PREFIX = o/third_party/gcc/bin/aarch64-linux-cosmo-
|
||||
else
|
||||
IGNORE := $(shell build/bootstrap/unbundle.com)
|
||||
PREFIX = o/third_party/gcc/bin/aarch64-linux-musl-
|
||||
endif
|
||||
endif # ($(ARCH),aarch64)
|
||||
endif # ($(USE_SYSTEM_TOOLCHAIN),)
|
||||
endif # ($(PREFIX),)
|
||||
|
||||
AS = $(PREFIX)as
|
||||
CC = $(PREFIX)gcc
|
||||
CXX = $(PREFIX)g++
|
||||
CXXFILT = $(PREFIX)c++filt
|
||||
LD = $(PREFIX)ld.bfd
|
||||
NM = $(PREFIX)nm
|
||||
GCC = $(PREFIX)gcc
|
||||
STRIP = $(PREFIX)strip
|
||||
OBJCOPY = $(PREFIX)objcopy
|
||||
OBJDUMP = $(PREFIX)objdump
|
||||
ifneq ($(wildcard $(PWD)/$(PREFIX)addr2line),)
|
||||
ADDR2LINE = $(PWD)/$(PREFIX)addr2line
|
||||
else
|
||||
ADDR2LINE = $(PREFIX)addr2line
|
||||
endif
|
||||
|
||||
export ADDR2LINE
|
||||
export LC_ALL
|
||||
export MKDIR
|
||||
export MODE
|
||||
export SOURCE_DATE_EPOCH
|
||||
export TMPDIR
|
||||
|
||||
ifeq ($(LANDLOCKMAKE_VERSION),)
|
||||
TMPSAFE = $(join $(TMPDIR),$(subst /,_,$@)).tmp
|
||||
TMPSAFE = $(join $(TMPDIR)/,$(subst /,_,$@)).tmp
|
||||
else
|
||||
TMPSAFE = $(TMPDIR)/
|
||||
endif
|
||||
|
||||
BACKTRACES = \
|
||||
-fno-schedule-insns2 \
|
||||
-fno-optimize-sibling-calls \
|
||||
-mno-omit-leaf-frame-pointer
|
||||
|
||||
ifneq ($(ARCH), aarch64)
|
||||
BACKTRACES += -fno-schedule-insns2
|
||||
endif
|
||||
|
||||
SANITIZER = \
|
||||
-fsanitize=address
|
||||
|
||||
NO_MAGIC = \
|
||||
-ffreestanding \
|
||||
-fno-stack-protector \
|
||||
|
@ -178,16 +87,12 @@ DEFAULT_CCFLAGS += \
|
|||
-frecord-gcc-switches
|
||||
|
||||
DEFAULT_COPTS ?= \
|
||||
-fno-math-errno \
|
||||
-fno-ident \
|
||||
-fno-common \
|
||||
-fno-gnu-unique \
|
||||
-fstrict-aliasing \
|
||||
-fstrict-overflow \
|
||||
-fno-semantic-interposition \
|
||||
-fno-dwarf2-cfi-asm \
|
||||
-fno-unwind-tables \
|
||||
-fno-asynchronous-unwind-tables
|
||||
-fno-semantic-interposition
|
||||
|
||||
ifeq ($(ARCH), x86_64)
|
||||
# Microsoft says "[a]ny memory below the stack beyond the red zone
|
||||
|
@ -207,13 +112,10 @@ ifeq ($(ARCH), aarch64)
|
|||
# - Cosmopolitan Libc uses x28 for thread-local storage because Apple
|
||||
# forbids us from using tpidr_el0 too.
|
||||
#
|
||||
# - Cosmopolitan currently lacks an implementation of the runtime
|
||||
# libraries needed by the -moutline-atomics flag
|
||||
#
|
||||
DEFAULT_COPTS += \
|
||||
-ffixed-x18 \
|
||||
-ffixed-x28 \
|
||||
-mno-outline-atomics
|
||||
-fsigned-char
|
||||
endif
|
||||
|
||||
MATHEMATICAL = \
|
||||
|
@ -223,20 +125,22 @@ MATHEMATICAL = \
|
|||
DEFAULT_CPPFLAGS += \
|
||||
-D_COSMO_SOURCE \
|
||||
-DMODE='"$(MODE)"' \
|
||||
-Wno-prio-ctor-dtor \
|
||||
-Wno-unknown-pragmas \
|
||||
-nostdinc \
|
||||
-iquote. \
|
||||
-isystem libc/isystem
|
||||
|
||||
DEFAULT_CFLAGS = \
|
||||
-std=gnu2x
|
||||
-std=gnu23
|
||||
|
||||
DEFAULT_CXXFLAGS = \
|
||||
-fno-rtti \
|
||||
-fno-exceptions \
|
||||
-std=gnu++23 \
|
||||
-fuse-cxa-atexit \
|
||||
-Wno-int-in-bool-context \
|
||||
-Wno-narrowing \
|
||||
-Wno-literal-suffix
|
||||
-Wno-literal-suffix \
|
||||
-isystem third_party/libcxx
|
||||
|
||||
DEFAULT_ASFLAGS = \
|
||||
-W \
|
||||
|
@ -248,6 +152,7 @@ DEFAULT_LDFLAGS = \
|
|||
-nostdlib \
|
||||
-znorelro \
|
||||
--gc-sections \
|
||||
-z noexecstack \
|
||||
--build-id=none \
|
||||
--no-dynamic-linker
|
||||
|
||||
|
@ -342,12 +247,12 @@ LD.libs = \
|
|||
$(LIBS)
|
||||
|
||||
COMPILE.c.flags = $(cc.flags) $(copt.flags) $(cpp.flags) $(c.flags)
|
||||
COMPILE.cxx.flags = $(cc.flags) $(copt.flags) $(cpp.flags) $(cxx.flags)
|
||||
COMPILE.cxx.flags = $(cc.flags) $(copt.flags) $(cxx.flags) $(cpp.flags)
|
||||
COMPILE.i.flags = $(cc.flags) $(copt.flags) $(c.flags)
|
||||
COMPILE.ii.flags = $(cc.flags) $(copt.flags) $(cxx.flags)
|
||||
LINK.flags = $(DEFAULT_LDFLAGS) $(CONFIG_LDFLAGS) $(LDFLAGS)
|
||||
OBJECTIFY.c.flags = $(cc.flags) $(o.flags) $(S.flags) $(cpp.flags) $(copt.flags) $(c.flags)
|
||||
OBJECTIFY.cxx.flags = $(cc.flags) $(o.flags) $(S.flags) $(cpp.flags) $(copt.flags) $(cxx.flags)
|
||||
OBJECTIFY.cxx.flags = $(cc.flags) $(o.flags) $(S.flags) $(cxx.flags) $(cpp.flags) $(copt.flags)
|
||||
OBJECTIFY.s.flags = $(ASONLYFLAGS) $(s.flags)
|
||||
OBJECTIFY.S.flags = $(cc.flags) $(o.flags) $(S.flags) $(cpp.flags)
|
||||
PREPROCESS.flags = -E $(copt.flags) $(cc.flags) $(cpp.flags)
|
||||
|
|
106
build/download-cosmocc.sh
Executable file
106
build/download-cosmocc.sh
Executable file
|
@ -0,0 +1,106 @@
|
|||
#!/bin/sh
|
||||
# cosmocc downloader script
|
||||
# https://justine.lol/cosmo3/#install
|
||||
# https://github.com/jart/cosmopolitan/blob/master/tool/cosmocc/README.md
|
||||
|
||||
# collect arguments
|
||||
OUTPUT_DIR=${1:?OUTPUT_DIR}
|
||||
COSMOCC_VERSION=${2:?COSMOCC_VERSION}
|
||||
COSMOCC_SHA256SUM=${3:?COSMOCC_SHA256SUM}
|
||||
URL1="https://github.com/jart/cosmopolitan/releases/download/${COSMOCC_VERSION}/cosmocc-${COSMOCC_VERSION}.zip"
|
||||
URL2="https://cosmo.zip/pub/cosmocc/cosmocc-${COSMOCC_VERSION}.zip"
|
||||
|
||||
# helper function
|
||||
abort() {
|
||||
printf '%s\n' "download terminated." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# exit if already downloaded
|
||||
# we need it because directory timestamps work wierdly
|
||||
OUTPUT_DIR=${OUTPUT_DIR%/}
|
||||
if [ -d "${OUTPUT_DIR}" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# find commands we need to securely download cosmocc
|
||||
if ! UNZIP=$(command -v unzip 2>/dev/null); then
|
||||
printf '%s\n' "$0: fatal error: you need the unzip command" >&2
|
||||
printf '%s\n' "please download https://cosmo.zip/pub/cosmos/bin/unzip and put it on the system path" >&2
|
||||
abort
|
||||
fi
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
# can use system sha256sum
|
||||
true
|
||||
elif command -v shasum >/dev/null 2>&1; then
|
||||
sha256sum() {
|
||||
shasum -a 256 "$@"
|
||||
}
|
||||
else
|
||||
if [ ! -f build/sha256sum.c ]; then
|
||||
printf '%s\n' "$0: fatal error: you need to install sha256sum" >&2
|
||||
printf '%s\n' "please download https://cosmo.zip/pub/cosmos/bin/sha256sum and put it on the system path" >&2
|
||||
abort
|
||||
fi
|
||||
if ! SHA256SUM=$(command -v "$PWD/o/build/sha256sum" 2>/dev/null); then
|
||||
if ! CC=$(command -v "$CC" 2>/dev/null); then
|
||||
if ! CC=$(command -v cc 2>/dev/null); then
|
||||
if ! CC=$(command -v cosmocc 2>/dev/null); then
|
||||
printf '%s\n' "$0: fatal error: you need to install either sha256sum, cc, or cosmocc" >&2
|
||||
printf '%s\n' "please download https://cosmo.zip/pub/cosmos/bin/sha256sum and put it on the system path" >&2
|
||||
abort
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
mkdir -p o/build || abort
|
||||
SHA256SUM="$PWD/o/build/sha256sum"
|
||||
printf '%s\n' "${CC} -w -O2 -o ${SHA256SUM} build/sha256sum.c" >&2
|
||||
"${CC}" -w -O2 -o "${SHA256SUM}.$$" build/sha256sum.c || abort
|
||||
mv -f "${SHA256SUM}.$$" "${SHA256SUM}" || abort
|
||||
fi
|
||||
sha256sum() {
|
||||
"${SHA256SUM}" "$@"
|
||||
}
|
||||
fi
|
||||
if WGET=$(command -v wget 2>/dev/null); then
|
||||
DOWNLOAD=$WGET
|
||||
DOWNLOAD_ARGS=-O
|
||||
elif CURL=$(command -v curl 2>/dev/null); then
|
||||
DOWNLOAD=$CURL
|
||||
DOWNLOAD_ARGS=-fLo
|
||||
else
|
||||
printf '%s\n' "$0: fatal error: you need to install either wget or curl" >&2
|
||||
printf '%s\n' "please download https://cosmo.zip/pub/cosmos/bin/wget and put it on the system path" >&2
|
||||
abort
|
||||
fi
|
||||
|
||||
# create temporary output directory
|
||||
OLDPWD=$PWD
|
||||
OUTPUT_TMP="${OUTPUT_DIR}.tmp.$$/"
|
||||
mkdir -p "${OUTPUT_TMP}" || abort
|
||||
cd "${OUTPUT_TMP}"
|
||||
die() {
|
||||
cd "${OLDPWD}"
|
||||
rm -rf "${OUTPUT_TMP}"
|
||||
abort
|
||||
}
|
||||
|
||||
# download cosmocc toolchain
|
||||
# multiple urls avoids outages and national firewalls
|
||||
if ! "${DOWNLOAD}" ${DOWNLOAD_ARGS} cosmocc.zip "${URL1}"; then
|
||||
rm -f cosmocc.zip
|
||||
"${DOWNLOAD}" ${DOWNLOAD_ARGS} cosmocc.zip "${URL2}" || die
|
||||
fi
|
||||
printf '%s\n' "${COSMOCC_SHA256SUM} *cosmocc.zip" >cosmocc.zip.sha256sum
|
||||
sha256sum -c cosmocc.zip.sha256sum || die
|
||||
"${UNZIP}" cosmocc.zip || die
|
||||
rm -f cosmocc.zip cosmocc.zip.sha256sum
|
||||
|
||||
# commit output directory
|
||||
cd "${OLDPWD}" || die
|
||||
mv "${OUTPUT_TMP}" "${OUTPUT_DIR}" || die
|
||||
|
||||
# update current symlink
|
||||
BASE=$(basename "${OUTPUT_DIR}")
|
||||
DIR=$(dirname "${OUTPUT_DIR}")
|
||||
ln -sfn "$BASE" "$DIR/current"
|
|
@ -55,7 +55,7 @@ set -- --regex-c='/_Atomic(\([^)]*\))/\1/b' "$@"
|
|||
set -- --regex-c='/^\(\(hidden\|extern\|const\) \)*[_[:alpha:]][_[:alnum:]]*[ *][ *]*\([_[:alpha:]][_[:alnum:]]*[ *][ *]*\)*\([_[:alpha:]][_$[:alnum:]]*\)/\4/b' "$@"
|
||||
|
||||
# ctags doesn't understand function prototypes, e.g.
|
||||
# bool isheap(void *p) dontthrow nocallback;
|
||||
# bool isheap(void *p) dontthrow dontcallback;
|
||||
set -- --regex-c='/^[_[:alpha:]][_[:alnum:]]*[ *][ *]*\([_[:alpha:]][_[:alnum:]]*[ *][ *]*\)*\([_[:alpha:]][_$[:alnum:]]*\)(.*/\2/b' "$@"
|
||||
|
||||
# ctags doesn't understand function pointers, e.g.
|
||||
|
@ -66,7 +66,7 @@ set -- --regex-c='/^extern [^(]*(\*const \([^)]*\))(/\1/b' "$@"
|
|||
# struct WorstSoftwareEver;
|
||||
set -- --regex-c='/^struct.*;$/uehocruehcroue/b' "$@"
|
||||
|
||||
exec $TAGS \
|
||||
build/run $TAGS \
|
||||
-e \
|
||||
--langmap=c:.c.h \
|
||||
--exclude=libc/nt/struct/imagefileheader.internal.h \
|
||||
|
|
|
@ -6,14 +6,14 @@ if [ -n "$OBJDUMP" ]; then
|
|||
fi
|
||||
|
||||
find_objdump() {
|
||||
if [ -x o/third_party/gcc/bin/$1-linux-cosmo-objdump ]; then
|
||||
OBJDUMP=o/third_party/gcc/bin/$1-linux-cosmo-objdump
|
||||
elif [ -x o/third_party/gcc/bin/$1-linux-musl-objdump ]; then
|
||||
OBJDUMP=o/third_party/gcc/bin/$1-linux-musl-objdump
|
||||
elif [ -x "$COSMO/o/third_party/gcc/bin/$1-linux-cosmo-objdump" ]; then
|
||||
OBJDUMP="$COSMO/o/third_party/gcc/bin/$1-linux-cosmo-objdump"
|
||||
elif [ -x "$COSMO/o/third_party/gcc/bin/$1-linux-musl-objdump" ]; then
|
||||
OBJDUMP="$COSMO/o/third_party/gcc/bin/$1-linux-musl-objdump"
|
||||
if [ -x .cosmocc/3.9.2/bin/$1-linux-cosmo-objdump ]; then
|
||||
OBJDUMP=.cosmocc/3.9.2/bin/$1-linux-cosmo-objdump
|
||||
elif [ -x .cosmocc/3.9.2/bin/$1-linux-musl-objdump ]; then
|
||||
OBJDUMP=.cosmocc/3.9.2/bin/$1-linux-musl-objdump
|
||||
elif [ -x "$COSMO/.cosmocc/3.9.2/bin/$1-linux-cosmo-objdump" ]; then
|
||||
OBJDUMP="$COSMO/.cosmocc/3.9.2/bin/$1-linux-cosmo-objdump"
|
||||
elif [ -x "$COSMO/.cosmocc/3.9.2/bin/$1-linux-musl-objdump" ]; then
|
||||
OBJDUMP="$COSMO/.cosmocc/3.9.2/bin/$1-linux-musl-objdump"
|
||||
else
|
||||
echo "error: toolchain not found (try running 'cosmocc --update' or 'make' in the cosmo monorepo)" >&2
|
||||
exit 1
|
||||
|
|
|
@ -22,13 +22,14 @@
|
|||
# - tool/build/runit.c
|
||||
# - tool/build/runitd.c
|
||||
|
||||
.PRECIOUS: o/$(MODE)/%.com.ok
|
||||
o/$(MODE)/%.com.ok: private .PLEDGE = stdio rpath wpath cpath proc fattr inet
|
||||
o/$(MODE)/%.com.ok: \
|
||||
o/$(MODE)/tool/build/runit.com \
|
||||
o/$(MODE)/tool/build/runitd.com \
|
||||
o/$(MODE)/%.com
|
||||
.PRECIOUS: o/$(MODE)/%.ok
|
||||
o/$(MODE)/%.ok: private .PLEDGE = stdio rpath wpath cpath proc fattr inet dns
|
||||
o/$(MODE)/%.ok: private .UNVEIL += r:/etc/resolv.conf
|
||||
o/$(MODE)/%.ok: \
|
||||
o/$(MODE)/tool/build/runit \
|
||||
o/$(MODE)/tool/build/runitd \
|
||||
o/$(MODE)/%
|
||||
@$(COMPILE) -wATEST -tT$@ $^ $(HOSTS)
|
||||
|
||||
.PHONY:
|
||||
o/tiny/tool/build/runit.com:
|
||||
o/tiny/tool/build/runit:
|
||||
|
|
|
@ -39,6 +39,10 @@ o/$(MODE)/%.h: %.c
|
|||
|
||||
o/$(MODE)/%.o: %.cc
|
||||
@$(COMPILE) -AOBJECTIFY.cxx $(OBJECTIFY.cxx) $(OUTPUT_OPTION) $<
|
||||
@$(COMPILE) -AFIXUPOBJ -wT$@ $(FIXUPOBJ) $@
|
||||
|
||||
o/$(MODE)/%.o: %.cpp
|
||||
@$(COMPILE) -AOBJECTIFY.cxx $(OBJECTIFY.cxx) $(OUTPUT_OPTION) $<
|
||||
|
||||
o/$(MODE)/%.lds: %.lds
|
||||
@$(COMPILE) -APREPROCESS $(PREPROCESS.lds) $(OUTPUT_OPTION) $<
|
||||
|
@ -75,17 +79,17 @@ o/$(MODE)/%.pkg:
|
|||
$(file >$(TMPSAFE).args,$(filter %.o,$^))
|
||||
@$(COMPILE) -APACKAGE -wT$@ $(PKG) $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) @$(TMPSAFE).args
|
||||
|
||||
o/$(MODE)/%.o: %.py o/$(MODE)/third_party/python/pyobj.com
|
||||
@$(COMPILE) -wAPYOBJ o/$(MODE)/third_party/python/pyobj.com $(PYFLAGS) -o $@ $<
|
||||
o/$(MODE)/%.o: %.py o/$(MODE)/third_party/python/pyobj
|
||||
@$(COMPILE) -wAPYOBJ o/$(MODE)/third_party/python/pyobj $(PYFLAGS) -o $@ $<
|
||||
|
||||
o/$(MODE)/%.pyc: %.py o/$(MODE)/third_party/python/pycomp.com
|
||||
@$(COMPILE) -wAPYCOMP o/$(MODE)/third_party/python/pycomp.com $(PYCFLAGS) -o $@ $<
|
||||
o/$(MODE)/%.pyc: %.py o/$(MODE)/third_party/python/pycomp
|
||||
@$(COMPILE) -wAPYCOMP o/$(MODE)/third_party/python/pycomp $(PYCFLAGS) -o $@ $<
|
||||
|
||||
o/$(MODE)/%.lua: %.lua o/$(MODE)/third_party/lua/luac.com
|
||||
@$(COMPILE) -wALUAC o/$(MODE)/third_party/lua/luac.com -s -o $@ $<
|
||||
o/$(MODE)/%.lua: %.lua o/$(MODE)/third_party/lua/luac
|
||||
@$(COMPILE) -wALUAC o/$(MODE)/third_party/lua/luac -s -o $@ $<
|
||||
|
||||
o/$(MODE)/%.lua.runs: %.lua o/$(MODE)/tool/net/redbean.com
|
||||
@$(COMPILE) -wALUA -tT$@ o/$(MODE)/tool/net/redbean.com $(LUAFLAGS) -i $<
|
||||
o/$(MODE)/%.lua.runs: %.lua o/$(MODE)/tool/net/redbean
|
||||
@$(COMPILE) -wALUA -tT$@ o/$(MODE)/tool/net/redbean $(LUAFLAGS) -i $<
|
||||
|
||||
################################################################################
|
||||
# LOCAL UNIT TESTS
|
||||
|
@ -104,22 +108,22 @@ o/$(MODE)/%.lua.runs: %.lua o/$(MODE)/tool/net/redbean.com
|
|||
#
|
||||
# You could then run a command like:
|
||||
#
|
||||
# make -j8 o//test/libc/calls/openbsd_test.com.runs
|
||||
# make -j8 o//test/libc/calls/openbsd_test.runs
|
||||
#
|
||||
# You need PROT_EXEC permission since ftrace morphs the binary. It's
|
||||
# also worth mentioning that the pledge.com command can simulate what
|
||||
# also worth mentioning that the pledge command can simulate what
|
||||
# Landlock Make does:
|
||||
#
|
||||
# o//tool/build/pledge.com \
|
||||
# o//tool/build/pledge \
|
||||
# -v. -p 'stdio rpath wpath cpath tty prot_exec' \
|
||||
# o//test/libc/calls/openbsd_test.com \
|
||||
# o//test/libc/calls/openbsd_test \
|
||||
# ----ftrace
|
||||
#
|
||||
# This is useful in the event a test binary should run by itself, but
|
||||
# fails to run beneath Landlock Make. It's also useful sometimes to
|
||||
# override the verbosity when running tests:
|
||||
#
|
||||
# make V=5 TESTARGS=-b o//test/libc/calls/openbsd_test.com.runs
|
||||
# make V=5 TESTARGS=-b o//test/libc/calls/openbsd_test.runs
|
||||
#
|
||||
# This way, if for some reason a test should fail but calls exit(0),
|
||||
# then the stdout/stderr output, which would normally be suppressed,
|
||||
|
@ -131,7 +135,7 @@ o/$(MODE)/%.runs: o/$(MODE)/%
|
|||
################################################################################
|
||||
# ELF ZIP FILES
|
||||
#
|
||||
# zipobj.com lets us do fast incremental linking of compressed data.
|
||||
# zipobj lets us do fast incremental linking of compressed data.
|
||||
# it's nice because if we link a hundred binaries that use the time zone
|
||||
# database, then that database only needs to be DEFLATE'd once.
|
||||
|
||||
|
@ -179,23 +183,6 @@ o/$(MODE)/%.okk: private .UNSANDBOXED = 1
|
|||
o/$(MODE)/%.okk: %
|
||||
@$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $<
|
||||
|
||||
################################################################################
|
||||
# EXECUTABLE HELPERS
|
||||
|
||||
MAKE_SYMTAB_CREATE = \
|
||||
$(COMPILE) -wASYMTAB \
|
||||
o/$(MODE)/tool/build/symtab.com \
|
||||
-o $(TMPSAFE)/.symtab \
|
||||
$<
|
||||
|
||||
MAKE_SYMTAB_ZIP = \
|
||||
$(COMPILE) -AZIP -T$@ \
|
||||
o/$(MODE)/third_party/zip/zip.com \
|
||||
-b$(TMPDIR) \
|
||||
-9qj \
|
||||
$@ \
|
||||
$(TMPSAFE)/.symtab
|
||||
|
||||
################################################################################
|
||||
# EMACS ASSEMBLY GENERATION
|
||||
|
||||
|
|
11
build/run
11
build/run
|
@ -1,9 +1,8 @@
|
|||
#!/bin/sh
|
||||
if printf '%s\n' "$*" | grep aarch64 >/dev/null 2>&1; then
|
||||
if [ ! -f o/third_party/qemu/qemu-aarch64 ]; then
|
||||
make -j8 o/third_party/qemu/qemu-aarch64
|
||||
fi
|
||||
exec o/third_party/qemu/qemu-aarch64 "$@"
|
||||
UNAMEM=$(uname -m)
|
||||
UNAMES=$(uname -s)
|
||||
if [ x"$UNAMES" = x"Darwin" ] && [ x"$UNAMEM" = x"arm64" ]; then
|
||||
exec ape "$@"
|
||||
else
|
||||
exec "$@"
|
||||
exec rusage "$@"
|
||||
fi
|
||||
|
|
|
@ -31,7 +31,7 @@ if [ ! -f /proc/sys/fs/binfmt_misc/status ]; then
|
|||
exit 0
|
||||
fi
|
||||
|
||||
if ! build/bootstrap/echo.com -n; then
|
||||
if ! build/bootstrap/echo -n; then
|
||||
cat <<'EOF' >&2
|
||||
|
||||
ERROR
|
||||
|
|
455
build/sha256sum.c
Normal file
455
build/sha256sum.c
Normal file
|
@ -0,0 +1,455 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// this file should not have dependencies, because everything will be
|
||||
// re-downloaded if the o/tool/sha256sum artifact becomes invalidated
|
||||
|
||||
#define PROG "sha256sum"
|
||||
#define USAGE \
|
||||
"\
|
||||
Usage: " PROG " [-?hbctw] [PATH...]\n\
|
||||
-h help\n\
|
||||
-c check mode\n\
|
||||
-b binary mode\n\
|
||||
-t textual mode\n\
|
||||
-w warning mode\n"
|
||||
|
||||
#define ROTR(a, b) (((a) >> (b)) | ((a) << (32 - (b))))
|
||||
#define CH(x, y, z) (((x) & (y)) ^ (~(x) & (z)))
|
||||
#define MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
|
||||
#define EP0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
|
||||
#define EP1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
|
||||
#define SIG0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ ((x) >> 3))
|
||||
#define SIG1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ ((x) >> 10))
|
||||
|
||||
struct Sha256Ctx {
|
||||
uint8_t data[64];
|
||||
uint32_t datalen;
|
||||
uint64_t bitlen;
|
||||
uint32_t state[8];
|
||||
};
|
||||
|
||||
static const uint32_t kSha256Tab[64] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, //
|
||||
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, //
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, //
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, //
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, //
|
||||
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, //
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, //
|
||||
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, //
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, //
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, //
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, //
|
||||
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, //
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, //
|
||||
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, //
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, //
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, //
|
||||
};
|
||||
|
||||
static bool g_warn;
|
||||
static char g_mode;
|
||||
static bool g_check;
|
||||
static int g_mismatches;
|
||||
|
||||
static void Sha256Transform(uint32_t state[8], const uint8_t data[64]) {
|
||||
unsigned i;
|
||||
uint32_t a, b, c, d, e, f, g, h, t1, t2, m[64];
|
||||
for (i = 0; i < 16; ++i, data += 4) {
|
||||
m[i] = (uint32_t)data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
|
||||
}
|
||||
for (; i < 64; ++i) {
|
||||
m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
|
||||
}
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
f = state[5];
|
||||
g = state[6];
|
||||
h = state[7];
|
||||
for (i = 0; i < 64; ++i) {
|
||||
t1 = h + EP1(e) + CH(e, f, g) + kSha256Tab[i] + m[i];
|
||||
t2 = EP0(a) + MAJ(a, b, c);
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + t1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = t1 + t2;
|
||||
}
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
state[5] += f;
|
||||
state[6] += g;
|
||||
state[7] += h;
|
||||
}
|
||||
|
||||
static void Sha256Init(struct Sha256Ctx *ctx) {
|
||||
ctx->datalen = 0;
|
||||
ctx->bitlen = 0;
|
||||
ctx->state[0] = 0x6a09e667;
|
||||
ctx->state[1] = 0xbb67ae85;
|
||||
ctx->state[2] = 0x3c6ef372;
|
||||
ctx->state[3] = 0xa54ff53a;
|
||||
ctx->state[4] = 0x510e527f;
|
||||
ctx->state[5] = 0x9b05688c;
|
||||
ctx->state[6] = 0x1f83d9ab;
|
||||
ctx->state[7] = 0x5be0cd19;
|
||||
}
|
||||
|
||||
static void Sha256Update(struct Sha256Ctx *ctx, const uint8_t *data,
|
||||
long size) {
|
||||
long i;
|
||||
for (i = 0; i < size; ++i) {
|
||||
ctx->data[ctx->datalen] = data[i];
|
||||
ctx->datalen++;
|
||||
if (ctx->datalen == 64) {
|
||||
Sha256Transform(ctx->state, ctx->data);
|
||||
ctx->bitlen += 512;
|
||||
ctx->datalen = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Sha256Final(struct Sha256Ctx *ctx, uint8_t *hash) {
|
||||
long i;
|
||||
i = ctx->datalen;
|
||||
ctx->data[i++] = 0x80;
|
||||
if (ctx->datalen < 56) {
|
||||
memset(ctx->data + i, 0, 56 - i);
|
||||
} else {
|
||||
memset(ctx->data + i, 0, 64 - i);
|
||||
Sha256Transform(ctx->state, ctx->data);
|
||||
memset(ctx->data, 0, 56);
|
||||
}
|
||||
ctx->bitlen += ctx->datalen * 8;
|
||||
ctx->data[63] = ctx->bitlen;
|
||||
ctx->data[62] = ctx->bitlen >> 8;
|
||||
ctx->data[61] = ctx->bitlen >> 16;
|
||||
ctx->data[60] = ctx->bitlen >> 24;
|
||||
ctx->data[59] = ctx->bitlen >> 32;
|
||||
ctx->data[58] = ctx->bitlen >> 40;
|
||||
ctx->data[57] = ctx->bitlen >> 48;
|
||||
ctx->data[56] = ctx->bitlen >> 56;
|
||||
Sha256Transform(ctx->state, ctx->data);
|
||||
for (i = 0; i < 4; ++i) {
|
||||
hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0xff;
|
||||
hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0xff;
|
||||
hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0xff;
|
||||
hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0xff;
|
||||
hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0xff;
|
||||
hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0xff;
|
||||
hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0xff;
|
||||
hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
static char *FormatUint32(char *p, uint32_t x) {
|
||||
char t;
|
||||
size_t i, a, b;
|
||||
i = 0;
|
||||
do {
|
||||
p[i++] = x % 10 + '0';
|
||||
x = x / 10;
|
||||
} while (x > 0);
|
||||
p[i] = '\0';
|
||||
if (i) {
|
||||
for (a = 0, b = i - 1; a < b; ++a, --b) {
|
||||
t = p[a];
|
||||
p[a] = p[b];
|
||||
p[b] = t;
|
||||
}
|
||||
}
|
||||
return p + i;
|
||||
}
|
||||
|
||||
static char *FormatInt32(char *p, int32_t x) {
|
||||
if (x < 0)
|
||||
*p++ = '-', x = -(uint32_t)x;
|
||||
return FormatUint32(p, x);
|
||||
}
|
||||
|
||||
static size_t StrCat(char *dst, const char *src, size_t dsize) {
|
||||
size_t m, n = dsize;
|
||||
const char *p = dst;
|
||||
const char *q = src;
|
||||
while (n-- != 0 && *dst != '\0')
|
||||
dst++;
|
||||
m = dst - p;
|
||||
n = dsize - m;
|
||||
if (n-- == 0) {
|
||||
return m + strlen(src);
|
||||
}
|
||||
while (*src != '\0') {
|
||||
if (n != 0) {
|
||||
*dst++ = *src;
|
||||
n--;
|
||||
}
|
||||
src++;
|
||||
}
|
||||
*dst = '\0';
|
||||
return m + (src - q);
|
||||
}
|
||||
|
||||
static void GetOpts(int argc, char *argv[]) {
|
||||
int opt;
|
||||
g_mode = ' ';
|
||||
while ((opt = getopt(argc, argv, "?hbctw")) != -1) {
|
||||
switch (opt) {
|
||||
case 'w':
|
||||
g_warn = true;
|
||||
break;
|
||||
case 'c':
|
||||
g_check = true;
|
||||
break;
|
||||
case 't':
|
||||
g_mode = ' ';
|
||||
break;
|
||||
case 'b':
|
||||
g_mode = '*';
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
(void)write(1, USAGE, sizeof(USAGE) - 1);
|
||||
exit(0);
|
||||
default:
|
||||
(void)write(2, USAGE, sizeof(USAGE) - 1);
|
||||
exit(64);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Write(int fd, const char *s, ...) {
|
||||
va_list va;
|
||||
char buf[512];
|
||||
buf[0] = 0;
|
||||
va_start(va, s);
|
||||
do {
|
||||
StrCat(buf, s, sizeof(buf));
|
||||
} while ((s = va_arg(va, const char *)));
|
||||
va_end(va);
|
||||
(void)write(fd, buf, strlen(buf));
|
||||
}
|
||||
|
||||
static bool IsModeCharacter(char c) {
|
||||
switch (c) {
|
||||
case ' ':
|
||||
case '*':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsSupportedPath(const char *path) {
|
||||
size_t i;
|
||||
for (i = 0;; ++i) {
|
||||
switch (path[i]) {
|
||||
case 0:
|
||||
if (i)
|
||||
return true;
|
||||
// fallthrough
|
||||
case '\r':
|
||||
case '\n':
|
||||
case '\\':
|
||||
Write(2, PROG, ": ", path, ": unsupported path\n", NULL);
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool GetDigest(const char *path, FILE *f, uint8_t digest[32]) {
|
||||
size_t got;
|
||||
uint8_t buf[512];
|
||||
struct Sha256Ctx ctx;
|
||||
Sha256Init(&ctx);
|
||||
while ((got = fread(buf, 1, sizeof(buf), f))) {
|
||||
Sha256Update(&ctx, buf, got);
|
||||
}
|
||||
if (ferror(f)) {
|
||||
Write(2, PROG, ": ", path, ": ", strerror(errno), "\n", NULL);
|
||||
return false;
|
||||
}
|
||||
Sha256Final(&ctx, digest);
|
||||
return true;
|
||||
}
|
||||
|
||||
static char *CopyHex(char *s, const void *p, size_t n) {
|
||||
const char *d, *e;
|
||||
for (d = (const char *)p, e = d + n; d < e; ++d) {
|
||||
*s++ = "0123456789abcdef"[(*d >> 4) & 15];
|
||||
*s++ = "0123456789abcdef"[(*d >> 0) & 15];
|
||||
}
|
||||
*s = 0;
|
||||
return s;
|
||||
}
|
||||
|
||||
static bool ProduceDigest(const char *path, FILE *f) {
|
||||
char hexdigest[65];
|
||||
char mode[2] = {g_mode};
|
||||
unsigned char digest[32];
|
||||
if (!IsSupportedPath(path))
|
||||
return false;
|
||||
if (!GetDigest(path, f, digest))
|
||||
return false;
|
||||
CopyHex(hexdigest, digest, 32);
|
||||
Write(1, hexdigest, " ", mode, path, "\n", NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
static char *Chomp(char *line) {
|
||||
size_t i;
|
||||
if (line) {
|
||||
for (i = strlen(line); i--;) {
|
||||
if (line[i] == '\r' || line[i] == '\n') {
|
||||
line[i] = '\0';
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
static int HexToInt(int c) {
|
||||
if ('0' <= c && c <= '9') {
|
||||
return c - '0';
|
||||
} else if ('a' <= c && c <= 'f') {
|
||||
return c - 'a' + 10;
|
||||
} else if ('A' <= c && c <= 'F') {
|
||||
return c - 'A' + 10;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static bool CheckDigests(const char *path, FILE *f) {
|
||||
FILE *f2;
|
||||
bool k = true;
|
||||
int a, b, i, line;
|
||||
const char *path2, *status;
|
||||
uint8_t wantdigest[32], gotdigest[32];
|
||||
char buf[64 + 2 + PATH_MAX + 1 + 1], *p;
|
||||
for (line = 0; fgets(buf, sizeof(buf), f); ++line) {
|
||||
if (!*Chomp(buf))
|
||||
continue;
|
||||
for (p = buf, i = 0; i < 32; ++i) {
|
||||
if ((a = HexToInt(*p++ & 255)) == -1)
|
||||
goto InvalidLine;
|
||||
if ((b = HexToInt(*p++ & 255)) == -1)
|
||||
goto InvalidLine;
|
||||
wantdigest[i] = a << 4 | b;
|
||||
}
|
||||
if (*p++ != ' ')
|
||||
goto InvalidLine;
|
||||
if (!IsModeCharacter(*p++))
|
||||
goto InvalidLine;
|
||||
path2 = p;
|
||||
if (!*path2)
|
||||
goto InvalidLine;
|
||||
if (!IsSupportedPath(path2))
|
||||
continue;
|
||||
if ((f2 = fopen(path2, "rb"))) {
|
||||
if (GetDigest(path2, f2, gotdigest)) {
|
||||
if (!memcmp(wantdigest, gotdigest, 32)) {
|
||||
status = "OK";
|
||||
} else {
|
||||
status = "FAILED";
|
||||
++g_mismatches;
|
||||
k = false;
|
||||
}
|
||||
Write(1, path2, ": ", status, "\n", NULL);
|
||||
} else {
|
||||
k = false;
|
||||
}
|
||||
fclose(f2);
|
||||
} else {
|
||||
Write(2, PROG, ": ", path2, ": ", strerror(errno), "\n", NULL);
|
||||
k = false;
|
||||
}
|
||||
continue;
|
||||
InvalidLine:
|
||||
if (g_warn) {
|
||||
char linestr[12];
|
||||
FormatInt32(linestr, line + 1);
|
||||
Write(2, PROG, ": ", path, ":", linestr, ": ",
|
||||
"improperly formatted checksum line", "\n", NULL);
|
||||
}
|
||||
}
|
||||
if (ferror(f)) {
|
||||
Write(2, PROG, ": ", path, ": ", strerror(errno), "\n", NULL);
|
||||
k = false;
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
static bool Process(const char *path, FILE *f) {
|
||||
if (g_check) {
|
||||
return CheckDigests(path, f);
|
||||
} else {
|
||||
return ProduceDigest(path, f);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
FILE *f;
|
||||
bool k = true;
|
||||
GetOpts(argc, argv);
|
||||
if (optind == argc) {
|
||||
f = stdin;
|
||||
k &= Process("-", f);
|
||||
} else {
|
||||
for (i = optind; i < argc; ++i) {
|
||||
if ((f = fopen(argv[i], "rb"))) {
|
||||
k &= Process(argv[i], f);
|
||||
fclose(f);
|
||||
} else {
|
||||
Write(2, PROG, ": ", argv[i], ": ", strerror(errno), "\n", NULL);
|
||||
k = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (g_mismatches) {
|
||||
char ibuf[12];
|
||||
FormatInt32(ibuf, g_mismatches);
|
||||
Write(2, PROG, ": WARNING: ", ibuf, " computed checksum did NOT match\n",
|
||||
NULL);
|
||||
}
|
||||
return !k;
|
||||
}
|
13
ctl/.clang-format
Normal file
13
ctl/.clang-format
Normal file
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
BasedOnStyle: Mozilla
|
||||
IndentWidth: 4
|
||||
ColumnLimit: 80
|
||||
---
|
||||
Language: Cpp
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AlignTrailingComments: false
|
||||
AlignEscapedNewlines: DontAlign
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
FixNamespaceComments: true
|
||||
---
|
55
ctl/BUILD.mk
Normal file
55
ctl/BUILD.mk
Normal file
|
@ -0,0 +1,55 @@
|
|||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#── vi: set noet ft=make ts=8 sw=8 fenc=utf-8 :vi ────────────────────┘
|
||||
|
||||
PKGS += CTL
|
||||
|
||||
CTL_ARTIFACTS += CTL_A
|
||||
CTL = $(CTL_A_DEPS) $(CTL_A)
|
||||
CTL_A = o/$(MODE)/ctl/ctl.a
|
||||
CTL_A_FILES := $(wildcard ctl/*)
|
||||
CTL_A_HDRS = $(filter %.h,$(CTL_A_FILES))
|
||||
CTL_A_SRCS = $(filter %.cc,$(CTL_A_FILES))
|
||||
CTL_A_OBJS = $(CTL_A_SRCS:%.cc=o/$(MODE)/%.o)
|
||||
|
||||
CTL_A_CHECKS = \
|
||||
$(CTL_A).pkg \
|
||||
$(CTL_A_HDRS:%=o/$(MODE)/%.okk) \
|
||||
|
||||
CTL_A_DIRECTDEPS = \
|
||||
LIBC_INTRIN \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
THIRD_PARTY_DOUBLECONVERSION \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_LIBCXXABI \
|
||||
THIRD_PARTY_LIBUNWIND \
|
||||
|
||||
CTL_A_DEPS := $(call uniq,$(foreach x,$(CTL_A_DIRECTDEPS),$($(x))))
|
||||
|
||||
$(CTL_A): ctl/ \
|
||||
$(CTL_A).pkg \
|
||||
$(CTL_A_OBJS)
|
||||
|
||||
$(CTL_A).pkg: \
|
||||
$(CTL_A_OBJS) \
|
||||
$(foreach x,$(CTL_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
$(CTL_A_OBJS): private \
|
||||
OVERRIDE_CXXFLAGS += \
|
||||
-Wframe-larger-than=4096 \
|
||||
-Walloca-larger-than=4096 \
|
||||
-ffunction-sections \
|
||||
-fdata-sections \
|
||||
-fexceptions \
|
||||
|
||||
CTL_LIBS = $(foreach x,$(CTL_ARTIFACTS),$($(x)))
|
||||
CTL_SRCS = $(foreach x,$(CTL_ARTIFACTS),$($(x)_SRCS))
|
||||
CTL_HDRS = $(foreach x,$(CTL_ARTIFACTS),$($(x)_HDRS))
|
||||
CTL_CHECKS = $(foreach x,$(CTL_ARTIFACTS),$($(x)_CHECKS))
|
||||
CTL_OBJS = $(foreach x,$(CTL_ARTIFACTS),$($(x)_OBJS))
|
||||
$(CTL_OBJS): $(BUILD_FILES) ctl/BUILD.mk
|
||||
|
||||
.PHONY: o/$(MODE)/ctl
|
||||
o/$(MODE)/ctl: $(CTL_CHECKS)
|
5015
ctl/README.md
Normal file
5015
ctl/README.md
Normal file
File diff suppressed because it is too large
Load diff
28
ctl/accumulate.h
Normal file
28
ctl/accumulate.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_ACCUMULATE_H_
|
||||
#define CTL_ACCUMULATE_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class InputIt, class T>
|
||||
constexpr T
|
||||
accumulate(InputIt first, InputIt last, T init)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
init = init + *first;
|
||||
return init;
|
||||
}
|
||||
|
||||
template<class InputIt, class T, class BinaryOperation>
|
||||
constexpr T
|
||||
accumulate(InputIt first, InputIt last, T init, BinaryOperation op)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
init = op(init, *first);
|
||||
return init;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ACCUMULATE_H_
|
55
ctl/add_lvalue_reference.h
Normal file
55
ctl/add_lvalue_reference.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_ADD_LVALUE_REFERENCE_H_
|
||||
#define CTL_ADD_LVALUE_REFERENCE_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct add_lvalue_reference
|
||||
{
|
||||
typedef T& type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct add_lvalue_reference<T&>
|
||||
{
|
||||
typedef T& type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct add_lvalue_reference<T&&>
|
||||
{
|
||||
typedef T& type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct add_lvalue_reference<void>
|
||||
{
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct add_lvalue_reference<const void>
|
||||
{
|
||||
typedef const void type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct add_lvalue_reference<volatile void>
|
||||
{
|
||||
typedef volatile void type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct add_lvalue_reference<const volatile void>
|
||||
{
|
||||
typedef const volatile void type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using add_lvalue_reference_t = typename add_lvalue_reference<T>::type;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ADD_LVALUE_REFERENCE_H_
|
43
ctl/add_pointer.h
Normal file
43
ctl/add_pointer.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_ADD_POINTER_H_
|
||||
#define CTL_ADD_POINTER_H_
|
||||
#include "remove_reference.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
// Primary template
|
||||
template<typename T>
|
||||
struct add_pointer
|
||||
{
|
||||
typedef typename remove_reference<T>::type* type;
|
||||
};
|
||||
|
||||
// Specialization for functions
|
||||
template<typename R, typename... Args>
|
||||
struct add_pointer<R(Args...)>
|
||||
{
|
||||
typedef R (*type)(Args...);
|
||||
};
|
||||
|
||||
// Specialization for function references
|
||||
template<typename R, typename... Args>
|
||||
struct add_pointer<R (&)(Args...)>
|
||||
{
|
||||
typedef R (*type)(Args...);
|
||||
};
|
||||
|
||||
// Specialization for rvalue references to functions
|
||||
template<typename R, typename... Args>
|
||||
struct add_pointer<R (&&)(Args...)>
|
||||
{
|
||||
typedef R (*type)(Args...);
|
||||
};
|
||||
|
||||
// Helper alias template (C++14 and later)
|
||||
template<typename T>
|
||||
using add_pointer_t = typename add_pointer<T>::type;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ADD_POINTER_H_
|
29
ctl/addressof.h
Normal file
29
ctl/addressof.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_ADDRESSOF_H_
|
||||
#define CTL_ADDRESSOF_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
T*
|
||||
addressof(T& arg) noexcept
|
||||
{
|
||||
return reinterpret_cast<T*>(
|
||||
&const_cast<char&>(reinterpret_cast<const volatile char&>(arg)));
|
||||
}
|
||||
|
||||
template<typename R, typename... Args>
|
||||
R (*addressof(R (*&arg)(Args...)) noexcept)
|
||||
(Args...)
|
||||
{
|
||||
return arg;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T*
|
||||
addressof(T&&) = delete;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ADDRESSOF_H_
|
24
ctl/advance.h
Normal file
24
ctl/advance.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_ADVANCE_H_
|
||||
#define CTL_ADVANCE_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class InputIt, class Distance>
|
||||
constexpr void
|
||||
advance(InputIt& it, Distance n)
|
||||
{
|
||||
while (n > 0) {
|
||||
--n;
|
||||
++it;
|
||||
}
|
||||
while (n < 0) {
|
||||
++n;
|
||||
--it;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ADVANCE_H_
|
20
ctl/all_of.h
Normal file
20
ctl/all_of.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_ALL_OF_H_
|
||||
#define CTL_ALL_OF_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class InputIt, class UnaryPredicate>
|
||||
constexpr bool
|
||||
all_of(InputIt first, InputIt last, UnaryPredicate p)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
if (!p(*first))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ALL_OF_H_
|
94
ctl/allocator.h
Normal file
94
ctl/allocator.h
Normal file
|
@ -0,0 +1,94 @@
|
|||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_ALLOCATOR_H_
|
||||
#define CTL_ALLOCATOR_H_
|
||||
#include "bad_alloc.h"
|
||||
#include "integral_constant.h"
|
||||
#include "new.h"
|
||||
#include "utility.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
class allocator
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using propagate_on_container_move_assignment = ctl::true_type;
|
||||
using is_always_equal = ctl::true_type;
|
||||
using pointer = T*;
|
||||
using const_pointer = const T*;
|
||||
using reference = T&;
|
||||
using const_reference = const T&;
|
||||
|
||||
constexpr allocator() noexcept = default;
|
||||
|
||||
constexpr allocator(const allocator&) noexcept = default;
|
||||
|
||||
template<class U>
|
||||
constexpr allocator(const allocator<U>&) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
constexpr ~allocator() = default;
|
||||
|
||||
[[nodiscard]] T* allocate(size_type n)
|
||||
{
|
||||
if (n > __SIZE_MAX__ / sizeof(T))
|
||||
throw ctl::bad_alloc();
|
||||
if (auto p = static_cast<T*>(::operator new(
|
||||
n * sizeof(T), ctl::align_val_t(alignof(T)), ctl::nothrow)))
|
||||
return p;
|
||||
throw ctl::bad_alloc();
|
||||
}
|
||||
|
||||
void deallocate(T* p, size_type n) noexcept
|
||||
{
|
||||
::operator delete(p, n * sizeof(T), ctl::align_val_t(alignof(T)));
|
||||
}
|
||||
|
||||
template<typename U, typename... Args>
|
||||
void construct(U* p, Args&&... args)
|
||||
{
|
||||
::new (static_cast<void*>(p)) U(ctl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
void destroy(U* p)
|
||||
{
|
||||
p->~U();
|
||||
}
|
||||
|
||||
size_type max_size() const noexcept
|
||||
{
|
||||
return __SIZE_MAX__ / sizeof(T);
|
||||
}
|
||||
|
||||
allocator& operator=(const allocator&) = default;
|
||||
|
||||
template<typename U>
|
||||
struct rebind
|
||||
{
|
||||
using other = allocator<U>;
|
||||
};
|
||||
};
|
||||
|
||||
template<class T, class U>
|
||||
bool
|
||||
operator==(const allocator<T>&, const allocator<U>&) noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
bool
|
||||
operator!=(const allocator<T>&, const allocator<U>&) noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ALLOCATOR_H_
|
70
ctl/allocator_traits.h
Normal file
70
ctl/allocator_traits.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_ALLOCATOR_TRAITS_H_
|
||||
#define CTL_ALLOCATOR_TRAITS_H_
|
||||
#include "integral_constant.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename Alloc>
|
||||
struct allocator_traits
|
||||
{
|
||||
using allocator_type = Alloc;
|
||||
using value_type = typename Alloc::value_type;
|
||||
using pointer = typename Alloc::value_type*;
|
||||
using const_pointer = const typename Alloc::value_type*;
|
||||
using void_pointer = void*;
|
||||
using const_void_pointer = const void*;
|
||||
using difference_type = ptrdiff_t;
|
||||
using size_type = size_t;
|
||||
|
||||
using propagate_on_container_copy_assignment = ctl::false_type;
|
||||
using propagate_on_container_move_assignment = ctl::true_type;
|
||||
using propagate_on_container_swap = ctl::false_type;
|
||||
using is_always_equal = ctl::true_type;
|
||||
|
||||
template<typename T>
|
||||
struct rebind_alloc
|
||||
{
|
||||
using other = typename Alloc::template rebind<T>::other;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using rebind_traits = allocator_traits<typename rebind_alloc<T>::other>;
|
||||
|
||||
static pointer allocate(Alloc& a, size_type n)
|
||||
{
|
||||
return a.allocate(n);
|
||||
}
|
||||
|
||||
static void deallocate(Alloc& a, pointer p, size_type n)
|
||||
{
|
||||
a.deallocate(p, n);
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
static void construct(Alloc& a, T* p, Args&&... args)
|
||||
{
|
||||
::new ((void*)p) T(static_cast<Args&&>(args)...);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void destroy(Alloc& a, T* p)
|
||||
{
|
||||
p->~T();
|
||||
}
|
||||
|
||||
static size_type max_size(const Alloc& a) noexcept
|
||||
{
|
||||
return a.max_size();
|
||||
}
|
||||
|
||||
static Alloc select_on_container_copy_construction(const Alloc& a)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ALLOCATOR_TRAITS_H_
|
20
ctl/any_of.h
Normal file
20
ctl/any_of.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_ANY_OF_H_
|
||||
#define CTL_ANY_OF_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class InputIt, class UnaryPredicate>
|
||||
constexpr bool
|
||||
any_of(InputIt first, InputIt last, UnaryPredicate p)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
if (p(*first))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ANY_OF_H_
|
248
ctl/array.h
Normal file
248
ctl/array.h
Normal file
|
@ -0,0 +1,248 @@
|
|||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_ARRAY_H_
|
||||
#define CTL_ARRAY_H_
|
||||
#include "initializer_list.h"
|
||||
#include "out_of_range.h"
|
||||
#include "reverse_iterator.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T, size_t N>
|
||||
struct array
|
||||
{
|
||||
using value_type = T;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
using pointer = value_type*;
|
||||
using const_pointer = const value_type*;
|
||||
using iterator = value_type*;
|
||||
using const_iterator = const value_type*;
|
||||
using reverse_iterator = ctl::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = ctl::reverse_iterator<const_iterator>;
|
||||
|
||||
T elems[N];
|
||||
|
||||
constexpr array() = default;
|
||||
|
||||
constexpr array(std::initializer_list<T> init)
|
||||
{
|
||||
auto it = init.begin();
|
||||
for (size_t i = 0; i < N && it != init.end(); ++i, ++it)
|
||||
elems[i] = *it;
|
||||
}
|
||||
|
||||
constexpr reference at(size_type pos)
|
||||
{
|
||||
if (pos >= N)
|
||||
throw ctl::out_of_range();
|
||||
return elems[pos];
|
||||
}
|
||||
|
||||
constexpr const_reference at(size_type pos) const
|
||||
{
|
||||
if (pos >= N)
|
||||
throw ctl::out_of_range();
|
||||
return elems[pos];
|
||||
}
|
||||
|
||||
constexpr reference operator[](size_type pos)
|
||||
{
|
||||
if (pos >= N)
|
||||
__builtin_trap();
|
||||
return elems[pos];
|
||||
}
|
||||
|
||||
constexpr const_reference operator[](size_type pos) const
|
||||
{
|
||||
if (pos >= N)
|
||||
__builtin_trap();
|
||||
return elems[pos];
|
||||
}
|
||||
|
||||
constexpr reference front()
|
||||
{
|
||||
return elems[0];
|
||||
}
|
||||
|
||||
constexpr const_reference front() const
|
||||
{
|
||||
return elems[0];
|
||||
}
|
||||
|
||||
constexpr reference back()
|
||||
{
|
||||
return elems[N - 1];
|
||||
}
|
||||
|
||||
constexpr const_reference back() const
|
||||
{
|
||||
return elems[N - 1];
|
||||
}
|
||||
|
||||
constexpr T* data() noexcept
|
||||
{
|
||||
return elems;
|
||||
}
|
||||
|
||||
constexpr const T* data() const noexcept
|
||||
{
|
||||
return elems;
|
||||
}
|
||||
|
||||
constexpr iterator begin() noexcept
|
||||
{
|
||||
return elems;
|
||||
}
|
||||
|
||||
constexpr const_iterator begin() const noexcept
|
||||
{
|
||||
return elems;
|
||||
}
|
||||
|
||||
constexpr iterator end() noexcept
|
||||
{
|
||||
return elems + N;
|
||||
}
|
||||
|
||||
constexpr const_iterator end() const noexcept
|
||||
{
|
||||
return elems + N;
|
||||
}
|
||||
|
||||
constexpr reverse_iterator rbegin() noexcept
|
||||
{
|
||||
return reverse_iterator(end());
|
||||
}
|
||||
|
||||
constexpr const_reverse_iterator rbegin() const noexcept
|
||||
{
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
|
||||
constexpr reverse_iterator rend() noexcept
|
||||
{
|
||||
return reverse_iterator(begin());
|
||||
}
|
||||
|
||||
constexpr const_reverse_iterator rend() const noexcept
|
||||
{
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
constexpr const_iterator cbegin() const noexcept
|
||||
{
|
||||
return begin();
|
||||
}
|
||||
|
||||
constexpr const_iterator cend() const noexcept
|
||||
{
|
||||
return end();
|
||||
}
|
||||
|
||||
constexpr const_reverse_iterator crbegin() const noexcept
|
||||
{
|
||||
return rbegin();
|
||||
}
|
||||
|
||||
constexpr const_reverse_iterator crend() const noexcept
|
||||
{
|
||||
return rend();
|
||||
}
|
||||
|
||||
constexpr bool empty() const noexcept
|
||||
{
|
||||
return N == 0;
|
||||
}
|
||||
|
||||
constexpr size_type size() const noexcept
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
constexpr size_type max_size() const noexcept
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
void fill(const T& value)
|
||||
{
|
||||
for (size_type i = 0; i < N; ++i) {
|
||||
elems[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void swap(array& other) noexcept
|
||||
{
|
||||
for (size_type i = 0; i < N; ++i) {
|
||||
T temp = elems[i];
|
||||
elems[i] = other.elems[i];
|
||||
other.elems[i] = temp;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, size_t N>
|
||||
bool
|
||||
operator==(const array<T, N>& lhs, const array<T, N>& rhs)
|
||||
{
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
if (!(lhs[i] == rhs[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T, size_t N>
|
||||
bool
|
||||
operator!=(const array<T, N>& lhs, const array<T, N>& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template<typename T, size_t N>
|
||||
bool
|
||||
operator<(const array<T, N>& lhs, const array<T, N>& rhs)
|
||||
{
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
if (lhs[i] < rhs[i])
|
||||
return true;
|
||||
if (rhs[i] < lhs[i])
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename T, size_t N>
|
||||
bool
|
||||
operator<=(const array<T, N>& lhs, const array<T, N>& rhs)
|
||||
{
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
template<typename T, size_t N>
|
||||
bool
|
||||
operator>(const array<T, N>& lhs, const array<T, N>& rhs)
|
||||
{
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template<typename T, size_t N>
|
||||
bool
|
||||
operator>=(const array<T, N>& lhs, const array<T, N>& rhs)
|
||||
{
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
template<typename T, size_t N>
|
||||
void
|
||||
swap(array<T, N>& lhs, array<T, N>& rhs) noexcept
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ARRAY_H_
|
64
ctl/back_inserter.h
Normal file
64
ctl/back_inserter.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_BACK_INSERTER_H_
|
||||
#define CTL_BACK_INSERTER_H_
|
||||
#include "iterator.h"
|
||||
#include "utility.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class Container>
|
||||
class back_insert_iterator
|
||||
{
|
||||
protected:
|
||||
Container* container;
|
||||
|
||||
public:
|
||||
using iterator_category = ctl::output_iterator_tag;
|
||||
using value_type = void;
|
||||
using difference_type = void;
|
||||
using pointer = void;
|
||||
using reference = void;
|
||||
|
||||
explicit back_insert_iterator(Container& c) : container(&c)
|
||||
{
|
||||
}
|
||||
|
||||
back_insert_iterator& operator=(const typename Container::value_type& value)
|
||||
{
|
||||
container->push_back(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
back_insert_iterator& operator=(typename Container::value_type&& value)
|
||||
{
|
||||
container->push_back(ctl::move(value));
|
||||
return *this;
|
||||
}
|
||||
|
||||
back_insert_iterator& operator*()
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
back_insert_iterator& operator++()
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
back_insert_iterator operator++(int)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template<class Container>
|
||||
back_insert_iterator<Container>
|
||||
back_inserter(Container& c)
|
||||
{
|
||||
return back_insert_iterator<Container>(c);
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_BACK_INSERTER_H_
|
23
ctl/bad_alloc.h
Normal file
23
ctl/bad_alloc.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_BAD_ALLOC_H_
|
||||
#define CTL_BAD_ALLOC_H_
|
||||
#include "exception.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
class bad_alloc : public ctl::exception
|
||||
{
|
||||
public:
|
||||
bad_alloc() noexcept = default;
|
||||
~bad_alloc() override = default;
|
||||
|
||||
const char* what() const noexcept override
|
||||
{
|
||||
return "ctl::bad_alloc";
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_BAD_ALLOC_H_
|
25
ctl/conditional.h
Normal file
25
ctl/conditional.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_CONDITIONAL_H_
|
||||
#define CTL_CONDITIONAL_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<bool B, class T, class F>
|
||||
struct conditional
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<class T, class F>
|
||||
struct conditional<false, T, F>
|
||||
{
|
||||
typedef F type;
|
||||
};
|
||||
|
||||
template<bool B, typename T, typename F>
|
||||
using conditional_t = typename conditional<B, T, F>::type;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_CONDITIONAL_H_
|
22
ctl/copy.h
Normal file
22
ctl/copy.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_COPY_H_
|
||||
#define CTL_COPY_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class InputIt, class OutputIt>
|
||||
OutputIt
|
||||
copy(InputIt first, InputIt last, OutputIt d_first)
|
||||
{
|
||||
while (first != last) {
|
||||
*d_first = *first;
|
||||
++d_first;
|
||||
++first;
|
||||
}
|
||||
return d_first;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_COPY_H_
|
36
ctl/decay.h
Normal file
36
ctl/decay.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_DECAY_H_
|
||||
#define CTL_DECAY_H_
|
||||
#include "add_pointer.h"
|
||||
#include "conditional.h"
|
||||
#include "is_array.h"
|
||||
#include "is_function.h"
|
||||
#include "remove_cv.h"
|
||||
#include "remove_extent.h"
|
||||
#include "remove_reference.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct decay
|
||||
{
|
||||
private:
|
||||
typedef typename ctl::remove_reference<T>::type U;
|
||||
|
||||
public:
|
||||
typedef typename ctl::conditional<
|
||||
ctl::is_array<U>::value,
|
||||
typename ctl::remove_extent<U>::type*,
|
||||
typename ctl::conditional<ctl::is_function<U>::value,
|
||||
typename ctl::add_pointer<U>::type,
|
||||
typename ctl::remove_cv<U>::type>::type>::type
|
||||
type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using decay_t = typename decay<T>::type;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_DECAY_H_
|
44
ctl/default_delete.h
Normal file
44
ctl/default_delete.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_DEFAULT_DELETE_H_
|
||||
#define CTL_DEFAULT_DELETE_H_
|
||||
#include "enable_if.h"
|
||||
#include "is_convertible.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct default_delete
|
||||
{
|
||||
constexpr default_delete() noexcept = default;
|
||||
template<typename U,
|
||||
typename = typename ctl::enable_if<
|
||||
ctl::is_convertible<U*, T*>::value>::type>
|
||||
constexpr default_delete(const default_delete<U>&) noexcept
|
||||
{
|
||||
}
|
||||
constexpr void operator()(T* const p) const noexcept
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct default_delete<T[]>
|
||||
{
|
||||
constexpr default_delete() noexcept = default;
|
||||
template<typename U,
|
||||
typename = typename ctl::enable_if<
|
||||
ctl::is_convertible<U (*)[], T (*)[]>::value>::type>
|
||||
constexpr default_delete(const default_delete<U[]>&) noexcept
|
||||
{
|
||||
}
|
||||
constexpr void operator()(T* const p) const noexcept
|
||||
{
|
||||
delete[] p;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_DEFAULT_DELETE_H_
|
39
ctl/distance.h
Normal file
39
ctl/distance.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_DISTANCE_H_
|
||||
#define CTL_DISTANCE_H_
|
||||
#include "iterator.h"
|
||||
#include "iterator_traits.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class InputIter>
|
||||
constexpr typename ctl::iterator_traits<InputIter>::difference_type
|
||||
distance_impl(InputIter first, InputIter last, input_iterator_tag)
|
||||
{
|
||||
typename ctl::iterator_traits<InputIter>::difference_type res(0);
|
||||
for (; first != last; ++first)
|
||||
++res;
|
||||
return res;
|
||||
}
|
||||
|
||||
template<class RandIter>
|
||||
constexpr typename ctl::iterator_traits<RandIter>::difference_type
|
||||
distance_impl(RandIter first, RandIter last, random_access_iterator_tag)
|
||||
{
|
||||
return last - first;
|
||||
}
|
||||
|
||||
template<class InputIter>
|
||||
constexpr typename ctl::iterator_traits<InputIter>::difference_type
|
||||
distance(InputIter first, InputIter last)
|
||||
{
|
||||
return distance_impl(
|
||||
first,
|
||||
last,
|
||||
typename ctl::iterator_traits<InputIter>::iterator_category());
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_DISTANCE_H_
|
35
ctl/dubble.cc
Normal file
35
ctl/dubble.cc
Normal file
|
@ -0,0 +1,35 @@
|
|||
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
//
|
||||
// Copyright 2024 Justine Alexandra Roberts Tunney
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for
|
||||
// any purpose with or without fee is hereby granted, provided that the
|
||||
// above copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include "dubble.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
const double_conversion::DoubleToStringConverter kDoubleToPrintfG(
|
||||
double_conversion::DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN |
|
||||
double_conversion::DoubleToStringConverter::NO_TRAILING_ZERO,
|
||||
"inf",
|
||||
"nan",
|
||||
'e',
|
||||
-6,
|
||||
10, // let 32-bit ints be represented without exponent
|
||||
6,
|
||||
0,
|
||||
0);
|
||||
|
||||
} // namespace ctl
|
13
ctl/dubble.h
Normal file
13
ctl/dubble.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef COSMOPOLITAN_CTL_DUBBLE_H_
|
||||
#define COSMOPOLITAN_CTL_DUBBLE_H_
|
||||
#include "third_party/double-conversion/double-to-string.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
extern const double_conversion::DoubleToStringConverter kDoubleToPrintfG;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // COSMOPOLITAN_CTL_DUBBLE_H_
|
23
ctl/enable_if.h
Normal file
23
ctl/enable_if.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_ENABLE_IF_H_
|
||||
#define CTL_ENABLE_IF_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<bool B, class T = void>
|
||||
struct enable_if
|
||||
{};
|
||||
|
||||
template<class T>
|
||||
struct enable_if<true, T>
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<bool B, class T = void>
|
||||
using enable_if_t = typename enable_if<B, T>::type;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ENABLE_IF_H_
|
64
ctl/equal.h
Normal file
64
ctl/equal.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_EQUAL_H_
|
||||
#define CTL_EQUAL_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class InputIt1, class InputIt2>
|
||||
bool
|
||||
equal(InputIt1 first1, InputIt1 last1, InputIt2 first2)
|
||||
{
|
||||
for (; first1 != last1; ++first1, ++first2) {
|
||||
if (!(*first1 == *first2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Overload that takes a predicate
|
||||
template<class InputIt1, class InputIt2, class BinaryPredicate>
|
||||
bool
|
||||
equal(InputIt1 first1, InputIt1 last1, InputIt2 first2, BinaryPredicate pred)
|
||||
{
|
||||
for (; first1 != last1; ++first1, ++first2) {
|
||||
if (!pred(*first1, *first2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Overloads that take two ranges (C++14 and later)
|
||||
template<class InputIt1, class InputIt2>
|
||||
bool
|
||||
equal(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2)
|
||||
{
|
||||
for (; first1 != last1 && first2 != last2; ++first1, ++first2) {
|
||||
if (!(*first1 == *first2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return first1 == last1 && first2 == last2;
|
||||
}
|
||||
|
||||
template<class InputIt1, class InputIt2, class BinaryPredicate>
|
||||
bool
|
||||
equal(InputIt1 first1,
|
||||
InputIt1 last1,
|
||||
InputIt2 first2,
|
||||
InputIt2 last2,
|
||||
BinaryPredicate pred)
|
||||
{
|
||||
for (; first1 != last1 && first2 != last2; ++first1, ++first2) {
|
||||
if (!pred(*first1, *first2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return first1 == last1 && first2 == last2;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif /* CTL_EQUAL_H_ */
|
22
ctl/exception.h
Normal file
22
ctl/exception.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_EXCEPTION_H_
|
||||
#define CTL_EXCEPTION_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
class exception
|
||||
{
|
||||
public:
|
||||
exception() noexcept = default;
|
||||
virtual ~exception() = default;
|
||||
|
||||
virtual const char* what() const noexcept
|
||||
{
|
||||
return "ctl::exception";
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_EXCEPTION_H_
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue