Compare commits
1565 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 628d5c2a51 | |||
| 5004e94d1d | |||
| 4ef7e57571 | |||
| 1a0edd8eeb | |||
| 2f3987dd88 | |||
| d1ee653b5c | |||
| 928b18b306 | |||
| 5ae7b7efe7 | |||
| 2f69f0e7f1 | |||
| 79452dbd80 | |||
| bddd69d0c1 | |||
| 5efaffe0f9 | |||
| 94a6da9116 | |||
| 07ec3b6591 | |||
| e5539a570f | |||
| 9529e09568 | |||
| 29e2f29231 | |||
| 3e49323a3a | |||
| 21e72cafc6 | |||
| eee9a80baa | |||
| 79643c293b | |||
| c11aad71b8 | |||
| 687f4d4923 | |||
| 675101ac0e | |||
| 7829a7ade9 | |||
| 58cc9efbc0 | |||
| 42acd32ac0 | |||
| b05d8df5f8 | |||
| c000373a08 | |||
| 2c6114be75 | |||
| 00642dd940 | |||
| aef1be7c1b | |||
| 8ef64676fe | |||
| 18a12c6c3d | |||
| 36bb60cacc | |||
| 2ed55a926b | |||
| 9f25fa39ea | |||
| ff6bc68260 | |||
| f285128657 | |||
| dd193bcb8c | |||
| 4a6ef0221f | |||
| 9e0e88346d | |||
| 59b0a36e81 | |||
| 63711f6ca7 | |||
| 845c74a82e | |||
| 86138c9f8a | |||
| 3a0d2177cd | |||
| 23b2eb2573 | |||
| 5472e117a5 | |||
| aec4a84e90 | |||
| 5af8e3ca35 | |||
| a78f829dca | |||
| e33aea434f | |||
| eaee4e6329 | |||
| 7db83596a2 | |||
| ab92ff9d41 | |||
| 7b29f6eb27 | |||
| 61fcc018fc | |||
| 9826cea092 | |||
| 7b6ba2c73a | |||
| 40328a0d09 | |||
| b9828bd863 | |||
| d827c0f166 | |||
| 91f0be8790 | |||
| b5deadbeea | |||
| e14b3e09a5 | |||
| d08c63b1e7 | |||
| 6952a079ae | |||
| 72532b8280 | |||
| 4f93e43593 | |||
| 0178565f71 | |||
| 00b08605a3 | |||
| 2073d2a80e | |||
| 2008296a10 | |||
| ae8e070b9e | |||
| 0c6398abcb | |||
| ebb17654f8 | |||
| 5d45042d5d | |||
| 12777ba774 | |||
| f2c2d7c52e | |||
| f131391b0d | |||
| 7d4d73dd83 | |||
| 4c148c1860 | |||
| a5e02650d7 | |||
| 285a7c62d4 | |||
| e38d185870 | |||
| d6b03de7a4 | |||
| 677f0c989d | |||
| 37a462de5d | |||
| 890a9ed033 | |||
| ea3265766c | |||
| 02aa400c5c | |||
| b4a6a7ece5 | |||
| 6d0c9dccd5 | |||
| 01b1738b3a | |||
| aaf017d9d1 | |||
| 36ac4166ef | |||
| cf8cbe625b | |||
| 40acadc7d5 | |||
| 4d982f86b2 | |||
| f4f68a3441 | |||
| 3a8817072c | |||
| 67c703610b | |||
| 9a1efda121 | |||
| 04f77881d0 | |||
| d4b2391221 | |||
| e17c6049c6 | |||
| cbd7ead0ff | |||
| 9a1e9c327a | |||
| 746a86a267 | |||
| b623e245c0 | |||
| 865b7962a1 | |||
| c13ba64832 | |||
| 29ad5b75c9 | |||
| 56e1eceb28 | |||
| 39ce623d2d | |||
| 593925ceb4 | |||
| f8b49936bc | |||
| b7053b673d | |||
| 7ea5cd5133 | |||
| ce2de698c4 | |||
| 5c8393d5aa | |||
| 954f010cc1 | |||
| 5fcf920675 | |||
| 59b040258a | |||
| 547edcc267 | |||
| 22a7f71282 | |||
| c95a5fa574 | |||
| cc33874363 | |||
| db6a589421 | |||
| d7089a09bf | |||
| 0977133cc9 | |||
| 73e1d6307b | |||
| cdc9aa06e3 | |||
| ca8b848b48 | |||
| f4d95ce43f | |||
| a125b8be15 | |||
| 81da1bb1a3 | |||
| d5b63a85a4 | |||
| c3ae8022ba | |||
| 68679e41f0 | |||
| b771313ffd | |||
| b0dde81c75 | |||
| 7bc11dc6c2 | |||
| 12beb13987 | |||
| d9bacaec04 | |||
| d0c1160299 | |||
| 92d6735e3f | |||
| 8973535fdc | |||
| 018f7a3f38 | |||
| a49139ca2f | |||
| 14e011b72c | |||
| f068673adc | |||
| 164ef739b3 | |||
| 12d3838f42 | |||
| c02849dd73 | |||
| 5aa74fd2f3 | |||
| 604f1c11a2 | |||
| b165eacffd | |||
| e7f5e412a1 | |||
| 3aacc160a1 | |||
| 1b10c3d246 | |||
| c7910a8754 | |||
| e4a7186b22 | |||
| ae34ade595 | |||
| 8de10072b6 | |||
| ac52c3f205 | |||
| b15c90ee32 | |||
| b2338968a2 | |||
| 39346f5c05 | |||
| cf9c2ed0ba | |||
| da8d2fa7aa | |||
| 60b23003c7 | |||
| e4c26cfaa0 | |||
| 7eba6d88df | |||
| ee5e2bad5a | |||
| 1b131b8c60 | |||
| d7d3e00867 | |||
| 6fba592fdb | |||
| 1733b3da6e | |||
| 49dec86a5d | |||
| 7a6f96373e | |||
| 4c94dfac00 | |||
| 0cc0fbecdc | |||
| a6fffd3fb5 | |||
| 2cf3ccae72 | |||
| a1034b697d | |||
| 06429ccc4c | |||
| f6a119d3fc | |||
| 43fbaf9970 | |||
| a39447e6a4 | |||
| d373bcb032 | |||
| 4a47bc4a6f | |||
| d62f9b6819 | |||
| 8b7c45b39e | |||
| 850dfd971b | |||
| 67be05d3a3 | |||
| 1182d12006 | |||
| c799dad4e9 | |||
| e9615065ac | |||
| eac69c920d | |||
| 9725d3418a | |||
| 162999ac0b | |||
| a8a73f87c7 | |||
| 3a923aa62d | |||
| 763bb2488d | |||
| b717f6cf5a | |||
| 6aeb2d6fa2 | |||
| cc7ff54d12 | |||
| 7724989b33 | |||
| 77ad82a9dd | |||
| 2283e25cde | |||
| de03566158 | |||
| 369d7b42c6 | |||
| cdbbd4a426 | |||
| 2253ef609e | |||
| 69fc62278a | |||
| cc305fc574 | |||
| 701e64b3a1 | |||
| d7a859fb84 | |||
| 6ed37efaeb | |||
| 2629918100 | |||
| 0090396132 | |||
| 880e3c7854 | |||
| 2e27cf525e | |||
| 4860ab12fa | |||
| c2488b5094 | |||
| 04ea2f9397 | |||
| 77a0294114 | |||
| 3ac6ef1848 | |||
| a2f2484e45 | |||
| 79f265745a | |||
| b1aad49df4 | |||
| bc53164293 | |||
| 7f8dc2f251 | |||
| e85148cc15 | |||
| 9f86748a58 | |||
| 3d2f86b39e | |||
| 76f07b163b | |||
| d36cd72788 | |||
| 12f6ffd152 | |||
| 2bc667f71c | |||
| 662051a91b | |||
| 4c4ce7ec03 | |||
| 9a449d4f6c | |||
| 2e5d4a4d25 | |||
| 1534373645 | |||
| 0b4b3cd55c | |||
| 10f2e0fefc | |||
| c6e3cb8ed3 | |||
| 884ec85838 | |||
| 7d6288abbe | |||
| f167081f84 | |||
| 18e1a5608f | |||
| 0be4208aa7 | |||
| a3f7a174f6 | |||
| 2cbc78f238 | |||
| 36eb561128 | |||
| 086c8f6702 | |||
| 0a06388d2a | |||
| b882ce527d | |||
| 4818ad61ab | |||
| 886f859bb9 | |||
| 76798b7d6b | |||
| fe3607d4e8 | |||
| 5baec1e4e8 | |||
| 74555698fb | |||
| a1c3510761 | |||
| 8ba70792e9 | |||
| 2ac349d2d2 | |||
| 15e6d23538 | |||
| e3ce41da79 | |||
| 3db0588de0 | |||
| 278a70c813 | |||
| 631fd4f0f5 | |||
| 0b2c3fe5ea | |||
| ae69586f20 | |||
| 46a330ec9e | |||
| f53e9b5d9a | |||
| e8b8b7eb25 | |||
| 64f93fe6e0 | |||
| 5156a13b3e | |||
| 64dde1548c | |||
| 3b12a400bf | |||
| 7fdd450e16 | |||
| cc4c3a5cb4 | |||
| a80ec357e3 | |||
| d1d45ff00d | |||
| f4b8847605 | |||
| 30d3cd5c88 | |||
| 81470916be | |||
| 4859c222e7 | |||
| 4f2a93ea90 | |||
| aeab6a986d | |||
| 8f502a3436 | |||
| 5799555566 | |||
| f2357390e9 | |||
| 0a558de76c | |||
| 225583230f | |||
| 4c7f8c6369 | |||
| 37a5da34b9 | |||
| e7d19e2a58 | |||
| 8feed5bbd5 | |||
| a7b354c8e0 | |||
| a1e45941bf | |||
| b8c50c7c64 | |||
| c7d499d4f2 | |||
| 72c2f59f17 | |||
| 82abb3313e | |||
| f389010fff | |||
| 7f702720af | |||
| 43ff8801bc | |||
| 35c1d5210c | |||
| e559a3e2e5 | |||
| a2721b8a31 | |||
| bd573fb7cc | |||
| f467791b12 | |||
| cb63dec86f | |||
| 25e67b9f58 | |||
| 9d7ec9b146 | |||
| 9aac2672e3 | |||
| f1be9266e2 | |||
| aba76239b3 | |||
| b599c453a0 | |||
| c40b7d6fb4 | |||
| a8280e8991 | |||
| 7c99077248 | |||
| a2c8cfb4a5 | |||
| c85145b5d1 | |||
| 87bcc943e2 | |||
| 29b5b989eb | |||
| 1a0f72dad8 | |||
| 57917c0e92 | |||
| 4621a824a8 | |||
| 799c10073d | |||
| a6d6d2cfb0 | |||
| 63a1319e50 | |||
| 05f71567ab | |||
| 6a97b47d3f | |||
| 84745ca770 | |||
| 7b406dbc61 | |||
| 06bab2aa81 | |||
| 27d97f6fe0 | |||
| 2c3195d54b | |||
| 634b2ed835 | |||
| e27b22f63c | |||
| eae28f6dd9 | |||
| 5c0b37a229 | |||
| a49badbb66 | |||
| e146cb3687 | |||
| 6448119fbc | |||
| 8656c80614 | |||
| c8887900b9 | |||
| 9fb9820b23 | |||
| 6742e41948 | |||
| 38099fe3d9 | |||
| 208b56b487 | |||
| b4c738eb62 | |||
| 456c829da8 | |||
| 50be35d152 | |||
| dc2d22b384 | |||
| 3ae46d8616 | |||
| 70857f9980 | |||
| ff94798253 | |||
| bf13674e11 | |||
| 3be933ec63 | |||
| 02e26006e7 | |||
| b43e1bf83b | |||
| 6cc5216c9c | |||
| e35f22b3df | |||
| f9dca89c1f | |||
| 6a069d1d9e | |||
| 2a68c68dc6 | |||
| a72c5f4aca | |||
| 6203a85713 | |||
| ec7abebc0b | |||
| d704a35b85 | |||
| 2f4e57f87a | |||
| e929538098 | |||
| 8b975877e6 | |||
| 3b06380738 | |||
| 651d38300a | |||
| 43f1b582ae | |||
| 6e88617762 | |||
| e84ea94dd0 | |||
| c29237d360 | |||
| 0af78b1e06 | |||
| 8db2f51706 | |||
| d9ed51b9f1 | |||
| 3013c5db50 | |||
| de70b2ae98 | |||
| a5409ecd36 | |||
| 626c713021 | |||
| 02d1a7fe6f | |||
| 7a48107080 | |||
| dcff3fd836 | |||
| fe4a3ae2b4 | |||
| b2a9cdf930 | |||
| 767cf86b38 | |||
| 13108776ae | |||
| dab6530fb4 | |||
| f1b88d9ea0 | |||
| 45860e9256 | |||
| 06ab5b7de2 | |||
| f3363af54d | |||
| 5dd9c042d6 | |||
| 7597c082e7 | |||
| 20a2355bc4 | |||
| 2606266c3f | |||
| 21a6701528 | |||
| d62db7b1b9 | |||
| 30f6a9c323 | |||
| f8cf25d76c | |||
| 15aa52a8e9 | |||
| 123031dcfe | |||
| 54c5423f35 | |||
| 8beb10b1bd | |||
| f13bd7fdd1 | |||
| 3be13d672f | |||
| cfc541019c | |||
| 75cb7033c7 | |||
| d2cb0959f3 | |||
| 6a9d070115 | |||
| 61dea7f52b | |||
| 16083a6020 | |||
| 8efa7a3ed8 | |||
| 3a5a7b3378 | |||
| d6d01e5614 | |||
| e6e31dd3b4 | |||
| f8fe67e7ba | |||
| 10fdea88f2 | |||
| 54fb8b9b2b | |||
| ba711deb0d | |||
| 378ea3ac0e | |||
| b399e87ef8 | |||
| dd9328bd41 | |||
| 68c4e95b6d | |||
| c9a8674c61 | |||
| 89b4fa80af | |||
| 4c8f51ace9 | |||
| be765f879d | |||
| 488981f9ec | |||
| 6d857f8db7 | |||
| 125e0e08da | |||
| 5a34907033 | |||
| 68d3c5f1b1 | |||
| 3584edf199 | |||
| 5bbce37789 | |||
| 67af78d0eb | |||
| 13a10ce7af | |||
| 6a16275817 | |||
| 6074616857 | |||
| 1ebd8a3d72 | |||
| 87ba8f8a08 | |||
| 8fca7bcbc1 | |||
| 0a0aec502b | |||
| 40d01d9d57 | |||
| c2c8806f04 | |||
| 912385b501 | |||
| 7bde036031 | |||
| b2cc25dd38 | |||
| 6d4ac9dba8 | |||
| 3a3fd3da39 | |||
| fa94f1b6d5 | |||
| 29e1c780aa | |||
| 601cb43f6c | |||
| 78d52c6e9f | |||
| 83f89912e0 | |||
| c68a0d5678 | |||
| 89ca696f8e | |||
| b9e03cbaed | |||
| 30aef27c76 | |||
| 7fe0beb916 | |||
| 5a005864a8 | |||
| 361f32b63c | |||
| 9f5e5f24dc | |||
| 47baf499bf | |||
| cb9e779ca1 | |||
| b2cc8f6d26 | |||
| 27cebdd688 | |||
| ba50c94c3f | |||
| 63cb2f3454 | |||
| 084b69b361 | |||
| d5eb1e2732 | |||
| d9ec8b4ab0 | |||
| 2b56f2882b | |||
| e5529dc883 | |||
| cf800b5282 | |||
| 2fdca9bd0a | |||
| f4fccc6d19 | |||
| 73dda0f32c | |||
| f2b86e985c | |||
| 588f032f75 | |||
| 54b6c8f025 | |||
| 862c76b25f | |||
| f4c036c3aa | |||
| 42d40da973 | |||
| 17372b4f69 | |||
| 3f98962054 | |||
| 6548aad36d | |||
| d13fb3f42b | |||
| bee72373be | |||
| 5dca9843dc | |||
| 65aeda1f59 | |||
| a88ec09131 | |||
| 229ca66726 | |||
| e01d1ce11b | |||
| 7a1e2a6269 | |||
| 0e667c5f25 | |||
| 6f12bb6a32 | |||
| 59653ee290 | |||
| cee4449f7c | |||
| 5715fb7ba6 | |||
| cdbeda1ca0 | |||
| 640c6d41a7 | |||
| 9443eef518 | |||
| 23de2ca7ca | |||
| f9f752d74c | |||
| 17bed54103 | |||
| 31fc29e70c | |||
| 269b8a1d3e | |||
| 37c976945a | |||
| 5eb2a8f7bd | |||
| 30a0f70d73 | |||
| fe905ed13c | |||
| 71f8fb32e3 | |||
| e93129b165 | |||
| 4ed6dca61d | |||
| fa2c6d29db | |||
| efd6947d8e | |||
| 96182ce8ad | |||
| a92be000fb | |||
| 2d027f0771 | |||
| 76503d8943 | |||
| f3ba7e8d8e | |||
| ec3488c7b0 | |||
| 0c539d6e4e | |||
| 513f4ba53c | |||
| 887d89c2bb | |||
| 74d0b24939 | |||
| 5690c6dcdf | |||
| 9a0ea6ff34 | |||
| 6266d29242 | |||
| 64acf45c40 | |||
| f60c95d2ca | |||
| d1a424c002 | |||
| f19e029468 | |||
| 20aeb15fc7 | |||
| 27a3f2ab77 | |||
| 4381bb2a22 | |||
| c19cc8b731 | |||
| ff874c87d7 | |||
| 97592716fb | |||
| 7ee59d2fdb | |||
| 1af4eb7ec0 | |||
| d38a1d0da3 | |||
| 73c368ddab | |||
| 264659b634 | |||
| 1eb22b2cb2 | |||
| 514b31cf28 | |||
| 5fac72298f | |||
| 38da5552e8 | |||
| 7aa0fbdf93 | |||
| 8b7453edf2 | |||
| c54db6f008 | |||
| d2502056a8 | |||
| 602f015e93 | |||
| 0dd801da03 | |||
| 42f212e678 | |||
| 47235d44e7 | |||
| c59f268fcd | |||
| f3c858c151 | |||
| f25c494a73 | |||
| 0f50a40b3f | |||
| aa3c7da128 | |||
| eaa031c21c | |||
| a88933386b | |||
| 047deceed0 | |||
| d0261ebb35 | |||
| 09340bd0f2 | |||
| 22ca2e5f7b | |||
| 1a0d363caa | |||
| 74dd5091f3 | |||
| b35a4f6372 | |||
| c71088e768 | |||
| 8dabff129a | |||
| c57ac53d28 | |||
| b3dda7519d | |||
| 2e260a6b29 | |||
| f35f65c2b8 | |||
| 594e53c6f1 | |||
| 87f2ab95bb | |||
| 8e9d65cb46 | |||
| 52669688bf | |||
| 434cad49ce | |||
| 5b969f2bae | |||
| 89fca557f3 | |||
| 6c0c6dd71b | |||
| 018ff409f1 | |||
| 543f32eb50 | |||
| 97312c9ae2 | |||
| 84fcb1b906 | |||
| aa069b3e0b | |||
| cea5101cba | |||
| 5b779448ab | |||
| 33b539e4c1 | |||
| 0c5abf0361 | |||
| aefb4fb116 | |||
| c41c20a943 | |||
| dc4aa9cf0b | |||
| 53874213fa | |||
| 46020f466f | |||
| 9a0c12888f | |||
| 7ac3dfaa49 | |||
| eef2f4d1f8 | |||
| 2ba67f2fe2 | |||
| 961d1304ab | |||
| bd956e5fe4 | |||
| 775ec444be | |||
| c514b0b705 | |||
| c9e48bf141 | |||
| e93ead5a8f | |||
| 62b83190bf | |||
| e7896f6c48 | |||
| 0aaa7264db | |||
| 083642fb17 | |||
| 5cb92284f2 | |||
| 51b093b598 | |||
| 7aa789575a | |||
| a321545fd0 | |||
| 0842d6504b | |||
| 09135f5bd1 | |||
| 51245d69e3 | |||
| 42545713a7 | |||
| 5b6b11cb65 | |||
| f04ac7343a | |||
| a8f3608f3c | |||
| 89832b3ac8 | |||
| e6c866a92d | |||
| 74af56d71b | |||
| 0d2332d368 | |||
| c6d42dd9e3 | |||
| 4e741f5583 | |||
| f7b3abc1b6 | |||
| 1c1da7dfcb | |||
| df1c7404eb | |||
| ae115ac6ff | |||
| e764fedba5 | |||
| 4a4e641b23 | |||
| 756a0d2edc | |||
| 1becb8c43a | |||
| f9b836d23e | |||
| 90bf583d28 | |||
| ee40035c4b | |||
| 63b079c231 | |||
| be035f8862 | |||
| 8aae8e1564 | |||
| fc9e3923f6 | |||
| de429a8df6 | |||
| e8377d259a | |||
| 925d9f6bbf | |||
| 05f17794e4 | |||
| 7049359c25 | |||
| 594bcd75d4 | |||
| a39f170ed3 | |||
| 4ced856b39 | |||
| 62b0b0d508 | |||
| 7dbd57f913 | |||
| fe57754c34 | |||
| 3075b8b69f | |||
| 52fd4d7e83 | |||
| 28dab8ece8 | |||
| 9325183b21 | |||
| ca75bbc1c9 | |||
| 8d05067ac7 | |||
| d66afa4586 | |||
| 35bcf93160 | |||
| 0a44d4543f | |||
| 950b4526c7 | |||
| 4bb16e01b2 | |||
| 37cd503c88 | |||
| 1a8af993e6 | |||
| 34edeaf066 | |||
| ee2a7685e6 | |||
| 583eaa498d | |||
| d6a5b39505 | |||
| 809f665a8a | |||
| 15eed4daf1 | |||
| d4e42fd9e0 | |||
| f5f561424a | |||
| fc0b7b9111 | |||
| fdd966629d | |||
| de0339ee93 | |||
| a614c40273 | |||
| 6180222760 | |||
| e0daa157b9 | |||
| 5c4c49a9d1 | |||
| 96cc56a0b5 | |||
| d6a1796122 | |||
| d818a8d10e | |||
| 8a042a220d | |||
| 869eb160bd | |||
| 7398fae8b6 | |||
| 0ac16556bc | |||
| a5279b648f | |||
| 52493a1ec3 | |||
| de43271204 | |||
| a613154191 | |||
| 55eb8f2779 | |||
| 9790289aec | |||
| 3cc215caeb | |||
| b4f36bce17 | |||
| 632f9f18e5 | |||
| 9b0c74b935 | |||
| 012a9b2eb3 | |||
| 02c8355c13 | |||
| 4c9173433e | |||
| 1c92751a73 | |||
| 484a05e8b3 | |||
| e102c234c1 | |||
| 44f84f406f | |||
| e32fc12308 | |||
| c6f2b30738 | |||
| 8c5b237963 | |||
| e7f7c4ea61 | |||
| a6642bc753 | |||
| a29aa9f599 | |||
| dd65d0c0c8 | |||
| 861602bbcc | |||
| 0684fb6e4c | |||
| d252838496 | |||
| 81dc144241 | |||
| f1c970beef | |||
| 8a972542be | |||
| 2b3ae4d8b8 | |||
| c36ee7237b | |||
| bf111188e1 | |||
| ebffc977b2 | |||
| 131dcac554 | |||
| 4963ca3a95 | |||
| 39b999ccea | |||
| d88f4053ea | |||
| 0396460c84 | |||
| 75bac011e4 | |||
| a7b71a311d | |||
| 571b4d4976 | |||
| 09bd4bc375 | |||
| 51b2e630b9 | |||
| f97f93c48d | |||
| 740f57738c | |||
| d4308c8a9b | |||
| 6f4b8db7d8 | |||
| e7f251fdb0 | |||
| bfa068df88 | |||
| 3c2121d4e0 | |||
| 460f57b37f | |||
| 75c5c04bee | |||
| 23fe526c55 | |||
| 057d23908a | |||
| edb95246d4 | |||
| e4d87a101a | |||
| 63882684b2 | |||
| 49259d3f01 | |||
| b517629371 | |||
| 1f3154b45c | |||
| 116cbda8d2 | |||
| aee3f68117 | |||
| f516ff72d8 | |||
| 0469c0c2c6 | |||
| 0f5fa8c9d4 | |||
| 3f4fbf9084 | |||
| 8e2b7c11b4 | |||
| 91675b5bc8 | |||
| fba3bf5161 | |||
| 758f681590 | |||
| 3c8cb95b80 | |||
| 0de7d30656 | |||
| 028378b8bf | |||
| 418a960f3b | |||
| e10a346356 | |||
| 26d629674a | |||
| 9d56ce42c6 | |||
| 614b2f5103 | |||
| baddbb98d5 | |||
| 1acc2a1a32 | |||
| dfa3845c33 | |||
| 6dcc8ee8d9 | |||
| aec6a48ca4 | |||
| db4452e98b | |||
| b22d386177 | |||
| dd711f4dee | |||
| 0451fac66c | |||
| d365813c90 | |||
| 4f187efc9b | |||
| 243ce18ecd | |||
| 21559bb503 | |||
| afc1ff134a | |||
| aff35892be | |||
| 7f14fcdee0 | |||
| ef9fee5a2b | |||
| 9eef8d7e2d | |||
| b309cd832d | |||
| d659377b24 | |||
| 6d99915154 | |||
| 7e4a60f78b | |||
| 658dc34d30 | |||
| 1e9dbfdf62 | |||
| 2a8bc8331b | |||
| b43299642b | |||
| 29b4c19d6e | |||
| 64acfbb8e3 | |||
| 9e9b850b90 | |||
| a0b4e21bbb | |||
| a567197b54 | |||
| 9dbf49fdcd | |||
| 2aa7597a2b | |||
| 043ecf2cf9 | |||
| 290ecb3e46 | |||
| 60f00508d3 | |||
| 10a7944aef | |||
| c2f4c1dbc9 | |||
| 28f4da526d | |||
| 2cc5db9de6 | |||
| 23098b694e | |||
| 35bdab7690 | |||
| 13cd7d5a5f | |||
| d0a4f2f845 | |||
| 76959416bb | |||
| 716ea87bb4 | |||
| f3a832ad12 | |||
| dfb07e473a | |||
| f661d5d1c0 | |||
| 9d24e61548 | |||
| 706a8de7a0 | |||
| 882b86e282 | |||
| 30d6f079c5 | |||
| 49ccf364c2 | |||
| eb6ddac1eb | |||
| 9cb594dca1 | |||
| 92e1127b64 | |||
| 59d74e194d | |||
| eb2fe7934c | |||
| e688d9c4d1 | |||
| 50c03f289f | |||
| 077e922cc6 | |||
| 26f953e11f | |||
| 6fe3e05ea0 | |||
| dbe18b92f0 | |||
| 07eb658a8a | |||
| 3dbf9f872a | |||
| 28912d84d9 | |||
| 82b9715f41 | |||
| 70eda382d3 | |||
| 0258fb3f5e | |||
| b52c822150 | |||
| c911facca6 | |||
| 16373257b0 | |||
| 8f5470fd27 | |||
| bab4e2896a | |||
| 7ab700315d | |||
| 6418f893e4 | |||
| 124e118f9f | |||
| ed00ddfb54 | |||
| c63c930e4a | |||
| 277b9abcd5 | |||
| c20ce5ffed | |||
| ff32c8cbbd | |||
| 34f5f57213 | |||
| d1dabccdce | |||
| 165f099c6b | |||
| 729709a8e6 | |||
| e6f163823c | |||
| c25ce6a5f3 | |||
| f1df1f9f0b | |||
| 83cb46afd8 | |||
| 2e8cb6b363 | |||
| 4e3b6732d5 | |||
| 128209788c | |||
| 66d7aa8553 | |||
| d5f85906cb | |||
| 1c4e8852dd | |||
| 07563de231 | |||
| 232a3311df | |||
| b10fa984f3 | |||
| face6f07f3 | |||
| 3aa52e88a7 | |||
| d5a9cd6953 | |||
| 540395c015 | |||
| a1ebe321d6 | |||
| 40c3d28a41 | |||
| b0546336c7 | |||
| d219d57acb | |||
| deee825a1c | |||
| b26213731c | |||
| 23a8855e50 | |||
| 40a7380a58 | |||
| d39a66c351 | |||
| 3bb3a3e322 | |||
| f6ca7d7c2d | |||
| b20307dca0 | |||
| b5adee798d | |||
| 442a7bbedc | |||
| ba8bd8c4e8 | |||
| 44599a032e | |||
| 9c57c222f6 | |||
| daf65c7a46 | |||
| ce53ac7e13 | |||
| 2a303c4b60 | |||
| d3e4fa71a5 | |||
| bc7f7356b9 | |||
| a9fcb973f6 | |||
| 3eb7b99799 | |||
| f82b48b839 | |||
| e7e9d57db5 | |||
| 65cbd40fce | |||
| 4a42983d13 | |||
| 7524a83d82 | |||
| 892ce75eb4 | |||
| 6da2639dfa | |||
| 3c88056f9d | |||
| 193328952d | |||
| fc910d4157 | |||
| cb046c78e4 | |||
| f6b364845e | |||
| 1b40f2d463 | |||
| 8b48b6959c | |||
| 2bf426b0fb | |||
| 7ff6940edd | |||
| a0f2baff12 | |||
| 83949290c9 | |||
| dec5e0a019 | |||
| e749d23030 | |||
| 992e50ef0f | |||
| 0e48937991 | |||
| 42811717da | |||
| 5f6309d87c | |||
| 8021ade2a9 | |||
| dc427272af | |||
| 5697ac0f84 | |||
| 86a38b47d1 | |||
| ecd8aca6d6 | |||
| 7b8e7feb3d | |||
| 67d5976622 | |||
| e9484e4d60 | |||
| 27e8174e10 | |||
| e4a89ae645 | |||
| c788f7ed26 | |||
| 6fa1f60830 | |||
| 7d43d45e56 | |||
| 0550a7b9db | |||
| 233e679c08 | |||
| ff9ef98f47 | |||
| 0a57c617c7 | |||
| 5b3e09ee16 | |||
| 878208485c | |||
| 482bd9c5f1 | |||
| b83d1c7ff0 | |||
| 37b6cd942c | |||
| 515d041153 | |||
| 75145ab92b | |||
| 019011f029 | |||
| dc443a8cc3 | |||
| 4c4ce80fcd | |||
| 52e02286f2 | |||
| 4718796c2b | |||
| 9cb0881cc4 | |||
| 5f098c89c3 | |||
| a9ea2ef64e | |||
| c2cdb451f5 | |||
| 758b437170 | |||
| b7e11afd2f | |||
| a7cc95cd90 | |||
| b8cab5f0be | |||
| b7eb7a43e0 | |||
| 463c9f386c | |||
| 9c27110de1 | |||
| 6e56734224 | |||
| 99fa77535a | |||
| 9fc785dcc6 | |||
| 6c11a18240 | |||
| 5f4ebaaabf | |||
| 55e618d8c0 | |||
| 6d923cbd0b | |||
| 30d91b82b2 | |||
| d3f6985ee9 | |||
| 587ee32a30 | |||
| 985a83ee69 | |||
| 53f634f579 | |||
| eaf7338946 | |||
| 919ae09d2f | |||
| 3361b05911 | |||
| ea5f8d59de | |||
| e206400d19 | |||
| 3ef9599af5 | |||
| 42abc98a99 | |||
| b6b34a7026 | |||
| 7e6e1b164c | |||
| 6a0928edfd | |||
| 9c169a186f | |||
| aff5380723 | |||
| 53a03cb0ba | |||
| 8bc07abd05 | |||
| ebe1ed15f8 | |||
| bf2973e857 | |||
| d7a0f3d526 | |||
| bf6db91993 | |||
| 72177be0fa | |||
| 7277286efd | |||
| 81107f8cd1 | |||
| e9cecfead3 | |||
| 0d61f9f4fd | |||
| da664d4919 | |||
| 30ec8aa2c9 | |||
| 07dbc6bd76 | |||
| 17778ba1b4 | |||
| 9c01673422 | |||
| cc210361d6 | |||
| fb09b03acf | |||
| 396a6dbb90 | |||
| b911a76de4 | |||
| 0567f699a2 | |||
| 541fbcf57c | |||
| 1fd9a5f249 | |||
| 05b4b76426 | |||
| 10a9081b66 | |||
| 18418254b9 | |||
| 8075447fad | |||
| 57f7de1e6d | |||
| 4c65f14f9a | |||
| 71fa4026f5 | |||
| a2dc22123f | |||
| 2f6467bce6 | |||
| 674d4e3695 | |||
| 234632d319 | |||
| 29a626cd7c | |||
| 5c5e237042 | |||
| da992bff56 | |||
| 8e7cd11bc0 | |||
| 2c0f9ce747 | |||
| e4be43f617 | |||
| 2e3eda4612 | |||
| cf6c8093ab | |||
| 1f1665fd58 | |||
| abbf0c9609 | |||
| 2dbe7ebee0 | |||
| b5da8aa35c | |||
| 6939ca7d7a | |||
| 776491bae9 | |||
| a6ffd2cc46 | |||
| cbc3723c66 | |||
| 727324fd73 | |||
| 9de73d0e5b | |||
| 844e244851 | |||
| 3927b0ab44 | |||
| 5fc1459eb9 | |||
| 0776de1ae6 | |||
| 257040e164 | |||
| ad324a0e4d | |||
| feed73ffcc | |||
| 5537817594 | |||
| 441bf9f00b | |||
| a63e6b3dd8 | |||
| 320eb0ecd0 | |||
| f265d7c5be | |||
| 878f466b67 | |||
| be0aed56bc | |||
| 72e9525828 | |||
| 3e67314b97 | |||
| 59f1b37be8 | |||
| 382c6efb39 | |||
| 7f0908eb8e | |||
| 2283243d95 | |||
| 4e99b55417 | |||
| 6e67d30486 | |||
| 829bc64ad6 | |||
| 7e731e0b01 | |||
| 5945de62cb | |||
| c7bdd31a18 | |||
| 6bc28203ca | |||
| 12ce441f5c | |||
| b5529c9b71 | |||
| 5921f00e90 | |||
| 8fd77a4b13 | |||
| 43a3c5677a | |||
| 50bfebfe3e | |||
| 90c6937f17 | |||
| ea24699798 | |||
| 3034114c14 | |||
| ccb74c6efc | |||
| 0a3c8abe95 | |||
| 996445a6a3 | |||
| 05f7371e46 | |||
| 91221645c5 | |||
| 5936c7a76e | |||
| 77b160c70d | |||
| 6f8fff4b1c | |||
| 06a8d5d89d | |||
| 454ce67d45 | |||
| 895e250564 | |||
| 9d38494435 | |||
| 1b653c4e60 | |||
| 009ceec188 | |||
| 326078a578 | |||
| c5552cbb39 | |||
| 3fa220237d | |||
| a573549df8 | |||
| fd05aca991 | |||
| 1f9f7ce6c8 | |||
| 3aa01b6907 | |||
| a7a415603f | |||
| 16c51a297d | |||
| f0227e737e | |||
| aead6d8fd0 | |||
| 5bcf1d42ff | |||
| cbd0d0473c | |||
| b389e4831d | |||
| 9daae71c2a | |||
| bb9d0e4aa1 | |||
| 285d1b05c4 | |||
| 7ca5fac214 | |||
| 3311a700e0 | |||
| 0b6d6549f1 | |||
| ed12713aa8 | |||
| c647fdfed3 | |||
| 8eec109cc0 | |||
| c8d4ea3ee6 | |||
| 4fb4790890 | |||
| 9bbb070104 | |||
| f5ded007c6 | |||
| 4d3ac1c0dc | |||
| b15aa83a8a | |||
| aa21e5fc3f | |||
| 6e8e6ad5d2 | |||
| 0cabecd5b5 | |||
| d14d0b5965 | |||
| 766e00c69e | |||
| 3d1a66f270 | |||
| 9d8758006d | |||
| 1bcc40c08f | |||
| 7647db27c0 | |||
| 56458e5e4c | |||
| 1ecd5f8f21 | |||
| 018f950851 | |||
| 08091ab2a9 | |||
| ff37adeeba | |||
| 43e6cad33f | |||
| 8015878a73 | |||
| 2b21dca567 | |||
| 93e2e16077 | |||
| 6a4220458c | |||
| 722732b616 | |||
| dc769fd977 | |||
| 3f627b1b40 | |||
| 5b1e11d1b1 | |||
| 62fbff93bc | |||
| 742339ca9e | |||
| dabd8dc6a2 | |||
| 79d05d7eda | |||
| b849165438 | |||
| ea804582b9 | |||
| afdc80629f | |||
| 92493a55b9 | |||
| bc0763f3ef | |||
| 14957bb8dc | |||
| 6999363916 | |||
| 78c8c2171b | |||
| 8c218b1608 | |||
| d071522bc5 | |||
| adcd0c9900 | |||
| e1abe80992 | |||
| 6abd64ae16 | |||
| 47ee733afa | |||
| ae137dbc03 | |||
| d9e4622f83 | |||
| f0b41aa57e | |||
| e39d2d61fa | |||
| c7e9ec8ae2 | |||
| c7ad4d3997 | |||
| cafb76abdd | |||
| 6d11736603 | |||
| bbf5c34ce8 | |||
| 43e95a9b92 | |||
| 57a17cb05f | |||
| 35dbc8d351 | |||
| 304473b68f | |||
| 5f9170d861 | |||
| 58b2b64183 | |||
| 29a6d24309 | |||
| 66fa211a05 | |||
| 97e165d8c7 | |||
| e1b20ed368 | |||
| e5849526a0 | |||
| fcf1104ea5 | |||
| 0ec7d0bc57 | |||
| 5f243a21f7 | |||
| e34d32aefe | |||
| cdc6209ff4 | |||
| 26b533c978 | |||
| ae097074ec | |||
| 77b7a98d4e | |||
| cc5a4e92ce | |||
| a24f537a38 | |||
| 4db812d34d | |||
| 19705ccc87 | |||
| dbc3e413cc | |||
| 2751d457bf | |||
| 42a6693a0b | |||
| af78348d4a | |||
| 90aec2076e | |||
| edead8e085 | |||
| 045a510ce5 | |||
| ca61b4cb63 | |||
| d3583e11d2 | |||
| a0c76f7ce5 | |||
| 31516989c0 | |||
| 3a89f66cfd | |||
| 5cec358a45 | |||
| befca562df | |||
| b7d68895b0 | |||
| 06de920be6 | |||
| d8139238e7 | |||
| c24d1e2b36 | |||
| d7965f2598 | |||
| 25501b3640 | |||
| b33c3a8e4f | |||
| 362849f0f6 | |||
| e91891625f | |||
| 898cf98ccc | |||
| f60fafe8fb | |||
| bebbd35e1a | |||
| 2cb0a994b8 | |||
| 659d3d1042 | |||
| d75535974a | |||
| 81d96c214a | |||
| 8d40424020 | |||
| 2610fdd126 | |||
| c568ca2932 | |||
| b2b7804f5b | |||
| cdfde8c0d4 | |||
| 16e82636fb | |||
| 01081729c8 | |||
| 41b96fede3 | |||
| c4c8b73903 | |||
| 8648fd39c4 | |||
| b0492eba84 | |||
| 7f2b720962 | |||
| 046ce1468e | |||
| e73678d8ad | |||
| f20878c592 | |||
| aa8b14e107 | |||
| a1baf1c92d | |||
| b419e150d1 | |||
| f1d802dc1e | |||
| 6d110ef0cb | |||
| 52acce0d34 | |||
| 54c0e501e3 | |||
| b2d01a67f2 | |||
| cfe98ab3b2 | |||
| cd2312fd56 | |||
| d6e210b1fd | |||
| 996fad7092 | |||
| 1d6115fd09 | |||
| b09435f17d | |||
| d3c2e99ed7 | |||
| d058390b75 | |||
| 122f6cfef5 | |||
| 9d46fa4d8c | |||
| 010e171071 | |||
| 40efea056b | |||
| 2fd2a9c520 | |||
| d177b8e974 | |||
| d3e44da527 | |||
| ca82b6df5b | |||
| d6a7942ec4 | |||
| 1e661cdbef | |||
| 8d0308d3ce | |||
| 13b7119994 | |||
| dd847cc67e | |||
| ef8a64c101 | |||
| c4620be999 | |||
| 1e969afd43 | |||
| a1de0ef8a1 | |||
| 211f95155a | |||
| b35abd1065 | |||
| 224cf04cf3 | |||
| 7912332137 | |||
| 3e354aed04 | |||
| 232e364f60 | |||
| 477e8eb4e0 | |||
| 41e552b696 | |||
| 7c13ec153e | |||
| ee13ed44d3 | |||
| cc5669939e | |||
| 7c305c5c0d | |||
| c5dd3f8706 | |||
| ccb29cfa2c | |||
| 50eab4369d | |||
| 1b1ff5c750 | |||
| ca57f30425 | |||
| a000f1a2c0 | |||
| bc98f6a029 | |||
| 76c4520cea | |||
| 4f5e978634 | |||
| 1f9f9f7d55 | |||
| 55bd1adae0 | |||
| d4d808fcc8 | |||
| 8028c35172 | |||
| 089b41da23 | |||
| c2a76870b5 | |||
| 3699b53ba2 | |||
| f29e6b00d7 | |||
| ca7f3a00e6 | |||
| c6f16547ff | |||
| 2f718d40d6 | |||
| 63ee4de162 | |||
| 23a409204f | |||
| 49be92f87f | |||
| 8374fcb4be | |||
| a1e62baad7 | |||
| 826cf0c61c | |||
| ffeefb2a8e | |||
| d0bf830ca7 | |||
| b0f8e31b63 | |||
| 87ec6dfacb | |||
| 18283feac1 | |||
| b52a1d612d | |||
| a227338a72 | |||
| a2a7efa946 | |||
| d214817c87 | |||
| 0ee34fe836 | |||
| 639ea0919f | |||
| 774856f9b2 | |||
| 3470882df6 | |||
| b013f5f0ed | |||
| 4f601f4896 | |||
| cfc1014c6e | |||
| 50f79e9a0e | |||
| 75920d2c12 | |||
| 3890ec58f0 | |||
| 4d67145aa1 | |||
| 06a6922cde | |||
| d7aa9c44f9 | |||
| 7108d0164e | |||
| 7e40d8c87b | |||
| 23bb883797 | |||
| 11043129f2 | |||
| c2ae141df3 | |||
| 031fc5da27 | |||
| 5632d96016 | |||
| 77c0a5b430 | |||
| 4d12c408fd | |||
| cdf298ba3a | |||
| dd0e6187db | |||
| b7ac90fd9f | |||
| 580dcd3c08 | |||
| b11c079d69 | |||
| 3c198a3a40 | |||
| 4d4ab1a75f | |||
| 161d93466c | |||
| e99857d125 | |||
| dec7ecd06b | |||
| 7e19ce23bd | |||
| 9325a29a74 | |||
| f5b1f872a0 | |||
| a7e71717cb | |||
| 083aa0ed55 | |||
| 72909b3f4c | |||
| 1c1a48b648 | |||
| b9a2dfded4 | |||
| a7fba79be7 | |||
| e676440e1f | |||
| 89259475ab | |||
| 54655a4e3b | |||
| f83ff041cc | |||
| 85766a41ff | |||
| 4da873ae79 | |||
| 76e53e86fa | |||
| a95a034219 | |||
| 56e304a2af | |||
| 0e766c6b53 | |||
| 96358469a4 | |||
| c291632492 | |||
| 799c8828c2 | |||
| 231d7a023a | |||
| 7b3fc9191a | |||
| e306e3f855 | |||
| 0cb3a893a1 | |||
| fb173dc787 | |||
| 14c8125108 | |||
| 620a459d93 | |||
| 332ae13af5 | |||
| dbe73d4bab | |||
| d0c9c46ff9 | |||
| 46fe488e05 | |||
| 6ced871d9a | |||
| bb376ff3fb | |||
| 284cc4eece | |||
| cd4082bf9f | |||
| 07c3ce02be | |||
| af78f4819a | |||
| 4198055d4a | |||
| 8adf1c3de0 | |||
| 42de0a0a46 | |||
| 40558b2608 | |||
| cfbe27490f | |||
| 0bcabc2163 | |||
| 18961114e2 | |||
| c6a31f709b | |||
| e1a8b288fb | |||
| 38ed9ccb22 | |||
| 12833a5a5c | |||
| 22fb6c5bf0 | |||
| 6304595a1d | |||
| 8812c2148f | |||
| a6a16cf233 | |||
| 013dff2aaf | |||
| 33f1033e0e | |||
| ec288a1b53 | |||
| 838c364ed5 | |||
| 3b7149612f | |||
| 1127c36ceb | |||
| b7b49d5801 | |||
| f6db153ea5 | |||
| f01c669771 | |||
| 85b80d0fe5 | |||
| 95424b3c69 | |||
| 851e4d399f | |||
| ffd9176cdf | |||
| 633b5474db | |||
| 7e725a803e | |||
| 93ddcca294 | |||
| 629c20f097 | |||
| 3e1b945e99 | |||
| 89a9e01676 | |||
| ba515d83df | |||
| ee824f3b19 | |||
| 9f39456dbd | |||
| 3224fa24c8 | |||
| 114ee16c21 | |||
| 1198ad3ae7 | |||
| ff0cebca87 | |||
| bf41415c8b | |||
| b14ee3ed39 | |||
| 853fdaad75 | |||
| a1ce114cd4 | |||
| 6afdf3fabf | |||
| 8f513f809b | |||
| cf03233e66 | |||
| b768e44678 | |||
| 1dd2f61d76 | |||
| 05d316b3a5 | |||
| 628c68abe3 | |||
| 98b2fba518 | |||
| 40b6a9c5cc | |||
| 543526cb85 | |||
| 6bca112340 | |||
| 846e495944 | |||
| 2096b85115 | |||
| a808dfe39c | |||
| 44e6c334e6 | |||
| 151d873aba | |||
| 3a07bc27c2 | |||
| d4308b4c5d | |||
| 2636b6f5b1 | |||
| 5cc52e4b19 | |||
| fc92d95b35 | |||
| 95ed0b59bd | |||
| b5192437c3 | |||
| 3ad7c62601 | |||
| 9de89e037a | |||
| 95e74373fe | |||
| 8b1222c3fb | |||
| c96040187f | |||
| aa4f7ed3a5 | |||
| 6b89b4620b | |||
| 4b1a1568bf | |||
| 8283f130d6 | |||
| 0157f7fcea | |||
| 608a6fcfad | |||
| e08ffa6474 | |||
| 25b9ac206b | |||
| ae4b64c491 | |||
| 4d506e6981 | |||
| 7a38acada9 | |||
| 0a245a386e | |||
| caa89878d6 | |||
| 5002dd720f | |||
| 07c897e558 | |||
| 18c6701841 | |||
| 654ca47351 | |||
| 7a7b3efe3a | |||
| 866d952924 | |||
| d9d7440a7f | |||
| 8860109efc | |||
| 432c3ad397 | |||
| de29e16024 | |||
| 16cf6e0267 | |||
| 0e423aae4d | |||
| 21abb75ccc | |||
| 7fcad36826 | |||
| 2e1d29203d | |||
| d25b1d2fa4 | |||
| 9f5db313ce | |||
| 50af0031c3 | |||
| 4f5d65e7a6 | |||
| 460d7fb2c3 | |||
| ef9545cf71 | |||
| cdf5cb2d56 | |||
| e2695b2380 | |||
| 01e519aa24 | |||
| 1a572d91b0 | |||
| 09116f83f7 | |||
| d9d2ec1992 | |||
| 3210d52eee | |||
| 6cf4b3bf82 | |||
| 2acf7e6915 | |||
| ba1a9543c8 | |||
| ee6ffbe73e | |||
| eea3f0ede6 | |||
| a6dfd7145f | |||
| f4d8fd3186 | |||
| 352f485649 | |||
| a9f2e9a9a7 | |||
| 2b16a3693e | |||
| 533cb67681 | |||
| c4b88cc1e6 | |||
| 083fd72e66 | |||
| 388d8ed8cf | |||
| 9a423140bc | |||
| 800a3a7a47 | |||
| 3855e4c4b9 | |||
| 64b2970cf4 | |||
| 5520526bef | |||
| bf987098dc | |||
| 341bc1b938 | |||
| 172517e4f8 | |||
| f5ef0af883 | |||
| e30dec7124 | |||
| 2aff4d41dd | |||
| 78e421cb72 | |||
| 457d3972f7 | |||
| 9fb0b77d89 | |||
| d64dba1c1e | |||
| a9aae80ae0 | |||
| d337caafe6 | |||
| d20e3f69e1 | |||
| a01ff6baf8 | |||
| 7251cbec76 | |||
| b720d0181f | |||
| 858ad52cf6 | |||
| 1a298045b6 | |||
| e57a314acf | |||
| 7da98c514a | |||
| bd91a5a11e | |||
| 28b72a667c | |||
| b8a5b9b551 | |||
| 7f29a7127c | |||
| 3ccd24c50e | |||
| ae49c54d60 | |||
| c1d1be4d61 | |||
| e39ff9d5a3 | |||
| aef8c1442d | |||
| af548fd1bc | |||
| b2b120bbc1 | |||
| 3267409c57 |
@@ -0,0 +1,7 @@
|
|||||||
|
[**.c]
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
[**.yml]
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
+11
-2
@@ -1,2 +1,11 @@
|
|||||||
Cargo.lock
|
.idea/
|
||||||
target
|
prefix/
|
||||||
|
sysroot/
|
||||||
|
**/target/
|
||||||
|
.gdb_history
|
||||||
|
*.patch
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
/.vim
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
|||||||
+64
-8
@@ -1,17 +1,73 @@
|
|||||||
image: "redoxos/redoxer"
|
image: "redoxos/redoxer:latest"
|
||||||
|
|
||||||
stages:
|
variables:
|
||||||
- build
|
GIT_SUBMODULE_STRATEGY: recursive
|
||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
rules:
|
rules:
|
||||||
- if: '$CI_COMMIT_BRANCH == "master" && $CI_PROJECT_NAMESPACE == "redox-os"'
|
- if: '$CI_COMMIT_BRANCH == "master" && $CI_PROJECT_NAMESPACE == "redox-os"'
|
||||||
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"'
|
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"'
|
||||||
|
|
||||||
build:linux:
|
stages:
|
||||||
stage: build
|
- build
|
||||||
script: cargo +nightly build
|
- cross-build
|
||||||
|
- test
|
||||||
|
before_script:
|
||||||
|
cargo install cbindgen
|
||||||
|
|
||||||
build:redox:
|
fmt:
|
||||||
stage: build
|
stage: build
|
||||||
script: redoxer build
|
needs: []
|
||||||
|
script:
|
||||||
|
- rustup component add rustfmt-preview
|
||||||
|
- ./fmt.sh -- --check
|
||||||
|
|
||||||
|
linux:
|
||||||
|
stage: build
|
||||||
|
script:
|
||||||
|
- ./check.sh --host
|
||||||
|
|
||||||
|
x86_64:
|
||||||
|
stage: build
|
||||||
|
script:
|
||||||
|
- ./check.sh --arch=x86_64
|
||||||
|
|
||||||
|
i586:
|
||||||
|
stage: cross-build
|
||||||
|
script:
|
||||||
|
- ./check.sh --arch=i586
|
||||||
|
|
||||||
|
aarch64:
|
||||||
|
stage: cross-build
|
||||||
|
image: "redoxos/redoxer:aarch64"
|
||||||
|
script:
|
||||||
|
- ./check.sh --arch=aarch64
|
||||||
|
|
||||||
|
riscv64gc:
|
||||||
|
stage: cross-build
|
||||||
|
script:
|
||||||
|
- ./check.sh --arch=riscv64gc
|
||||||
|
|
||||||
|
test:linux:
|
||||||
|
stage: test
|
||||||
|
needs: [linux]
|
||||||
|
script:
|
||||||
|
- ./check.sh --host --test
|
||||||
|
|
||||||
|
test:x86_64:
|
||||||
|
stage: test
|
||||||
|
needs: [x86_64]
|
||||||
|
script:
|
||||||
|
# timeout: https://gitlab.redox-os.org/redox-os/relibc/-/issues/238
|
||||||
|
- timeout -s KILL 9m ./check.sh --arch=x86_64 --test
|
||||||
|
|
||||||
|
test:aarch64:
|
||||||
|
stage: test
|
||||||
|
needs: [aarch64]
|
||||||
|
image: "redoxos/redoxer:aarch64"
|
||||||
|
# many issues that not exist in x86_64, and lack of interest to fix so far
|
||||||
|
allow_failure: true
|
||||||
|
script:
|
||||||
|
- timeout -s KILL 9m ./check.sh --arch=aarch64 --test
|
||||||
|
|
||||||
|
#TODO: Enable more arch once dynamic linker working
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[submodule "openlibm"]
|
||||||
|
path = openlibm
|
||||||
|
url = https://gitlab.redox-os.org/redox-os/openlibm.git
|
||||||
|
branch = master
|
||||||
|
[submodule "src/dlmalloc-rs"]
|
||||||
|
path = dlmalloc-rs
|
||||||
|
url = https://gitlab.redox-os.org/redox-os/dlmalloc-rs.git
|
||||||
+123
@@ -0,0 +1,123 @@
|
|||||||
|
# Contributing
|
||||||
|
|
||||||
|
## Table of contents
|
||||||
|
1. [What to do](#what-to-do)
|
||||||
|
2. [Code style](#code-style)
|
||||||
|
3. [Sending merge requests](#sending-merge-requests)
|
||||||
|
4. [Writing tests](#writing-tests)
|
||||||
|
5. [Running tests](#running-tests)
|
||||||
|
|
||||||
|
Maintaining a libc is tough work, and we'd love some help!
|
||||||
|
|
||||||
|
## What to do
|
||||||
|
|
||||||
|
For now, we are still trying to get full libc compatibility before we move on to
|
||||||
|
any optimisation.
|
||||||
|
|
||||||
|
- We currently have a number of unimplemented functions. Search for
|
||||||
|
`unimplemented!()` and hop right in!
|
||||||
|
- If you notice any missing functionality, feel free to add it in
|
||||||
|
|
||||||
|
## Code style
|
||||||
|
|
||||||
|
We have a `rustfmt.toml` in the root directory of relibc. Please run `./fmt.sh`
|
||||||
|
before sending in any merge requests as it will automatically format your code.
|
||||||
|
|
||||||
|
With regards to general style:
|
||||||
|
|
||||||
|
### Where applicable, prefer using references to raw pointers
|
||||||
|
|
||||||
|
This is most obvious when looking at `stdio` functions. If raw pointers were
|
||||||
|
used instead of references, then the resulting code would be significantly
|
||||||
|
uglier. Instead try to check for pointer being valid with `pointer::as_ref()`
|
||||||
|
and `pointer::as_mut()` and then immediately use those references instead.
|
||||||
|
|
||||||
|
Internal functions should always take references.
|
||||||
|
|
||||||
|
### Use the c types exposed in our platform module instead of Rust's inbuilt integer types
|
||||||
|
|
||||||
|
This is so we can guarantee that everything works across platforms. While it is
|
||||||
|
generally accepted these days that an `int` has 32 bits (which matches against
|
||||||
|
an `i32`), some platforms have `int` as having 16 bits, and others have long as
|
||||||
|
being 32 bits instead of 64. If you use the types in platform, then we can
|
||||||
|
guarantee that your code will "just work" should we port relibc to a different
|
||||||
|
architecture.
|
||||||
|
|
||||||
|
### Use our internal functions
|
||||||
|
|
||||||
|
If you need to use a C string, don't reinvent the wheel. We have functions in
|
||||||
|
the platform module that convert C strings to Rust slices.
|
||||||
|
|
||||||
|
We also have structures that wrap files, wrap writable strings, and wrap various
|
||||||
|
other commonly used things that you should use instead of rolling your own.
|
||||||
|
|
||||||
|
## Sending merge requests
|
||||||
|
|
||||||
|
If you have sent us a merge request, first of all, thanks for taking your time
|
||||||
|
to help us!
|
||||||
|
|
||||||
|
The first thing to note is that we do most of our development on our
|
||||||
|
[GitLab server](https://gitlab.redox-os.org/redox-os/relibc), and as such it is
|
||||||
|
possible that none of the maintainers will see your merge request if it is
|
||||||
|
opened on GitHub.
|
||||||
|
|
||||||
|
In your merge request, please put in the description:
|
||||||
|
- What functions (if any) have been implemented or changed
|
||||||
|
- The rationale behind your merge request (e.g. why you thought this change was
|
||||||
|
required. If you are just implementing some functions, you can ignore this)
|
||||||
|
- Any issues that are related to the merge request
|
||||||
|
|
||||||
|
We have CI attached to our GitLab instance, so all merge requests are checked to
|
||||||
|
make sure that they are tested before they are merged. Please write tests for
|
||||||
|
the functions that you add/change and test locally on your own machine
|
||||||
|
***before*** submitting a merge request.
|
||||||
|
|
||||||
|
## Writing tests
|
||||||
|
|
||||||
|
Every function that gets written needs to have a test in C in order to make sure
|
||||||
|
it works as intended. Here are a few guidelines for writing good tests.
|
||||||
|
|
||||||
|
### Ensure that any literals you have are mapped to variables instead of being directly passed to a function.
|
||||||
|
|
||||||
|
Sometimes compilers take literals put into libc functions and run them
|
||||||
|
internally during compilation, which can cause some false positives. All tests
|
||||||
|
are compiled with `-fno-builtin`, which theoretically solves this issue, but
|
||||||
|
just in case, it'd be a good idea to map inputs to variables.
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "string.h"
|
||||||
|
#include "stdio.h"
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
// Don't do this
|
||||||
|
printf("%d\n", strcspn("Hello", "Hi"));
|
||||||
|
|
||||||
|
// Do this
|
||||||
|
char *first = "Hello";
|
||||||
|
char *second = "Hi";
|
||||||
|
printf("%d\n", strcspn(first, second));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ensure your tests cover every section of code.
|
||||||
|
|
||||||
|
What happens if a string in `strcmp()` is shorter than the other string? What
|
||||||
|
happens if the first argument to `strcspn()` is longer than the second string?
|
||||||
|
In order to make sure that all functions work as expected, we ask that any tests
|
||||||
|
cover as much of the code that you have written as possible.
|
||||||
|
|
||||||
|
## Running tests
|
||||||
|
|
||||||
|
Running tests is an important part in trying to find bugs. Before opening a
|
||||||
|
merge request, we ask that you test on your own machine to make sure there are
|
||||||
|
no regressions.
|
||||||
|
|
||||||
|
You can run tests with `make test` in the root directory of relibc to compile
|
||||||
|
relibc, compile the tests and run them. This *will* print a lot of output to
|
||||||
|
stdout, so be warned!
|
||||||
|
|
||||||
|
You can test against verified correct output with `make verify` in the tests
|
||||||
|
directory. You will need to manually create the correct output and put it in the
|
||||||
|
tests/expected directory. Running any `make` commands in the tests directory
|
||||||
|
will ***not*** rebuild relibc, so you'll need to go back to the root directory
|
||||||
|
if you need to rebuild relibc.
|
||||||
Generated
+729
@@ -0,0 +1,729 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "argon2"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072"
|
||||||
|
dependencies = [
|
||||||
|
"base64ct",
|
||||||
|
"blake2",
|
||||||
|
"cpufeatures",
|
||||||
|
"password-hash",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64ct"
|
||||||
|
version = "1.8.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bcrypt-pbkdf"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6aeac2e1fe888769f34f05ac343bbef98b14d1ffb292ab69d4608b3abc86f2a2"
|
||||||
|
dependencies = [
|
||||||
|
"blowfish",
|
||||||
|
"pbkdf2",
|
||||||
|
"sha2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "2.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "blake2"
|
||||||
|
version = "0.10.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
|
||||||
|
dependencies = [
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-buffer"
|
||||||
|
version = "0.10.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "blowfish"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"cipher",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cbitset"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "29b6ad25ae296159fb0da12b970b2fe179b234584d7cd294c891e2bbb284466b"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.1.22"
|
||||||
|
source = "git+https://github.com/tea/cc-rs?branch=riscv-abi-arch-fix#588ceacb084af41415690c57688e338a32a1f1b4"
|
||||||
|
dependencies = [
|
||||||
|
"shlex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono-tz"
|
||||||
|
version = "0.10.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a6139a8597ed92cf816dfb33f5dd6cf0bb93a6adc938f11039f371bc5bcd26c3"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
"phf",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cipher"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-common",
|
||||||
|
"inout",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crt0"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crti"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crtn"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-common"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "digest"
|
||||||
|
version = "0.10.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||||
|
dependencies = [
|
||||||
|
"block-buffer",
|
||||||
|
"crypto-common",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dlmalloc"
|
||||||
|
version = "0.2.8"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "drm-sys"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ecc8e1361066d91f5ffccff060a3c3be9c3ecde15be2959c1937595f7a82a9f8"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"linux-raw-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-rt"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "goblin"
|
||||||
|
version = "0.10.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "17582616a7718cca54cec18e534a76c7c4aec11a8b9a85695712f262fd15a4c8"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"plain",
|
||||||
|
"scroll",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hmac"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||||
|
dependencies = [
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inout"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ioslice"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5e571352c8a3b89074d12e3ee5173ffe162159105352aaaf1fc5764da747e31b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ld_so"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.186"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libm"
|
||||||
|
version = "0.2.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libredox"
|
||||||
|
version = "0.1.18+rb0.3.0"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"libc",
|
||||||
|
"plain",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lock_api"
|
||||||
|
version = "0.4.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
|
||||||
|
dependencies = [
|
||||||
|
"scopeguard",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.33"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "md-5"
|
||||||
|
version = "0.10.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "object"
|
||||||
|
version = "0.36.7"
|
||||||
|
source = "git+https://gitlab.redox-os.org/andypython/object#7270e3f0d06e5ef4c2b80abc6166d31f4ddf4fea"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "password-hash"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
|
||||||
|
dependencies = [
|
||||||
|
"base64ct",
|
||||||
|
"rand_core 0.6.4",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pbkdf2"
|
||||||
|
version = "0.12.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
|
||||||
|
dependencies = [
|
||||||
|
"digest",
|
||||||
|
"hmac",
|
||||||
|
"sha2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7"
|
||||||
|
dependencies = [
|
||||||
|
"phf_shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_shared"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981"
|
||||||
|
dependencies = [
|
||||||
|
"siphasher",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "plain"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "posix-regex"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "66df580334caab2f744839ab1be85493d7ec731a92d6cf928008ab0b212bf3bc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.106"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.46"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.10.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core 0.10.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_jitter"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3fdcd80e68f0a8f9ca5ec7cfd02fd5fbb8fbe6ef4e9b90ea2f48bb929b74f88e"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"rand_core 0.10.1",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_xorshift"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "60aa6af80be32871323012e02e6e65f8a7cc7890931ae421d217ad8fe0df2ccf"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core 0.10.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox-ioctl"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"drm-sys",
|
||||||
|
"redox_syscall",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox-path"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "436d45c2b6a5b159d43da708e62b25be3a4a3d5550d654b72216ade4c4bfd717"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox-rt"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"generic-rt",
|
||||||
|
"goblin",
|
||||||
|
"ioslice",
|
||||||
|
"libredox",
|
||||||
|
"plain",
|
||||||
|
"redox-path",
|
||||||
|
"redox_syscall",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_event"
|
||||||
|
version = "0.4.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c5018d583d6d2f5499352aea8d177e9067d1eb03ab17c78169d5ba7a30001b15"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"libredox",
|
||||||
|
"redox_syscall",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_syscall"
|
||||||
|
version = "0.9.0+rb0.3.0"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "relibc"
|
||||||
|
version = "0.6.0+rb0.3.0"
|
||||||
|
dependencies = [
|
||||||
|
"argon2",
|
||||||
|
"base64ct",
|
||||||
|
"bcrypt-pbkdf",
|
||||||
|
"bitflags",
|
||||||
|
"cbitset",
|
||||||
|
"cc",
|
||||||
|
"chrono",
|
||||||
|
"chrono-tz",
|
||||||
|
"dlmalloc",
|
||||||
|
"generic-rt",
|
||||||
|
"ioslice",
|
||||||
|
"libc",
|
||||||
|
"libm",
|
||||||
|
"libredox",
|
||||||
|
"log",
|
||||||
|
"md-5",
|
||||||
|
"memchr",
|
||||||
|
"object",
|
||||||
|
"pbkdf2",
|
||||||
|
"plain",
|
||||||
|
"posix-regex",
|
||||||
|
"rand",
|
||||||
|
"rand_jitter",
|
||||||
|
"rand_xorshift",
|
||||||
|
"redox-ioctl",
|
||||||
|
"redox-path",
|
||||||
|
"redox-rt",
|
||||||
|
"redox_event",
|
||||||
|
"redox_syscall",
|
||||||
|
"sc",
|
||||||
|
"scrypt",
|
||||||
|
"sha-crypt",
|
||||||
|
"sha2",
|
||||||
|
"spin",
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "salsa20"
|
||||||
|
version = "0.10.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213"
|
||||||
|
dependencies = [
|
||||||
|
"cipher",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sc"
|
||||||
|
version = "0.2.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "010e18bd3bfd1d45a7e666b236c78720df0d9a7698ebaa9c1c559961eb60a38b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scopeguard"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scroll"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c1257cd4248b4132760d6524d6dda4e053bc648c9070b960929bf50cfb1e7add"
|
||||||
|
dependencies = [
|
||||||
|
"scroll_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scroll_derive"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed76efe62313ab6610570951494bdaa81568026e0318eaa55f167de70eeea67d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scrypt"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f"
|
||||||
|
dependencies = [
|
||||||
|
"password-hash",
|
||||||
|
"pbkdf2",
|
||||||
|
"salsa20",
|
||||||
|
"sha2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha-crypt"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "88e79009728d8311d42d754f2f319a975f9e38f156fd5e422d2451486c78b286"
|
||||||
|
dependencies = [
|
||||||
|
"base64ct",
|
||||||
|
"sha2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha2"
|
||||||
|
version = "0.10.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shlex"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "siphasher"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.9.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subtle"
|
||||||
|
version = "2.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.118"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.20.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.59.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_gnullvm",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
|
[[patch.unused]]
|
||||||
|
name = "redox-scheme"
|
||||||
|
version = "0.11.2+rb0.3.0"
|
||||||
+143
-17
@@ -1,25 +1,151 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "redox_syscall"
|
name = "relibc"
|
||||||
version = "0.9.0+rb0.3.0"
|
version = "0.6.0+rb0.3.0"
|
||||||
description = "A Rust library to access raw Redox system calls"
|
|
||||||
license = "MIT"
|
|
||||||
authors = ["Jeremy Soller <jackpot51@gmail.com>", "vasilito <adminpupkin@gmail.com>"]
|
authors = ["Jeremy Soller <jackpot51@gmail.com>", "vasilito <adminpupkin@gmail.com>"]
|
||||||
repository = "https://gitlab.redox-os.org/redox-os/syscall"
|
edition = "2024"
|
||||||
documentation = "https://docs.rs/redox_syscall"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "syscall"
|
name = "relibc"
|
||||||
|
crate-type = ["staticlib"]
|
||||||
|
|
||||||
[features]
|
[workspace]
|
||||||
default = ["userspace"]
|
members = [
|
||||||
rustc-dep-of-std = ["core", "bitflags/rustc-dep-of-std"]
|
"src/crt0",
|
||||||
userspace = []
|
"src/crti",
|
||||||
std = []
|
"src/crtn",
|
||||||
|
"redox-rt",
|
||||||
|
"ld_so",
|
||||||
|
"generic-rt",
|
||||||
|
]
|
||||||
|
exclude = ["tests", "dlmalloc-rs"]
|
||||||
|
|
||||||
|
[workspace.lints.clippy]
|
||||||
|
borrow_as_ptr = "deny"
|
||||||
|
cast_lossless = "warn" # TODO review occurrences
|
||||||
|
cast_possible_truncation = "allow" # TODO review occurrences
|
||||||
|
cast_possible_wrap = "allow" # TODO review occurrences
|
||||||
|
cast_precision_loss = "allow" # TODO review occurrences
|
||||||
|
cast_ptr_alignment = "allow" # TODO review occurrences
|
||||||
|
cast_sign_loss = "allow" # TODO review occurrences
|
||||||
|
missing_errors_doc = "allow" # TODO review occurrences
|
||||||
|
missing_panics_doc = "allow" # TODO review occurrences
|
||||||
|
missing_safety_doc = "allow" # TODO review occurrences
|
||||||
|
mut_from_ref = "warn" # TODO review occurrences
|
||||||
|
precedence = "deny"
|
||||||
|
ptr_as_ptr = "warn" # TODO review occurrences
|
||||||
|
ptr_cast_constness = "warn" # TODO review occurrences
|
||||||
|
ref_as_ptr = "warn" # TODO review occurrences
|
||||||
|
upper_case_acronyms = "allow" # TODO review occurrences
|
||||||
|
zero_ptr = "warn" # must allow on public constants due to cbindgen issue
|
||||||
|
|
||||||
|
[workspace.lints.rust]
|
||||||
|
dangling_pointers_from_temporaries = "deny"
|
||||||
|
dead_code = "allow" # TODO review occuurences
|
||||||
|
deprecated = "deny"
|
||||||
|
improper_ctypes_definitions = "deny"
|
||||||
|
internal_features = "allow" # core_intrinsics and lang_items
|
||||||
|
irrefutable_let_patterns = "deny"
|
||||||
|
mismatched_lifetime_syntaxes = "deny"
|
||||||
|
non_camel_case_types = "allow" # needed for most POSIX type names
|
||||||
|
non_snake_case = "allow" # TODO review occuurences
|
||||||
|
non_upper_case_globals = "allow" # TODO review occuurences
|
||||||
|
unexpected_cfgs = "deny"
|
||||||
|
unpredictable_function_pointer_comparisons = "deny"
|
||||||
|
unreachable_code = "allow" # TODO review occuurences
|
||||||
|
unsafe_op_in_unsafe_fn = "deny"
|
||||||
|
unused_imports = "deny"
|
||||||
|
unused_must_use = "deny"
|
||||||
|
unused_mut = "deny"
|
||||||
|
unused_unsafe = "deny"
|
||||||
|
unused_variables = "allow" # TODO review occurrences (too many for now)
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
|
[workspace.dependencies]
|
||||||
|
bitflags = "2"
|
||||||
|
ioslice = { version = "0.6", default-features = false }
|
||||||
|
plain = "0.2"
|
||||||
|
redox-path = "0.3"
|
||||||
|
redox_protocols = { package = "libredox", path = "../libredox", default-features = false, features = ["protocol"] }
|
||||||
|
redox_syscall = { path = "../syscall" }
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
cc = "1"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bitflags = "2.4"
|
bitflags.workspace = true
|
||||||
core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" }
|
cbitset = "0.2"
|
||||||
|
posix-regex = { version = "0.1.4", features = ["no_std"] }
|
||||||
|
|
||||||
[target.'cfg(loom)'.dev-dependencies]
|
rand = { version = "0.10", default-features = false }
|
||||||
loom = "0.7"
|
rand_xorshift = "0.5"
|
||||||
|
rand_jitter = "0.6"
|
||||||
|
|
||||||
|
memchr = { version = "2.2.0", default-features = false }
|
||||||
|
plain.workspace = true
|
||||||
|
unicode-width = "0.1"
|
||||||
|
__libc_only_for_layout_checks = { package = "libc", version = "0.2.149", optional = true }
|
||||||
|
md5-crypto = { package = "md-5", version = "0.10.6", default-features = false }
|
||||||
|
sha-crypt = { version = "0.5", default-features = false }
|
||||||
|
base64ct = { version = "1.6", default-features = false, features = ["alloc"] }
|
||||||
|
bcrypt-pbkdf = { version = "0.10", default-features = false, features = [
|
||||||
|
"alloc",
|
||||||
|
] }
|
||||||
|
scrypt = { version = "0.11", default-features = false, features = ["simple"] }
|
||||||
|
pbkdf2 = { version = "0.12", features = ["sha2"] }
|
||||||
|
sha2 = { version = "0.10", default-features = false }
|
||||||
|
generic-rt = { path = "generic-rt" }
|
||||||
|
chrono-tz = { version = "0.10", default-features = false }
|
||||||
|
chrono = { version = "0.4", default-features = false, features = ["alloc"] }
|
||||||
|
libm = "0.2"
|
||||||
|
log = "0.4"
|
||||||
|
spin = "0.9.8"
|
||||||
|
argon2 = "0.5.3"
|
||||||
|
|
||||||
|
[dependencies.dlmalloc]
|
||||||
|
path = "dlmalloc-rs"
|
||||||
|
default-features = false
|
||||||
|
features = ["c_api"]
|
||||||
|
|
||||||
|
[dependencies.object]
|
||||||
|
version = "0.36.7"
|
||||||
|
git = "https://gitlab.redox-os.org/andypython/object"
|
||||||
|
default-features = false
|
||||||
|
features = ["elf", "read_core"]
|
||||||
|
|
||||||
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
|
sc = "0.2.7"
|
||||||
|
|
||||||
|
[target.'cfg(target_os = "redox")'.dependencies]
|
||||||
|
redox_syscall.workspace = true
|
||||||
|
redox-rt = { path = "redox-rt" }
|
||||||
|
redox-path.workspace = true
|
||||||
|
redox_event = { version = "0.4.8", default-features = false, features = [
|
||||||
|
"redox_syscall",
|
||||||
|
] }
|
||||||
|
ioslice.workspace = true
|
||||||
|
redox-ioctl = { path = "redox-ioctl" }
|
||||||
|
redox_protocols.workspace = true
|
||||||
|
|
||||||
|
[features]
|
||||||
|
# to enable trace level, take out this `no_trace`
|
||||||
|
default = ["check_against_libc_crate", "ld_so_cache", "no_trace"]
|
||||||
|
check_against_libc_crate = ["__libc_only_for_layout_checks"]
|
||||||
|
ld_so_cache = []
|
||||||
|
math_libm = []
|
||||||
|
no_trace = ["log/release_max_level_debug"]
|
||||||
|
# for very verbose activity beyond trace level
|
||||||
|
trace_tls = []
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
panic = "abort"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
panic = "abort"
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
cc-11 = { git = "https://github.com/tea/cc-rs", branch = "riscv-abi-arch-fix", package = "cc" }
|
||||||
|
redox_syscall = { path = "../syscall" }
|
||||||
|
libredox = { path = "../libredox" }
|
||||||
|
redox-scheme = { path = "../redox-scheme" }
|
||||||
|
|||||||
@@ -1,22 +1,21 @@
|
|||||||
Copyright (c) 2017 Redox OS Developers
|
|
||||||
|
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Copyright (c) 2018 Redox OS
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
included in all copies or substantial portions of the Software.
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
The above copyright notice and this permission notice shall be included in all
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
copies or substantial portions of the Software.
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|||||||
@@ -0,0 +1,226 @@
|
|||||||
|
include config.mk
|
||||||
|
|
||||||
|
CARGO?=cargo
|
||||||
|
CARGO_TEST?=$(CARGO)
|
||||||
|
CARGO_COMMON_FLAGS=-Z build-std=core,alloc,compiler_builtins
|
||||||
|
CARGOFLAGS?=$(CARGO_COMMON_FLAGS)
|
||||||
|
CC_WRAPPER?=
|
||||||
|
RUSTCFLAGS?=
|
||||||
|
LINKFLAGS?=-lgcc
|
||||||
|
USE_RUST_LIBM?=
|
||||||
|
TESTBIN?=
|
||||||
|
export OBJCOPY?=objcopy
|
||||||
|
|
||||||
|
export CARGO_TARGET_DIR?=$(shell pwd)/target
|
||||||
|
BUILD?=$(CARGO_TARGET_DIR)/$(TARGET)
|
||||||
|
CARGOFLAGS+=--target=$(TARGET)
|
||||||
|
EXCEPT_MATH=-not -name "math"
|
||||||
|
FEATURE_MATH=
|
||||||
|
ifneq ($(USE_RUST_LIBM),)
|
||||||
|
FEATURE_MATH=--features math_libm
|
||||||
|
EXCEPT_MATH=
|
||||||
|
endif
|
||||||
|
|
||||||
|
TARGET_HEADERS?=$(BUILD)/include
|
||||||
|
export CFLAGS=-I$(TARGET_HEADERS)
|
||||||
|
|
||||||
|
PROFILE?=release
|
||||||
|
|
||||||
|
HEADERS_UNPARSED=$(shell find src/header -mindepth 1 -maxdepth 1 -type d -not -name "_*" $(EXCEPT_MATH) -printf "%f\n")
|
||||||
|
HEADERS_DEPS=$(shell find src/header -type f \( -name "cbindgen.toml" -o -name "*.rs" \))
|
||||||
|
#HEADERS=$(patsubst %,%.h,$(subst _,/,$(HEADERS_UNPARSED)))
|
||||||
|
|
||||||
|
SRC=\
|
||||||
|
Cargo.* \
|
||||||
|
$(shell find src/ redox-rt/src/ ld_so/src/ redox-ioctl/src/ include/ -type f)
|
||||||
|
|
||||||
|
BUILTINS_VERSION=0.1.70
|
||||||
|
|
||||||
|
.PHONY: all clean fmt install install-libs install-headers install-tests libs headers submodules test
|
||||||
|
|
||||||
|
all: | headers libs
|
||||||
|
|
||||||
|
headers: $(HEADERS_DEPS)
|
||||||
|
rm -rf $(TARGET_HEADERS)
|
||||||
|
mkdir -p $(TARGET_HEADERS)
|
||||||
|
cp -r include/* $(TARGET_HEADERS)
|
||||||
|
ifeq ($(USE_RUST_LIBM),)
|
||||||
|
cp "openlibm/include"/*.h $(TARGET_HEADERS)
|
||||||
|
cp "openlibm/src"/*.h $(TARGET_HEADERS)
|
||||||
|
endif
|
||||||
|
@set -e ; \
|
||||||
|
for header in $(HEADERS_UNPARSED); do \
|
||||||
|
if test -f "src/header/$$header/cbindgen.toml"; then \
|
||||||
|
echo -e "\033[0;36;49mWriting Header $$header\033[0m"; \
|
||||||
|
out=`echo "$$header" | sed 's/_/\//g'`; \
|
||||||
|
out="$(TARGET_HEADERS)/$$out.h"; \
|
||||||
|
cat "src/header/$$header/cbindgen.toml" cbindgen.globdefs.toml \
|
||||||
|
| cbindgen "src/header/$$header/mod.rs" --config=/dev/stdin --output "$$out" 2>/dev/null; \
|
||||||
|
fi \
|
||||||
|
done; echo -e "\033[0;36;49mAll headers written\033[0m";
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(CARGO) clean
|
||||||
|
$(MAKE) -C tests clean
|
||||||
|
rm -rf sysroot
|
||||||
|
|
||||||
|
check:
|
||||||
|
$(CARGO) check
|
||||||
|
|
||||||
|
fmt:
|
||||||
|
./fmt.sh
|
||||||
|
|
||||||
|
install-headers: headers libs
|
||||||
|
mkdir -pv "$(DESTDIR)/include"
|
||||||
|
cp -rv "$(TARGET_HEADERS)"/* "$(DESTDIR)/include"
|
||||||
|
|
||||||
|
libs: \
|
||||||
|
$(BUILD)/$(PROFILE)/libc.a \
|
||||||
|
$(BUILD)/$(PROFILE)/libc.so \
|
||||||
|
$(BUILD)/$(PROFILE)/crt0.o \
|
||||||
|
$(BUILD)/$(PROFILE)/crti.o \
|
||||||
|
$(BUILD)/$(PROFILE)/crtn.o \
|
||||||
|
$(BUILD)/$(PROFILE)/ld.so
|
||||||
|
|
||||||
|
install-libs: headers libs
|
||||||
|
mkdir -pv "$(DESTDIR)/lib"
|
||||||
|
cp -v "$(BUILD)/$(PROFILE)/libc.a" "$(DESTDIR)/lib"
|
||||||
|
cp -v "$(BUILD)/$(PROFILE)/libc.so" "$(DESTDIR)/lib"
|
||||||
|
ln -vnfs libc.so "$(DESTDIR)/lib/libc.so.6"
|
||||||
|
cp -v "$(BUILD)/$(PROFILE)/crt0.o" "$(DESTDIR)/lib"
|
||||||
|
ln -vnfs crt0.o "$(DESTDIR)/lib/crt1.o"
|
||||||
|
cp -v "$(BUILD)/$(PROFILE)/crti.o" "$(DESTDIR)/lib"
|
||||||
|
cp -v "$(BUILD)/$(PROFILE)/crtn.o" "$(DESTDIR)/lib"
|
||||||
|
cp -v "$(BUILD)/$(PROFILE)/ld.so" "$(DESTDIR)/$(LD_SO_PATH)"
|
||||||
|
ifeq ($(USE_RUST_LIBM),)
|
||||||
|
cp -v "$(BUILD)/openlibm/libopenlibm.a" "$(DESTDIR)/lib/libm.a"
|
||||||
|
endif
|
||||||
|
# Empty libraries for dl, pthread, and rt
|
||||||
|
$(AR) -rcs "$(DESTDIR)/lib/libdl.a"
|
||||||
|
$(AR) -rcs "$(DESTDIR)/lib/libpthread.a"
|
||||||
|
$(AR) -rcs "$(DESTDIR)/lib/librt.a"
|
||||||
|
|
||||||
|
install-tests: tests
|
||||||
|
$(MAKE) -C tests
|
||||||
|
mkdir -p "$(DESTDIR)/relibc-tests"
|
||||||
|
cp -vr tests/build_$(TARGET)/* "$(DESTDIR)/relibc-tests/"
|
||||||
|
|
||||||
|
install: install-headers install-libs
|
||||||
|
|
||||||
|
submodules:
|
||||||
|
git submodule sync
|
||||||
|
git submodule update --init --recursive
|
||||||
|
|
||||||
|
sysroot:
|
||||||
|
@mkdir -p $@
|
||||||
|
|
||||||
|
.PHONY: sysroot/$(TARGET)
|
||||||
|
sysroot/$(TARGET): | sysroot
|
||||||
|
rm -rf $@
|
||||||
|
rm -rf $@.partial
|
||||||
|
mkdir -p $@.partial
|
||||||
|
$(MAKE) install DESTDIR=$(shell pwd)/$@.partial
|
||||||
|
mv $@.partial $@
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
test: sysroot/$(TARGET)
|
||||||
|
# TODO: Fix SIGILL when running cargo test
|
||||||
|
# $(CARGO_TEST) test
|
||||||
|
$(MAKE) -C tests run
|
||||||
|
|
||||||
|
test-once: sysroot/$(TARGET)
|
||||||
|
$(MAKE) -C tests run-once TESTBIN=$(TESTBIN)
|
||||||
|
|
||||||
|
|
||||||
|
$(BUILD)/$(PROFILE)/libc.so: $(BUILD)/$(PROFILE)/libc.a
|
||||||
|
$(CC) -nostdlib \
|
||||||
|
-shared \
|
||||||
|
-Wl,--gc-sections \
|
||||||
|
-Wl,-z,pack-relative-relocs \
|
||||||
|
-Wl,--sort-common \
|
||||||
|
-Wl,--whole-archive $^ -Wl,--no-whole-archive \
|
||||||
|
-Wl,-soname,libc.so.6 \
|
||||||
|
$(LINKFLAGS) \
|
||||||
|
-o $@
|
||||||
|
|
||||||
|
$(BUILD)/$(PROFILE)/ld.so: $(BUILD)/$(PROFILE)/ld_so.o $(BUILD)/$(PROFILE)/libc.a
|
||||||
|
# TODO: merge ld.so with libc.so: --dynamic-list=dynamic-list-file
|
||||||
|
$(LD) --shared -Bsymbolic --no-relax -T ld_so/ld_script/$(TARGET).ld --gc-sections $^ -o $@
|
||||||
|
|
||||||
|
$(BUILD)/$(PROFILE)/libc.a: $(BUILD)/$(PROFILE)/librelibc.a $(BUILD)/openlibm/libopenlibm.a
|
||||||
|
echo "create $@" > "$@.mri"
|
||||||
|
for lib in $^; do\
|
||||||
|
echo "addlib $$lib" >> "$@.mri"; \
|
||||||
|
done
|
||||||
|
echo "save" >> "$@.mri"
|
||||||
|
echo "end" >> "$@.mri"
|
||||||
|
$(AR) -M < "$@.mri"
|
||||||
|
|
||||||
|
# Debug targets
|
||||||
|
|
||||||
|
$(BUILD)/debug/librelibc.a: $(SRC)
|
||||||
|
$(CARGO) rustc $(CARGOFLAGS) $(FEATURE_MATH) -- --emit link=$@ -g -C debug-assertions=no $(RUSTCFLAGS)
|
||||||
|
./renamesyms.sh "$@" "$(BUILD)/debug/deps/"
|
||||||
|
./stripcore.sh "$@"
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
$(BUILD)/debug/crt0.o: $(SRC)
|
||||||
|
$(CARGO) rustc --manifest-path src/crt0/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
$(BUILD)/debug/crti.o: $(SRC)
|
||||||
|
$(CARGO) rustc --manifest-path src/crti/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
$(BUILD)/debug/crtn.o: $(SRC)
|
||||||
|
$(CARGO) rustc --manifest-path src/crtn/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
$(BUILD)/debug/ld_so.o: $(SRC)
|
||||||
|
$(CARGO) rustc --manifest-path ld_so/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort -g -C debug-assertions=no $(RUSTCFLAGS)
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
# Release targets
|
||||||
|
|
||||||
|
$(BUILD)/release/librelibc.a: $(SRC)
|
||||||
|
$(CARGO) rustc --release $(CARGOFLAGS) -- --emit link=$@ $(RUSTCFLAGS)
|
||||||
|
@# TODO: Better to only allow a certain whitelisted set of symbols? Perhaps
|
||||||
|
@# use some cbindgen hook, specify them manually, or grep for #[unsafe(no_mangle)].
|
||||||
|
./renamesyms.sh "$@" "$(BUILD)/release/deps/"
|
||||||
|
./stripcore.sh "$@"
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
$(BUILD)/release/crt0.o: $(SRC)
|
||||||
|
$(CARGO) rustc --release --manifest-path src/crt0/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
$(BUILD)/release/crti.o: $(SRC)
|
||||||
|
$(CARGO) rustc --release --manifest-path src/crti/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
$(BUILD)/release/crtn.o: $(SRC)
|
||||||
|
$(CARGO) rustc --release --manifest-path src/crtn/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
$(BUILD)/release/ld_so.o: $(SRC)
|
||||||
|
$(CARGO) rustc --release --manifest-path ld_so/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
# Other targets
|
||||||
|
|
||||||
|
$(BUILD)/openlibm: openlibm
|
||||||
|
rm -rf $@ $@.partial
|
||||||
|
mkdir -p $(BUILD)
|
||||||
|
cp -r $< $@.partial
|
||||||
|
mv $@.partial $@
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
ifeq ($(USE_RUST_LIBM),)
|
||||||
|
$(BUILD)/openlibm/libopenlibm.a: $(BUILD)/openlibm $(BUILD)/$(PROFILE)/librelibc.a
|
||||||
|
$(MAKE) -s AR=$(AR) CC="$(CC_WRAPPER) $(CC)" LD=$(LD) CPPFLAGS="$(CPPFLAGS) -fno-stack-protector -I$(shell pwd)/include -I$(TARGET_HEADERS)" -C $< libopenlibm.a
|
||||||
|
./renamesyms.sh "$@" "$(BUILD)/release/deps/"
|
||||||
|
else
|
||||||
|
$(BUILD)/openlibm/libopenlibm.a:
|
||||||
|
mkdir -p "$(BUILD)/openlibm"
|
||||||
|
$(AR) -rcs "$(BUILD)/openlibm/libopenlibm.a"
|
||||||
|
endif
|
||||||
@@ -1,7 +1,173 @@
|
|||||||
# syscall
|
# Redox C Library (relibc)
|
||||||
|
|
||||||
This crate contains the system call numbers and Rust wrappers for the inline Assembly code of system calls.
|
relibc is a portable C standard library written in Rust and is under heavy development, this library contain the following items:
|
||||||
|
|
||||||
[](./LICENSE)
|
- C, Linux, BSD functions and extensions
|
||||||
[](https://crates.io/crates/redox_syscall)
|
- POSIX compatibility layer
|
||||||
[](https://docs.rs/redox_syscall)
|
- Interfaces for system components
|
||||||
|
|
||||||
|
The motivation for this project is twofold: Reduce issues that the Redox developers were having with [newlib](https://sourceware.org/newlib/), and create a more stable and safe alternative to C standard libraries written in C. It is mainly designed to be used under Redox, as an alternative to newlib, but it also supports Linux via the [sc](https://crates.io/crates/sc) crate.
|
||||||
|
|
||||||
|
Currently Redox and Linux are supported.
|
||||||
|
|
||||||
|
## `redox-rt`
|
||||||
|
|
||||||
|
`redox-rt` is a runtime library that provides much of the code that enables POSIX on Redox, like `fork`, `exec`, signal handling, etc.
|
||||||
|
Relibc uses it as backend in `src/platform/redox`, and it's intended to eventually be usable independently, without relibc.
|
||||||
|
|
||||||
|
## Repository Layout
|
||||||
|
|
||||||
|
- `include` - Header files (mostly macros and variadic functions `cbindgen` can't generate)
|
||||||
|
- `src` - Source files
|
||||||
|
- `src/c` - C code
|
||||||
|
- `src/crt0` - Runtime code
|
||||||
|
- `src/crti` - Runtime code
|
||||||
|
- `src/crtn` - Runtime code
|
||||||
|
- `src/header` - Header files implementation
|
||||||
|
- `src/header/*` - Each folder has a `cbindgen.toml` file, it generates a C-to-Rust interface and header files
|
||||||
|
- `src/ld_so` - Dynamic loader code
|
||||||
|
- `src/platform` - Platform-specific and common code
|
||||||
|
- `src/platform/redox` - Redox-specific code
|
||||||
|
- `src/platform/linux` - Linux-specific code
|
||||||
|
- `src/pthread` - pthread implementation
|
||||||
|
- `src/sync` - Synchronization primitives
|
||||||
|
- `tests` - C tests (each MR needs to give success in all of them)
|
||||||
|
|
||||||
|
## Download the sources
|
||||||
|
|
||||||
|
To download the relibc sources run the following command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone --recursive https://gitlab.redox-os.org/redox-os/relibc
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build Instructions
|
||||||
|
|
||||||
|
To build relibc out of the Redox build system, do the following steps:
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
- Install `cbindgen`
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo install cbindgen
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Install the `expect` tool
|
||||||
|
|
||||||
|
- Debian, Ubuntu and PopOS:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo apt install expect
|
||||||
|
```
|
||||||
|
|
||||||
|
- Fedora:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo dnf install expect
|
||||||
|
```
|
||||||
|
|
||||||
|
- Arch Linux:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo pacman -S expect
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build Relibc
|
||||||
|
|
||||||
|
To build the relibc library objects, run the following command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make all
|
||||||
|
```
|
||||||
|
|
||||||
|
- Clean old library objects and tests
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make clean
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build relibc inside the Redox build system
|
||||||
|
|
||||||
|
Inside of your Redox build system, run:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make prefix
|
||||||
|
```
|
||||||
|
|
||||||
|
If you need to rebuild `relibc` for testing a Cookbook recipe, run:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
touch relibc
|
||||||
|
make prefix r.recipe-name
|
||||||
|
```
|
||||||
|
|
||||||
|
Touching (changing the "last modified time" of) the `relibc` folder is needed to trigger recompilation for `make prefix`. Replace `recipe-name` with your desired recipe name.
|
||||||
|
|
||||||
|
Note: Do not edit `relibc` inside `prefix` folder! Do your work on `relibc` folder directly inside your Redox build system instead.
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
Relibc has a test suite that also runs every time a new commit get pushed. You can see `.gitlab-ci.yml` to see how it's being executed. That being said, `./check.sh` is the recommended way to run tests. Here's few examples:
|
||||||
|
|
||||||
|
+ `./check.sh` - Run build, without running the test
|
||||||
|
+ `./check.sh --test` - Run all tests in x86_64 Redox using Redoxer
|
||||||
|
+ `./check.sh --test --host` - Run all tests in host (Linux)
|
||||||
|
+ `./check.sh --test --arch=aarch64` - Run all tests in specified arch
|
||||||
|
- Arch can be `x86_64`, `aarch64`, `i586`, or `riscv64gc`
|
||||||
|
+ `./check.sh --test=stdio/printf` - Run a single test
|
||||||
|
- Can be combined with `--host` or `--arch`
|
||||||
|
- Will run statically linked test in Linux, dynamically linked in Redox
|
||||||
|
|
||||||
|
Couple of notes:
|
||||||
|
|
||||||
|
- Relibc and its tests will rebuild if files changed, however switching between arch or host requires you to run `make clean`
|
||||||
|
- Redoxer is needed to run tests for Redox without `--host`. You can install it using `cargo install redoxer`
|
||||||
|
- Tests can hangs, the test runner can anticipate this, assuming the kernel doesn't hang too.
|
||||||
|
|
||||||
|
## Issues
|
||||||
|
|
||||||
|
#### I'm building for my own platform which I run, and am getting `x86_64-linux-gnu-ar: command not found` (or similar)
|
||||||
|
|
||||||
|
The Makefile expects GNU compiler tools prefixed with the platform specifier, as would be present when you installed a cross compiler. Since you are building for your own platform, some Linux distributions (like Manjaro) don't install/symlink the prefixed executables.
|
||||||
|
|
||||||
|
An easy fix would be to replace the corresponding lines in `config.mk`, e.g.
|
||||||
|
|
||||||
|
```diff
|
||||||
|
ifeq ($(TARGET),x86_64-unknown-linux-gnu)
|
||||||
|
- export CC=x86_64-linux-gnu-gcc
|
||||||
|
- export LD=x86_64-linux-gnu-ld
|
||||||
|
- export AR=x86_64-linux-gnu-ar
|
||||||
|
- export NM=x86_64-linux-gnu-nm
|
||||||
|
+ export CC=gcc
|
||||||
|
+ export LD=ld
|
||||||
|
+ export AR=ar
|
||||||
|
+ export NM=nm
|
||||||
|
export OBJCOPY=objcopy
|
||||||
|
export CPPFLAGS=
|
||||||
|
LD_SO_PATH=lib/ld64.so.1
|
||||||
|
endif
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Before starting to contribute, read [this](CONTRIBUTING.md) document.
|
||||||
|
|
||||||
|
## Supported OSes
|
||||||
|
|
||||||
|
- Redox OS
|
||||||
|
- Linux
|
||||||
|
|
||||||
|
## Supported architectures
|
||||||
|
|
||||||
|
- i586 (Intel/AMD)
|
||||||
|
- x86_64 (Intel/AMD)
|
||||||
|
- aarch64 (ARM64)
|
||||||
|
- riscv64gc (RISC-V)
|
||||||
|
|
||||||
|
## Funding - _Unix-style Signals and Process Management_
|
||||||
|
|
||||||
|
This project is funded through [NGI Zero Core](https://nlnet.nl/core), a fund established by [NLnet](https://nlnet.nl) with financial support from the European Commission's [Next Generation Internet](https://ngi.eu) program. Learn more at the [NLnet project page](https://nlnet.nl/project/RedoxOS-Signals).
|
||||||
|
|
||||||
|
[<img src="https://nlnet.nl/logo/banner.png" alt="NLnet foundation logo" width="20%" />](https://nlnet.nl)
|
||||||
|
[<img src="https://nlnet.nl/image/logos/NGI0_tag.svg" alt="NGI Zero Logo" width="20%" />](https://nlnet.nl/core)
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
extern crate cc;
|
||||||
|
|
||||||
|
use std::{env, fs};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _crate_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
|
||||||
|
let target = env::var("TARGET").unwrap();
|
||||||
|
|
||||||
|
println!("cargo:rerun-if-changed=src/c");
|
||||||
|
|
||||||
|
// The Redoxer toolchain and some upstream nightlies keep the older
|
||||||
|
// `VaList<'a>` ABI for `extern "C" fn(...)` parameters, while others
|
||||||
|
// pass `VaListImpl<'f>` and require `.as_va_list()` to obtain
|
||||||
|
// `VaList<'_, '_>`. This is a host-compiler property, so probe
|
||||||
|
// directly with the host rustc (avoiding autocfg's target probing).
|
||||||
|
println!("cargo:rustc-check-cfg=cfg(relibc_valist_impl)");
|
||||||
|
let rustc = env::var("RUSTC").unwrap_or_else(|_| "rustc".to_string());
|
||||||
|
let out_dir = env::var("OUT_DIR").unwrap_or_else(|_| "/tmp".to_string());
|
||||||
|
let probe_file = std::path::Path::new(&out_dir).join("relibc_valist_probe.rs");
|
||||||
|
let probe_out = std::path::Path::new(&out_dir).join("librelibc_valist_probe.rlib");
|
||||||
|
std::fs::write(
|
||||||
|
&probe_file,
|
||||||
|
"#![feature(c_variadic)] pub fn _relibc_valist_probe(_: core::ffi::VaList<'_, '_>) {}",
|
||||||
|
)
|
||||||
|
.ok();
|
||||||
|
let probe_ok = std::process::Command::new(&rustc)
|
||||||
|
.args([
|
||||||
|
"--crate-type",
|
||||||
|
"lib",
|
||||||
|
"--edition",
|
||||||
|
"2024",
|
||||||
|
probe_file.to_str().unwrap(),
|
||||||
|
"-o",
|
||||||
|
probe_out.to_str().unwrap(),
|
||||||
|
])
|
||||||
|
.status()
|
||||||
|
.ok()
|
||||||
|
.map_or(false, |s| s.success());
|
||||||
|
if probe_ok {
|
||||||
|
println!("cargo:rustc-cfg=relibc_valist_impl");
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut cc_builder = &mut cc::Build::new();
|
||||||
|
|
||||||
|
cc_builder = cc_builder.flag("-nostdinc").flag("-nostdlib");
|
||||||
|
|
||||||
|
if target.starts_with("aarch64") {
|
||||||
|
cc_builder = cc_builder.flag("-mno-outline-atomics")
|
||||||
|
}
|
||||||
|
|
||||||
|
cc_builder
|
||||||
|
.flag("-fno-stack-protector")
|
||||||
|
.flag("-Wno-expansion-to-defined")
|
||||||
|
.files(
|
||||||
|
fs::read_dir("src/c")
|
||||||
|
.expect("src/c directory missing")
|
||||||
|
.map(|res| res.expect("read_dir error").path()),
|
||||||
|
)
|
||||||
|
.compile("relibc_c");
|
||||||
|
|
||||||
|
println!("cargo:rustc-link-lib=static=relibc_c");
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
# needs a leading newline
|
||||||
|
[defines]
|
||||||
|
"target_os=redox" = "__redox__"
|
||||||
|
"target_os=linux" = "__linux__"
|
||||||
|
"target_pointer_width=64" = "__LP64__"
|
||||||
|
"target_pointer_width=32" = "__ILP32__"
|
||||||
|
"target_arch=x86" = "__i386__"
|
||||||
|
"target_arch=x86_64" = "__x86_64__"
|
||||||
|
"target_arch=aarch64" = "__aarch64__"
|
||||||
|
# This is not exact. It should be `defined(__riscv) && defined(__LP64__)`, or `defined(__riscv) && __riscv_xlen==64`
|
||||||
|
# This will do however, as long as we only support riscv64 and not riscv32
|
||||||
|
"target_arch=riscv64" = "__riscv"
|
||||||
|
|
||||||
|
# XXX: silences a warning
|
||||||
|
"feature = no_std" = "__relibc__"
|
||||||
|
|
||||||
|
# Ensure attributes are passed down from Rust
|
||||||
|
# <features.h> must be included where attributes are used in relibc
|
||||||
|
[fn]
|
||||||
|
must_use = "__nodiscard"
|
||||||
|
deprecated = "__deprecated"
|
||||||
|
deprecated_with_note = "__deprecatedNote({})"
|
||||||
|
no_return = "__noreturn"
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
RED='\033[1;38;5;196m'
|
||||||
|
GREEN='\033[1;38;5;46m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
show_help() {
|
||||||
|
echo "Usage: $(basename "$0") [OPTIONS]"
|
||||||
|
echo ""
|
||||||
|
echo "Description:"
|
||||||
|
echo " Wrapper for Makefile / Cargo to run checks or tests on Redox OS targets."
|
||||||
|
echo ""
|
||||||
|
echo "Options:"
|
||||||
|
echo " --test Run 'make test' instead of 'make all'"
|
||||||
|
echo " --test= Run single 'make test'"
|
||||||
|
echo " --cargo Run 'cargo check' / 'cargo test' instead"
|
||||||
|
echo " (note: cargo test is currently not maintained for relibc)"
|
||||||
|
echo " --host Run the command on host (linux) target"
|
||||||
|
echo " --all-target Run the command on all supported Redox architectures"
|
||||||
|
echo " --target=<target> Override the target architecture (e.g., i586-unknown-redox)"
|
||||||
|
echo " --arch=<arch> Override the target architecture using arch (e.g., i586)"
|
||||||
|
echo " --help Show this help message"
|
||||||
|
echo ""
|
||||||
|
echo "Supported Targets:"
|
||||||
|
for t in "${SUPPORTED_TARGETS[@]}"; do
|
||||||
|
echo " - $t"
|
||||||
|
done
|
||||||
|
echo " - $(uname -m)-unknown-linux-gnu"
|
||||||
|
echo ""
|
||||||
|
echo "Environment:"
|
||||||
|
echo " TARGET Sets the default target (overridden by --target)"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ! command -v cbindgen &> /dev/null; then
|
||||||
|
echo "Error: 'cbindgen' CLI not found."
|
||||||
|
echo "Please install it: cargo install cbindgen"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
SUPPORTED_TARGETS=(
|
||||||
|
"x86_64-unknown-redox"
|
||||||
|
"i586-unknown-redox"
|
||||||
|
"aarch64-unknown-redox"
|
||||||
|
"riscv64gc-unknown-redox"
|
||||||
|
)
|
||||||
|
|
||||||
|
CURRENT_TARGET="${TARGET:-x86_64-unknown-redox}"
|
||||||
|
CHECK_ALL=false
|
||||||
|
CMD_ACTION="make"
|
||||||
|
CARGO_ACTION="check"
|
||||||
|
MAKE_ACTION="all"
|
||||||
|
TEST_BIN=""
|
||||||
|
IS_HOST=0
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--all-target)
|
||||||
|
CHECK_ALL=true
|
||||||
|
;;
|
||||||
|
--test)
|
||||||
|
MAKE_ACTION="test"
|
||||||
|
CARGO_ACTION="test"
|
||||||
|
;;
|
||||||
|
--test=*)
|
||||||
|
TEST_BIN="${1#*=}"
|
||||||
|
MAKE_ACTION="test-once"
|
||||||
|
;;
|
||||||
|
--cargo)
|
||||||
|
CMD_ACTION="cargo"
|
||||||
|
;;
|
||||||
|
--host)
|
||||||
|
CURRENT_TARGET="$(uname -m)-unknown-linux-gnu"
|
||||||
|
IS_HOST=1
|
||||||
|
;;
|
||||||
|
--target=*)
|
||||||
|
CURRENT_TARGET="${1#*=}"
|
||||||
|
;;
|
||||||
|
--arch=*)
|
||||||
|
CURRENT_TARGET="${1#*=}-unknown-redox"
|
||||||
|
;;
|
||||||
|
--help)
|
||||||
|
show_help
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo -e "${RED}Error: Unknown option '$1'${NC}"
|
||||||
|
show_help
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$IS_HOST" -eq 0 ]; then
|
||||||
|
if ! command -v redoxer &> /dev/null; then
|
||||||
|
echo "Error: 'redoxer' CLI not found."
|
||||||
|
echo "Please install it: cargo install redoxer"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
run_redoxer() {
|
||||||
|
export TARGET=$1
|
||||||
|
REDOXER_ENV="redoxer env"
|
||||||
|
if [ "$IS_HOST" -eq 0 ]; then
|
||||||
|
redoxer toolchain || { echo -e "${RED}Fail: redoxer toolchain for: $target.${NC}" && exit 1; }
|
||||||
|
export CARGO_TEST="redoxer"
|
||||||
|
export TEST_RUNNER="redoxer exec --folder ../../sysroot/$TARGET/:/usr --folder . --"
|
||||||
|
# TODO: Identify hang issue with pthread/barrier and pthread/once tests in multi core to get rid of this limit
|
||||||
|
export REDOXER_QEMU_ARGS="-smp 1"
|
||||||
|
|
||||||
|
MAKE_ACTION="$MAKE_ACTION IS_REDOX=1"
|
||||||
|
else
|
||||||
|
REDOXER_ENV=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$TEST_BIN" != "" ]; then
|
||||||
|
if [ "$IS_HOST" -eq 0 ]; then
|
||||||
|
MAKE_ACTION="$MAKE_ACTION TESTBIN=bins_dynamic/$TEST_BIN"
|
||||||
|
else
|
||||||
|
MAKE_ACTION="$MAKE_ACTION TESTBIN=bins_static/$TEST_BIN"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$CMD_ACTION" == "make" ]; then
|
||||||
|
CMD_OPT="-j $(nproc) $MAKE_ACTION"
|
||||||
|
else
|
||||||
|
CMD_OPT="$CARGO_ACTION"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "----------------------------------------"
|
||||||
|
echo "Running $REDOXER_ENV $CMD_ACTION $CMD_OPT for: $TARGET"
|
||||||
|
|
||||||
|
if $REDOXER_ENV $CMD_ACTION $CMD_OPT; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo -e "${RED}Fail: $CMD_ACTION $CMD_OPT for $TARGET failed.${NC}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$CHECK_ALL" = true ]; then
|
||||||
|
echo "Running $CMD_ACTION for all supported Redox targets..."
|
||||||
|
|
||||||
|
has_error=false
|
||||||
|
|
||||||
|
for target in "${SUPPORTED_TARGETS[@]}"; do
|
||||||
|
if ! run_redoxer "$target"; then
|
||||||
|
has_error=true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "----------------------------------------"
|
||||||
|
if [ "$has_error" = true ]; then
|
||||||
|
echo -e "${RED}Summary: One or more targets failed.${NC}"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}Summary: All targets passed!${NC}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if run_redoxer "$CURRENT_TARGET"; then
|
||||||
|
echo -e "${GREEN}Success: $CARGO_ACTION for $CURRENT_TARGET passed.${NC}"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
ifndef TARGET
|
||||||
|
export TARGET:=$(shell rustc -Z unstable-options --print target-spec-json | grep llvm-target | cut -d '"' -f4)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(TARGET),aarch64-unknown-linux-gnu)
|
||||||
|
export CC=aarch64-linux-gnu-gcc
|
||||||
|
export LD=aarch64-linux-gnu-ld
|
||||||
|
export AR=aarch64-linux-gnu-ar
|
||||||
|
export NM=aarch64-linux-gnu-nm
|
||||||
|
export OBJCOPY=aarch64-linux-gnu-objcopy
|
||||||
|
export CPPFLAGS=
|
||||||
|
LD_SO_PATH=lib/ld.so.1
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(TARGET),aarch64-unknown-redox)
|
||||||
|
export CC=aarch64-unknown-redox-gcc
|
||||||
|
export LD=aarch64-unknown-redox-ld
|
||||||
|
export AR=aarch64-unknown-redox-ar
|
||||||
|
export NM=aarch64-unknown-redox-nm
|
||||||
|
export OBJCOPY=aarch64-unknown-redox-objcopy
|
||||||
|
export CPPFLAGS=
|
||||||
|
LD_SO_PATH=lib/ld.so.1
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(TARGET),i586-unknown-redox)
|
||||||
|
export CC=i586-unknown-redox-gcc
|
||||||
|
export LD=i586-unknown-redox-ld
|
||||||
|
export AR=i586-unknown-redox-ar
|
||||||
|
export NM=i586-unknown-redox-nm
|
||||||
|
export OBJCOPY=i586-unknown-redox-objcopy
|
||||||
|
export CPPFLAGS=
|
||||||
|
LD_SO_PATH=lib/libc.so.1
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(TARGET),i686-unknown-redox)
|
||||||
|
export CC=i686-unknown-redox-gcc
|
||||||
|
export LD=i686-unknown-redox-ld
|
||||||
|
export AR=i686-unknown-redox-ar
|
||||||
|
export NM=i686-unknown-redox-nm
|
||||||
|
export OBJCOPY=i686-unknown-redox-objcopy
|
||||||
|
export CPPFLAGS=
|
||||||
|
LD_SO_PATH=lib/libc.so.1
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(TARGET),x86_64-unknown-linux-gnu)
|
||||||
|
export CC=x86_64-linux-gnu-gcc
|
||||||
|
export LD=x86_64-linux-gnu-ld
|
||||||
|
export AR=x86_64-linux-gnu-ar
|
||||||
|
export NM=x86_64-linux-gnu-nm
|
||||||
|
export OBJCOPY=objcopy
|
||||||
|
export CPPFLAGS=
|
||||||
|
LD_SO_PATH=lib/ld64.so.1
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(TARGET),x86_64-unknown-redox)
|
||||||
|
export CC=x86_64-unknown-redox-gcc
|
||||||
|
export LD=x86_64-unknown-redox-ld
|
||||||
|
export AR=x86_64-unknown-redox-ar
|
||||||
|
export NM=x86_64-unknown-redox-nm
|
||||||
|
export OBJCOPY=x86_64-unknown-redox-objcopy
|
||||||
|
export CPPFLAGS=
|
||||||
|
LD_SO_PATH=lib/ld64.so.1
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(TARGET),riscv64gc-unknown-redox)
|
||||||
|
export CC=riscv64-unknown-redox-gcc
|
||||||
|
export LD=riscv64-unknown-redox-ld
|
||||||
|
export AR=riscv64-unknown-redox-ar
|
||||||
|
export NM=riscv64-unknown-redox-nm
|
||||||
|
export OBJCOPY=riscv64-unknown-redox-objcopy
|
||||||
|
export CPPFLAGS=-march=rv64gc -mabi=lp64d
|
||||||
|
LD_SO_PATH=lib/ld.so.1
|
||||||
|
endif
|
||||||
+117
@@ -0,0 +1,117 @@
|
|||||||
|
name: CI
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
name: Test
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: ubuntu-latest
|
||||||
|
rust: stable
|
||||||
|
- os: ubuntu-latest
|
||||||
|
rust: beta
|
||||||
|
- os: ubuntu-latest
|
||||||
|
rust: nightly
|
||||||
|
- os: macos-latest
|
||||||
|
rust: stable
|
||||||
|
- os: windows-latest
|
||||||
|
rust: stable
|
||||||
|
- os: ubuntu-latest
|
||||||
|
rust: stable
|
||||||
|
target: wasm32-wasip1
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }}
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
# Configure cross-builds by adding the rustup target and configuring future
|
||||||
|
# cargo invocations.
|
||||||
|
- run: |
|
||||||
|
rustup target add ${{ matrix.target }}
|
||||||
|
echo CARGO_BUILD_TARGET=${{ matrix.target }} >> $GITHUB_ENV
|
||||||
|
if: matrix.target != ''
|
||||||
|
|
||||||
|
# For wasm install wasmtime as a test runner and configure it with Cargo.
|
||||||
|
- name: Setup `wasmtime`
|
||||||
|
uses: bytecodealliance/actions/wasmtime/setup@v1
|
||||||
|
if: matrix.target == 'wasm32-wasip1'
|
||||||
|
- run: echo CARGO_TARGET_WASM32_WASIP1_RUNNER=wasmtime >> $GITHUB_ENV
|
||||||
|
if: matrix.target == 'wasm32-wasip1'
|
||||||
|
|
||||||
|
- run: cargo test
|
||||||
|
- run: cargo test --features debug
|
||||||
|
- run: cargo test --features global
|
||||||
|
- run: cargo test --release
|
||||||
|
env:
|
||||||
|
CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS: true
|
||||||
|
- run: cargo test --release
|
||||||
|
env:
|
||||||
|
CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS: false
|
||||||
|
- run: cargo test --features debug --release
|
||||||
|
env:
|
||||||
|
CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS: true
|
||||||
|
- run: RUSTFLAGS='--cfg test_lots' cargo test --release
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS: true
|
||||||
|
- run: RUSTFLAGS='--cfg test_lots' cargo test --release --features debug
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS: true
|
||||||
|
|
||||||
|
rustfmt:
|
||||||
|
name: Rustfmt
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install Rust
|
||||||
|
run: rustup update stable && rustup default stable && rustup component add rustfmt
|
||||||
|
- run: cargo fmt -- --check
|
||||||
|
|
||||||
|
wasm:
|
||||||
|
name: WebAssembly
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install Rust
|
||||||
|
run: rustup update stable && rustup default stable && rustup target add wasm32-unknown-unknown
|
||||||
|
- run: cargo build --target wasm32-unknown-unknown
|
||||||
|
- run: cargo build --target wasm32-unknown-unknown --release
|
||||||
|
|
||||||
|
external-platform:
|
||||||
|
name: external-platform
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install Rust
|
||||||
|
run: rustup update stable && rustup default stable && rustup target add x86_64-fortanix-unknown-sgx
|
||||||
|
- run: cargo build --target x86_64-fortanix-unknown-sgx
|
||||||
|
|
||||||
|
fuzz:
|
||||||
|
name: Build Fuzzers
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install Rust
|
||||||
|
run: rustup update nightly && rustup default nightly
|
||||||
|
- run: cargo install cargo-fuzz
|
||||||
|
- run: cargo fuzz build --dev
|
||||||
|
|
||||||
|
miri:
|
||||||
|
name: Miri
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install Miri
|
||||||
|
run: |
|
||||||
|
rustup toolchain install nightly --component miri
|
||||||
|
rustup override set nightly
|
||||||
|
cargo miri setup
|
||||||
|
- name: Test with Miri Stack Borrows
|
||||||
|
run: cargo miri test
|
||||||
|
- name: Test with Miri Tree Borrows
|
||||||
|
run: cargo miri test
|
||||||
|
env:
|
||||||
|
MIRIFLAGS: -Zmiri-tree-borrows
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
/target/
|
||||||
|
**/*.rs.bk
|
||||||
|
Cargo.lock
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
[package]
|
||||||
|
name = "dlmalloc"
|
||||||
|
version = "0.2.8"
|
||||||
|
authors = ["Alex Crichton <alex@alexcrichton.com>"]
|
||||||
|
license = "MIT/Apache-2.0"
|
||||||
|
readme = "README.md"
|
||||||
|
repository = "https://github.com/alexcrichton/dlmalloc-rs"
|
||||||
|
homepage = "https://github.com/alexcrichton/dlmalloc-rs"
|
||||||
|
documentation = "https://docs.rs/dlmalloc"
|
||||||
|
description = """
|
||||||
|
A Rust port of the dlmalloc allocator
|
||||||
|
"""
|
||||||
|
edition.workspace = true
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
members = ['fuzz']
|
||||||
|
|
||||||
|
[workspace.package]
|
||||||
|
edition = '2021'
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
features = ['global']
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
doctest = false
|
||||||
|
|
||||||
|
[target.'cfg(all(unix, not(target_arch = "wasm32")))'.dependencies]
|
||||||
|
libc = { version = "0.2", default-features = false, optional = true }
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
# For more information on these dependencies see rust-lang/rust's
|
||||||
|
# `src/tools/rustc-std-workspace` folder
|
||||||
|
core = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-core' }
|
||||||
|
compiler_builtins = { version = '0.1.0', optional = true }
|
||||||
|
cfg-if = "1.0"
|
||||||
|
|
||||||
|
[target.'cfg(target_os = "windows")'.dependencies.windows-sys]
|
||||||
|
version = ">=0.52.0, <=0.59.*"
|
||||||
|
features = [
|
||||||
|
"Win32_Foundation",
|
||||||
|
"Win32_System_Memory",
|
||||||
|
"Win32_System_Threading",
|
||||||
|
"Win32_System_SystemInformation",
|
||||||
|
]
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
arbitrary = "1.3.2"
|
||||||
|
rand = { version = "0.8", features = ['small_rng'] }
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
debug-assertions = true
|
||||||
|
|
||||||
|
[features]
|
||||||
|
# Enable implementations of the `GlobalAlloc` standard library API, exporting a
|
||||||
|
# new `GlobalDlmalloc` as well which implements this trait.
|
||||||
|
global = ["system", "rust_api"]
|
||||||
|
|
||||||
|
# Enable very expensive debug checks in this crate
|
||||||
|
debug = []
|
||||||
|
|
||||||
|
# Enables OS APIs based on the current target, can be implemented manually
|
||||||
|
# otherwise.
|
||||||
|
system = ["libc"]
|
||||||
|
|
||||||
|
rustc-dep-of-std = ['core', 'compiler_builtins/rustc-dep-of-std']
|
||||||
|
|
||||||
|
c_api = []
|
||||||
|
rust_api = []
|
||||||
|
|
||||||
|
default = ["global", "rust_api"]
|
||||||
@@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
Copyright (c) 2014 Alex Crichton
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any
|
||||||
|
person obtaining a copy of this software and associated
|
||||||
|
documentation files (the "Software"), to deal in the
|
||||||
|
Software without restriction, including without
|
||||||
|
limitation the rights to use, copy, modify, merge,
|
||||||
|
publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software
|
||||||
|
is furnished to do so, subject to the following
|
||||||
|
conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice
|
||||||
|
shall be included in all copies or substantial portions
|
||||||
|
of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||||
|
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||||
|
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||||
|
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||||
|
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# dlmalloc-rs
|
||||||
|
|
||||||
|
A port of [dlmalloc] to Rust.
|
||||||
|
|
||||||
|
[Documentation](https://docs.rs/dlmalloc)
|
||||||
|
|
||||||
|
[dlmalloc]: https://gee.cs.oswego.edu/dl/html/malloc.html
|
||||||
|
|
||||||
|
## Why dlmalloc?
|
||||||
|
|
||||||
|
This crate is a port of [dlmalloc] to Rust, and doesn't rely on C. The primary
|
||||||
|
purpose of this crate is to serve as the default allocator for Rust on the
|
||||||
|
`wasm32-unknown-unknown` target. At the time this was written the wasm target
|
||||||
|
didn't support C code, so it was required to have a Rust-only solution.
|
||||||
|
|
||||||
|
This allocator is not the most performant by a longshot. It is primarily, I
|
||||||
|
think, intended for being easy to port and easy to learn. I didn't dive too deep
|
||||||
|
into the implementation when writing it, it's just a straight port of the C
|
||||||
|
version.
|
||||||
|
|
||||||
|
It's unlikely that Rust code needs to worry/interact with this allocator in
|
||||||
|
general. Most of the time you'll be manually switching to a different allocator
|
||||||
|
:)
|
||||||
|
|
||||||
|
# License
|
||||||
|
|
||||||
|
This project is licensed under either of
|
||||||
|
|
||||||
|
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
||||||
|
http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
at your option.
|
||||||
|
|
||||||
|
### Contribution
|
||||||
|
|
||||||
|
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||||
|
for inclusion in this project by you, as defined in the Apache-2.0 license,
|
||||||
|
shall be dual licensed as above, without any additional terms or conditions.
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
corpus
|
||||||
|
artifacts
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
[package]
|
||||||
|
name = "dlmalloc-fuzz"
|
||||||
|
version = "0.0.1"
|
||||||
|
publish = false
|
||||||
|
edition.workspace = true
|
||||||
|
|
||||||
|
[package.metadata]
|
||||||
|
cargo-fuzz = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
arbitrary = "1.3.2"
|
||||||
|
dlmalloc = { path = '..' }
|
||||||
|
libfuzzer-sys = "0.4.7"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "alloc"
|
||||||
|
path = "fuzz_targets/alloc.rs"
|
||||||
|
test = false
|
||||||
|
bench = false
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use arbitrary::Unstructured;
|
||||||
|
use libfuzzer_sys::fuzz_target;
|
||||||
|
|
||||||
|
fuzz_target!(|bytes: &[u8]| {
|
||||||
|
let _ = dlmalloc_fuzz::run(&mut Unstructured::new(bytes));
|
||||||
|
});
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
use arbitrary::{Result, Unstructured};
|
||||||
|
use dlmalloc::Dlmalloc;
|
||||||
|
use std::cmp;
|
||||||
|
|
||||||
|
const MAX_ALLOCATED: usize = 100 << 20; // 100 MB
|
||||||
|
|
||||||
|
pub fn run(u: &mut Unstructured<'_>) -> Result<()> {
|
||||||
|
let mut a = Dlmalloc::new();
|
||||||
|
let mut ptrs = Vec::new();
|
||||||
|
let mut allocated = 0;
|
||||||
|
unsafe {
|
||||||
|
while u.arbitrary()? {
|
||||||
|
// If there are pointers to free then have a chance of deallocating
|
||||||
|
// a pointer. Try not to deallocate things until there's a "large"
|
||||||
|
// working set but afterwards give it a 50/50 chance of allocating
|
||||||
|
// or deallocating.
|
||||||
|
let free = match ptrs.len() {
|
||||||
|
0 => false,
|
||||||
|
0..=10_000 => u.ratio(1, 3)?,
|
||||||
|
_ => u.arbitrary()?,
|
||||||
|
};
|
||||||
|
if free {
|
||||||
|
let idx = u.choose_index(ptrs.len())?;
|
||||||
|
let (ptr, size, align) = ptrs.swap_remove(idx);
|
||||||
|
allocated -= size;
|
||||||
|
a.free(ptr, size, align);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1/100 chance of reallocating a pointer to a different size.
|
||||||
|
if ptrs.len() > 0 && u.ratio(1, 100)? {
|
||||||
|
let idx = u.choose_index(ptrs.len())?;
|
||||||
|
let (ptr, size, align) = ptrs.swap_remove(idx);
|
||||||
|
|
||||||
|
// Arbitrarily choose whether to make this allocation either
|
||||||
|
// twice as large or half as small.
|
||||||
|
let new_size = if u.arbitrary()? {
|
||||||
|
u.int_in_range(size..=size * 2)?
|
||||||
|
} else if size > 10 {
|
||||||
|
u.int_in_range(size / 2..=size)?
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if allocated + new_size - size > MAX_ALLOCATED {
|
||||||
|
ptrs.push((ptr, size, align));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
allocated -= size;
|
||||||
|
allocated += new_size;
|
||||||
|
|
||||||
|
// Perform the `realloc` and assert that all bytes were copied.
|
||||||
|
let mut tmp = Vec::new();
|
||||||
|
for i in 0..cmp::min(size, new_size) {
|
||||||
|
tmp.push(*ptr.offset(i as isize));
|
||||||
|
}
|
||||||
|
let ptr = a.realloc(ptr, size, align, new_size);
|
||||||
|
assert!(!ptr.is_null());
|
||||||
|
for (i, byte) in tmp.iter().enumerate() {
|
||||||
|
assert_eq!(*byte, *ptr.offset(i as isize));
|
||||||
|
}
|
||||||
|
ptrs.push((ptr, new_size, align));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aribtrarily choose a size to allocate as well as an alignment.
|
||||||
|
// Enable small sizes with standard alignment happening a fair bit.
|
||||||
|
let size = if u.arbitrary()? {
|
||||||
|
u.int_in_range(1..=128)?
|
||||||
|
} else {
|
||||||
|
u.int_in_range(1..=128 * 1024)?
|
||||||
|
};
|
||||||
|
let align = if u.ratio(1, 10)? {
|
||||||
|
1 << u.int_in_range(3..=8)?
|
||||||
|
} else {
|
||||||
|
8
|
||||||
|
};
|
||||||
|
|
||||||
|
if size + allocated > MAX_ALLOCATED {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
allocated += size;
|
||||||
|
|
||||||
|
// Choose arbitrarily between a zero-allocated chunk and a normal
|
||||||
|
// allocated chunk.
|
||||||
|
let zero = u.ratio(1, 50)?;
|
||||||
|
let ptr = if zero {
|
||||||
|
a.calloc(size, align)
|
||||||
|
} else {
|
||||||
|
a.malloc(size, align)
|
||||||
|
};
|
||||||
|
for i in 0..size {
|
||||||
|
if zero {
|
||||||
|
assert_eq!(*ptr.offset(i as isize), 0);
|
||||||
|
}
|
||||||
|
*ptr.offset(i as isize) = 0xce;
|
||||||
|
}
|
||||||
|
ptrs.push((ptr, size, align));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deallocate everythign when we're done.
|
||||||
|
for (ptr, size, align) in ptrs {
|
||||||
|
a.free(ptr, size, align);
|
||||||
|
}
|
||||||
|
|
||||||
|
a.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,42 @@
|
|||||||
|
use crate::Allocator;
|
||||||
|
use core::ptr;
|
||||||
|
|
||||||
|
pub struct System {
|
||||||
|
_priv: (),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl System {
|
||||||
|
pub const fn new() -> System {
|
||||||
|
System { _priv: () }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Allocator for System {
|
||||||
|
fn alloc(&self, _size: usize) -> (*mut u8, usize, u32) {
|
||||||
|
(ptr::null_mut(), 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remap(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 {
|
||||||
|
ptr::null_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn free_part(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn free(&self, _ptr: *mut u8, _size: usize) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_release_part(&self, _flags: u32) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn allocates_zeros(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn page_size(&self) -> usize {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
use crate::Dlmalloc;
|
||||||
|
use core::alloc::{GlobalAlloc, Layout};
|
||||||
|
use core::ptr;
|
||||||
|
|
||||||
|
pub use crate::sys::enable_alloc_after_fork;
|
||||||
|
|
||||||
|
/// An instance of a "global allocator" backed by `Dlmalloc`
|
||||||
|
///
|
||||||
|
/// This API requires the `global` feature is activated, and this type
|
||||||
|
/// implements the `GlobalAlloc` trait in the standard library.
|
||||||
|
pub struct GlobalDlmalloc;
|
||||||
|
|
||||||
|
static mut DLMALLOC: Dlmalloc = Dlmalloc::new();
|
||||||
|
|
||||||
|
unsafe impl GlobalAlloc for GlobalDlmalloc {
|
||||||
|
#[inline]
|
||||||
|
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||||
|
let _guard = lock();
|
||||||
|
let dlmalloc = ptr::addr_of_mut!(DLMALLOC);
|
||||||
|
(*dlmalloc).malloc(layout.size(), layout.align())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||||
|
let _guard = lock();
|
||||||
|
let dlmalloc = ptr::addr_of_mut!(DLMALLOC);
|
||||||
|
(*dlmalloc).free(ptr, layout.size(), layout.align())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
|
||||||
|
let _guard = lock();
|
||||||
|
let dlmalloc = ptr::addr_of_mut!(DLMALLOC);
|
||||||
|
(*dlmalloc).calloc(layout.size(), layout.align())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
|
||||||
|
let _guard = lock();
|
||||||
|
let dlmalloc = ptr::addr_of_mut!(DLMALLOC);
|
||||||
|
(*dlmalloc).realloc(ptr, layout.size(), layout.align(), new_size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn lock() -> impl Drop {
|
||||||
|
crate::sys::acquire_global_lock();
|
||||||
|
|
||||||
|
struct Guard;
|
||||||
|
impl Drop for Guard {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
crate::sys::release_global_lock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Guard
|
||||||
|
}
|
||||||
@@ -0,0 +1,230 @@
|
|||||||
|
//! A Rust port of the `dlmalloc` allocator.
|
||||||
|
//!
|
||||||
|
//! The `dlmalloc` allocator is described at
|
||||||
|
//! <https://gee.cs.oswego.edu/dl/html/malloc.html> and this Rust crate is a straight
|
||||||
|
//! port of the C code for the allocator into Rust. The implementation is
|
||||||
|
//! wrapped up in a `Dlmalloc` type and has support for Linux, OSX, and Wasm
|
||||||
|
//! currently.
|
||||||
|
//!
|
||||||
|
//! The primary purpose of this crate is that it serves as the default memory
|
||||||
|
//! allocator for the `wasm32-unknown-unknown` target in the standard library.
|
||||||
|
//! Support for other platforms is largely untested and unused, but is used when
|
||||||
|
//! testing this crate.
|
||||||
|
|
||||||
|
#![allow(dead_code)]
|
||||||
|
#![no_std]
|
||||||
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
|
#[cfg(feature = "rust_api")]
|
||||||
|
use core::{cmp, ptr};
|
||||||
|
|
||||||
|
#[cfg(feature = "system")]
|
||||||
|
use sys::System;
|
||||||
|
|
||||||
|
#[cfg(feature = "global")]
|
||||||
|
pub use self::global::{enable_alloc_after_fork, GlobalDlmalloc};
|
||||||
|
|
||||||
|
mod dlmalloc;
|
||||||
|
|
||||||
|
#[cfg(feature = "c_api")]
|
||||||
|
pub use dlmalloc::Dlmalloc as DlmallocCApi;
|
||||||
|
|
||||||
|
#[cfg(feature = "global")]
|
||||||
|
mod global;
|
||||||
|
|
||||||
|
/// In order for this crate to efficiently manage memory, it needs a way to communicate with the
|
||||||
|
/// underlying platform. This `Allocator` trait provides an interface for this communication.
|
||||||
|
pub unsafe trait Allocator: Send {
|
||||||
|
/// Allocates system memory region of at least `size` bytes
|
||||||
|
/// Returns a triple of `(base, size, flags)` where `base` is a pointer to the beginning of the
|
||||||
|
/// allocated memory region. `size` is the actual size of the region while `flags` specifies
|
||||||
|
/// properties of the allocated region. If `EXTERN_BIT` (bit 0) set in flags, then we did not
|
||||||
|
/// allocate this segment and so should not try to deallocate or merge with others.
|
||||||
|
/// This function can return a `std::ptr::null_mut()` when allocation fails (other values of
|
||||||
|
/// the triple will be ignored).
|
||||||
|
fn alloc(&self, size: usize) -> (*mut u8, usize, u32);
|
||||||
|
|
||||||
|
/// Remaps system memory region at `ptr` with size `oldsize` to a potential new location with
|
||||||
|
/// size `newsize`. `can_move` indicates if the location is allowed to move to a completely new
|
||||||
|
/// location, or that it is only allowed to change in size. Returns a pointer to the new
|
||||||
|
/// location in memory.
|
||||||
|
/// This function can return a `std::ptr::null_mut()` to signal an error.
|
||||||
|
fn remap(&self, ptr: *mut u8, oldsize: usize, newsize: usize, can_move: bool) -> *mut u8;
|
||||||
|
|
||||||
|
/// Frees a part of a memory chunk. The original memory chunk starts at `ptr` with size `oldsize`
|
||||||
|
/// and is turned into a memory region starting at the same address but with `newsize` bytes.
|
||||||
|
/// Returns `true` iff the access memory region could be freed.
|
||||||
|
fn free_part(&self, ptr: *mut u8, oldsize: usize, newsize: usize) -> bool;
|
||||||
|
|
||||||
|
/// Frees an entire memory region. Returns `true` iff the operation succeeded. When `false` is
|
||||||
|
/// returned, the `dlmalloc` may re-use the location on future allocation requests
|
||||||
|
fn free(&self, ptr: *mut u8, size: usize) -> bool;
|
||||||
|
|
||||||
|
/// Indicates if the system can release a part of memory. For the `flags` argument, see
|
||||||
|
/// `Allocator::alloc`
|
||||||
|
fn can_release_part(&self, flags: u32) -> bool;
|
||||||
|
|
||||||
|
/// Indicates whether newly allocated regions contain zeros.
|
||||||
|
fn allocates_zeros(&self) -> bool;
|
||||||
|
|
||||||
|
/// Returns the page size. Must be a power of two
|
||||||
|
fn page_size(&self) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An allocator instance
|
||||||
|
///
|
||||||
|
/// Instances of this type are used to allocate blocks of memory. For best
|
||||||
|
/// results only use one of these. Currently doesn't implement `Drop` to release
|
||||||
|
/// lingering memory back to the OS. That may happen eventually though!
|
||||||
|
#[cfg(feature = "rust_api")]
|
||||||
|
pub struct Dlmalloc<
|
||||||
|
#[cfg(feature = "system")]
|
||||||
|
A = System,
|
||||||
|
#[cfg(not(feature = "system"))]
|
||||||
|
A,
|
||||||
|
>(dlmalloc::Dlmalloc<A>);
|
||||||
|
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(all(feature = "system", target_family = "wasm"))] {
|
||||||
|
#[path = "wasm.rs"]
|
||||||
|
mod sys;
|
||||||
|
} else if #[cfg(all(feature = "system", target_os = "windows"))] {
|
||||||
|
#[path = "windows.rs"]
|
||||||
|
mod sys;
|
||||||
|
} else if #[cfg(all(feature = "system", target_os = "xous"))] {
|
||||||
|
#[path = "xous.rs"]
|
||||||
|
mod sys;
|
||||||
|
} else if #[cfg(all(feature = "system", any(target_os = "linux", target_os = "macos", target_os = "redox")))] {
|
||||||
|
#[path = "unix.rs"]
|
||||||
|
mod sys;
|
||||||
|
} else {
|
||||||
|
#[path = "dummy.rs"]
|
||||||
|
mod sys;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "system")]
|
||||||
|
#[cfg(feature = "rust_api")]
|
||||||
|
impl Dlmalloc<System> {
|
||||||
|
/// Creates a new instance of an allocator
|
||||||
|
pub const fn new() -> Dlmalloc<System> {
|
||||||
|
Dlmalloc(dlmalloc::Dlmalloc::new(System::new()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "rust_api")]
|
||||||
|
impl<A> Dlmalloc<A> {
|
||||||
|
/// Creates a new instance of an allocator
|
||||||
|
pub const fn new_with_allocator(sys_allocator: A) -> Dlmalloc<A> {
|
||||||
|
Dlmalloc(dlmalloc::Dlmalloc::new(sys_allocator))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "rust_api")]
|
||||||
|
impl<A: Allocator> Dlmalloc<A> {
|
||||||
|
/// Allocates `size` bytes with `align` align.
|
||||||
|
///
|
||||||
|
/// Returns a null pointer if allocation fails. Returns a valid pointer
|
||||||
|
/// otherwise.
|
||||||
|
///
|
||||||
|
/// Safety and contracts are largely governed by the `GlobalAlloc::alloc`
|
||||||
|
/// method contracts.
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn malloc(&mut self, size: usize, align: usize) -> *mut u8 {
|
||||||
|
if align <= self.0.malloc_alignment() {
|
||||||
|
self.0.malloc(size)
|
||||||
|
} else {
|
||||||
|
self.0.memalign(align, size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same as `malloc`, except if the allocation succeeds it's guaranteed to
|
||||||
|
/// point to `size` bytes of zeros.
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn calloc(&mut self, size: usize, align: usize) -> *mut u8 {
|
||||||
|
let ptr = self.malloc(size, align);
|
||||||
|
if !ptr.is_null() && self.0.calloc_must_clear(ptr) {
|
||||||
|
ptr::write_bytes(ptr, 0, size);
|
||||||
|
}
|
||||||
|
ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deallocates a `ptr` with `size` and `align` as the previous request used
|
||||||
|
/// to allocate it.
|
||||||
|
///
|
||||||
|
/// Safety and contracts are largely governed by the `GlobalAlloc::dealloc`
|
||||||
|
/// method contracts.
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn free(&mut self, ptr: *mut u8, size: usize, align: usize) {
|
||||||
|
let _ = align;
|
||||||
|
self.0.validate_size(ptr, size);
|
||||||
|
self.0.free(ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reallocates `ptr`, a previous allocation with `old_size` and
|
||||||
|
/// `old_align`, to have `new_size` and the same alignment as before.
|
||||||
|
///
|
||||||
|
/// Returns a null pointer if the memory couldn't be reallocated, but `ptr`
|
||||||
|
/// is still valid. Returns a valid pointer and frees `ptr` if the request
|
||||||
|
/// is satisfied.
|
||||||
|
///
|
||||||
|
/// Safety and contracts are largely governed by the `GlobalAlloc::realloc`
|
||||||
|
/// method contracts.
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn realloc(
|
||||||
|
&mut self,
|
||||||
|
ptr: *mut u8,
|
||||||
|
old_size: usize,
|
||||||
|
old_align: usize,
|
||||||
|
new_size: usize,
|
||||||
|
) -> *mut u8 {
|
||||||
|
self.0.validate_size(ptr, old_size);
|
||||||
|
|
||||||
|
if old_align <= self.0.malloc_alignment() {
|
||||||
|
self.0.realloc(ptr, new_size)
|
||||||
|
} else {
|
||||||
|
let res = self.malloc(new_size, old_align);
|
||||||
|
if !res.is_null() {
|
||||||
|
let size = cmp::min(old_size, new_size);
|
||||||
|
ptr::copy_nonoverlapping(ptr, res, size);
|
||||||
|
self.free(ptr, old_size, old_align);
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If possible, gives memory back to the system if there is unused memory
|
||||||
|
/// at the high end of the malloc pool or in unused segments.
|
||||||
|
///
|
||||||
|
/// You can call this after freeing large blocks of memory to potentially
|
||||||
|
/// reduce the system-level memory requirements of a program. However, it
|
||||||
|
/// cannot guarantee to reduce memory. Under some allocation patterns, some
|
||||||
|
/// large free blocks of memory will be locked between two used chunks, so
|
||||||
|
/// they cannot be given back to the system.
|
||||||
|
///
|
||||||
|
/// The `pad` argument represents the amount of free trailing space to
|
||||||
|
/// leave untrimmed. If this argument is zero, only the minimum amount of
|
||||||
|
/// memory to maintain internal data structures will be left. Non-zero
|
||||||
|
/// arguments can be supplied to maintain enough trailing space to service
|
||||||
|
/// future expected allocations without having to re-obtain memory from the
|
||||||
|
/// system.
|
||||||
|
///
|
||||||
|
/// Returns `true` if it actually released any memory, else `false`.
|
||||||
|
pub unsafe fn trim(&mut self, pad: usize) -> bool {
|
||||||
|
self.0.trim(pad)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Releases all allocations in this allocator back to the system,
|
||||||
|
/// consuming self and preventing further use.
|
||||||
|
///
|
||||||
|
/// Returns the number of bytes released to the system.
|
||||||
|
pub unsafe fn destroy(self) -> usize {
|
||||||
|
self.0.destroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a reference the underlying [`Allocator`] that this `Dlmalloc` was
|
||||||
|
/// constructed with.
|
||||||
|
pub fn allocator(&self) -> &A {
|
||||||
|
self.0.allocator()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
use crate::Allocator;
|
||||||
|
use core::ptr;
|
||||||
|
|
||||||
|
/// System setting for Linux
|
||||||
|
pub struct System {
|
||||||
|
_priv: (),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl System {
|
||||||
|
pub const fn new() -> System {
|
||||||
|
System { _priv: () }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "global")]
|
||||||
|
static mut LOCK: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
unsafe impl Allocator for System {
|
||||||
|
fn alloc(&self, size: usize) -> (*mut u8, usize, u32) {
|
||||||
|
let addr = unsafe {
|
||||||
|
libc::mmap(
|
||||||
|
ptr::null_mut(),
|
||||||
|
size,
|
||||||
|
libc::PROT_WRITE | libc::PROT_READ,
|
||||||
|
libc::MAP_ANON | libc::MAP_PRIVATE,
|
||||||
|
-1,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if addr == libc::MAP_FAILED {
|
||||||
|
(ptr::null_mut(), 0, 0)
|
||||||
|
} else {
|
||||||
|
(addr.cast(), size, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
fn remap(&self, ptr: *mut u8, oldsize: usize, newsize: usize, can_move: bool) -> *mut u8 {
|
||||||
|
let flags = if can_move { libc::MREMAP_MAYMOVE } else { 0 };
|
||||||
|
let ptr = unsafe { libc::mremap(ptr.cast(), oldsize, newsize, flags) };
|
||||||
|
if ptr == libc::MAP_FAILED {
|
||||||
|
ptr::null_mut()
|
||||||
|
} else {
|
||||||
|
ptr.cast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "redox", target_os = "macos"))]
|
||||||
|
fn remap(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 {
|
||||||
|
ptr::null_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
fn free_part(&self, ptr: *mut u8, oldsize: usize, newsize: usize) -> bool {
|
||||||
|
unsafe {
|
||||||
|
let rc = libc::mremap(ptr.cast(), oldsize, newsize, 0);
|
||||||
|
if rc != libc::MAP_FAILED {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
libc::munmap(ptr.add(newsize).cast(), oldsize - newsize) == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "redox", target_os = "macos"))]
|
||||||
|
fn free_part(&self, ptr: *mut u8, oldsize: usize, newsize: usize) -> bool {
|
||||||
|
unsafe { libc::munmap(ptr.add(newsize).cast(), oldsize - newsize) == 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn free(&self, ptr: *mut u8, size: usize) -> bool {
|
||||||
|
unsafe { libc::munmap(ptr.cast(), size) == 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_release_part(&self, _flags: u32) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn allocates_zeros(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn page_size(&self) -> usize {
|
||||||
|
4096
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "global")]
|
||||||
|
pub fn acquire_global_lock() {
|
||||||
|
unsafe { assert_eq!(libc::pthread_mutex_lock(ptr::addr_of_mut!(LOCK)), 0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "global")]
|
||||||
|
pub fn release_global_lock() {
|
||||||
|
unsafe { assert_eq!(libc::pthread_mutex_unlock(ptr::addr_of_mut!(LOCK)), 0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "global")]
|
||||||
|
/// allows the allocator to remain unsable in the child process,
|
||||||
|
/// after a call to `fork(2)`
|
||||||
|
///
|
||||||
|
/// #Safety
|
||||||
|
///
|
||||||
|
/// if used, this function must be called,
|
||||||
|
/// before any allocations are made with the global allocator.
|
||||||
|
pub unsafe fn enable_alloc_after_fork() {
|
||||||
|
// atfork must only be called once, to avoid a deadlock,
|
||||||
|
// where the handler attempts to acquire the global lock twice
|
||||||
|
static mut FORK_PROTECTED: bool = false;
|
||||||
|
|
||||||
|
unsafe extern "C" fn _acquire_global_lock() {
|
||||||
|
acquire_global_lock()
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn _release_global_lock() {
|
||||||
|
release_global_lock()
|
||||||
|
}
|
||||||
|
|
||||||
|
acquire_global_lock();
|
||||||
|
// if a process forks,
|
||||||
|
// it will acquire the lock before any other thread,
|
||||||
|
// protecting it from deadlock,
|
||||||
|
// due to the child being created with only the calling thread.
|
||||||
|
if !FORK_PROTECTED {
|
||||||
|
libc::pthread_atfork(
|
||||||
|
Some(_acquire_global_lock),
|
||||||
|
Some(_release_global_lock),
|
||||||
|
Some(_release_global_lock),
|
||||||
|
);
|
||||||
|
FORK_PROTECTED = true;
|
||||||
|
}
|
||||||
|
release_global_lock();
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
use crate::Allocator;
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
use core::arch::wasm32 as wasm;
|
||||||
|
#[cfg(target_arch = "wasm64")]
|
||||||
|
use core::arch::wasm64 as wasm;
|
||||||
|
use core::ptr;
|
||||||
|
|
||||||
|
/// System setting for Wasm
|
||||||
|
pub struct System {
|
||||||
|
_priv: (),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl System {
|
||||||
|
pub const fn new() -> System {
|
||||||
|
System { _priv: () }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Allocator for System {
|
||||||
|
fn alloc(&self, size: usize) -> (*mut u8, usize, u32) {
|
||||||
|
let pages = size / self.page_size();
|
||||||
|
let prev = wasm::memory_grow(0, pages);
|
||||||
|
if prev == usize::max_value() {
|
||||||
|
return (ptr::null_mut(), 0, 0);
|
||||||
|
}
|
||||||
|
(
|
||||||
|
(prev * self.page_size()) as *mut u8,
|
||||||
|
pages * self.page_size(),
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remap(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 {
|
||||||
|
// TODO: I think this can be implemented near the end?
|
||||||
|
ptr::null_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn free_part(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn free(&self, _ptr: *mut u8, _size: usize) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_release_part(&self, _flags: u32) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn allocates_zeros(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn page_size(&self) -> usize {
|
||||||
|
64 * 1024
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "global")]
|
||||||
|
pub fn acquire_global_lock() {
|
||||||
|
// single threaded, no need!
|
||||||
|
assert!(!cfg!(target_feature = "atomics"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "global")]
|
||||||
|
pub fn release_global_lock() {
|
||||||
|
// single threaded, no need!
|
||||||
|
assert!(!cfg!(target_feature = "atomics"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
#[cfg(feature = "global")]
|
||||||
|
pub unsafe fn enable_alloc_after_fork() {
|
||||||
|
// single threaded, no need!
|
||||||
|
assert!(!cfg!(target_feature = "atomics"));
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
use crate::Allocator;
|
||||||
|
use core::mem::MaybeUninit;
|
||||||
|
use core::ptr;
|
||||||
|
use windows_sys::Win32::System::Memory::*;
|
||||||
|
use windows_sys::Win32::System::SystemInformation::*;
|
||||||
|
#[cfg(feature = "global")]
|
||||||
|
use windows_sys::Win32::System::Threading::*;
|
||||||
|
|
||||||
|
pub struct System {
|
||||||
|
_priv: (),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl System {
|
||||||
|
pub const fn new() -> System {
|
||||||
|
System { _priv: () }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Allocator for System {
|
||||||
|
fn alloc(&self, size: usize) -> (*mut u8, usize, u32) {
|
||||||
|
let addr = unsafe {
|
||||||
|
VirtualAlloc(
|
||||||
|
ptr::null_mut(),
|
||||||
|
size,
|
||||||
|
MEM_RESERVE | MEM_COMMIT,
|
||||||
|
PAGE_READWRITE,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if addr.is_null() {
|
||||||
|
(ptr::null_mut(), 0, 0)
|
||||||
|
} else {
|
||||||
|
(addr.cast(), size, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remap(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 {
|
||||||
|
ptr::null_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn free_part(&self, ptr: *mut u8, oldsize: usize, newsize: usize) -> bool {
|
||||||
|
unsafe { VirtualFree(ptr.add(newsize).cast(), oldsize - newsize, MEM_DECOMMIT) != 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn free(&self, ptr: *mut u8, _size: usize) -> bool {
|
||||||
|
unsafe { VirtualFree(ptr.cast(), 0, MEM_DECOMMIT) != 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_release_part(&self, _flags: u32) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn allocates_zeros(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn page_size(&self) -> usize {
|
||||||
|
unsafe {
|
||||||
|
let mut info = MaybeUninit::uninit();
|
||||||
|
GetSystemInfo(info.as_mut_ptr());
|
||||||
|
info.assume_init_ref().dwPageSize as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NB: `SRWLOCK_INIT` doesn't appear to be in `windows-sys`
|
||||||
|
#[cfg(feature = "global")]
|
||||||
|
static mut LOCK: SRWLOCK = SRWLOCK {
|
||||||
|
Ptr: ptr::null_mut(),
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "global")]
|
||||||
|
pub fn acquire_global_lock() {
|
||||||
|
unsafe {
|
||||||
|
AcquireSRWLockExclusive(ptr::addr_of_mut!(LOCK));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "global")]
|
||||||
|
pub fn release_global_lock() {
|
||||||
|
unsafe {
|
||||||
|
ReleaseSRWLockExclusive(ptr::addr_of_mut!(LOCK));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Not needed on Windows
|
||||||
|
#[cfg(feature = "global")]
|
||||||
|
pub unsafe fn enable_alloc_after_fork() {}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
use crate::Allocator;
|
||||||
|
use core::ptr;
|
||||||
|
|
||||||
|
pub struct System {
|
||||||
|
_priv: (),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl System {
|
||||||
|
pub const fn new() -> System {
|
||||||
|
System { _priv: () }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "riscv32")]
|
||||||
|
mod sys {
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
pub fn increase_heap(length: usize) -> Result<(usize, usize), ()> {
|
||||||
|
let syscall_no_increase_heap = 10usize;
|
||||||
|
let memory_flags_read_write = 2usize | 4usize;
|
||||||
|
|
||||||
|
let mut a0 = syscall_no_increase_heap;
|
||||||
|
let mut a1 = length;
|
||||||
|
let mut a2 = memory_flags_read_write;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
asm!(
|
||||||
|
"ecall",
|
||||||
|
inlateout("a0") a0,
|
||||||
|
inlateout("a1") a1,
|
||||||
|
inlateout("a2") a2,
|
||||||
|
out("a3") _,
|
||||||
|
out("a4") _,
|
||||||
|
out("a5") _,
|
||||||
|
out("a6") _,
|
||||||
|
out("a7") _,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = a0;
|
||||||
|
let address = a1;
|
||||||
|
let length = a2;
|
||||||
|
|
||||||
|
// 3 is the "MemoryRange" type, and the result is only valid
|
||||||
|
// if we get nonzero address and length.
|
||||||
|
if result == 3 && address != 0 && length != 0 {
|
||||||
|
Ok((address, length))
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Allocator for System {
|
||||||
|
/// Allocate an additional `size` bytes on the heap, and return a new
|
||||||
|
/// chunk of memory, as well as the size of the allocation and some
|
||||||
|
/// flags. Since flags are unused on this platform, they will always
|
||||||
|
/// be `0`.
|
||||||
|
fn alloc(&self, size: usize) -> (*mut u8, usize, u32) {
|
||||||
|
let size = if size == 0 {
|
||||||
|
4096
|
||||||
|
} else if size & 4095 == 0 {
|
||||||
|
size
|
||||||
|
} else {
|
||||||
|
size + (4096 - (size & 4095))
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Ok((address, length)) = sys::increase_heap(size) {
|
||||||
|
let start = address - size + length;
|
||||||
|
(start as *mut u8, size, 0)
|
||||||
|
} else {
|
||||||
|
(ptr::null_mut(), 0, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remap(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 {
|
||||||
|
// TODO
|
||||||
|
ptr::null_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn free_part(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn free(&self, _ptr: *mut u8, _size: usize) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_release_part(&self, _flags: u32) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn allocates_zeros(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn page_size(&self) -> usize {
|
||||||
|
4 * 1024
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "global")]
|
||||||
|
pub fn acquire_global_lock() {
|
||||||
|
// global feature should not be enabled
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "global")]
|
||||||
|
pub fn release_global_lock() {
|
||||||
|
// global feature should not be enabled
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "global")]
|
||||||
|
pub unsafe fn enable_alloc_after_fork() {
|
||||||
|
// platform does not support `fork()` call
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
extern crate dlmalloc;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
|
#[global_allocator]
|
||||||
|
#[cfg(feature = "global")]
|
||||||
|
static A: dlmalloc::GlobalDlmalloc = dlmalloc::GlobalDlmalloc;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn foo() {
|
||||||
|
println!("hello");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map() {
|
||||||
|
let mut m = HashMap::new();
|
||||||
|
m.insert(1, 2);
|
||||||
|
m.insert(5, 3);
|
||||||
|
drop(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn strings() {
|
||||||
|
format!("foo, bar, {}", "baz");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(not(target_family = "wasm"))]
|
||||||
|
fn threads() {
|
||||||
|
assert!(thread::spawn(|| panic!()).join().is_err());
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
use arbitrary::Unstructured;
|
||||||
|
use dlmalloc::Dlmalloc;
|
||||||
|
use rand::{rngs::SmallRng, RngCore, SeedableRng};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn smoke() {
|
||||||
|
let mut a = Dlmalloc::new();
|
||||||
|
unsafe {
|
||||||
|
let ptr = a.malloc(1, 1);
|
||||||
|
assert!(!ptr.is_null());
|
||||||
|
*ptr = 9;
|
||||||
|
assert_eq!(*ptr, 9);
|
||||||
|
a.free(ptr, 1, 1);
|
||||||
|
|
||||||
|
let ptr = a.malloc(1, 1);
|
||||||
|
assert!(!ptr.is_null());
|
||||||
|
*ptr = 10;
|
||||||
|
assert_eq!(*ptr, 10);
|
||||||
|
a.free(ptr, 1, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[path = "../fuzz/src/lib.rs"]
|
||||||
|
mod fuzz;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn stress() {
|
||||||
|
let mut rng = SmallRng::seed_from_u64(0);
|
||||||
|
let mut buf = vec![0; 4096];
|
||||||
|
let iters = if cfg!(miri) { 5 } else { 2000 };
|
||||||
|
for _ in 0..iters {
|
||||||
|
rng.fill_bytes(&mut buf);
|
||||||
|
let mut u = Unstructured::new(&buf);
|
||||||
|
let _ = fuzz::run(&mut u);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
cargo fmt --package relibc --package crt0 --package redox-rt "$@"
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[package]
|
||||||
|
name = "generic-rt"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![allow(internal_features)]
|
||||||
|
#![feature(core_intrinsics)]
|
||||||
|
#![deny(unsafe_op_in_unsafe_fn)]
|
||||||
|
|
||||||
|
use core::{
|
||||||
|
arch::asm,
|
||||||
|
mem::{self, offset_of},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct GenericTcb<Os> {
|
||||||
|
/// Pointer to the end of static TLS. Must be the first member
|
||||||
|
pub tls_end: *mut u8,
|
||||||
|
/// Size of the memory allocated for the static TLS in bytes (multiple of page size)
|
||||||
|
pub tls_len: usize,
|
||||||
|
/// Pointer to this structure
|
||||||
|
pub tcb_ptr: *mut Self,
|
||||||
|
/// Size of the memory allocated for this structure in bytes (should be same as page size)
|
||||||
|
pub tcb_len: usize,
|
||||||
|
pub os_specific: Os,
|
||||||
|
}
|
||||||
|
impl<Os> GenericTcb<Os> {
|
||||||
|
/// Architecture specific code to read a usize from the TCB - aarch64
|
||||||
|
#[allow(unsafe_op_in_unsafe_fn)]
|
||||||
|
#[inline(always)]
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
pub unsafe fn arch_read(offset: usize) -> usize {
|
||||||
|
let abi_ptr: usize;
|
||||||
|
asm!(
|
||||||
|
"mrs {}, tpidr_el0",
|
||||||
|
out(reg) abi_ptr,
|
||||||
|
);
|
||||||
|
|
||||||
|
let tcb_ptr = *(abi_ptr as *const usize);
|
||||||
|
*((tcb_ptr + offset) as *const usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Architecture specific code to read a usize from the TCB - x86
|
||||||
|
#[allow(unsafe_op_in_unsafe_fn)]
|
||||||
|
#[inline(always)]
|
||||||
|
#[cfg(target_arch = "x86")]
|
||||||
|
pub unsafe fn arch_read(offset: usize) -> usize {
|
||||||
|
let value;
|
||||||
|
asm!(
|
||||||
|
"
|
||||||
|
mov {}, gs:[{}]
|
||||||
|
",
|
||||||
|
out(reg) value,
|
||||||
|
in(reg) offset,
|
||||||
|
);
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Architecture specific code to read a usize from the TCB - x86_64
|
||||||
|
#[allow(unsafe_op_in_unsafe_fn)]
|
||||||
|
#[inline(always)]
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
pub unsafe fn arch_read(offset: usize) -> usize {
|
||||||
|
let value;
|
||||||
|
asm!(
|
||||||
|
"
|
||||||
|
mov {}, fs:[{}]
|
||||||
|
",
|
||||||
|
out(reg) value,
|
||||||
|
in(reg) offset,
|
||||||
|
);
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Architecture specific code to read a usize from the TCB - riscv64
|
||||||
|
#[allow(unsafe_op_in_unsafe_fn)]
|
||||||
|
#[inline(always)]
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
unsafe fn arch_read(offset: usize) -> usize {
|
||||||
|
let value;
|
||||||
|
asm!(
|
||||||
|
"ld {value}, -8(tp)", // TCB
|
||||||
|
"add {value}, {value}, {offset}",
|
||||||
|
"ld {value}, 0({value})",
|
||||||
|
value = out(reg) value,
|
||||||
|
offset = in(reg) offset,
|
||||||
|
);
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn current_ptr() -> Option<*mut Self> {
|
||||||
|
let tcb_ptr = unsafe { Self::arch_read(offset_of!(Self, tcb_ptr)) as *mut Self };
|
||||||
|
let tcb_len = unsafe { Self::arch_read(offset_of!(Self, tcb_len)) };
|
||||||
|
if tcb_ptr.is_null() || tcb_len < mem::size_of::<Self>() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(tcb_ptr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub unsafe fn current() -> Option<&'static mut Self> {
|
||||||
|
unsafe { Some(&mut *Self::current_ptr()?) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn panic_notls(_msg: impl core::fmt::Display) -> ! {
|
||||||
|
// TODO: actually print _msg, perhaps by having panic_notls take a `T: DebugBackend` that can
|
||||||
|
// propagate until called by e.g. relibc start
|
||||||
|
core::intrinsics::abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ExpectTlsFree {
|
||||||
|
type Unwrapped;
|
||||||
|
|
||||||
|
fn expect_notls(self, msg: &str) -> Self::Unwrapped;
|
||||||
|
}
|
||||||
|
impl<T, E: core::fmt::Debug> ExpectTlsFree for Result<T, E> {
|
||||||
|
type Unwrapped = T;
|
||||||
|
|
||||||
|
fn expect_notls(self, msg: &str) -> T {
|
||||||
|
match self {
|
||||||
|
Ok(t) => t,
|
||||||
|
Err(err) => panic_notls(format_args!(
|
||||||
|
"{msg}: expect failed for Result with err: {err:?}",
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> ExpectTlsFree for Option<T> {
|
||||||
|
type Unwrapped = T;
|
||||||
|
|
||||||
|
fn expect_notls(self, msg: &str) -> T {
|
||||||
|
match self {
|
||||||
|
Some(t) => t,
|
||||||
|
None => panic_notls(format_args!("{msg}: expect failed for Option")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#ifndef _ALLOCA_H
|
||||||
|
#define _ALLOCA_H
|
||||||
|
|
||||||
|
#define alloca(size) __builtin_alloca (size)
|
||||||
|
|
||||||
|
#endif /* _ALLOCA_H */
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
#include <openlibm_complex.h>
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
* Copyright (c) 2020 Rich Felker musl-libc
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _FEATURES_H__RELIBC
|
||||||
|
#define _FEATURES_H__RELIBC
|
||||||
|
|
||||||
|
// Version metadata for feature gating
|
||||||
|
// This is useful for divergent implementation specific behavior
|
||||||
|
// glibc, ulibc, and likely others define a similar macro
|
||||||
|
// musl does not define an equivalent macro
|
||||||
|
#define __RELIBC__ 1
|
||||||
|
#define __RELIBC__MAJOR 0
|
||||||
|
#define __RELIBC__MINOR 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sources:
|
||||||
|
* https://en.cppreference.com/w/c/language/attributes
|
||||||
|
* https://clang.llvm.org/docs/LanguageExtensions.html
|
||||||
|
* https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005fc_005fattribute.html
|
||||||
|
* https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Clang doesn't define __has_cpp_attribute if compiling C code
|
||||||
|
#if !defined(__has_cpp_attribute)
|
||||||
|
#define __has_cpp_attribute(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Clang doesn't define __has_c_attribute if compiling C++ code
|
||||||
|
#if !defined(__has_c_attribute)
|
||||||
|
#define __has_c_attribute(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Check if C23+ attributes are available
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
// HACK: GCC backports C++ attributes to C++98 but doesn't accept attributes
|
||||||
|
// placed before the function like cbindgen emits.
|
||||||
|
// Let's just disable attributes for C++98 by checking if a random C++11
|
||||||
|
// feature is available.
|
||||||
|
#define __HAS_ATTRIBUTE(x) __cpp_variable_templates &&__has_cpp_attribute(x)
|
||||||
|
#else
|
||||||
|
#define __HAS_ATTRIBUTE(x) \
|
||||||
|
(__has_c_attribute(x) || __STDC_VERSION__ >= 202311L || \
|
||||||
|
__has_cpp_attribute(x))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// TODO: Not emitted with cbindgen
|
||||||
|
#if __STDC_VERSION__ >= 199901L
|
||||||
|
#define __restrict restrict
|
||||||
|
#elif !defined(__GNUC__)
|
||||||
|
#define __restrict
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// TODO: Not emitted with cbindgen
|
||||||
|
#if __STDC_VERSION__ >= 199901L || defined(__cplusplus)
|
||||||
|
#define __inline inline
|
||||||
|
#elif !defined(__GNUC__)
|
||||||
|
#define __inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Analogous to Rust's Never type
|
||||||
|
//TODO: clang fails to compile C with [[noreturn]]
|
||||||
|
#if defined(__cplusplus) && __HAS_ATTRIBUTE(noreturn) && !(__clang__)
|
||||||
|
#define __noreturn [[noreturn]]
|
||||||
|
// #elif __STDC_VERSION__ >= 201112L
|
||||||
|
// FIXME: cbindgen incorrectly places _Noreturn
|
||||||
|
// #define __noreturn _Noreturn
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
#define __noreturn __attribute__((__noreturn__))
|
||||||
|
#else
|
||||||
|
#define __noreturn
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Analogous to Rust's #[must_use]
|
||||||
|
// C23 only
|
||||||
|
#if __HAS_ATTRIBUTE(nodiscard)
|
||||||
|
#define __nodiscard [[nodiscard]]
|
||||||
|
#define __nodiscardNote(x) [[nodiscard(x)]]
|
||||||
|
#else
|
||||||
|
#define __nodiscard
|
||||||
|
#define __nodiscardNote(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Analogous to Rust's #[deprecated]
|
||||||
|
// C23 only
|
||||||
|
#if __HAS_ATTRIBUTE(deprecated)
|
||||||
|
#define __deprecated [[deprecated]]
|
||||||
|
#define __deprecatedNote(x) [[deprecated(x)]]
|
||||||
|
#else
|
||||||
|
#define __deprecated
|
||||||
|
#define __deprecatedNote(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#include <openlibm_fenv.h>
|
||||||
|
#undef complex
|
||||||
|
#undef I
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
// Copied from musl
|
||||||
|
|
||||||
|
#ifndef _ISO646_H
|
||||||
|
#define _ISO646_H
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
|
||||||
|
#define and &&
|
||||||
|
#define and_eq &=
|
||||||
|
#define bitand &
|
||||||
|
#define bitor |
|
||||||
|
#define compl ~
|
||||||
|
#define not !
|
||||||
|
#define not_eq !=
|
||||||
|
#define or ||
|
||||||
|
#define or_eq |=
|
||||||
|
#define xor ^
|
||||||
|
#define xor_eq ^=
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#ifndef __MACHINE_ENDIAN_H__
|
||||||
|
|
||||||
|
/* TODO: Forcing little endian, if you need a big endian system, fix this { */
|
||||||
|
#ifndef BIG_ENDIAN
|
||||||
|
#define BIG_ENDIAN 4321
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LITTLE_ENDIAN
|
||||||
|
#define LITTLE_ENDIAN 1234
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef BYTE_ORDER
|
||||||
|
#define BYTE_ORDER LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
#endif /* __MACHINE_ENDIAN_H__ */
|
||||||
+113
@@ -0,0 +1,113 @@
|
|||||||
|
#include <openlibm_math.h>
|
||||||
|
|
||||||
|
// Missing typedefs
|
||||||
|
typedef float float_t;
|
||||||
|
typedef double double_t;
|
||||||
|
|
||||||
|
/* double */
|
||||||
|
|
||||||
|
#ifndef M_PI
|
||||||
|
#define M_PI 3.14159265358979323846 /* pi */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef M_PI_2
|
||||||
|
#define M_PI_2 1.57079632679489661923 /* pi/2 */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef M_PI_4
|
||||||
|
#define M_PI_4 0.78539816339744830962 /* pi/4 */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef M_2_PI
|
||||||
|
#define M_2_PI 0.63661977236758134308 /* 2/pi */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef M_E
|
||||||
|
#define M_E 2.7182818284590452354 /* e */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef M_LOG2E
|
||||||
|
#define M_LOG2E 1.4426950408889634074 /* log_2 e */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef M_LOG10E
|
||||||
|
#define M_LOG10E 0.43429448190325182765 /* log_10 e */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef M_LN2
|
||||||
|
#define M_LN2 0.69314718055994530942 /* log_e 2 */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef M_LN10
|
||||||
|
#define M_LN10 2.30258509299404568402 /* log_e 10 */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef M_1_PI
|
||||||
|
#define M_1_PI 0.31830988618379067154 /* 1/pi */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef M_2_SQRTPI
|
||||||
|
#define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef M_SQRT2
|
||||||
|
#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef M_SQRT1_2
|
||||||
|
#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* long double */
|
||||||
|
|
||||||
|
#ifndef M_El
|
||||||
|
#define M_El 2.718281828459045235360287471352662498L /* e */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef M_LOG2El
|
||||||
|
#define M_LOG2El 1.442695040888963407359924681001892137L /* log_2 e */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef M_LOG10El
|
||||||
|
#define M_LOG10El 0.434294481903251827651128918916605082L /* log_10 e */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef M_LN2l
|
||||||
|
#define M_LN2l 0.693147180559945309417232121458176568L /* log_e 2 */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef M_LN10l
|
||||||
|
#define M_LN10l 2.302585092994045684017991454684364208L /* log_e 10 */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef M_PIl
|
||||||
|
#define M_PIl 3.141592653589793238462643383279502884L /* pi */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef M_PI_2l
|
||||||
|
#define M_PI_2l 1.570796326794896619231321691639751442L /* pi/2 */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef M_PI_4l
|
||||||
|
#define M_PI_4l 0.785398163397448309615660845819875721L /* pi/4 */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef M_1_PIl
|
||||||
|
#define M_1_PIl 0.318309886183790671537767526745028724L /* 1/pi */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef M_2_PIl
|
||||||
|
#define M_2_PIl 0.636619772367581343075535053490057448L /* 2/pi */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef M_2_SQRTPIl
|
||||||
|
#define M_2_SQRTPIl 1.128379167095512573896158903121545172L /* 2/sqrt(pi) */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef M_SQRT2l
|
||||||
|
#define M_SQRT2l 1.414213562373095048801688724209698079L /* sqrt(2) */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef M_SQRT1_2l
|
||||||
|
#define M_SQRT1_2l 0.707106781186547524400844362104849039L /* 1/sqrt(2) */
|
||||||
|
#endif
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
#include <string.h>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#ifndef _NETINET_IN_SYSTM_H
|
||||||
|
#define _NETINET_IN_SYSTM_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef uint16_t n_short;
|
||||||
|
typedef uint32_t n_long;
|
||||||
|
typedef uint32_t n_time;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#ifndef _RELIBC_PATHS_H
|
||||||
|
#define _RELIBC_PATHS_H
|
||||||
|
|
||||||
|
#define _PATH_BSHELL "/bin/sh"
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
#ifndef _SETJMP_H
|
||||||
|
#define _SETJMP_H
|
||||||
|
|
||||||
|
#ifdef __aarch64__
|
||||||
|
typedef unsigned long jmp_buf[22];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __arm__
|
||||||
|
typedef unsigned long long jmp_buf[32];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __i386__
|
||||||
|
typedef unsigned long jmp_buf[6];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __m68k__
|
||||||
|
typedef unsigned long jmp_buf[39];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __microblaze__
|
||||||
|
typedef unsigned long jmp_buf[18];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __mips__
|
||||||
|
typedef unsigned long long jmp_buf[13];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __mips64__
|
||||||
|
typedef unsigned long long jmp_buf[23];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __mipsn32__
|
||||||
|
typedef unsigned long long jmp_buf[23];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __or1k__
|
||||||
|
typedef unsigned long jmp_buf[13];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __powerpc__
|
||||||
|
typedef unsigned long long jmp_buf[56];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __powerpc64__
|
||||||
|
typedef uint128_t jmp_buf[32];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __s390x__
|
||||||
|
typedef unsigned long jmp_buf[18];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __sh__
|
||||||
|
typedef unsigned long jmp_buf[15];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __x32__
|
||||||
|
typedef unsigned long long jmp_buf[8];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __x86_64__
|
||||||
|
typedef unsigned long jmp_buf[16];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __riscv
|
||||||
|
typedef unsigned long jmp_buf[26];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef jmp_buf sigjmp_buf;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int setjmp(jmp_buf buf);
|
||||||
|
void longjmp(jmp_buf buf, int value);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _SETJMP_H */
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#ifndef _STDARG_H
|
||||||
|
#define _STDARG_H
|
||||||
|
|
||||||
|
typedef __builtin_va_list va_list;
|
||||||
|
#define va_start(v,l) __builtin_va_start(v,l)
|
||||||
|
#define va_end(v) __builtin_va_end(v)
|
||||||
|
#define va_arg(v,l) __builtin_va_arg(v,l)
|
||||||
|
#define va_copy(d,s) __builtin_va_copy(d,s)
|
||||||
|
|
||||||
|
#endif /* _STDARG_H */
|
||||||
@@ -0,0 +1,243 @@
|
|||||||
|
/* Copyright (C) 2013-2022 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This file is part of GCC.
|
||||||
|
|
||||||
|
GCC is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3, or (at your option)
|
||||||
|
any later version.
|
||||||
|
|
||||||
|
GCC is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
Under Section 7 of GPL version 3, you are granted additional
|
||||||
|
permissions described in the GCC Runtime Library Exception, version
|
||||||
|
3.1, as published by the Free Software Foundation.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License and
|
||||||
|
a copy of the GCC Runtime Library Exception along with this program;
|
||||||
|
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
/* ISO C11 Standard: 7.17 Atomics <stdatomic.h>. */
|
||||||
|
|
||||||
|
#ifndef _STDATOMIC_H
|
||||||
|
#define _STDATOMIC_H
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
memory_order_relaxed = __ATOMIC_RELAXED,
|
||||||
|
memory_order_consume = __ATOMIC_CONSUME,
|
||||||
|
memory_order_acquire = __ATOMIC_ACQUIRE,
|
||||||
|
memory_order_release = __ATOMIC_RELEASE,
|
||||||
|
memory_order_acq_rel = __ATOMIC_ACQ_REL,
|
||||||
|
memory_order_seq_cst = __ATOMIC_SEQ_CST
|
||||||
|
} memory_order;
|
||||||
|
|
||||||
|
|
||||||
|
typedef _Atomic _Bool atomic_bool;
|
||||||
|
typedef _Atomic char atomic_char;
|
||||||
|
typedef _Atomic signed char atomic_schar;
|
||||||
|
typedef _Atomic unsigned char atomic_uchar;
|
||||||
|
typedef _Atomic short atomic_short;
|
||||||
|
typedef _Atomic unsigned short atomic_ushort;
|
||||||
|
typedef _Atomic int atomic_int;
|
||||||
|
typedef _Atomic unsigned int atomic_uint;
|
||||||
|
typedef _Atomic long atomic_long;
|
||||||
|
typedef _Atomic unsigned long atomic_ulong;
|
||||||
|
typedef _Atomic long long atomic_llong;
|
||||||
|
typedef _Atomic unsigned long long atomic_ullong;
|
||||||
|
typedef _Atomic __CHAR16_TYPE__ atomic_char16_t;
|
||||||
|
typedef _Atomic __CHAR32_TYPE__ atomic_char32_t;
|
||||||
|
typedef _Atomic __WCHAR_TYPE__ atomic_wchar_t;
|
||||||
|
typedef _Atomic __INT_LEAST8_TYPE__ atomic_int_least8_t;
|
||||||
|
typedef _Atomic __UINT_LEAST8_TYPE__ atomic_uint_least8_t;
|
||||||
|
typedef _Atomic __INT_LEAST16_TYPE__ atomic_int_least16_t;
|
||||||
|
typedef _Atomic __UINT_LEAST16_TYPE__ atomic_uint_least16_t;
|
||||||
|
typedef _Atomic __INT_LEAST32_TYPE__ atomic_int_least32_t;
|
||||||
|
typedef _Atomic __UINT_LEAST32_TYPE__ atomic_uint_least32_t;
|
||||||
|
typedef _Atomic __INT_LEAST64_TYPE__ atomic_int_least64_t;
|
||||||
|
typedef _Atomic __UINT_LEAST64_TYPE__ atomic_uint_least64_t;
|
||||||
|
typedef _Atomic __INT_FAST8_TYPE__ atomic_int_fast8_t;
|
||||||
|
typedef _Atomic __UINT_FAST8_TYPE__ atomic_uint_fast8_t;
|
||||||
|
typedef _Atomic __INT_FAST16_TYPE__ atomic_int_fast16_t;
|
||||||
|
typedef _Atomic __UINT_FAST16_TYPE__ atomic_uint_fast16_t;
|
||||||
|
typedef _Atomic __INT_FAST32_TYPE__ atomic_int_fast32_t;
|
||||||
|
typedef _Atomic __UINT_FAST32_TYPE__ atomic_uint_fast32_t;
|
||||||
|
typedef _Atomic __INT_FAST64_TYPE__ atomic_int_fast64_t;
|
||||||
|
typedef _Atomic __UINT_FAST64_TYPE__ atomic_uint_fast64_t;
|
||||||
|
typedef _Atomic __INTPTR_TYPE__ atomic_intptr_t;
|
||||||
|
typedef _Atomic __UINTPTR_TYPE__ atomic_uintptr_t;
|
||||||
|
typedef _Atomic __SIZE_TYPE__ atomic_size_t;
|
||||||
|
typedef _Atomic __PTRDIFF_TYPE__ atomic_ptrdiff_t;
|
||||||
|
typedef _Atomic __INTMAX_TYPE__ atomic_intmax_t;
|
||||||
|
typedef _Atomic __UINTMAX_TYPE__ atomic_uintmax_t;
|
||||||
|
|
||||||
|
|
||||||
|
#define ATOMIC_VAR_INIT(VALUE) (VALUE)
|
||||||
|
|
||||||
|
/* Initialize an atomic object pointed to by PTR with VAL. */
|
||||||
|
#define atomic_init(PTR, VAL) \
|
||||||
|
atomic_store_explicit (PTR, VAL, __ATOMIC_RELAXED)
|
||||||
|
|
||||||
|
#define kill_dependency(Y) \
|
||||||
|
__extension__ \
|
||||||
|
({ \
|
||||||
|
__auto_type __kill_dependency_tmp = (Y); \
|
||||||
|
__kill_dependency_tmp; \
|
||||||
|
})
|
||||||
|
|
||||||
|
extern void atomic_thread_fence (memory_order);
|
||||||
|
#define atomic_thread_fence(MO) __atomic_thread_fence (MO)
|
||||||
|
extern void atomic_signal_fence (memory_order);
|
||||||
|
#define atomic_signal_fence(MO) __atomic_signal_fence (MO)
|
||||||
|
#define atomic_is_lock_free(OBJ) __atomic_is_lock_free (sizeof (*(OBJ)), (OBJ))
|
||||||
|
|
||||||
|
#define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE
|
||||||
|
#define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE
|
||||||
|
#define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE
|
||||||
|
#define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE
|
||||||
|
#define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE
|
||||||
|
#define ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE
|
||||||
|
#define ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE
|
||||||
|
#define ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE
|
||||||
|
#define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE
|
||||||
|
#define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE
|
||||||
|
|
||||||
|
|
||||||
|
/* Note that these macros require __auto_type to remove
|
||||||
|
_Atomic qualifiers (and const qualifiers, if those are valid on
|
||||||
|
macro operands).
|
||||||
|
|
||||||
|
Also note that the header file uses the generic form of __atomic
|
||||||
|
builtins, which requires the address to be taken of the value
|
||||||
|
parameter, and then we pass that value on. This allows the macros
|
||||||
|
to work for any type, and the compiler is smart enough to convert
|
||||||
|
these to lock-free _N variants if possible, and throw away the
|
||||||
|
temps. */
|
||||||
|
|
||||||
|
#define atomic_store_explicit(PTR, VAL, MO) \
|
||||||
|
__extension__ \
|
||||||
|
({ \
|
||||||
|
__auto_type __atomic_store_ptr = (PTR); \
|
||||||
|
__typeof__ ((void)0, *__atomic_store_ptr) __atomic_store_tmp = (VAL); \
|
||||||
|
__atomic_store (__atomic_store_ptr, &__atomic_store_tmp, (MO)); \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define atomic_store(PTR, VAL) \
|
||||||
|
atomic_store_explicit (PTR, VAL, __ATOMIC_SEQ_CST)
|
||||||
|
|
||||||
|
|
||||||
|
#define atomic_load_explicit(PTR, MO) \
|
||||||
|
__extension__ \
|
||||||
|
({ \
|
||||||
|
__auto_type __atomic_load_ptr = (PTR); \
|
||||||
|
__typeof__ ((void)0, *__atomic_load_ptr) __atomic_load_tmp; \
|
||||||
|
__atomic_load (__atomic_load_ptr, &__atomic_load_tmp, (MO)); \
|
||||||
|
__atomic_load_tmp; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define atomic_load(PTR) atomic_load_explicit (PTR, __ATOMIC_SEQ_CST)
|
||||||
|
|
||||||
|
|
||||||
|
#define atomic_exchange_explicit(PTR, VAL, MO) \
|
||||||
|
__extension__ \
|
||||||
|
({ \
|
||||||
|
__auto_type __atomic_exchange_ptr = (PTR); \
|
||||||
|
__typeof__ ((void)0, *__atomic_exchange_ptr) __atomic_exchange_val = (VAL); \
|
||||||
|
__typeof__ ((void)0, *__atomic_exchange_ptr) __atomic_exchange_tmp; \
|
||||||
|
__atomic_exchange (__atomic_exchange_ptr, &__atomic_exchange_val, \
|
||||||
|
&__atomic_exchange_tmp, (MO)); \
|
||||||
|
__atomic_exchange_tmp; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define atomic_exchange(PTR, VAL) \
|
||||||
|
atomic_exchange_explicit (PTR, VAL, __ATOMIC_SEQ_CST)
|
||||||
|
|
||||||
|
|
||||||
|
#define atomic_compare_exchange_strong_explicit(PTR, VAL, DES, SUC, FAIL) \
|
||||||
|
__extension__ \
|
||||||
|
({ \
|
||||||
|
__auto_type __atomic_compare_exchange_ptr = (PTR); \
|
||||||
|
__typeof__ ((void)0, *__atomic_compare_exchange_ptr) __atomic_compare_exchange_tmp \
|
||||||
|
= (DES); \
|
||||||
|
__atomic_compare_exchange (__atomic_compare_exchange_ptr, (VAL), \
|
||||||
|
&__atomic_compare_exchange_tmp, 0, \
|
||||||
|
(SUC), (FAIL)); \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define atomic_compare_exchange_strong(PTR, VAL, DES) \
|
||||||
|
atomic_compare_exchange_strong_explicit (PTR, VAL, DES, __ATOMIC_SEQ_CST, \
|
||||||
|
__ATOMIC_SEQ_CST)
|
||||||
|
|
||||||
|
#define atomic_compare_exchange_weak_explicit(PTR, VAL, DES, SUC, FAIL) \
|
||||||
|
__extension__ \
|
||||||
|
({ \
|
||||||
|
__auto_type __atomic_compare_exchange_ptr = (PTR); \
|
||||||
|
__typeof__ ((void)0, *__atomic_compare_exchange_ptr) __atomic_compare_exchange_tmp \
|
||||||
|
= (DES); \
|
||||||
|
__atomic_compare_exchange (__atomic_compare_exchange_ptr, (VAL), \
|
||||||
|
&__atomic_compare_exchange_tmp, 1, \
|
||||||
|
(SUC), (FAIL)); \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define atomic_compare_exchange_weak(PTR, VAL, DES) \
|
||||||
|
atomic_compare_exchange_weak_explicit (PTR, VAL, DES, __ATOMIC_SEQ_CST, \
|
||||||
|
__ATOMIC_SEQ_CST)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define atomic_fetch_add(PTR, VAL) __atomic_fetch_add ((PTR), (VAL), \
|
||||||
|
__ATOMIC_SEQ_CST)
|
||||||
|
#define atomic_fetch_add_explicit(PTR, VAL, MO) \
|
||||||
|
__atomic_fetch_add ((PTR), (VAL), (MO))
|
||||||
|
|
||||||
|
#define atomic_fetch_sub(PTR, VAL) __atomic_fetch_sub ((PTR), (VAL), \
|
||||||
|
__ATOMIC_SEQ_CST)
|
||||||
|
#define atomic_fetch_sub_explicit(PTR, VAL, MO) \
|
||||||
|
__atomic_fetch_sub ((PTR), (VAL), (MO))
|
||||||
|
|
||||||
|
#define atomic_fetch_or(PTR, VAL) __atomic_fetch_or ((PTR), (VAL), \
|
||||||
|
__ATOMIC_SEQ_CST)
|
||||||
|
#define atomic_fetch_or_explicit(PTR, VAL, MO) \
|
||||||
|
__atomic_fetch_or ((PTR), (VAL), (MO))
|
||||||
|
|
||||||
|
#define atomic_fetch_xor(PTR, VAL) __atomic_fetch_xor ((PTR), (VAL), \
|
||||||
|
__ATOMIC_SEQ_CST)
|
||||||
|
#define atomic_fetch_xor_explicit(PTR, VAL, MO) \
|
||||||
|
__atomic_fetch_xor ((PTR), (VAL), (MO))
|
||||||
|
|
||||||
|
#define atomic_fetch_and(PTR, VAL) __atomic_fetch_and ((PTR), (VAL), \
|
||||||
|
__ATOMIC_SEQ_CST)
|
||||||
|
#define atomic_fetch_and_explicit(PTR, VAL, MO) \
|
||||||
|
__atomic_fetch_and ((PTR), (VAL), (MO))
|
||||||
|
|
||||||
|
|
||||||
|
typedef _Atomic struct
|
||||||
|
{
|
||||||
|
#if __GCC_ATOMIC_TEST_AND_SET_TRUEVAL == 1
|
||||||
|
_Bool __val;
|
||||||
|
#else
|
||||||
|
unsigned char __val;
|
||||||
|
#endif
|
||||||
|
} atomic_flag;
|
||||||
|
|
||||||
|
#define ATOMIC_FLAG_INIT { 0 }
|
||||||
|
|
||||||
|
|
||||||
|
extern _Bool atomic_flag_test_and_set (volatile atomic_flag *);
|
||||||
|
#define atomic_flag_test_and_set(PTR) \
|
||||||
|
__atomic_test_and_set ((PTR), __ATOMIC_SEQ_CST)
|
||||||
|
extern _Bool atomic_flag_test_and_set_explicit (volatile atomic_flag *,
|
||||||
|
memory_order);
|
||||||
|
#define atomic_flag_test_and_set_explicit(PTR, MO) \
|
||||||
|
__atomic_test_and_set ((PTR), (MO))
|
||||||
|
|
||||||
|
extern void atomic_flag_clear (volatile atomic_flag *);
|
||||||
|
#define atomic_flag_clear(PTR) __atomic_clear ((PTR), __ATOMIC_SEQ_CST)
|
||||||
|
extern void atomic_flag_clear_explicit (volatile atomic_flag *, memory_order);
|
||||||
|
#define atomic_flag_clear_explicit(PTR, MO) __atomic_clear ((PTR), (MO))
|
||||||
|
|
||||||
|
#endif /* _STDATOMIC_H */
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef _STDBOOL_H
|
||||||
|
#define _STDBOOL_H
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
#define bool _Bool
|
||||||
|
#define true 1
|
||||||
|
#define false 0
|
||||||
|
#else /* __cplusplus */
|
||||||
|
#if __cplusplus < 201103L
|
||||||
|
#define bool bool
|
||||||
|
#define false false
|
||||||
|
#define true true
|
||||||
|
#endif /*__cplusplus < 201103L*/
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#define __bool_true_false_are_defined 1
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _STDBOOL_H */
|
||||||
@@ -0,0 +1,377 @@
|
|||||||
|
/* Copyright (C) 2008-2018 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This file is part of GCC.
|
||||||
|
|
||||||
|
GCC is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3, or (at your option)
|
||||||
|
any later version.
|
||||||
|
|
||||||
|
GCC is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
Under Section 7 of GPL version 3, you are granted additional
|
||||||
|
permissions described in the GCC Runtime Library Exception, version
|
||||||
|
3.1, as published by the Free Software Foundation.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License and
|
||||||
|
a copy of the GCC Runtime Library Exception along with this program;
|
||||||
|
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ISO C Standard: 7.18 Integer types <stdint.h>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _STDINT_H
|
||||||
|
#define _STDINT_H
|
||||||
|
|
||||||
|
/* 7.8.1.1 Exact-width integer types */
|
||||||
|
|
||||||
|
#ifdef __INT8_TYPE__
|
||||||
|
typedef __INT8_TYPE__ int8_t;
|
||||||
|
#endif
|
||||||
|
#ifdef __INT16_TYPE__
|
||||||
|
typedef __INT16_TYPE__ int16_t;
|
||||||
|
#endif
|
||||||
|
#ifdef __INT32_TYPE__
|
||||||
|
typedef __INT32_TYPE__ int32_t;
|
||||||
|
#endif
|
||||||
|
#ifdef __INT64_TYPE__
|
||||||
|
typedef __INT64_TYPE__ int64_t;
|
||||||
|
#endif
|
||||||
|
#ifdef __UINT8_TYPE__
|
||||||
|
typedef __UINT8_TYPE__ uint8_t;
|
||||||
|
typedef __UINT8_TYPE__ u_int8_t;
|
||||||
|
#endif
|
||||||
|
#ifdef __UINT16_TYPE__
|
||||||
|
typedef __UINT16_TYPE__ uint16_t;
|
||||||
|
typedef __UINT16_TYPE__ u_int16_t;
|
||||||
|
#endif
|
||||||
|
#ifdef __UINT32_TYPE__
|
||||||
|
typedef __UINT32_TYPE__ uint32_t;
|
||||||
|
typedef __UINT32_TYPE__ u_int32_t;
|
||||||
|
// Required by openlibm
|
||||||
|
typedef __UINT32_TYPE__ __uint32_t;
|
||||||
|
#endif
|
||||||
|
#ifdef __UINT64_TYPE__
|
||||||
|
typedef __UINT64_TYPE__ uint64_t;
|
||||||
|
typedef __UINT64_TYPE__ u_int64_t;
|
||||||
|
// Required by openlibm
|
||||||
|
typedef __UINT64_TYPE__ __uint64_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* 7.8.1.2 Minimum-width integer types */
|
||||||
|
|
||||||
|
typedef __INT_LEAST8_TYPE__ int_least8_t;
|
||||||
|
typedef __INT_LEAST16_TYPE__ int_least16_t;
|
||||||
|
typedef __INT_LEAST32_TYPE__ int_least32_t;
|
||||||
|
typedef __INT_LEAST64_TYPE__ int_least64_t;
|
||||||
|
typedef __UINT_LEAST8_TYPE__ uint_least8_t;
|
||||||
|
typedef __UINT_LEAST16_TYPE__ uint_least16_t;
|
||||||
|
typedef __UINT_LEAST32_TYPE__ uint_least32_t;
|
||||||
|
typedef __UINT_LEAST64_TYPE__ uint_least64_t;
|
||||||
|
|
||||||
|
/* 7.8.1.3 Fastest minimum-width integer types */
|
||||||
|
|
||||||
|
typedef __INT_FAST8_TYPE__ int_fast8_t;
|
||||||
|
typedef __INT_FAST16_TYPE__ int_fast16_t;
|
||||||
|
typedef __INT_FAST32_TYPE__ int_fast32_t;
|
||||||
|
typedef __INT_FAST64_TYPE__ int_fast64_t;
|
||||||
|
typedef __UINT_FAST8_TYPE__ uint_fast8_t;
|
||||||
|
typedef __UINT_FAST16_TYPE__ uint_fast16_t;
|
||||||
|
typedef __UINT_FAST32_TYPE__ uint_fast32_t;
|
||||||
|
typedef __UINT_FAST64_TYPE__ uint_fast64_t;
|
||||||
|
|
||||||
|
/* 7.8.1.4 Integer types capable of holding object pointers */
|
||||||
|
|
||||||
|
#ifdef __INTPTR_TYPE__
|
||||||
|
typedef __INTPTR_TYPE__ intptr_t;
|
||||||
|
#endif
|
||||||
|
#ifdef __UINTPTR_TYPE__
|
||||||
|
typedef __UINTPTR_TYPE__ uintptr_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* 7.8.1.5 Greatest-width integer types */
|
||||||
|
|
||||||
|
typedef __INTMAX_TYPE__ intmax_t;
|
||||||
|
typedef __UINTMAX_TYPE__ uintmax_t;
|
||||||
|
|
||||||
|
#if (!defined __cplusplus || __cplusplus >= 201103L \
|
||||||
|
|| defined __STDC_LIMIT_MACROS)
|
||||||
|
|
||||||
|
/* 7.18.2 Limits of specified-width integer types */
|
||||||
|
|
||||||
|
#ifdef __INT8_MAX__
|
||||||
|
# undef INT8_MAX
|
||||||
|
# define INT8_MAX __INT8_MAX__
|
||||||
|
# undef INT8_MIN
|
||||||
|
# define INT8_MIN (-INT8_MAX - 1)
|
||||||
|
#endif
|
||||||
|
#ifdef __UINT8_MAX__
|
||||||
|
# undef UINT8_MAX
|
||||||
|
# define UINT8_MAX __UINT8_MAX__
|
||||||
|
#endif
|
||||||
|
#ifdef __INT16_MAX__
|
||||||
|
# undef INT16_MAX
|
||||||
|
# define INT16_MAX __INT16_MAX__
|
||||||
|
# undef INT16_MIN
|
||||||
|
# define INT16_MIN (-INT16_MAX - 1)
|
||||||
|
#endif
|
||||||
|
#ifdef __UINT16_MAX__
|
||||||
|
# undef UINT16_MAX
|
||||||
|
# define UINT16_MAX __UINT16_MAX__
|
||||||
|
#endif
|
||||||
|
#ifdef __INT32_MAX__
|
||||||
|
# undef INT32_MAX
|
||||||
|
# define INT32_MAX __INT32_MAX__
|
||||||
|
# undef INT32_MIN
|
||||||
|
# define INT32_MIN (-INT32_MAX - 1)
|
||||||
|
#endif
|
||||||
|
#ifdef __UINT32_MAX__
|
||||||
|
# undef UINT32_MAX
|
||||||
|
# define UINT32_MAX __UINT32_MAX__
|
||||||
|
#endif
|
||||||
|
#ifdef __INT64_MAX__
|
||||||
|
# undef INT64_MAX
|
||||||
|
# define INT64_MAX __INT64_MAX__
|
||||||
|
# undef INT64_MIN
|
||||||
|
# define INT64_MIN (-INT64_MAX - 1)
|
||||||
|
#endif
|
||||||
|
#ifdef __UINT64_MAX__
|
||||||
|
# undef UINT64_MAX
|
||||||
|
# define UINT64_MAX __UINT64_MAX__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef INT_LEAST8_MAX
|
||||||
|
#define INT_LEAST8_MAX __INT_LEAST8_MAX__
|
||||||
|
#undef INT_LEAST8_MIN
|
||||||
|
#define INT_LEAST8_MIN (-INT_LEAST8_MAX - 1)
|
||||||
|
#undef UINT_LEAST8_MAX
|
||||||
|
#define UINT_LEAST8_MAX __UINT_LEAST8_MAX__
|
||||||
|
#undef INT_LEAST16_MAX
|
||||||
|
#define INT_LEAST16_MAX __INT_LEAST16_MAX__
|
||||||
|
#undef INT_LEAST16_MIN
|
||||||
|
#define INT_LEAST16_MIN (-INT_LEAST16_MAX - 1)
|
||||||
|
#undef UINT_LEAST16_MAX
|
||||||
|
#define UINT_LEAST16_MAX __UINT_LEAST16_MAX__
|
||||||
|
#undef INT_LEAST32_MAX
|
||||||
|
#define INT_LEAST32_MAX __INT_LEAST32_MAX__
|
||||||
|
#undef INT_LEAST32_MIN
|
||||||
|
#define INT_LEAST32_MIN (-INT_LEAST32_MAX - 1)
|
||||||
|
#undef UINT_LEAST32_MAX
|
||||||
|
#define UINT_LEAST32_MAX __UINT_LEAST32_MAX__
|
||||||
|
#undef INT_LEAST64_MAX
|
||||||
|
#define INT_LEAST64_MAX __INT_LEAST64_MAX__
|
||||||
|
#undef INT_LEAST64_MIN
|
||||||
|
#define INT_LEAST64_MIN (-INT_LEAST64_MAX - 1)
|
||||||
|
#undef UINT_LEAST64_MAX
|
||||||
|
#define UINT_LEAST64_MAX __UINT_LEAST64_MAX__
|
||||||
|
|
||||||
|
#undef INT_FAST8_MAX
|
||||||
|
#define INT_FAST8_MAX __INT_FAST8_MAX__
|
||||||
|
#undef INT_FAST8_MIN
|
||||||
|
#define INT_FAST8_MIN (-INT_FAST8_MAX - 1)
|
||||||
|
#undef UINT_FAST8_MAX
|
||||||
|
#define UINT_FAST8_MAX __UINT_FAST8_MAX__
|
||||||
|
#undef INT_FAST16_MAX
|
||||||
|
#define INT_FAST16_MAX __INT_FAST16_MAX__
|
||||||
|
#undef INT_FAST16_MIN
|
||||||
|
#define INT_FAST16_MIN (-INT_FAST16_MAX - 1)
|
||||||
|
#undef UINT_FAST16_MAX
|
||||||
|
#define UINT_FAST16_MAX __UINT_FAST16_MAX__
|
||||||
|
#undef INT_FAST32_MAX
|
||||||
|
#define INT_FAST32_MAX __INT_FAST32_MAX__
|
||||||
|
#undef INT_FAST32_MIN
|
||||||
|
#define INT_FAST32_MIN (-INT_FAST32_MAX - 1)
|
||||||
|
#undef UINT_FAST32_MAX
|
||||||
|
#define UINT_FAST32_MAX __UINT_FAST32_MAX__
|
||||||
|
#undef INT_FAST64_MAX
|
||||||
|
#define INT_FAST64_MAX __INT_FAST64_MAX__
|
||||||
|
#undef INT_FAST64_MIN
|
||||||
|
#define INT_FAST64_MIN (-INT_FAST64_MAX - 1)
|
||||||
|
#undef UINT_FAST64_MAX
|
||||||
|
#define UINT_FAST64_MAX __UINT_FAST64_MAX__
|
||||||
|
|
||||||
|
#ifdef __INTPTR_MAX__
|
||||||
|
# undef INTPTR_MAX
|
||||||
|
# define INTPTR_MAX __INTPTR_MAX__
|
||||||
|
# undef INTPTR_MIN
|
||||||
|
# define INTPTR_MIN (-INTPTR_MAX - 1)
|
||||||
|
#endif
|
||||||
|
#ifdef __UINTPTR_MAX__
|
||||||
|
# undef UINTPTR_MAX
|
||||||
|
# define UINTPTR_MAX __UINTPTR_MAX__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef INTMAX_MAX
|
||||||
|
#define INTMAX_MAX __INTMAX_MAX__
|
||||||
|
#undef INTMAX_MIN
|
||||||
|
#define INTMAX_MIN (-INTMAX_MAX - 1)
|
||||||
|
#undef UINTMAX_MAX
|
||||||
|
#define UINTMAX_MAX __UINTMAX_MAX__
|
||||||
|
|
||||||
|
/* 7.18.3 Limits of other integer types */
|
||||||
|
|
||||||
|
#undef PTRDIFF_MAX
|
||||||
|
#define PTRDIFF_MAX __PTRDIFF_MAX__
|
||||||
|
#undef PTRDIFF_MIN
|
||||||
|
#define PTRDIFF_MIN (-PTRDIFF_MAX - 1)
|
||||||
|
|
||||||
|
#undef SIG_ATOMIC_MAX
|
||||||
|
#define SIG_ATOMIC_MAX __SIG_ATOMIC_MAX__
|
||||||
|
#undef SIG_ATOMIC_MIN
|
||||||
|
#define SIG_ATOMIC_MIN __SIG_ATOMIC_MIN__
|
||||||
|
|
||||||
|
#undef SIZE_MAX
|
||||||
|
#define SIZE_MAX __SIZE_MAX__
|
||||||
|
|
||||||
|
#undef WCHAR_MAX
|
||||||
|
#define WCHAR_MAX __WCHAR_MAX__
|
||||||
|
#undef WCHAR_MIN
|
||||||
|
#define WCHAR_MIN __WCHAR_MIN__
|
||||||
|
|
||||||
|
#undef WINT_MAX
|
||||||
|
#define WINT_MAX __WINT_MAX__
|
||||||
|
#undef WINT_MIN
|
||||||
|
#define WINT_MIN __WINT_MIN__
|
||||||
|
|
||||||
|
#endif /* (!defined __cplusplus || __cplusplus >= 201103L
|
||||||
|
|| defined __STDC_LIMIT_MACROS) */
|
||||||
|
|
||||||
|
#if (!defined __cplusplus || __cplusplus >= 201103L \
|
||||||
|
|| defined __STDC_CONSTANT_MACROS)
|
||||||
|
|
||||||
|
#undef INT8_C
|
||||||
|
#define INT8_C(c) __INT8_C(c)
|
||||||
|
#undef INT16_C
|
||||||
|
#define INT16_C(c) __INT16_C(c)
|
||||||
|
#undef INT32_C
|
||||||
|
#define INT32_C(c) __INT32_C(c)
|
||||||
|
#undef INT64_C
|
||||||
|
#define INT64_C(c) __INT64_C(c)
|
||||||
|
#undef UINT8_C
|
||||||
|
#define UINT8_C(c) __UINT8_C(c)
|
||||||
|
#undef UINT16_C
|
||||||
|
#define UINT16_C(c) __UINT16_C(c)
|
||||||
|
#undef UINT32_C
|
||||||
|
#define UINT32_C(c) __UINT32_C(c)
|
||||||
|
#undef UINT64_C
|
||||||
|
#define UINT64_C(c) __UINT64_C(c)
|
||||||
|
#undef INTMAX_C
|
||||||
|
#define INTMAX_C(c) __INTMAX_C(c)
|
||||||
|
#undef UINTMAX_C
|
||||||
|
#define UINTMAX_C(c) __UINTMAX_C(c)
|
||||||
|
|
||||||
|
#endif /* (!defined __cplusplus || __cplusplus >= 201103L
|
||||||
|
|| defined __STDC_CONSTANT_MACROS) */
|
||||||
|
|
||||||
|
#ifdef __STDC_WANT_IEC_60559_BFP_EXT__
|
||||||
|
/* TS 18661-1 widths of integer types. */
|
||||||
|
|
||||||
|
#ifdef __INT8_TYPE__
|
||||||
|
# undef INT8_WIDTH
|
||||||
|
# define INT8_WIDTH 8
|
||||||
|
#endif
|
||||||
|
#ifdef __UINT8_TYPE__
|
||||||
|
# undef UINT8_WIDTH
|
||||||
|
# define UINT8_WIDTH 8
|
||||||
|
#endif
|
||||||
|
#ifdef __INT16_TYPE__
|
||||||
|
# undef INT16_WIDTH
|
||||||
|
# define INT16_WIDTH 16
|
||||||
|
#endif
|
||||||
|
#ifdef __UINT16_TYPE__
|
||||||
|
# undef UINT16_WIDTH
|
||||||
|
# define UINT16_WIDTH 16
|
||||||
|
#endif
|
||||||
|
#ifdef __INT32_TYPE__
|
||||||
|
# undef INT32_WIDTH
|
||||||
|
# define INT32_WIDTH 32
|
||||||
|
#endif
|
||||||
|
#ifdef __UINT32_TYPE__
|
||||||
|
# undef UINT32_WIDTH
|
||||||
|
# define UINT32_WIDTH 32
|
||||||
|
#endif
|
||||||
|
#ifdef __INT64_TYPE__
|
||||||
|
# undef INT64_WIDTH
|
||||||
|
# define INT64_WIDTH 64
|
||||||
|
#endif
|
||||||
|
#ifdef __UINT64_TYPE__
|
||||||
|
# undef UINT64_WIDTH
|
||||||
|
# define UINT64_WIDTH 64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef INT_LEAST8_WIDTH
|
||||||
|
#define INT_LEAST8_WIDTH __INT_LEAST8_WIDTH__
|
||||||
|
#undef UINT_LEAST8_WIDTH
|
||||||
|
#define UINT_LEAST8_WIDTH __INT_LEAST8_WIDTH__
|
||||||
|
#undef INT_LEAST16_WIDTH
|
||||||
|
#define INT_LEAST16_WIDTH __INT_LEAST16_WIDTH__
|
||||||
|
#undef UINT_LEAST16_WIDTH
|
||||||
|
#define UINT_LEAST16_WIDTH __INT_LEAST16_WIDTH__
|
||||||
|
#undef INT_LEAST32_WIDTH
|
||||||
|
#define INT_LEAST32_WIDTH __INT_LEAST32_WIDTH__
|
||||||
|
#undef UINT_LEAST32_WIDTH
|
||||||
|
#define UINT_LEAST32_WIDTH __INT_LEAST32_WIDTH__
|
||||||
|
#undef INT_LEAST64_WIDTH
|
||||||
|
#define INT_LEAST64_WIDTH __INT_LEAST64_WIDTH__
|
||||||
|
#undef UINT_LEAST64_WIDTH
|
||||||
|
#define UINT_LEAST64_WIDTH __INT_LEAST64_WIDTH__
|
||||||
|
|
||||||
|
#undef INT_FAST8_WIDTH
|
||||||
|
#define INT_FAST8_WIDTH __INT_FAST8_WIDTH__
|
||||||
|
#undef UINT_FAST8_WIDTH
|
||||||
|
#define UINT_FAST8_WIDTH __INT_FAST8_WIDTH__
|
||||||
|
#undef INT_FAST16_WIDTH
|
||||||
|
#define INT_FAST16_WIDTH __INT_FAST16_WIDTH__
|
||||||
|
#undef UINT_FAST16_WIDTH
|
||||||
|
#define UINT_FAST16_WIDTH __INT_FAST16_WIDTH__
|
||||||
|
#undef INT_FAST32_WIDTH
|
||||||
|
#define INT_FAST32_WIDTH __INT_FAST32_WIDTH__
|
||||||
|
#undef UINT_FAST32_WIDTH
|
||||||
|
#define UINT_FAST32_WIDTH __INT_FAST32_WIDTH__
|
||||||
|
#undef INT_FAST64_WIDTH
|
||||||
|
#define INT_FAST64_WIDTH __INT_FAST64_WIDTH__
|
||||||
|
#undef UINT_FAST64_WIDTH
|
||||||
|
#define UINT_FAST64_WIDTH __INT_FAST64_WIDTH__
|
||||||
|
|
||||||
|
#ifdef __INTPTR_TYPE__
|
||||||
|
# undef INTPTR_WIDTH
|
||||||
|
# define INTPTR_WIDTH __INTPTR_WIDTH__
|
||||||
|
#endif
|
||||||
|
#ifdef __UINTPTR_TYPE__
|
||||||
|
# undef UINTPTR_WIDTH
|
||||||
|
# define UINTPTR_WIDTH __INTPTR_WIDTH__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef INTMAX_WIDTH
|
||||||
|
#define INTMAX_WIDTH __INTMAX_WIDTH__
|
||||||
|
#undef UINTMAX_WIDTH
|
||||||
|
#define UINTMAX_WIDTH __INTMAX_WIDTH__
|
||||||
|
|
||||||
|
#undef PTRDIFF_WIDTH
|
||||||
|
#define PTRDIFF_WIDTH __PTRDIFF_WIDTH__
|
||||||
|
|
||||||
|
#undef SIG_ATOMIC_WIDTH
|
||||||
|
#define SIG_ATOMIC_WIDTH __SIG_ATOMIC_WIDTH__
|
||||||
|
|
||||||
|
#undef SIZE_WIDTH
|
||||||
|
#define SIZE_WIDTH __SIZE_WIDTH__
|
||||||
|
|
||||||
|
#undef WCHAR_WIDTH
|
||||||
|
#define WCHAR_WIDTH __WCHAR_WIDTH__
|
||||||
|
|
||||||
|
#undef WINT_WIDTH
|
||||||
|
#define WINT_WIDTH __WINT_WIDTH__
|
||||||
|
|
||||||
|
#ifdef __ILP32__
|
||||||
|
#define SIZE_MAX UINT32_MAX
|
||||||
|
#else
|
||||||
|
#define SIZE_MAX UINT64_MAX
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _GCC_STDINT_H */
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#ifndef _STDIO_EXT_H
|
||||||
|
#define _STDIO_EXT_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
size_t __freadahead(FILE *stream);
|
||||||
|
size_t __fpending(FILE *stream);
|
||||||
|
int __freadable(FILE *stream);
|
||||||
|
int __freading(FILE *stream);
|
||||||
|
void __fseterr(FILE *stream);
|
||||||
|
int __fwritable(FILE *stream);
|
||||||
|
int __fwriting(FILE *stream);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _STDIO_EXT_H */
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/* Spec:
|
||||||
|
* The <stdnoreturn.h> header shall define the macro noreturn which shall
|
||||||
|
* expand to _Noreturn */
|
||||||
|
|
||||||
|
#ifndef _STDNORETURN_H
|
||||||
|
#define _STDNORETURN_H
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
/* Borrowed from musl */
|
||||||
|
#if __STDC_VERSION__ >= 201112L
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
#define _Noreturn __attribute__((__noreturn__))
|
||||||
|
#else
|
||||||
|
#define _Noreturn
|
||||||
|
#endif
|
||||||
|
#define noreturn _Noreturn
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#ifndef _SYS_PARAM_H
|
||||||
|
#define _SYS_PARAM_H
|
||||||
|
|
||||||
|
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||||
|
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
|
||||||
|
|
||||||
|
#define __bitop(array, index, op) ((array)[(index) / 8] op (1 << (index) % 8))
|
||||||
|
#define setbit(array, index) __bitop(array, index, |=)
|
||||||
|
#define clrbit(array, index) __bitop(array, index, &= ~)
|
||||||
|
#define isset(array, index) __bitop(array, index, &)
|
||||||
|
#define isclr(array, index) !isset(array, index)
|
||||||
|
|
||||||
|
#define howmany(bits, size) (((bits) + (size) - 1) / (size))
|
||||||
|
#define roundup(bits, size) (howmany(bits, size) * (size))
|
||||||
|
#define powerof2(n) !(((n) - 1) & (n))
|
||||||
|
|
||||||
|
// Shamelessly copied from musl.
|
||||||
|
// Tweak as needed.
|
||||||
|
#define MAXSYMLINKS 20
|
||||||
|
#define MAXHOSTNAMELEN 64
|
||||||
|
#define MAXNAMLEN 255
|
||||||
|
#define MAXPATHLEN 4096
|
||||||
|
#define NBBY 8
|
||||||
|
#define NGROUPS 32
|
||||||
|
#define CANBSIZ 255
|
||||||
|
#define NOFILE 256
|
||||||
|
#define NCARGS 131072
|
||||||
|
#define DEV_BSIZE 512
|
||||||
|
#define NOGROUP (-1)
|
||||||
|
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include <machine/endian.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
#include <poll.h>
|
||||||
@@ -0,0 +1,846 @@
|
|||||||
|
/* $NetBSD: queue.h,v 1.70 2015/11/02 15:21:23 christos Exp $ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1991, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* @(#)queue.h 8.5 (Berkeley) 8/20/94
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SYS_QUEUE_H_
|
||||||
|
#define _SYS_QUEUE_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file defines five types of data structures: singly-linked lists,
|
||||||
|
* lists, simple queues, tail queues, and circular queues.
|
||||||
|
*
|
||||||
|
* A singly-linked list is headed by a single forward pointer. The
|
||||||
|
* elements are singly linked for minimum space and pointer manipulation
|
||||||
|
* overhead at the expense of O(n) removal for arbitrary elements. New
|
||||||
|
* elements can be added to the list after an existing element or at the
|
||||||
|
* head of the list. Elements being removed from the head of the list
|
||||||
|
* should use the explicit macro for this purpose for optimum
|
||||||
|
* efficiency. A singly-linked list may only be traversed in the forward
|
||||||
|
* direction. Singly-linked lists are ideal for applications with large
|
||||||
|
* datasets and few or no removals or for implementing a LIFO queue.
|
||||||
|
*
|
||||||
|
* A list is headed by a single forward pointer (or an array of forward
|
||||||
|
* pointers for a hash table header). The elements are doubly linked
|
||||||
|
* so that an arbitrary element can be removed without a need to
|
||||||
|
* traverse the list. New elements can be added to the list before
|
||||||
|
* or after an existing element or at the head of the list. A list
|
||||||
|
* may only be traversed in the forward direction.
|
||||||
|
*
|
||||||
|
* A simple queue is headed by a pair of pointers, one the head of the
|
||||||
|
* list and the other to the tail of the list. The elements are singly
|
||||||
|
* linked to save space, so elements can only be removed from the
|
||||||
|
* head of the list. New elements can be added to the list after
|
||||||
|
* an existing element, at the head of the list, or at the end of the
|
||||||
|
* list. A simple queue may only be traversed in the forward direction.
|
||||||
|
*
|
||||||
|
* A tail queue is headed by a pair of pointers, one to the head of the
|
||||||
|
* list and the other to the tail of the list. The elements are doubly
|
||||||
|
* linked so that an arbitrary element can be removed without a need to
|
||||||
|
* traverse the list. New elements can be added to the list before or
|
||||||
|
* after an existing element, at the head of the list, or at the end of
|
||||||
|
* the list. A tail queue may be traversed in either direction.
|
||||||
|
*
|
||||||
|
* A circle queue is headed by a pair of pointers, one to the head of the
|
||||||
|
* list and the other to the tail of the list. The elements are doubly
|
||||||
|
* linked so that an arbitrary element can be removed without a need to
|
||||||
|
* traverse the list. New elements can be added to the list before or after
|
||||||
|
* an existing element, at the head of the list, or at the end of the list.
|
||||||
|
* A circle queue may be traversed in either direction, but has a more
|
||||||
|
* complex end of list detection.
|
||||||
|
*
|
||||||
|
* For details on the use of these macros, see the queue(3) manual page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Include the definition of NULL only on NetBSD because sys/null.h
|
||||||
|
* is not available elsewhere. This conditional makes the header
|
||||||
|
* portable and it can simply be dropped verbatim into any system.
|
||||||
|
* The caveat is that on other systems some other header
|
||||||
|
* must provide NULL before the macros can be used.
|
||||||
|
*/
|
||||||
|
#ifdef __NetBSD__
|
||||||
|
#include <sys/null.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(QUEUEDEBUG)
|
||||||
|
# if defined(_KERNEL)
|
||||||
|
# define QUEUEDEBUG_ABORT(...) panic(__VA_ARGS__)
|
||||||
|
# else
|
||||||
|
# include <err.h>
|
||||||
|
# define QUEUEDEBUG_ABORT(...) err(1, __VA_ARGS__)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Singly-linked List definitions.
|
||||||
|
*/
|
||||||
|
#define SLIST_HEAD(name, type) \
|
||||||
|
struct name { \
|
||||||
|
struct type *slh_first; /* first element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SLIST_HEAD_INITIALIZER(head) \
|
||||||
|
{ NULL }
|
||||||
|
|
||||||
|
#define SLIST_ENTRY(type) \
|
||||||
|
struct { \
|
||||||
|
struct type *sle_next; /* next element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Singly-linked List access methods.
|
||||||
|
*/
|
||||||
|
#define SLIST_FIRST(head) ((head)->slh_first)
|
||||||
|
#define SLIST_END(head) NULL
|
||||||
|
#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
|
||||||
|
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
|
||||||
|
|
||||||
|
#define SLIST_FOREACH(var, head, field) \
|
||||||
|
for((var) = (head)->slh_first; \
|
||||||
|
(var) != SLIST_END(head); \
|
||||||
|
(var) = (var)->field.sle_next)
|
||||||
|
|
||||||
|
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
|
||||||
|
for ((var) = SLIST_FIRST((head)); \
|
||||||
|
(var) != SLIST_END(head) && \
|
||||||
|
((tvar) = SLIST_NEXT((var), field), 1); \
|
||||||
|
(var) = (tvar))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Singly-linked List functions.
|
||||||
|
*/
|
||||||
|
#define SLIST_INIT(head) do { \
|
||||||
|
(head)->slh_first = SLIST_END(head); \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
|
||||||
|
(elm)->field.sle_next = (slistelm)->field.sle_next; \
|
||||||
|
(slistelm)->field.sle_next = (elm); \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define SLIST_INSERT_HEAD(head, elm, field) do { \
|
||||||
|
(elm)->field.sle_next = (head)->slh_first; \
|
||||||
|
(head)->slh_first = (elm); \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define SLIST_REMOVE_AFTER(slistelm, field) do { \
|
||||||
|
(slistelm)->field.sle_next = \
|
||||||
|
SLIST_NEXT(SLIST_NEXT((slistelm), field), field); \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define SLIST_REMOVE_HEAD(head, field) do { \
|
||||||
|
(head)->slh_first = (head)->slh_first->field.sle_next; \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define SLIST_REMOVE(head, elm, type, field) do { \
|
||||||
|
if ((head)->slh_first == (elm)) { \
|
||||||
|
SLIST_REMOVE_HEAD((head), field); \
|
||||||
|
} \
|
||||||
|
else { \
|
||||||
|
struct type *curelm = (head)->slh_first; \
|
||||||
|
while(curelm->field.sle_next != (elm)) \
|
||||||
|
curelm = curelm->field.sle_next; \
|
||||||
|
curelm->field.sle_next = \
|
||||||
|
curelm->field.sle_next->field.sle_next; \
|
||||||
|
} \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List definitions.
|
||||||
|
*/
|
||||||
|
#define LIST_HEAD(name, type) \
|
||||||
|
struct name { \
|
||||||
|
struct type *lh_first; /* first element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LIST_HEAD_INITIALIZER(head) \
|
||||||
|
{ NULL }
|
||||||
|
|
||||||
|
#define LIST_ENTRY(type) \
|
||||||
|
struct { \
|
||||||
|
struct type *le_next; /* next element */ \
|
||||||
|
struct type **le_prev; /* address of previous next element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List access methods.
|
||||||
|
*/
|
||||||
|
#define LIST_FIRST(head) ((head)->lh_first)
|
||||||
|
#define LIST_END(head) NULL
|
||||||
|
#define LIST_EMPTY(head) ((head)->lh_first == LIST_END(head))
|
||||||
|
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
|
||||||
|
|
||||||
|
#define LIST_FOREACH(var, head, field) \
|
||||||
|
for ((var) = ((head)->lh_first); \
|
||||||
|
(var) != LIST_END(head); \
|
||||||
|
(var) = ((var)->field.le_next))
|
||||||
|
|
||||||
|
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
|
||||||
|
for ((var) = LIST_FIRST((head)); \
|
||||||
|
(var) != LIST_END(head) && \
|
||||||
|
((tvar) = LIST_NEXT((var), field), 1); \
|
||||||
|
(var) = (tvar))
|
||||||
|
|
||||||
|
#define LIST_MOVE(head1, head2) do { \
|
||||||
|
LIST_INIT((head2)); \
|
||||||
|
if (!LIST_EMPTY((head1))) { \
|
||||||
|
(head2)->lh_first = (head1)->lh_first; \
|
||||||
|
LIST_INIT((head1)); \
|
||||||
|
} \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List functions.
|
||||||
|
*/
|
||||||
|
#if defined(QUEUEDEBUG)
|
||||||
|
#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) \
|
||||||
|
if ((head)->lh_first && \
|
||||||
|
(head)->lh_first->field.le_prev != &(head)->lh_first) \
|
||||||
|
QUEUEDEBUG_ABORT("LIST_INSERT_HEAD %p %s:%d", (head), \
|
||||||
|
__FILE__, __LINE__);
|
||||||
|
#define QUEUEDEBUG_LIST_OP(elm, field) \
|
||||||
|
if ((elm)->field.le_next && \
|
||||||
|
(elm)->field.le_next->field.le_prev != \
|
||||||
|
&(elm)->field.le_next) \
|
||||||
|
QUEUEDEBUG_ABORT("LIST_* forw %p %s:%d", (elm), \
|
||||||
|
__FILE__, __LINE__); \
|
||||||
|
if (*(elm)->field.le_prev != (elm)) \
|
||||||
|
QUEUEDEBUG_ABORT("LIST_* back %p %s:%d", (elm), \
|
||||||
|
__FILE__, __LINE__);
|
||||||
|
#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) \
|
||||||
|
(elm)->field.le_next = (void *)1L; \
|
||||||
|
(elm)->field.le_prev = (void *)1L;
|
||||||
|
#else
|
||||||
|
#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field)
|
||||||
|
#define QUEUEDEBUG_LIST_OP(elm, field)
|
||||||
|
#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define LIST_INIT(head) do { \
|
||||||
|
(head)->lh_first = LIST_END(head); \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
|
||||||
|
QUEUEDEBUG_LIST_OP((listelm), field) \
|
||||||
|
if (((elm)->field.le_next = (listelm)->field.le_next) != \
|
||||||
|
LIST_END(head)) \
|
||||||
|
(listelm)->field.le_next->field.le_prev = \
|
||||||
|
&(elm)->field.le_next; \
|
||||||
|
(listelm)->field.le_next = (elm); \
|
||||||
|
(elm)->field.le_prev = &(listelm)->field.le_next; \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
|
||||||
|
QUEUEDEBUG_LIST_OP((listelm), field) \
|
||||||
|
(elm)->field.le_prev = (listelm)->field.le_prev; \
|
||||||
|
(elm)->field.le_next = (listelm); \
|
||||||
|
*(listelm)->field.le_prev = (elm); \
|
||||||
|
(listelm)->field.le_prev = &(elm)->field.le_next; \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define LIST_INSERT_HEAD(head, elm, field) do { \
|
||||||
|
QUEUEDEBUG_LIST_INSERT_HEAD((head), (elm), field) \
|
||||||
|
if (((elm)->field.le_next = (head)->lh_first) != LIST_END(head))\
|
||||||
|
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
|
||||||
|
(head)->lh_first = (elm); \
|
||||||
|
(elm)->field.le_prev = &(head)->lh_first; \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define LIST_REMOVE(elm, field) do { \
|
||||||
|
QUEUEDEBUG_LIST_OP((elm), field) \
|
||||||
|
if ((elm)->field.le_next != NULL) \
|
||||||
|
(elm)->field.le_next->field.le_prev = \
|
||||||
|
(elm)->field.le_prev; \
|
||||||
|
*(elm)->field.le_prev = (elm)->field.le_next; \
|
||||||
|
QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define LIST_REPLACE(elm, elm2, field) do { \
|
||||||
|
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
|
||||||
|
(elm2)->field.le_next->field.le_prev = \
|
||||||
|
&(elm2)->field.le_next; \
|
||||||
|
(elm2)->field.le_prev = (elm)->field.le_prev; \
|
||||||
|
*(elm2)->field.le_prev = (elm2); \
|
||||||
|
QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simple queue definitions.
|
||||||
|
*/
|
||||||
|
#define SIMPLEQ_HEAD(name, type) \
|
||||||
|
struct name { \
|
||||||
|
struct type *sqh_first; /* first element */ \
|
||||||
|
struct type **sqh_last; /* addr of last next element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SIMPLEQ_HEAD_INITIALIZER(head) \
|
||||||
|
{ NULL, &(head).sqh_first }
|
||||||
|
|
||||||
|
#define SIMPLEQ_ENTRY(type) \
|
||||||
|
struct { \
|
||||||
|
struct type *sqe_next; /* next element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simple queue access methods.
|
||||||
|
*/
|
||||||
|
#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
|
||||||
|
#define SIMPLEQ_END(head) NULL
|
||||||
|
#define SIMPLEQ_EMPTY(head) ((head)->sqh_first == SIMPLEQ_END(head))
|
||||||
|
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
|
||||||
|
|
||||||
|
#define SIMPLEQ_FOREACH(var, head, field) \
|
||||||
|
for ((var) = ((head)->sqh_first); \
|
||||||
|
(var) != SIMPLEQ_END(head); \
|
||||||
|
(var) = ((var)->field.sqe_next))
|
||||||
|
|
||||||
|
#define SIMPLEQ_FOREACH_SAFE(var, head, field, next) \
|
||||||
|
for ((var) = ((head)->sqh_first); \
|
||||||
|
(var) != SIMPLEQ_END(head) && \
|
||||||
|
((next = ((var)->field.sqe_next)), 1); \
|
||||||
|
(var) = (next))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simple queue functions.
|
||||||
|
*/
|
||||||
|
#define SIMPLEQ_INIT(head) do { \
|
||||||
|
(head)->sqh_first = NULL; \
|
||||||
|
(head)->sqh_last = &(head)->sqh_first; \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||||
|
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
|
||||||
|
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||||
|
(head)->sqh_first = (elm); \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||||
|
(elm)->field.sqe_next = NULL; \
|
||||||
|
*(head)->sqh_last = (elm); \
|
||||||
|
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||||
|
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
|
||||||
|
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||||
|
(listelm)->field.sqe_next = (elm); \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
|
||||||
|
if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
|
||||||
|
(head)->sqh_last = &(head)->sqh_first; \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
|
||||||
|
if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
|
||||||
|
== NULL) \
|
||||||
|
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define SIMPLEQ_REMOVE(head, elm, type, field) do { \
|
||||||
|
if ((head)->sqh_first == (elm)) { \
|
||||||
|
SIMPLEQ_REMOVE_HEAD((head), field); \
|
||||||
|
} else { \
|
||||||
|
struct type *curelm = (head)->sqh_first; \
|
||||||
|
while (curelm->field.sqe_next != (elm)) \
|
||||||
|
curelm = curelm->field.sqe_next; \
|
||||||
|
if ((curelm->field.sqe_next = \
|
||||||
|
curelm->field.sqe_next->field.sqe_next) == NULL) \
|
||||||
|
(head)->sqh_last = &(curelm)->field.sqe_next; \
|
||||||
|
} \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define SIMPLEQ_CONCAT(head1, head2) do { \
|
||||||
|
if (!SIMPLEQ_EMPTY((head2))) { \
|
||||||
|
*(head1)->sqh_last = (head2)->sqh_first; \
|
||||||
|
(head1)->sqh_last = (head2)->sqh_last; \
|
||||||
|
SIMPLEQ_INIT((head2)); \
|
||||||
|
} \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define SIMPLEQ_LAST(head, type, field) \
|
||||||
|
(SIMPLEQ_EMPTY((head)) ? \
|
||||||
|
NULL : \
|
||||||
|
((struct type *)(void *) \
|
||||||
|
((char *)((head)->sqh_last) - offsetof(struct type, field))))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tail queue definitions.
|
||||||
|
*/
|
||||||
|
#define _TAILQ_HEAD(name, type, qual) \
|
||||||
|
struct name { \
|
||||||
|
qual type *tqh_first; /* first element */ \
|
||||||
|
qual type *qual *tqh_last; /* addr of last next element */ \
|
||||||
|
}
|
||||||
|
#define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type,)
|
||||||
|
|
||||||
|
#define TAILQ_HEAD_INITIALIZER(head) \
|
||||||
|
{ TAILQ_END(head), &(head).tqh_first }
|
||||||
|
|
||||||
|
#define _TAILQ_ENTRY(type, qual) \
|
||||||
|
struct { \
|
||||||
|
qual type *tqe_next; /* next element */ \
|
||||||
|
qual type *qual *tqe_prev; /* address of previous next element */\
|
||||||
|
}
|
||||||
|
#define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type,)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tail queue access methods.
|
||||||
|
*/
|
||||||
|
#define TAILQ_FIRST(head) ((head)->tqh_first)
|
||||||
|
#define TAILQ_END(head) (NULL)
|
||||||
|
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
|
||||||
|
#define TAILQ_LAST(head, headname) \
|
||||||
|
(*(((struct headname *)(void *)((head)->tqh_last))->tqh_last))
|
||||||
|
#define TAILQ_PREV(elm, headname, field) \
|
||||||
|
(*(((struct headname *)(void *)((elm)->field.tqe_prev))->tqh_last))
|
||||||
|
#define TAILQ_EMPTY(head) (TAILQ_FIRST(head) == TAILQ_END(head))
|
||||||
|
|
||||||
|
|
||||||
|
#define TAILQ_FOREACH(var, head, field) \
|
||||||
|
for ((var) = ((head)->tqh_first); \
|
||||||
|
(var) != TAILQ_END(head); \
|
||||||
|
(var) = ((var)->field.tqe_next))
|
||||||
|
|
||||||
|
#define TAILQ_FOREACH_SAFE(var, head, field, next) \
|
||||||
|
for ((var) = ((head)->tqh_first); \
|
||||||
|
(var) != TAILQ_END(head) && \
|
||||||
|
((next) = TAILQ_NEXT(var, field), 1); (var) = (next))
|
||||||
|
|
||||||
|
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
|
||||||
|
for ((var) = TAILQ_LAST((head), headname); \
|
||||||
|
(var) != TAILQ_END(head); \
|
||||||
|
(var) = TAILQ_PREV((var), headname, field))
|
||||||
|
|
||||||
|
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, prev) \
|
||||||
|
for ((var) = TAILQ_LAST((head), headname); \
|
||||||
|
(var) != TAILQ_END(head) && \
|
||||||
|
((prev) = TAILQ_PREV((var), headname, field), 1); (var) = (prev))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tail queue functions.
|
||||||
|
*/
|
||||||
|
#if defined(QUEUEDEBUG)
|
||||||
|
#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field) \
|
||||||
|
if ((head)->tqh_first && \
|
||||||
|
(head)->tqh_first->field.tqe_prev != &(head)->tqh_first) \
|
||||||
|
QUEUEDEBUG_ABORT("TAILQ_INSERT_HEAD %p %s:%d", (head), \
|
||||||
|
__FILE__, __LINE__);
|
||||||
|
#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field) \
|
||||||
|
if (*(head)->tqh_last != NULL) \
|
||||||
|
QUEUEDEBUG_ABORT("TAILQ_INSERT_TAIL %p %s:%d", (head), \
|
||||||
|
__FILE__, __LINE__);
|
||||||
|
#define QUEUEDEBUG_TAILQ_OP(elm, field) \
|
||||||
|
if ((elm)->field.tqe_next && \
|
||||||
|
(elm)->field.tqe_next->field.tqe_prev != \
|
||||||
|
&(elm)->field.tqe_next) \
|
||||||
|
QUEUEDEBUG_ABORT("TAILQ_* forw %p %s:%d", (elm), \
|
||||||
|
__FILE__, __LINE__); \
|
||||||
|
if (*(elm)->field.tqe_prev != (elm)) \
|
||||||
|
QUEUEDEBUG_ABORT("TAILQ_* back %p %s:%d", (elm), \
|
||||||
|
__FILE__, __LINE__);
|
||||||
|
#define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field) \
|
||||||
|
if ((elm)->field.tqe_next == NULL && \
|
||||||
|
(head)->tqh_last != &(elm)->field.tqe_next) \
|
||||||
|
QUEUEDEBUG_ABORT("TAILQ_PREREMOVE head %p elm %p %s:%d",\
|
||||||
|
(head), (elm), __FILE__, __LINE__);
|
||||||
|
#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field) \
|
||||||
|
(elm)->field.tqe_next = (void *)1L; \
|
||||||
|
(elm)->field.tqe_prev = (void *)1L;
|
||||||
|
#else
|
||||||
|
#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field)
|
||||||
|
#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field)
|
||||||
|
#define QUEUEDEBUG_TAILQ_OP(elm, field)
|
||||||
|
#define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field)
|
||||||
|
#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TAILQ_INIT(head) do { \
|
||||||
|
(head)->tqh_first = TAILQ_END(head); \
|
||||||
|
(head)->tqh_last = &(head)->tqh_first; \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||||
|
QUEUEDEBUG_TAILQ_INSERT_HEAD((head), (elm), field) \
|
||||||
|
if (((elm)->field.tqe_next = (head)->tqh_first) != TAILQ_END(head))\
|
||||||
|
(head)->tqh_first->field.tqe_prev = \
|
||||||
|
&(elm)->field.tqe_next; \
|
||||||
|
else \
|
||||||
|
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||||
|
(head)->tqh_first = (elm); \
|
||||||
|
(elm)->field.tqe_prev = &(head)->tqh_first; \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||||
|
QUEUEDEBUG_TAILQ_INSERT_TAIL((head), (elm), field) \
|
||||||
|
(elm)->field.tqe_next = TAILQ_END(head); \
|
||||||
|
(elm)->field.tqe_prev = (head)->tqh_last; \
|
||||||
|
*(head)->tqh_last = (elm); \
|
||||||
|
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||||
|
QUEUEDEBUG_TAILQ_OP((listelm), field) \
|
||||||
|
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != \
|
||||||
|
TAILQ_END(head)) \
|
||||||
|
(elm)->field.tqe_next->field.tqe_prev = \
|
||||||
|
&(elm)->field.tqe_next; \
|
||||||
|
else \
|
||||||
|
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||||
|
(listelm)->field.tqe_next = (elm); \
|
||||||
|
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
|
||||||
|
QUEUEDEBUG_TAILQ_OP((listelm), field) \
|
||||||
|
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
|
||||||
|
(elm)->field.tqe_next = (listelm); \
|
||||||
|
*(listelm)->field.tqe_prev = (elm); \
|
||||||
|
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define TAILQ_REMOVE(head, elm, field) do { \
|
||||||
|
QUEUEDEBUG_TAILQ_PREREMOVE((head), (elm), field) \
|
||||||
|
QUEUEDEBUG_TAILQ_OP((elm), field) \
|
||||||
|
if (((elm)->field.tqe_next) != TAILQ_END(head)) \
|
||||||
|
(elm)->field.tqe_next->field.tqe_prev = \
|
||||||
|
(elm)->field.tqe_prev; \
|
||||||
|
else \
|
||||||
|
(head)->tqh_last = (elm)->field.tqe_prev; \
|
||||||
|
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
|
||||||
|
QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field); \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define TAILQ_REPLACE(head, elm, elm2, field) do { \
|
||||||
|
if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != \
|
||||||
|
TAILQ_END(head)) \
|
||||||
|
(elm2)->field.tqe_next->field.tqe_prev = \
|
||||||
|
&(elm2)->field.tqe_next; \
|
||||||
|
else \
|
||||||
|
(head)->tqh_last = &(elm2)->field.tqe_next; \
|
||||||
|
(elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
|
||||||
|
*(elm2)->field.tqe_prev = (elm2); \
|
||||||
|
QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field); \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define TAILQ_CONCAT(head1, head2, field) do { \
|
||||||
|
if (!TAILQ_EMPTY(head2)) { \
|
||||||
|
*(head1)->tqh_last = (head2)->tqh_first; \
|
||||||
|
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
|
||||||
|
(head1)->tqh_last = (head2)->tqh_last; \
|
||||||
|
TAILQ_INIT((head2)); \
|
||||||
|
} \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Singly-linked Tail queue declarations.
|
||||||
|
*/
|
||||||
|
#define STAILQ_HEAD(name, type) \
|
||||||
|
struct name { \
|
||||||
|
struct type *stqh_first; /* first element */ \
|
||||||
|
struct type **stqh_last; /* addr of last next element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define STAILQ_HEAD_INITIALIZER(head) \
|
||||||
|
{ NULL, &(head).stqh_first }
|
||||||
|
|
||||||
|
#define STAILQ_ENTRY(type) \
|
||||||
|
struct { \
|
||||||
|
struct type *stqe_next; /* next element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Singly-linked Tail queue access methods.
|
||||||
|
*/
|
||||||
|
#define STAILQ_FIRST(head) ((head)->stqh_first)
|
||||||
|
#define STAILQ_END(head) NULL
|
||||||
|
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
|
||||||
|
#define STAILQ_EMPTY(head) (STAILQ_FIRST(head) == STAILQ_END(head))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Singly-linked Tail queue functions.
|
||||||
|
*/
|
||||||
|
#define STAILQ_INIT(head) do { \
|
||||||
|
(head)->stqh_first = NULL; \
|
||||||
|
(head)->stqh_last = &(head)->stqh_first; \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define STAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||||
|
if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \
|
||||||
|
(head)->stqh_last = &(elm)->field.stqe_next; \
|
||||||
|
(head)->stqh_first = (elm); \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define STAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||||
|
(elm)->field.stqe_next = NULL; \
|
||||||
|
*(head)->stqh_last = (elm); \
|
||||||
|
(head)->stqh_last = &(elm)->field.stqe_next; \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||||
|
if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\
|
||||||
|
(head)->stqh_last = &(elm)->field.stqe_next; \
|
||||||
|
(listelm)->field.stqe_next = (elm); \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define STAILQ_REMOVE_HEAD(head, field) do { \
|
||||||
|
if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \
|
||||||
|
(head)->stqh_last = &(head)->stqh_first; \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define STAILQ_REMOVE(head, elm, type, field) do { \
|
||||||
|
if ((head)->stqh_first == (elm)) { \
|
||||||
|
STAILQ_REMOVE_HEAD((head), field); \
|
||||||
|
} else { \
|
||||||
|
struct type *curelm = (head)->stqh_first; \
|
||||||
|
while (curelm->field.stqe_next != (elm)) \
|
||||||
|
curelm = curelm->field.stqe_next; \
|
||||||
|
if ((curelm->field.stqe_next = \
|
||||||
|
curelm->field.stqe_next->field.stqe_next) == NULL) \
|
||||||
|
(head)->stqh_last = &(curelm)->field.stqe_next; \
|
||||||
|
} \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define STAILQ_FOREACH(var, head, field) \
|
||||||
|
for ((var) = ((head)->stqh_first); \
|
||||||
|
(var); \
|
||||||
|
(var) = ((var)->field.stqe_next))
|
||||||
|
|
||||||
|
#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
|
||||||
|
for ((var) = STAILQ_FIRST((head)); \
|
||||||
|
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
|
||||||
|
(var) = (tvar))
|
||||||
|
|
||||||
|
#define STAILQ_CONCAT(head1, head2) do { \
|
||||||
|
if (!STAILQ_EMPTY((head2))) { \
|
||||||
|
*(head1)->stqh_last = (head2)->stqh_first; \
|
||||||
|
(head1)->stqh_last = (head2)->stqh_last; \
|
||||||
|
STAILQ_INIT((head2)); \
|
||||||
|
} \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define STAILQ_LAST(head, type, field) \
|
||||||
|
(STAILQ_EMPTY((head)) ? \
|
||||||
|
NULL : \
|
||||||
|
((struct type *)(void *) \
|
||||||
|
((char *)((head)->stqh_last) - offsetof(struct type, field))))
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _KERNEL
|
||||||
|
/*
|
||||||
|
* Circular queue definitions. Do not use. We still keep the macros
|
||||||
|
* for compatibility but because of pointer aliasing issues their use
|
||||||
|
* is discouraged!
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* __launder_type(): We use this ugly hack to work around the the compiler
|
||||||
|
* noticing that two types may not alias each other and elide tests in code.
|
||||||
|
* We hit this in the CIRCLEQ macros when comparing 'struct name *' and
|
||||||
|
* 'struct type *' (see CIRCLEQ_HEAD()). Modern compilers (such as GCC
|
||||||
|
* 4.8) declare these comparisons as always false, causing the code to
|
||||||
|
* not run as designed.
|
||||||
|
*
|
||||||
|
* This hack is only to be used for comparisons and thus can be fully const.
|
||||||
|
* Do not use for assignment.
|
||||||
|
*
|
||||||
|
* If we ever choose to change the ABI of the CIRCLEQ macros, we could fix
|
||||||
|
* this by changing the head/tail sentinal values, but see the note above
|
||||||
|
* this one.
|
||||||
|
*/
|
||||||
|
static __inline const void * __launder_type(const void *);
|
||||||
|
static __inline const void *
|
||||||
|
__launder_type(const void *__x)
|
||||||
|
{
|
||||||
|
__asm __volatile("" : "+r" (__x));
|
||||||
|
return __x;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(QUEUEDEBUG)
|
||||||
|
#define QUEUEDEBUG_CIRCLEQ_HEAD(head, field) \
|
||||||
|
if ((head)->cqh_first != CIRCLEQ_ENDC(head) && \
|
||||||
|
(head)->cqh_first->field.cqe_prev != CIRCLEQ_ENDC(head)) \
|
||||||
|
QUEUEDEBUG_ABORT("CIRCLEQ head forw %p %s:%d", (head), \
|
||||||
|
__FILE__, __LINE__); \
|
||||||
|
if ((head)->cqh_last != CIRCLEQ_ENDC(head) && \
|
||||||
|
(head)->cqh_last->field.cqe_next != CIRCLEQ_ENDC(head)) \
|
||||||
|
QUEUEDEBUG_ABORT("CIRCLEQ head back %p %s:%d", (head), \
|
||||||
|
__FILE__, __LINE__);
|
||||||
|
#define QUEUEDEBUG_CIRCLEQ_ELM(head, elm, field) \
|
||||||
|
if ((elm)->field.cqe_next == CIRCLEQ_ENDC(head)) { \
|
||||||
|
if ((head)->cqh_last != (elm)) \
|
||||||
|
QUEUEDEBUG_ABORT("CIRCLEQ elm last %p %s:%d", \
|
||||||
|
(elm), __FILE__, __LINE__); \
|
||||||
|
} else { \
|
||||||
|
if ((elm)->field.cqe_next->field.cqe_prev != (elm)) \
|
||||||
|
QUEUEDEBUG_ABORT("CIRCLEQ elm forw %p %s:%d", \
|
||||||
|
(elm), __FILE__, __LINE__); \
|
||||||
|
} \
|
||||||
|
if ((elm)->field.cqe_prev == CIRCLEQ_ENDC(head)) { \
|
||||||
|
if ((head)->cqh_first != (elm)) \
|
||||||
|
QUEUEDEBUG_ABORT("CIRCLEQ elm first %p %s:%d", \
|
||||||
|
(elm), __FILE__, __LINE__); \
|
||||||
|
} else { \
|
||||||
|
if ((elm)->field.cqe_prev->field.cqe_next != (elm)) \
|
||||||
|
QUEUEDEBUG_ABORT("CIRCLEQ elm prev %p %s:%d", \
|
||||||
|
(elm), __FILE__, __LINE__); \
|
||||||
|
}
|
||||||
|
#define QUEUEDEBUG_CIRCLEQ_POSTREMOVE(elm, field) \
|
||||||
|
(elm)->field.cqe_next = (void *)1L; \
|
||||||
|
(elm)->field.cqe_prev = (void *)1L;
|
||||||
|
#else
|
||||||
|
#define QUEUEDEBUG_CIRCLEQ_HEAD(head, field)
|
||||||
|
#define QUEUEDEBUG_CIRCLEQ_ELM(head, elm, field)
|
||||||
|
#define QUEUEDEBUG_CIRCLEQ_POSTREMOVE(elm, field)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CIRCLEQ_HEAD(name, type) \
|
||||||
|
struct name { \
|
||||||
|
struct type *cqh_first; /* first element */ \
|
||||||
|
struct type *cqh_last; /* last element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CIRCLEQ_HEAD_INITIALIZER(head) \
|
||||||
|
{ CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
|
||||||
|
|
||||||
|
#define CIRCLEQ_ENTRY(type) \
|
||||||
|
struct { \
|
||||||
|
struct type *cqe_next; /* next element */ \
|
||||||
|
struct type *cqe_prev; /* previous element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Circular queue functions.
|
||||||
|
*/
|
||||||
|
#define CIRCLEQ_INIT(head) do { \
|
||||||
|
(head)->cqh_first = CIRCLEQ_END(head); \
|
||||||
|
(head)->cqh_last = CIRCLEQ_END(head); \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||||
|
QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \
|
||||||
|
QUEUEDEBUG_CIRCLEQ_ELM((head), (listelm), field) \
|
||||||
|
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
|
||||||
|
(elm)->field.cqe_prev = (listelm); \
|
||||||
|
if ((listelm)->field.cqe_next == CIRCLEQ_ENDC(head)) \
|
||||||
|
(head)->cqh_last = (elm); \
|
||||||
|
else \
|
||||||
|
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
|
||||||
|
(listelm)->field.cqe_next = (elm); \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
|
||||||
|
QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \
|
||||||
|
QUEUEDEBUG_CIRCLEQ_ELM((head), (listelm), field) \
|
||||||
|
(elm)->field.cqe_next = (listelm); \
|
||||||
|
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
|
||||||
|
if ((listelm)->field.cqe_prev == CIRCLEQ_ENDC(head)) \
|
||||||
|
(head)->cqh_first = (elm); \
|
||||||
|
else \
|
||||||
|
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
|
||||||
|
(listelm)->field.cqe_prev = (elm); \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||||
|
QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \
|
||||||
|
(elm)->field.cqe_next = (head)->cqh_first; \
|
||||||
|
(elm)->field.cqe_prev = CIRCLEQ_END(head); \
|
||||||
|
if ((head)->cqh_last == CIRCLEQ_ENDC(head)) \
|
||||||
|
(head)->cqh_last = (elm); \
|
||||||
|
else \
|
||||||
|
(head)->cqh_first->field.cqe_prev = (elm); \
|
||||||
|
(head)->cqh_first = (elm); \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||||
|
QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \
|
||||||
|
(elm)->field.cqe_next = CIRCLEQ_END(head); \
|
||||||
|
(elm)->field.cqe_prev = (head)->cqh_last; \
|
||||||
|
if ((head)->cqh_first == CIRCLEQ_ENDC(head)) \
|
||||||
|
(head)->cqh_first = (elm); \
|
||||||
|
else \
|
||||||
|
(head)->cqh_last->field.cqe_next = (elm); \
|
||||||
|
(head)->cqh_last = (elm); \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define CIRCLEQ_REMOVE(head, elm, field) do { \
|
||||||
|
QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \
|
||||||
|
QUEUEDEBUG_CIRCLEQ_ELM((head), (elm), field) \
|
||||||
|
if ((elm)->field.cqe_next == CIRCLEQ_ENDC(head)) \
|
||||||
|
(head)->cqh_last = (elm)->field.cqe_prev; \
|
||||||
|
else \
|
||||||
|
(elm)->field.cqe_next->field.cqe_prev = \
|
||||||
|
(elm)->field.cqe_prev; \
|
||||||
|
if ((elm)->field.cqe_prev == CIRCLEQ_ENDC(head)) \
|
||||||
|
(head)->cqh_first = (elm)->field.cqe_next; \
|
||||||
|
else \
|
||||||
|
(elm)->field.cqe_prev->field.cqe_next = \
|
||||||
|
(elm)->field.cqe_next; \
|
||||||
|
QUEUEDEBUG_CIRCLEQ_POSTREMOVE((elm), field) \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
#define CIRCLEQ_FOREACH(var, head, field) \
|
||||||
|
for ((var) = ((head)->cqh_first); \
|
||||||
|
(var) != CIRCLEQ_ENDC(head); \
|
||||||
|
(var) = ((var)->field.cqe_next))
|
||||||
|
|
||||||
|
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
|
||||||
|
for ((var) = ((head)->cqh_last); \
|
||||||
|
(var) != CIRCLEQ_ENDC(head); \
|
||||||
|
(var) = ((var)->field.cqe_prev))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Circular queue access methods.
|
||||||
|
*/
|
||||||
|
#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
|
||||||
|
#define CIRCLEQ_LAST(head) ((head)->cqh_last)
|
||||||
|
/* For comparisons */
|
||||||
|
#define CIRCLEQ_ENDC(head) (__launder_type(head))
|
||||||
|
/* For assignments */
|
||||||
|
#define CIRCLEQ_END(head) ((void *)(head))
|
||||||
|
#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
|
||||||
|
#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
|
||||||
|
#define CIRCLEQ_EMPTY(head) \
|
||||||
|
(CIRCLEQ_FIRST(head) == CIRCLEQ_ENDC(head))
|
||||||
|
|
||||||
|
#define CIRCLEQ_LOOP_NEXT(head, elm, field) \
|
||||||
|
(((elm)->field.cqe_next == CIRCLEQ_ENDC(head)) \
|
||||||
|
? ((head)->cqh_first) \
|
||||||
|
: (elm->field.cqe_next))
|
||||||
|
#define CIRCLEQ_LOOP_PREV(head, elm, field) \
|
||||||
|
(((elm)->field.cqe_prev == CIRCLEQ_ENDC(head)) \
|
||||||
|
? ((head)->cqh_last) \
|
||||||
|
: (elm->field.cqe_prev))
|
||||||
|
#endif /* !_KERNEL */
|
||||||
|
|
||||||
|
#endif /* !_SYS_QUEUE_H_ */
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#ifndef _SYS_REDOX_H
|
||||||
|
#define _SYS_REDOX_H
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __redox__
|
||||||
|
|
||||||
|
ssize_t redox_fpath(int fd, void * buf, size_t count);
|
||||||
|
void * redox_physalloc(size_t size);
|
||||||
|
int redox_physfree(void * physical_address, size_t size);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// From musl, license MIT
|
||||||
|
#ifndef _SYS_SYSMACROS_H
|
||||||
|
#define _SYS_SYSMACROS_H
|
||||||
|
|
||||||
|
#define major(x) \
|
||||||
|
((unsigned)( (((x)>>31>>1) & 0xfffff000) | (((x)>>8) & 0x00000fff) ))
|
||||||
|
#define minor(x) \
|
||||||
|
((unsigned)( (((x)>>12) & 0xffffff00) | ((x) & 0x000000ff) ))
|
||||||
|
|
||||||
|
#define makedev(x,y) ( \
|
||||||
|
(((x)&0xfffff000ULL) << 32) | \
|
||||||
|
(((x)&0x00000fffULL) << 8) | \
|
||||||
|
(((y)&0xffffff00ULL) << 12) | \
|
||||||
|
(((y)&0x000000ffULL)) )
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#ifndef _SYS_USER_H
|
||||||
|
#define _SYS_USER_H
|
||||||
|
#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64)
|
||||||
|
#include <arch/x64/user.h>
|
||||||
|
#elif defined(__aarch64__)
|
||||||
|
#include <arch/aarch64/user.h>
|
||||||
|
#elif defined(__riscv) && __riscv_xlen==64
|
||||||
|
#include <arch/riscv64/user.h>
|
||||||
|
#else
|
||||||
|
#error "Unknown architecture"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef _SYSEXITS_H
|
||||||
|
#define _SYSEXITS_H
|
||||||
|
|
||||||
|
#define EX_OK 0
|
||||||
|
#define EX_USAGE 64
|
||||||
|
#define EX_DATAERR 65
|
||||||
|
#define EX_NOINPUT 66
|
||||||
|
#define EX_NOUSER 67
|
||||||
|
#define EX_NOHOST 68
|
||||||
|
#define EX_UNAVAILABLE 69
|
||||||
|
#define EX_SOFTWARE 70
|
||||||
|
#define EX_OSERR 71
|
||||||
|
#define EX_OSFILE 72
|
||||||
|
#define EX_CANTCREAT 73
|
||||||
|
#define EX_IOERR 74
|
||||||
|
#define EX_TEMPFAIL 75
|
||||||
|
#define EX_PROTOCOL 76
|
||||||
|
#define EX_NOPERM 77
|
||||||
|
#define EX_CONFIG 78
|
||||||
|
|
||||||
|
#endif /* _SYSEXITS_H */
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
#include <sys/syslog.h>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "ld_so"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Jeremy Soller <jackpot51@gmail.com>"]
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "ld_so"
|
||||||
|
crate-type = ["staticlib"]
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
@@ -0,0 +1,263 @@
|
|||||||
|
/* Script for -z combreloc */
|
||||||
|
/* Copyright (C) 2014-2025 Free Software Foundation, Inc.
|
||||||
|
Copying and distribution of this script, with or without modification,
|
||||||
|
are permitted in any medium without royalty provided the copyright
|
||||||
|
notice and this notice are preserved. */
|
||||||
|
OUTPUT_FORMAT("elf64-littleaarch64", "elf64-bigaarch64", "elf64-littleaarch64")
|
||||||
|
OUTPUT_ARCH(aarch64)
|
||||||
|
ENTRY(_start)
|
||||||
|
SEARCH_DIR("=/usr/aarch64-linux-gnu/lib64"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/aarch64-linux-gnu/lib"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib");
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
/* Read-only sections, merged into text segment: */
|
||||||
|
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000));
|
||||||
|
. = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
|
||||||
|
/* Place the build-id as close to the ELF headers as possible. This
|
||||||
|
maximises the chance the build-id will be present in core files,
|
||||||
|
which GDB can then use to locate the associated debuginfo file. */
|
||||||
|
.note.gnu.build-id : { *(.note.gnu.build-id) }
|
||||||
|
.interp : { *(.interp) }
|
||||||
|
.hash : { *(.hash) }
|
||||||
|
.gnu.hash : { *(.gnu.hash) }
|
||||||
|
.dynsym : { *(.dynsym) }
|
||||||
|
.dynstr : { *(.dynstr) }
|
||||||
|
.gnu.version : { *(.gnu.version) }
|
||||||
|
.gnu.version_d : { *(.gnu.version_d) }
|
||||||
|
.gnu.version_r : { *(.gnu.version_r) }
|
||||||
|
.rela.dyn :
|
||||||
|
{
|
||||||
|
*(.rela.init)
|
||||||
|
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
|
||||||
|
*(.rela.fini)
|
||||||
|
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
|
||||||
|
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
|
||||||
|
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
|
||||||
|
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
|
||||||
|
*(.rela.ctors)
|
||||||
|
*(.rela.dtors)
|
||||||
|
*(.rela.got)
|
||||||
|
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
|
||||||
|
*(.rela.ifunc)
|
||||||
|
}
|
||||||
|
.rela.plt :
|
||||||
|
{
|
||||||
|
*(.rela.plt)
|
||||||
|
PROVIDE_HIDDEN (__rela_iplt_start = .);
|
||||||
|
*(.rela.iplt)
|
||||||
|
PROVIDE_HIDDEN (__rela_iplt_end = .);
|
||||||
|
}
|
||||||
|
.relr.dyn : { *(.relr.dyn) }
|
||||||
|
/* Start of the executable code region. */
|
||||||
|
.init :
|
||||||
|
{
|
||||||
|
KEEP (*(SORT_NONE(.init)))
|
||||||
|
} =0x1f2003d5
|
||||||
|
.plt : ALIGN(16) { *(.plt) *(.iplt) }
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
|
||||||
|
*(.text.exit .text.exit.*)
|
||||||
|
*(.text.startup .text.startup.*)
|
||||||
|
*(.text.hot .text.hot.*)
|
||||||
|
*(SORT(.text.sorted.*))
|
||||||
|
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||||
|
/* .gnu.warning sections are handled specially by elf.em. */
|
||||||
|
*(.gnu.warning)
|
||||||
|
} =0x1f2003d5
|
||||||
|
.fini :
|
||||||
|
{
|
||||||
|
KEEP (*(SORT_NONE(.fini)))
|
||||||
|
} =0x1f2003d5
|
||||||
|
PROVIDE (__etext = .);
|
||||||
|
PROVIDE (_etext = .);
|
||||||
|
PROVIDE (etext = .);
|
||||||
|
/* Start of the Read Only Data region. */
|
||||||
|
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
|
||||||
|
.rodata1 : { *(.rodata1) }
|
||||||
|
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
|
||||||
|
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
|
||||||
|
.sframe : ONLY_IF_RO { *(.sframe) *(.sframe.*) }
|
||||||
|
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
|
||||||
|
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
|
||||||
|
/* These sections are generated by the Sun/Oracle C++ compiler. */
|
||||||
|
.exception_ranges : ONLY_IF_RO { *(.exception_ranges*) }
|
||||||
|
/* Various note sections. Placed here so that they are always included
|
||||||
|
in the read-only segment and not treated as orphan sections. The
|
||||||
|
current orphan handling algorithm does place note sections after R/O
|
||||||
|
data, but this is not guaranteed to always be the case. */
|
||||||
|
.note.build-id : { *(.note.build-id) }
|
||||||
|
.note.GNU-stack : { *(.note.GNU-stack) }
|
||||||
|
.note.gnu-property : { *(.note.gnu-property) }
|
||||||
|
.note.ABI-tag : { *(.note.ABI-tag) }
|
||||||
|
.note.package : { *(.note.package) }
|
||||||
|
.note.dlopen : { *(.note.dlopen) }
|
||||||
|
.note.netbsd.ident : { *(.note.netbsd.ident) }
|
||||||
|
.note.openbsd.ident : { *(.note.openbsd.ident) }
|
||||||
|
/* Start of the Read Write Data region. */
|
||||||
|
/* Adjust the address for the data segment. We want to adjust up to
|
||||||
|
the same address within the page on the next page up. */
|
||||||
|
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
|
||||||
|
/* Exception handling. */
|
||||||
|
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
|
||||||
|
.sframe : ONLY_IF_RW { *(.sframe) *(.sframe.*) }
|
||||||
|
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
|
||||||
|
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
|
||||||
|
.exception_ranges : ONLY_IF_RW { *(.exception_ranges*) }
|
||||||
|
/* Thread Local Storage sections. */
|
||||||
|
/* .tdata :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__tdata_start = .);
|
||||||
|
*(.tdata .tdata.* .gnu.linkonce.td.*)
|
||||||
|
}
|
||||||
|
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } */
|
||||||
|
.preinit_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||||
|
KEEP (*(.preinit_array))
|
||||||
|
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||||
|
}
|
||||||
|
/* .init_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__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))
|
||||||
|
PROVIDE_HIDDEN (__init_array_end = .);
|
||||||
|
} */
|
||||||
|
.fini_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||||
|
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
|
||||||
|
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
|
||||||
|
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||||
|
}
|
||||||
|
.ctors :
|
||||||
|
{
|
||||||
|
/* gcc uses crtbegin.o to find the start of
|
||||||
|
the constructors, so we make sure it is
|
||||||
|
first. Because this is a wildcard, it
|
||||||
|
doesn't matter if the user does not
|
||||||
|
actually link against crtbegin.o; the
|
||||||
|
linker won't look for a file to match a
|
||||||
|
wildcard. The wildcard also means that it
|
||||||
|
doesn't matter which directory crtbegin.o
|
||||||
|
is in. */
|
||||||
|
KEEP (*crtbegin.o(.ctors))
|
||||||
|
KEEP (*crtbegin?.o(.ctors))
|
||||||
|
/* We don't want to include the .ctor section from
|
||||||
|
the crtend.o file until after the sorted ctors.
|
||||||
|
The .ctor section from the crtend file contains the
|
||||||
|
end of ctors marker and it must be last */
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
|
||||||
|
KEEP (*(SORT(.ctors.*)))
|
||||||
|
KEEP (*(.ctors))
|
||||||
|
}
|
||||||
|
.dtors :
|
||||||
|
{
|
||||||
|
KEEP (*crtbegin.o(.dtors))
|
||||||
|
KEEP (*crtbegin?.o(.dtors))
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
|
||||||
|
KEEP (*(SORT(.dtors.*)))
|
||||||
|
KEEP (*(.dtors))
|
||||||
|
}
|
||||||
|
.jcr : { KEEP (*(.jcr)) }
|
||||||
|
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
|
||||||
|
.dynamic : { *(.dynamic) }
|
||||||
|
.got : { *(.got) *(.igot) }
|
||||||
|
. = DATA_SEGMENT_RELRO_END (24, .);
|
||||||
|
.got.plt : { *(.got.plt) *(.igot.plt) }
|
||||||
|
.data :
|
||||||
|
{
|
||||||
|
PROVIDE (__data_start = .);
|
||||||
|
*(.data .data.* .gnu.linkonce.d.*)
|
||||||
|
SORT(CONSTRUCTORS)
|
||||||
|
}
|
||||||
|
.data1 : { *(.data1) }
|
||||||
|
_edata = .;
|
||||||
|
PROVIDE (edata = .);
|
||||||
|
. = ALIGN(ALIGNOF(NEXT_SECTION));
|
||||||
|
__bss_start = .;
|
||||||
|
__bss_start__ = .;
|
||||||
|
.bss :
|
||||||
|
{
|
||||||
|
*(.dynbss)
|
||||||
|
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||||
|
*(COMMON)
|
||||||
|
/* Align here to ensure that in the common case of there only being one
|
||||||
|
type of .bss section, the section occupies space up to _end.
|
||||||
|
Align after .bss to ensure correct alignment even if the
|
||||||
|
.bss section disappears because there are no input sections.
|
||||||
|
FIXME: Why do we need it? When there is no .bss section, we do not
|
||||||
|
pad the .data section. */
|
||||||
|
. = ALIGN(. != 0 ? 64 / 8 : 1);
|
||||||
|
}
|
||||||
|
_bss_end__ = .; __bss_end__ = .;
|
||||||
|
. = ALIGN(64 / 8);
|
||||||
|
/* Start of the Large Data region. */
|
||||||
|
. = SEGMENT_START("ldata-segment", .);
|
||||||
|
. = ALIGN(64 / 8);
|
||||||
|
__end__ = .;
|
||||||
|
_end = .;
|
||||||
|
PROVIDE (end = .);
|
||||||
|
. = DATA_SEGMENT_END (.);
|
||||||
|
/* Start of the Tiny Data region. */
|
||||||
|
/* Stabs debugging sections. */
|
||||||
|
.stab 0 : { *(.stab) }
|
||||||
|
.stabstr 0 : { *(.stabstr) }
|
||||||
|
.stab.excl 0 : { *(.stab.excl) }
|
||||||
|
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||||
|
.stab.index 0 : { *(.stab.index) }
|
||||||
|
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||||
|
.comment 0 (INFO) : { *(.comment); LINKER_VERSION; }
|
||||||
|
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
|
||||||
|
/* DWARF debug sections.
|
||||||
|
Symbols in the DWARF debugging sections are relative to the beginning
|
||||||
|
of the section so we begin them at 0. */
|
||||||
|
/* DWARF 1. */
|
||||||
|
.debug 0 : { *(.debug) }
|
||||||
|
.line 0 : { *(.line) }
|
||||||
|
/* GNU DWARF 1 extensions. */
|
||||||
|
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||||
|
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||||
|
/* DWARF 1.1 and DWARF 2. */
|
||||||
|
.debug_aranges 0 : { *(.debug_aranges) }
|
||||||
|
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||||
|
/* DWARF 2. */
|
||||||
|
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||||
|
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||||
|
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
|
||||||
|
.debug_frame 0 : { *(.debug_frame) }
|
||||||
|
.debug_str 0 : { *(.debug_str) }
|
||||||
|
.debug_loc 0 : { *(.debug_loc) }
|
||||||
|
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||||
|
/* SGI/MIPS DWARF 2 extensions. */
|
||||||
|
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||||
|
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||||
|
.debug_typenames 0 : { *(.debug_typenames) }
|
||||||
|
.debug_varnames 0 : { *(.debug_varnames) }
|
||||||
|
/* DWARF 3. */
|
||||||
|
.debug_pubtypes 0 : { *(.debug_pubtypes) }
|
||||||
|
.debug_ranges 0 : { *(.debug_ranges) }
|
||||||
|
/* DWARF 5. */
|
||||||
|
.debug_addr 0 : { *(.debug_addr) }
|
||||||
|
.debug_line_str 0 : { *(.debug_line_str) }
|
||||||
|
.debug_loclists 0 : { *(.debug_loclists) }
|
||||||
|
.debug_macro 0 : { *(.debug_macro) }
|
||||||
|
.debug_names 0 : { *(.debug_names) }
|
||||||
|
.debug_rnglists 0 : { *(.debug_rnglists) }
|
||||||
|
.debug_str_offsets 0 : { *(.debug_str_offsets) }
|
||||||
|
.debug_sup 0 : { *(.debug_sup) }
|
||||||
|
.ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) }
|
||||||
|
.note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
|
||||||
|
/DISCARD/ : {
|
||||||
|
*(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*)
|
||||||
|
/*
|
||||||
|
* XXX: As of now, ld.so links with relibc which has the main functionality. In the next refactor,
|
||||||
|
* ld.so will be moved out of relibc. So, till that time, we have to discard any sections
|
||||||
|
* that may reference use thread local storage.
|
||||||
|
*
|
||||||
|
* .init_array also depends on TLS and is discarded as we don't need it.
|
||||||
|
*/
|
||||||
|
*(.gnu.linkonce.tb.*) *(.tcommon)
|
||||||
|
*(.init_array)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,255 @@
|
|||||||
|
/* Script for -z combreloc */
|
||||||
|
/* Copyright (C) 2014-2020 Free Software Foundation, Inc.
|
||||||
|
Copying and distribution of this script, with or without modification,
|
||||||
|
are permitted in any medium without royalty provided the copyright
|
||||||
|
notice and this notice are preserved. */
|
||||||
|
OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64",
|
||||||
|
"elf64-littleaarch64")
|
||||||
|
OUTPUT_ARCH(aarch64)
|
||||||
|
ENTRY(_start)
|
||||||
|
SEARCH_DIR("/aarch64-unknown-redox/lib");
|
||||||
|
SEARCH_DIR("/usr/local/lib64");
|
||||||
|
SEARCH_DIR("/lib64");
|
||||||
|
SEARCH_DIR("/usr/lib64");
|
||||||
|
SEARCH_DIR("/usr/local/lib");
|
||||||
|
SEARCH_DIR("/lib");
|
||||||
|
SEARCH_DIR("/usr/lib");
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
/* Read-only sections, merged into text segment: */
|
||||||
|
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x20000000) + SIZEOF_HEADERS;
|
||||||
|
.interp : { *(.interp) }
|
||||||
|
.note.gnu.build-id : { *(.note.gnu.build-id) }
|
||||||
|
.hash : { *(.hash) }
|
||||||
|
.gnu.hash : { *(.gnu.hash) }
|
||||||
|
.dynsym : { *(.dynsym) }
|
||||||
|
.dynstr : { *(.dynstr) }
|
||||||
|
.gnu.version : { *(.gnu.version) }
|
||||||
|
.gnu.version_d : { *(.gnu.version_d) }
|
||||||
|
.gnu.version_r : { *(.gnu.version_r) }
|
||||||
|
.rela.dyn :
|
||||||
|
{
|
||||||
|
*(.rela.init)
|
||||||
|
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
|
||||||
|
*(.rela.fini)
|
||||||
|
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
|
||||||
|
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
|
||||||
|
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
|
||||||
|
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
|
||||||
|
*(.rela.ctors)
|
||||||
|
*(.rela.dtors)
|
||||||
|
*(.rela.got)
|
||||||
|
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
|
||||||
|
*(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
|
||||||
|
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
|
||||||
|
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
|
||||||
|
*(.rela.ifunc)
|
||||||
|
}
|
||||||
|
.rela.plt :
|
||||||
|
{
|
||||||
|
*(.rela.plt)
|
||||||
|
PROVIDE_HIDDEN (__rela_iplt_start = .);
|
||||||
|
*(.rela.iplt)
|
||||||
|
PROVIDE_HIDDEN (__rela_iplt_end = .);
|
||||||
|
}
|
||||||
|
. = ALIGN(CONSTANT (MAXPAGESIZE));
|
||||||
|
.init :
|
||||||
|
{
|
||||||
|
KEEP (*(SORT_NONE(.init)))
|
||||||
|
}
|
||||||
|
.plt : { *(.plt) *(.iplt) }
|
||||||
|
.plt.got : { *(.plt.got) }
|
||||||
|
.plt.sec : { *(.plt.sec) }
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
|
||||||
|
*(.text.exit .text.exit.*)
|
||||||
|
*(.text.startup .text.startup.*)
|
||||||
|
*(.text.hot .text.hot.*)
|
||||||
|
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||||
|
/* .gnu.warning sections are handled specially by elf.em. */
|
||||||
|
*(.gnu.warning)
|
||||||
|
}
|
||||||
|
.fini :
|
||||||
|
{
|
||||||
|
KEEP (*(SORT_NONE(.fini)))
|
||||||
|
}
|
||||||
|
PROVIDE (__etext = .);
|
||||||
|
PROVIDE (_etext = .);
|
||||||
|
PROVIDE (etext = .);
|
||||||
|
. = ALIGN(CONSTANT (MAXPAGESIZE));
|
||||||
|
/* Adjust the address for the rodata segment. We want to adjust up to
|
||||||
|
the same address within the page on the next page up. */
|
||||||
|
. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
|
||||||
|
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
|
||||||
|
.rodata1 : { *(.rodata1) }
|
||||||
|
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
|
||||||
|
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
|
||||||
|
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
|
||||||
|
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
|
||||||
|
/* These sections are generated by the Sun/Oracle C++ compiler. */
|
||||||
|
.exception_ranges : ONLY_IF_RO { *(.exception_ranges*) }
|
||||||
|
/* Adjust the address for the data segment. We want to adjust up to
|
||||||
|
the same address within the page on the next page up. */
|
||||||
|
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
|
||||||
|
/* Exception handling */
|
||||||
|
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
|
||||||
|
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
|
||||||
|
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
|
||||||
|
.exception_ranges : ONLY_IF_RW { *(.exception_ranges*) }
|
||||||
|
/* Thread Local Storage sections */
|
||||||
|
/* .tdata :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__tdata_start = .);
|
||||||
|
*(.tdata .tdata.* .gnu.linkonce.td.*)
|
||||||
|
}
|
||||||
|
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } */
|
||||||
|
.preinit_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||||
|
KEEP (*(.preinit_array))
|
||||||
|
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||||
|
}
|
||||||
|
.init_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__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))
|
||||||
|
PROVIDE_HIDDEN (__init_array_end = .);
|
||||||
|
}
|
||||||
|
.fini_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||||
|
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
|
||||||
|
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
|
||||||
|
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||||
|
}
|
||||||
|
.ctors :
|
||||||
|
{
|
||||||
|
/* gcc uses crtbegin.o to find the start of
|
||||||
|
the constructors, so we make sure it is
|
||||||
|
first. Because this is a wildcard, it
|
||||||
|
doesn't matter if the user does not
|
||||||
|
actually link against crtbegin.o; the
|
||||||
|
linker won't look for a file to match a
|
||||||
|
wildcard. The wildcard also means that it
|
||||||
|
doesn't matter which directory crtbegin.o
|
||||||
|
is in. */
|
||||||
|
KEEP (*crtbegin.o(.ctors))
|
||||||
|
KEEP (*crtbegin?.o(.ctors))
|
||||||
|
/* We don't want to include the .ctor section from
|
||||||
|
the crtend.o file until after the sorted ctors.
|
||||||
|
The .ctor section from the crtend file contains the
|
||||||
|
end of ctors marker and it must be last */
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
|
||||||
|
KEEP (*(SORT(.ctors.*)))
|
||||||
|
KEEP (*(.ctors))
|
||||||
|
}
|
||||||
|
.dtors :
|
||||||
|
{
|
||||||
|
KEEP (*crtbegin.o(.dtors))
|
||||||
|
KEEP (*crtbegin?.o(.dtors))
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
|
||||||
|
KEEP (*(SORT(.dtors.*)))
|
||||||
|
KEEP (*(.dtors))
|
||||||
|
}
|
||||||
|
.jcr : { KEEP (*(.jcr)) }
|
||||||
|
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
|
||||||
|
.dynamic : { *(.dynamic) }
|
||||||
|
.got : { *(.got) *(.igot) }
|
||||||
|
. = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
|
||||||
|
.got.plt : { *(.got.plt) *(.igot.plt) }
|
||||||
|
.data :
|
||||||
|
{
|
||||||
|
*(.data .data.* .gnu.linkonce.d.*)
|
||||||
|
SORT(CONSTRUCTORS)
|
||||||
|
}
|
||||||
|
.data1 : { *(.data1) }
|
||||||
|
_edata = .; PROVIDE (edata = .);
|
||||||
|
. = .;
|
||||||
|
__bss_start = .;
|
||||||
|
.bss :
|
||||||
|
{
|
||||||
|
*(.dynbss)
|
||||||
|
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||||
|
*(COMMON)
|
||||||
|
/* Align here to ensure that the .bss section occupies space up to
|
||||||
|
_end. Align after .bss to ensure correct alignment even if the
|
||||||
|
.bss section disappears because there are no input sections.
|
||||||
|
FIXME: Why do we need it? When there is no .bss section, we do not
|
||||||
|
pad the .data section. */
|
||||||
|
. = ALIGN(. != 0 ? 64 / 8 : 1);
|
||||||
|
}
|
||||||
|
.lbss :
|
||||||
|
{
|
||||||
|
*(.dynlbss)
|
||||||
|
*(.lbss .lbss.* .gnu.linkonce.lb.*)
|
||||||
|
*(LARGE_COMMON)
|
||||||
|
}
|
||||||
|
. = ALIGN(64 / 8);
|
||||||
|
. = SEGMENT_START("ldata-segment", .);
|
||||||
|
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
|
||||||
|
{
|
||||||
|
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
|
||||||
|
}
|
||||||
|
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
|
||||||
|
{
|
||||||
|
*(.ldata .ldata.* .gnu.linkonce.l.*)
|
||||||
|
. = ALIGN(. != 0 ? 64 / 8 : 1);
|
||||||
|
}
|
||||||
|
. = ALIGN(64 / 8);
|
||||||
|
_end = .; PROVIDE (end = .);
|
||||||
|
. = DATA_SEGMENT_END (.);
|
||||||
|
/* Stabs debugging sections. */
|
||||||
|
.stab 0 : { *(.stab) }
|
||||||
|
.stabstr 0 : { *(.stabstr) }
|
||||||
|
.stab.excl 0 : { *(.stab.excl) }
|
||||||
|
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||||
|
.stab.index 0 : { *(.stab.index) }
|
||||||
|
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||||
|
.comment 0 : { *(.comment) }
|
||||||
|
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
|
||||||
|
/* DWARF debug sections.
|
||||||
|
Symbols in the DWARF debugging sections are relative to the beginning
|
||||||
|
of the section so we begin them at 0. */
|
||||||
|
/* DWARF 1 */
|
||||||
|
.debug 0 : { *(.debug) }
|
||||||
|
.line 0 : { *(.line) }
|
||||||
|
/* GNU DWARF 1 extensions */
|
||||||
|
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||||
|
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||||
|
/* DWARF 1.1 and DWARF 2 */
|
||||||
|
.debug_aranges 0 : { *(.debug_aranges) }
|
||||||
|
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||||
|
/* DWARF 2 */
|
||||||
|
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||||
|
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||||
|
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
|
||||||
|
.debug_frame 0 : { *(.debug_frame) }
|
||||||
|
.debug_str 0 : { *(.debug_str) }
|
||||||
|
.debug_loc 0 : { *(.debug_loc) }
|
||||||
|
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||||
|
/* SGI/MIPS DWARF 2 extensions */
|
||||||
|
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||||
|
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||||
|
.debug_typenames 0 : { *(.debug_typenames) }
|
||||||
|
.debug_varnames 0 : { *(.debug_varnames) }
|
||||||
|
/* DWARF 3 */
|
||||||
|
.debug_pubtypes 0 : { *(.debug_pubtypes) }
|
||||||
|
.debug_ranges 0 : { *(.debug_ranges) }
|
||||||
|
/* DWARF Extension. */
|
||||||
|
.debug_macro 0 : { *(.debug_macro) }
|
||||||
|
.debug_addr 0 : { *(.debug_addr) }
|
||||||
|
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
|
||||||
|
/DISCARD/ : {
|
||||||
|
*(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*)
|
||||||
|
/*
|
||||||
|
* XXX: As of now, ld.so links with relibc which has the main functionality. In the next refactor,
|
||||||
|
* ld.so will be moved out of relibc. So, till that time, we have to discard any sections
|
||||||
|
* that may reference use thread local storage.
|
||||||
|
*
|
||||||
|
* .init_array need to be not discarded unlike x86_64 linker variant
|
||||||
|
*/
|
||||||
|
*(.gnu.linkonce.tb.*) *(.tcommon)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,256 @@
|
|||||||
|
/* Script for -z combreloc */
|
||||||
|
/* Copyright (C) 2014-2020 Free Software Foundation, Inc.
|
||||||
|
Copying and distribution of this script, with or without modification,
|
||||||
|
are permitted in any medium without royalty provided the copyright
|
||||||
|
notice and this notice are preserved. */
|
||||||
|
OUTPUT_FORMAT("elf32-i386", "elf32-i386",
|
||||||
|
"elf32-i386")
|
||||||
|
OUTPUT_ARCH(i386)
|
||||||
|
ENTRY(_start)
|
||||||
|
SEARCH_DIR("/i686-unknown-redox/lib");
|
||||||
|
SEARCH_DIR("/usr/local/lib32");
|
||||||
|
SEARCH_DIR("/lib32");
|
||||||
|
SEARCH_DIR("/usr/lib32");
|
||||||
|
SEARCH_DIR("/usr/local/lib");
|
||||||
|
SEARCH_DIR("/lib");
|
||||||
|
SEARCH_DIR("/usr/lib");
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
/* Read-only sections, merged into text segment: */
|
||||||
|
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x20000000) + SIZEOF_HEADERS;
|
||||||
|
.interp : { *(.interp) }
|
||||||
|
.note.gnu.build-id : { *(.note.gnu.build-id) }
|
||||||
|
.hash : { *(.hash) }
|
||||||
|
.gnu.hash : { *(.gnu.hash) }
|
||||||
|
.dynsym : { *(.dynsym) }
|
||||||
|
.dynstr : { *(.dynstr) }
|
||||||
|
.gnu.version : { *(.gnu.version) }
|
||||||
|
.gnu.version_d : { *(.gnu.version_d) }
|
||||||
|
.gnu.version_r : { *(.gnu.version_r) }
|
||||||
|
.rela.dyn :
|
||||||
|
{
|
||||||
|
*(.rela.init)
|
||||||
|
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
|
||||||
|
*(.rela.fini)
|
||||||
|
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
|
||||||
|
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
|
||||||
|
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
|
||||||
|
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
|
||||||
|
*(.rela.ctors)
|
||||||
|
*(.rela.dtors)
|
||||||
|
*(.rela.got)
|
||||||
|
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
|
||||||
|
*(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
|
||||||
|
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
|
||||||
|
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
|
||||||
|
*(.rela.ifunc)
|
||||||
|
}
|
||||||
|
.rela.plt :
|
||||||
|
{
|
||||||
|
*(.rela.plt)
|
||||||
|
PROVIDE_HIDDEN (__rela_iplt_start = .);
|
||||||
|
*(.rela.iplt)
|
||||||
|
PROVIDE_HIDDEN (__rela_iplt_end = .);
|
||||||
|
}
|
||||||
|
. = ALIGN(CONSTANT (MAXPAGESIZE));
|
||||||
|
.init :
|
||||||
|
{
|
||||||
|
KEEP (*(SORT_NONE(.init)))
|
||||||
|
}
|
||||||
|
.plt : { *(.plt) *(.iplt) }
|
||||||
|
.plt.got : { *(.plt.got) }
|
||||||
|
.plt.sec : { *(.plt.sec) }
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
|
||||||
|
*(.text.exit .text.exit.*)
|
||||||
|
*(.text.startup .text.startup.*)
|
||||||
|
*(.text.hot .text.hot.*)
|
||||||
|
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||||
|
/* .gnu.warning sections are handled specially by elf.em. */
|
||||||
|
*(.gnu.warning)
|
||||||
|
}
|
||||||
|
.fini :
|
||||||
|
{
|
||||||
|
KEEP (*(SORT_NONE(.fini)))
|
||||||
|
}
|
||||||
|
PROVIDE (__etext = .);
|
||||||
|
PROVIDE (_etext = .);
|
||||||
|
PROVIDE (etext = .);
|
||||||
|
. = ALIGN(CONSTANT (MAXPAGESIZE));
|
||||||
|
/* Adjust the address for the rodata segment. We want to adjust up to
|
||||||
|
the same address within the page on the next page up. */
|
||||||
|
. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
|
||||||
|
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
|
||||||
|
.rodata1 : { *(.rodata1) }
|
||||||
|
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
|
||||||
|
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
|
||||||
|
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
|
||||||
|
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
|
||||||
|
/* These sections are generated by the Sun/Oracle C++ compiler. */
|
||||||
|
.exception_ranges : ONLY_IF_RO { *(.exception_ranges*) }
|
||||||
|
/* Adjust the address for the data segment. We want to adjust up to
|
||||||
|
the same address within the page on the next page up. */
|
||||||
|
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
|
||||||
|
/* Exception handling */
|
||||||
|
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
|
||||||
|
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
|
||||||
|
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
|
||||||
|
.exception_ranges : ONLY_IF_RW { *(.exception_ranges*) }
|
||||||
|
/* Thread Local Storage sections */
|
||||||
|
/* .tdata :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__tdata_start = .);
|
||||||
|
*(.tdata .tdata.* .gnu.linkonce.td.*)
|
||||||
|
}
|
||||||
|
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } */
|
||||||
|
.preinit_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||||
|
KEEP (*(.preinit_array))
|
||||||
|
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||||
|
}
|
||||||
|
/* .init_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__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))
|
||||||
|
PROVIDE_HIDDEN (__init_array_end = .);
|
||||||
|
} */
|
||||||
|
.fini_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||||
|
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
|
||||||
|
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
|
||||||
|
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||||
|
}
|
||||||
|
.ctors :
|
||||||
|
{
|
||||||
|
/* gcc uses crtbegin.o to find the start of
|
||||||
|
the constructors, so we make sure it is
|
||||||
|
first. Because this is a wildcard, it
|
||||||
|
doesn't matter if the user does not
|
||||||
|
actually link against crtbegin.o; the
|
||||||
|
linker won't look for a file to match a
|
||||||
|
wildcard. The wildcard also means that it
|
||||||
|
doesn't matter which directory crtbegin.o
|
||||||
|
is in. */
|
||||||
|
KEEP (*crtbegin.o(.ctors))
|
||||||
|
KEEP (*crtbegin?.o(.ctors))
|
||||||
|
/* We don't want to include the .ctor section from
|
||||||
|
the crtend.o file until after the sorted ctors.
|
||||||
|
The .ctor section from the crtend file contains the
|
||||||
|
end of ctors marker and it must be last */
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
|
||||||
|
KEEP (*(SORT(.ctors.*)))
|
||||||
|
KEEP (*(.ctors))
|
||||||
|
}
|
||||||
|
.dtors :
|
||||||
|
{
|
||||||
|
KEEP (*crtbegin.o(.dtors))
|
||||||
|
KEEP (*crtbegin?.o(.dtors))
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
|
||||||
|
KEEP (*(SORT(.dtors.*)))
|
||||||
|
KEEP (*(.dtors))
|
||||||
|
}
|
||||||
|
.jcr : { KEEP (*(.jcr)) }
|
||||||
|
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
|
||||||
|
.dynamic : { *(.dynamic) }
|
||||||
|
.got : { *(.got) *(.igot) }
|
||||||
|
. = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
|
||||||
|
.got.plt : { *(.got.plt) *(.igot.plt) }
|
||||||
|
.data :
|
||||||
|
{
|
||||||
|
*(.data .data.* .gnu.linkonce.d.*)
|
||||||
|
SORT(CONSTRUCTORS)
|
||||||
|
}
|
||||||
|
.data1 : { *(.data1) }
|
||||||
|
_edata = .; PROVIDE (edata = .);
|
||||||
|
. = .;
|
||||||
|
__bss_start = .;
|
||||||
|
.bss :
|
||||||
|
{
|
||||||
|
*(.dynbss)
|
||||||
|
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||||
|
*(COMMON)
|
||||||
|
/* Align here to ensure that the .bss section occupies space up to
|
||||||
|
_end. Align after .bss to ensure correct alignment even if the
|
||||||
|
.bss section disappears because there are no input sections.
|
||||||
|
FIXME: Why do we need it? When there is no .bss section, we do not
|
||||||
|
pad the .data section. */
|
||||||
|
. = ALIGN(. != 0 ? 64 / 8 : 1);
|
||||||
|
}
|
||||||
|
.lbss :
|
||||||
|
{
|
||||||
|
*(.dynlbss)
|
||||||
|
*(.lbss .lbss.* .gnu.linkonce.lb.*)
|
||||||
|
*(LARGE_COMMON)
|
||||||
|
}
|
||||||
|
. = ALIGN(64 / 8);
|
||||||
|
. = SEGMENT_START("ldata-segment", .);
|
||||||
|
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
|
||||||
|
{
|
||||||
|
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
|
||||||
|
}
|
||||||
|
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
|
||||||
|
{
|
||||||
|
*(.ldata .ldata.* .gnu.linkonce.l.*)
|
||||||
|
. = ALIGN(. != 0 ? 64 / 8 : 1);
|
||||||
|
}
|
||||||
|
. = ALIGN(64 / 8);
|
||||||
|
_end = .; PROVIDE (end = .);
|
||||||
|
. = DATA_SEGMENT_END (.);
|
||||||
|
/* Stabs debugging sections. */
|
||||||
|
.stab 0 : { *(.stab) }
|
||||||
|
.stabstr 0 : { *(.stabstr) }
|
||||||
|
.stab.excl 0 : { *(.stab.excl) }
|
||||||
|
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||||
|
.stab.index 0 : { *(.stab.index) }
|
||||||
|
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||||
|
.comment 0 : { *(.comment) }
|
||||||
|
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
|
||||||
|
/* DWARF debug sections.
|
||||||
|
Symbols in the DWARF debugging sections are relative to the beginning
|
||||||
|
of the section so we begin them at 0. */
|
||||||
|
/* DWARF 1 */
|
||||||
|
.debug 0 : { *(.debug) }
|
||||||
|
.line 0 : { *(.line) }
|
||||||
|
/* GNU DWARF 1 extensions */
|
||||||
|
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||||
|
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||||
|
/* DWARF 1.1 and DWARF 2 */
|
||||||
|
.debug_aranges 0 : { *(.debug_aranges) }
|
||||||
|
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||||
|
/* DWARF 2 */
|
||||||
|
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||||
|
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||||
|
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
|
||||||
|
.debug_frame 0 : { *(.debug_frame) }
|
||||||
|
.debug_str 0 : { *(.debug_str) }
|
||||||
|
.debug_loc 0 : { *(.debug_loc) }
|
||||||
|
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||||
|
/* SGI/MIPS DWARF 2 extensions */
|
||||||
|
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||||
|
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||||
|
.debug_typenames 0 : { *(.debug_typenames) }
|
||||||
|
.debug_varnames 0 : { *(.debug_varnames) }
|
||||||
|
/* DWARF 3 */
|
||||||
|
.debug_pubtypes 0 : { *(.debug_pubtypes) }
|
||||||
|
.debug_ranges 0 : { *(.debug_ranges) }
|
||||||
|
/* DWARF Extension. */
|
||||||
|
.debug_macro 0 : { *(.debug_macro) }
|
||||||
|
.debug_addr 0 : { *(.debug_addr) }
|
||||||
|
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
|
||||||
|
/DISCARD/ : {
|
||||||
|
*(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*)
|
||||||
|
/*
|
||||||
|
* XXX: As of now, ld.so links with relibc which has the main functionality. In the next refactor,
|
||||||
|
* ld.so will be moved out of relibc. So, till that time, we have to discard any sections
|
||||||
|
* that may reference use thread local storage.
|
||||||
|
*
|
||||||
|
* .init_array also depends on TLS and is discarded as we don't need it.
|
||||||
|
*/
|
||||||
|
*(.gnu.linkonce.tb.*) *(.tcommon)
|
||||||
|
*(.init_array)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,256 @@
|
|||||||
|
/* Script for -z combreloc */
|
||||||
|
/* Copyright (C) 2014-2020 Free Software Foundation, Inc.
|
||||||
|
Copying and distribution of this script, with or without modification,
|
||||||
|
are permitted in any medium without royalty provided the copyright
|
||||||
|
notice and this notice are preserved. */
|
||||||
|
OUTPUT_FORMAT("elf32-i386", "elf32-i386",
|
||||||
|
"elf32-i386")
|
||||||
|
OUTPUT_ARCH(i386)
|
||||||
|
ENTRY(_start)
|
||||||
|
SEARCH_DIR("/i686-unknown-redox/lib");
|
||||||
|
SEARCH_DIR("/usr/local/lib32");
|
||||||
|
SEARCH_DIR("/lib32");
|
||||||
|
SEARCH_DIR("/usr/lib32");
|
||||||
|
SEARCH_DIR("/usr/local/lib");
|
||||||
|
SEARCH_DIR("/lib");
|
||||||
|
SEARCH_DIR("/usr/lib");
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
/* Read-only sections, merged into text segment: */
|
||||||
|
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x20000000) + SIZEOF_HEADERS;
|
||||||
|
.interp : { *(.interp) }
|
||||||
|
.note.gnu.build-id : { *(.note.gnu.build-id) }
|
||||||
|
.hash : { *(.hash) }
|
||||||
|
.gnu.hash : { *(.gnu.hash) }
|
||||||
|
.dynsym : { *(.dynsym) }
|
||||||
|
.dynstr : { *(.dynstr) }
|
||||||
|
.gnu.version : { *(.gnu.version) }
|
||||||
|
.gnu.version_d : { *(.gnu.version_d) }
|
||||||
|
.gnu.version_r : { *(.gnu.version_r) }
|
||||||
|
.rela.dyn :
|
||||||
|
{
|
||||||
|
*(.rela.init)
|
||||||
|
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
|
||||||
|
*(.rela.fini)
|
||||||
|
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
|
||||||
|
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
|
||||||
|
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
|
||||||
|
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
|
||||||
|
*(.rela.ctors)
|
||||||
|
*(.rela.dtors)
|
||||||
|
*(.rela.got)
|
||||||
|
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
|
||||||
|
*(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
|
||||||
|
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
|
||||||
|
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
|
||||||
|
*(.rela.ifunc)
|
||||||
|
}
|
||||||
|
.rela.plt :
|
||||||
|
{
|
||||||
|
*(.rela.plt)
|
||||||
|
PROVIDE_HIDDEN (__rela_iplt_start = .);
|
||||||
|
*(.rela.iplt)
|
||||||
|
PROVIDE_HIDDEN (__rela_iplt_end = .);
|
||||||
|
}
|
||||||
|
. = ALIGN(CONSTANT (MAXPAGESIZE));
|
||||||
|
.init :
|
||||||
|
{
|
||||||
|
KEEP (*(SORT_NONE(.init)))
|
||||||
|
}
|
||||||
|
.plt : { *(.plt) *(.iplt) }
|
||||||
|
.plt.got : { *(.plt.got) }
|
||||||
|
.plt.sec : { *(.plt.sec) }
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
|
||||||
|
*(.text.exit .text.exit.*)
|
||||||
|
*(.text.startup .text.startup.*)
|
||||||
|
*(.text.hot .text.hot.*)
|
||||||
|
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||||
|
/* .gnu.warning sections are handled specially by elf.em. */
|
||||||
|
*(.gnu.warning)
|
||||||
|
}
|
||||||
|
.fini :
|
||||||
|
{
|
||||||
|
KEEP (*(SORT_NONE(.fini)))
|
||||||
|
}
|
||||||
|
PROVIDE (__etext = .);
|
||||||
|
PROVIDE (_etext = .);
|
||||||
|
PROVIDE (etext = .);
|
||||||
|
. = ALIGN(CONSTANT (MAXPAGESIZE));
|
||||||
|
/* Adjust the address for the rodata segment. We want to adjust up to
|
||||||
|
the same address within the page on the next page up. */
|
||||||
|
. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
|
||||||
|
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
|
||||||
|
.rodata1 : { *(.rodata1) }
|
||||||
|
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
|
||||||
|
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
|
||||||
|
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
|
||||||
|
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
|
||||||
|
/* These sections are generated by the Sun/Oracle C++ compiler. */
|
||||||
|
.exception_ranges : ONLY_IF_RO { *(.exception_ranges*) }
|
||||||
|
/* Adjust the address for the data segment. We want to adjust up to
|
||||||
|
the same address within the page on the next page up. */
|
||||||
|
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
|
||||||
|
/* Exception handling */
|
||||||
|
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
|
||||||
|
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
|
||||||
|
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
|
||||||
|
.exception_ranges : ONLY_IF_RW { *(.exception_ranges*) }
|
||||||
|
/* Thread Local Storage sections */
|
||||||
|
/* .tdata :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__tdata_start = .);
|
||||||
|
*(.tdata .tdata.* .gnu.linkonce.td.*)
|
||||||
|
}
|
||||||
|
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } */
|
||||||
|
.preinit_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||||
|
KEEP (*(.preinit_array))
|
||||||
|
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||||
|
}
|
||||||
|
/* .init_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__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))
|
||||||
|
PROVIDE_HIDDEN (__init_array_end = .);
|
||||||
|
} */
|
||||||
|
.fini_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||||
|
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
|
||||||
|
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
|
||||||
|
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||||
|
}
|
||||||
|
.ctors :
|
||||||
|
{
|
||||||
|
/* gcc uses crtbegin.o to find the start of
|
||||||
|
the constructors, so we make sure it is
|
||||||
|
first. Because this is a wildcard, it
|
||||||
|
doesn't matter if the user does not
|
||||||
|
actually link against crtbegin.o; the
|
||||||
|
linker won't look for a file to match a
|
||||||
|
wildcard. The wildcard also means that it
|
||||||
|
doesn't matter which directory crtbegin.o
|
||||||
|
is in. */
|
||||||
|
KEEP (*crtbegin.o(.ctors))
|
||||||
|
KEEP (*crtbegin?.o(.ctors))
|
||||||
|
/* We don't want to include the .ctor section from
|
||||||
|
the crtend.o file until after the sorted ctors.
|
||||||
|
The .ctor section from the crtend file contains the
|
||||||
|
end of ctors marker and it must be last */
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
|
||||||
|
KEEP (*(SORT(.ctors.*)))
|
||||||
|
KEEP (*(.ctors))
|
||||||
|
}
|
||||||
|
.dtors :
|
||||||
|
{
|
||||||
|
KEEP (*crtbegin.o(.dtors))
|
||||||
|
KEEP (*crtbegin?.o(.dtors))
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
|
||||||
|
KEEP (*(SORT(.dtors.*)))
|
||||||
|
KEEP (*(.dtors))
|
||||||
|
}
|
||||||
|
.jcr : { KEEP (*(.jcr)) }
|
||||||
|
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
|
||||||
|
.dynamic : { *(.dynamic) }
|
||||||
|
.got : { *(.got) *(.igot) }
|
||||||
|
. = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
|
||||||
|
.got.plt : { *(.got.plt) *(.igot.plt) }
|
||||||
|
.data :
|
||||||
|
{
|
||||||
|
*(.data .data.* .gnu.linkonce.d.*)
|
||||||
|
SORT(CONSTRUCTORS)
|
||||||
|
}
|
||||||
|
.data1 : { *(.data1) }
|
||||||
|
_edata = .; PROVIDE (edata = .);
|
||||||
|
. = .;
|
||||||
|
__bss_start = .;
|
||||||
|
.bss :
|
||||||
|
{
|
||||||
|
*(.dynbss)
|
||||||
|
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||||
|
*(COMMON)
|
||||||
|
/* Align here to ensure that the .bss section occupies space up to
|
||||||
|
_end. Align after .bss to ensure correct alignment even if the
|
||||||
|
.bss section disappears because there are no input sections.
|
||||||
|
FIXME: Why do we need it? When there is no .bss section, we do not
|
||||||
|
pad the .data section. */
|
||||||
|
. = ALIGN(. != 0 ? 64 / 8 : 1);
|
||||||
|
}
|
||||||
|
.lbss :
|
||||||
|
{
|
||||||
|
*(.dynlbss)
|
||||||
|
*(.lbss .lbss.* .gnu.linkonce.lb.*)
|
||||||
|
*(LARGE_COMMON)
|
||||||
|
}
|
||||||
|
. = ALIGN(64 / 8);
|
||||||
|
. = SEGMENT_START("ldata-segment", .);
|
||||||
|
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
|
||||||
|
{
|
||||||
|
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
|
||||||
|
}
|
||||||
|
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
|
||||||
|
{
|
||||||
|
*(.ldata .ldata.* .gnu.linkonce.l.*)
|
||||||
|
. = ALIGN(. != 0 ? 64 / 8 : 1);
|
||||||
|
}
|
||||||
|
. = ALIGN(64 / 8);
|
||||||
|
_end = .; PROVIDE (end = .);
|
||||||
|
. = DATA_SEGMENT_END (.);
|
||||||
|
/* Stabs debugging sections. */
|
||||||
|
.stab 0 : { *(.stab) }
|
||||||
|
.stabstr 0 : { *(.stabstr) }
|
||||||
|
.stab.excl 0 : { *(.stab.excl) }
|
||||||
|
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||||
|
.stab.index 0 : { *(.stab.index) }
|
||||||
|
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||||
|
.comment 0 : { *(.comment) }
|
||||||
|
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
|
||||||
|
/* DWARF debug sections.
|
||||||
|
Symbols in the DWARF debugging sections are relative to the beginning
|
||||||
|
of the section so we begin them at 0. */
|
||||||
|
/* DWARF 1 */
|
||||||
|
.debug 0 : { *(.debug) }
|
||||||
|
.line 0 : { *(.line) }
|
||||||
|
/* GNU DWARF 1 extensions */
|
||||||
|
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||||
|
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||||
|
/* DWARF 1.1 and DWARF 2 */
|
||||||
|
.debug_aranges 0 : { *(.debug_aranges) }
|
||||||
|
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||||
|
/* DWARF 2 */
|
||||||
|
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||||
|
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||||
|
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
|
||||||
|
.debug_frame 0 : { *(.debug_frame) }
|
||||||
|
.debug_str 0 : { *(.debug_str) }
|
||||||
|
.debug_loc 0 : { *(.debug_loc) }
|
||||||
|
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||||
|
/* SGI/MIPS DWARF 2 extensions */
|
||||||
|
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||||
|
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||||
|
.debug_typenames 0 : { *(.debug_typenames) }
|
||||||
|
.debug_varnames 0 : { *(.debug_varnames) }
|
||||||
|
/* DWARF 3 */
|
||||||
|
.debug_pubtypes 0 : { *(.debug_pubtypes) }
|
||||||
|
.debug_ranges 0 : { *(.debug_ranges) }
|
||||||
|
/* DWARF Extension. */
|
||||||
|
.debug_macro 0 : { *(.debug_macro) }
|
||||||
|
.debug_addr 0 : { *(.debug_addr) }
|
||||||
|
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
|
||||||
|
/DISCARD/ : {
|
||||||
|
*(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*)
|
||||||
|
/*
|
||||||
|
* XXX: As of now, ld.so links with relibc which has the main functionality. In the next refactor,
|
||||||
|
* ld.so will be moved out of relibc. So, till that time, we have to discard any sections
|
||||||
|
* that may reference use thread local storage.
|
||||||
|
*
|
||||||
|
* .init_array also depends on TLS and is discarded as we don't need it.
|
||||||
|
*/
|
||||||
|
*(.gnu.linkonce.tb.*) *(.tcommon)
|
||||||
|
*(.init_array)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,247 @@
|
|||||||
|
/* Script for -z combreloc */
|
||||||
|
/* Copyright (C) 2014-2020 Free Software Foundation, Inc.
|
||||||
|
Copying and distribution of this script, with or without modification,
|
||||||
|
are permitted in any medium without royalty provided the copyright
|
||||||
|
notice and this notice are preserved. */
|
||||||
|
OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv", "elf64-littleriscv" )
|
||||||
|
OUTPUT_ARCH(riscv)
|
||||||
|
ENTRY(_start)
|
||||||
|
SEARCH_DIR("/riscv64-unknown-redox/lib");
|
||||||
|
SEARCH_DIR("/usr/local/lib64");
|
||||||
|
SEARCH_DIR("/lib64");
|
||||||
|
SEARCH_DIR("/usr/lib64");
|
||||||
|
SEARCH_DIR("/usr/local/lib");
|
||||||
|
SEARCH_DIR("/lib");
|
||||||
|
SEARCH_DIR("/usr/lib");
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
/* Read-only sections, merged into text segment: */
|
||||||
|
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x20000000) + SIZEOF_HEADERS;
|
||||||
|
.interp : { *(.interp) }
|
||||||
|
.note.gnu.build-id : { *(.note.gnu.build-id) }
|
||||||
|
.hash : { *(.hash) }
|
||||||
|
.gnu.hash : { *(.gnu.hash) }
|
||||||
|
.dynsym : { *(.dynsym) }
|
||||||
|
.dynstr : { *(.dynstr) }
|
||||||
|
.gnu.version : { *(.gnu.version) }
|
||||||
|
.gnu.version_d : { *(.gnu.version_d) }
|
||||||
|
.gnu.version_r : { *(.gnu.version_r) }
|
||||||
|
.rela.dyn :
|
||||||
|
{
|
||||||
|
*(.rela.init)
|
||||||
|
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
|
||||||
|
*(.rela.fini)
|
||||||
|
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
|
||||||
|
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
|
||||||
|
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
|
||||||
|
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
|
||||||
|
*(.rela.ctors)
|
||||||
|
*(.rela.dtors)
|
||||||
|
*(.rela.got)
|
||||||
|
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
|
||||||
|
*(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
|
||||||
|
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
|
||||||
|
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
|
||||||
|
*(.rela.ifunc)
|
||||||
|
}
|
||||||
|
.rela.plt :
|
||||||
|
{
|
||||||
|
*(.rela.plt)
|
||||||
|
PROVIDE_HIDDEN (__rela_iplt_start = .);
|
||||||
|
*(.rela.iplt)
|
||||||
|
PROVIDE_HIDDEN (__rela_iplt_end = .);
|
||||||
|
}
|
||||||
|
. = ALIGN(CONSTANT (MAXPAGESIZE));
|
||||||
|
.plt : { *(.plt) *(.iplt) }
|
||||||
|
.plt.got : { *(.plt.got) }
|
||||||
|
.plt.sec : { *(.plt.sec) }
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
|
||||||
|
*(.text.exit .text.exit.*)
|
||||||
|
*(.text.startup .text.startup.*)
|
||||||
|
*(.text.hot .text.hot.*)
|
||||||
|
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||||
|
/* .gnu.warning sections are handled specially by elf.em. */
|
||||||
|
*(.gnu.warning)
|
||||||
|
}
|
||||||
|
PROVIDE (__etext = .);
|
||||||
|
PROVIDE (_etext = .);
|
||||||
|
PROVIDE (etext = .);
|
||||||
|
. = ALIGN(CONSTANT (MAXPAGESIZE));
|
||||||
|
/* Adjust the address for the rodata segment. We want to adjust up to
|
||||||
|
the same address within the page on the next page up. */
|
||||||
|
. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
|
||||||
|
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
|
||||||
|
.rodata1 : { *(.rodata1) }
|
||||||
|
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
|
||||||
|
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
|
||||||
|
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
|
||||||
|
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
|
||||||
|
/* These sections are generated by the Sun/Oracle C++ compiler. */
|
||||||
|
.exception_ranges : ONLY_IF_RO { *(.exception_ranges*) }
|
||||||
|
/* Adjust the address for the data segment. We want to adjust up to
|
||||||
|
the same address within the page on the next page up. */
|
||||||
|
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
|
||||||
|
/* Exception handling */
|
||||||
|
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
|
||||||
|
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
|
||||||
|
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
|
||||||
|
.exception_ranges : ONLY_IF_RW { *(.exception_ranges*) }
|
||||||
|
/* Thread Local Storage sections */
|
||||||
|
/* .tdata :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__tdata_start = .);
|
||||||
|
*(.tdata .tdata.* .gnu.linkonce.td.*)
|
||||||
|
}
|
||||||
|
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } */
|
||||||
|
.preinit_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||||
|
KEEP (*(.preinit_array))
|
||||||
|
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||||
|
}
|
||||||
|
/* .init_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__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))
|
||||||
|
PROVIDE_HIDDEN (__init_array_end = .);
|
||||||
|
} */
|
||||||
|
.fini_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||||
|
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
|
||||||
|
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
|
||||||
|
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||||
|
}
|
||||||
|
.ctors :
|
||||||
|
{
|
||||||
|
/* gcc uses crtbegin.o to find the start of
|
||||||
|
the constructors, so we make sure it is
|
||||||
|
first. Because this is a wildcard, it
|
||||||
|
doesn't matter if the user does not
|
||||||
|
actually link against crtbegin.o; the
|
||||||
|
linker won't look for a file to match a
|
||||||
|
wildcard. The wildcard also means that it
|
||||||
|
doesn't matter which directory crtbegin.o
|
||||||
|
is in. */
|
||||||
|
KEEP (*crtbegin.o(.ctors))
|
||||||
|
KEEP (*crtbegin?.o(.ctors))
|
||||||
|
/* We don't want to include the .ctor section from
|
||||||
|
the crtend.o file until after the sorted ctors.
|
||||||
|
The .ctor section from the crtend file contains the
|
||||||
|
end of ctors marker and it must be last */
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
|
||||||
|
KEEP (*(SORT(.ctors.*)))
|
||||||
|
KEEP (*(.ctors))
|
||||||
|
}
|
||||||
|
.dtors :
|
||||||
|
{
|
||||||
|
KEEP (*crtbegin.o(.dtors))
|
||||||
|
KEEP (*crtbegin?.o(.dtors))
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
|
||||||
|
KEEP (*(SORT(.dtors.*)))
|
||||||
|
KEEP (*(.dtors))
|
||||||
|
}
|
||||||
|
.jcr : { KEEP (*(.jcr)) }
|
||||||
|
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
|
||||||
|
.dynamic : { *(.dynamic) }
|
||||||
|
.got : { *(.got) *(.igot) }
|
||||||
|
. = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
|
||||||
|
.got.plt : { *(.got.plt) *(.igot.plt) }
|
||||||
|
.data :
|
||||||
|
{
|
||||||
|
*(.data .data.* .gnu.linkonce.d.*)
|
||||||
|
SORT(CONSTRUCTORS)
|
||||||
|
}
|
||||||
|
.data1 : { *(.data1) }
|
||||||
|
_edata = .; PROVIDE (edata = .);
|
||||||
|
. = .;
|
||||||
|
__bss_start = .;
|
||||||
|
.bss :
|
||||||
|
{
|
||||||
|
*(.dynbss)
|
||||||
|
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||||
|
*(COMMON)
|
||||||
|
/* Align here to ensure that the .bss section occupies space up to
|
||||||
|
_end. Align after .bss to ensure correct alignment even if the
|
||||||
|
.bss section disappears because there are no input sections.
|
||||||
|
FIXME: Why do we need it? When there is no .bss section, we do not
|
||||||
|
pad the .data section. */
|
||||||
|
. = ALIGN(. != 0 ? 64 / 8 : 1);
|
||||||
|
}
|
||||||
|
.lbss :
|
||||||
|
{
|
||||||
|
*(.dynlbss)
|
||||||
|
*(.lbss .lbss.* .gnu.linkonce.lb.*)
|
||||||
|
*(LARGE_COMMON)
|
||||||
|
}
|
||||||
|
. = ALIGN(64 / 8);
|
||||||
|
. = SEGMENT_START("ldata-segment", .);
|
||||||
|
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
|
||||||
|
{
|
||||||
|
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
|
||||||
|
}
|
||||||
|
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
|
||||||
|
{
|
||||||
|
*(.ldata .ldata.* .gnu.linkonce.l.*)
|
||||||
|
. = ALIGN(. != 0 ? 64 / 8 : 1);
|
||||||
|
}
|
||||||
|
. = ALIGN(64 / 8);
|
||||||
|
_end = .; PROVIDE (end = .);
|
||||||
|
. = DATA_SEGMENT_END (.);
|
||||||
|
/* Stabs debugging sections. */
|
||||||
|
.stab 0 : { *(.stab) }
|
||||||
|
.stabstr 0 : { *(.stabstr) }
|
||||||
|
.stab.excl 0 : { *(.stab.excl) }
|
||||||
|
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||||
|
.stab.index 0 : { *(.stab.index) }
|
||||||
|
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||||
|
.comment 0 : { *(.comment) }
|
||||||
|
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
|
||||||
|
/* DWARF debug sections.
|
||||||
|
Symbols in the DWARF debugging sections are relative to the beginning
|
||||||
|
of the section so we begin them at 0. */
|
||||||
|
/* DWARF 1 */
|
||||||
|
.debug 0 : { *(.debug) }
|
||||||
|
.line 0 : { *(.line) }
|
||||||
|
/* GNU DWARF 1 extensions */
|
||||||
|
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||||
|
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||||
|
/* DWARF 1.1 and DWARF 2 */
|
||||||
|
.debug_aranges 0 : { *(.debug_aranges) }
|
||||||
|
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||||
|
/* DWARF 2 */
|
||||||
|
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||||
|
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||||
|
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
|
||||||
|
.debug_frame 0 : { *(.debug_frame) }
|
||||||
|
.debug_str 0 : { *(.debug_str) }
|
||||||
|
.debug_loc 0 : { *(.debug_loc) }
|
||||||
|
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||||
|
/* SGI/MIPS DWARF 2 extensions */
|
||||||
|
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||||
|
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||||
|
.debug_typenames 0 : { *(.debug_typenames) }
|
||||||
|
.debug_varnames 0 : { *(.debug_varnames) }
|
||||||
|
/* DWARF 3 */
|
||||||
|
.debug_pubtypes 0 : { *(.debug_pubtypes) }
|
||||||
|
.debug_ranges 0 : { *(.debug_ranges) }
|
||||||
|
/* DWARF Extension. */
|
||||||
|
.debug_macro 0 : { *(.debug_macro) }
|
||||||
|
.debug_addr 0 : { *(.debug_addr) }
|
||||||
|
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
|
||||||
|
/DISCARD/ : {
|
||||||
|
*(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*)
|
||||||
|
/*
|
||||||
|
* XXX: As of now, ld.so links with relibc which has the main functionality. In the next refactor,
|
||||||
|
* ld.so will be moved out of relibc. So, till that time, we have to discard any sections
|
||||||
|
* that may reference use thread local storage.
|
||||||
|
*
|
||||||
|
* .init_array also depends on TLS and is discarded as we don't need it.
|
||||||
|
*/
|
||||||
|
*(.gnu.linkonce.tb.*) *(.tcommon)
|
||||||
|
*(.init_array)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,259 @@
|
|||||||
|
/* Script for -z combreloc */
|
||||||
|
/* Copyright (C) 2014-2020 Free Software Foundation, Inc.
|
||||||
|
Copying and distribution of this script, with or without modification,
|
||||||
|
are permitted in any medium without royalty provided the copyright
|
||||||
|
notice and this notice are preserved. */
|
||||||
|
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64",
|
||||||
|
"elf64-x86-64")
|
||||||
|
OUTPUT_ARCH(i386:x86-64)
|
||||||
|
ENTRY(_start)
|
||||||
|
SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib64");
|
||||||
|
SEARCH_DIR("/usr/lib64/binutils/x86_64-pc-linux-gnu/2.33.164");
|
||||||
|
SEARCH_DIR("/usr/local/lib64");
|
||||||
|
SEARCH_DIR("/lib64");
|
||||||
|
SEARCH_DIR("/usr/lib64");
|
||||||
|
SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib");
|
||||||
|
SEARCH_DIR("/usr/lib64/binutils/x86_64-pc-linux-gnu/2.33.1");
|
||||||
|
SEARCH_DIR("/usr/local/lib");
|
||||||
|
SEARCH_DIR("/lib");
|
||||||
|
SEARCH_DIR("/usr/lib");
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
/* Read-only sections, merged into text segment: */
|
||||||
|
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x20000000) + SIZEOF_HEADERS;
|
||||||
|
.interp : { *(.interp) }
|
||||||
|
.note.gnu.build-id : { *(.note.gnu.build-id) }
|
||||||
|
.hash : { *(.hash) }
|
||||||
|
.gnu.hash : { *(.gnu.hash) }
|
||||||
|
.dynsym : { *(.dynsym) }
|
||||||
|
.dynstr : { *(.dynstr) }
|
||||||
|
.gnu.version : { *(.gnu.version) }
|
||||||
|
.gnu.version_d : { *(.gnu.version_d) }
|
||||||
|
.gnu.version_r : { *(.gnu.version_r) }
|
||||||
|
.rela.dyn :
|
||||||
|
{
|
||||||
|
*(.rela.init)
|
||||||
|
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
|
||||||
|
*(.rela.fini)
|
||||||
|
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
|
||||||
|
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
|
||||||
|
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
|
||||||
|
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
|
||||||
|
*(.rela.ctors)
|
||||||
|
*(.rela.dtors)
|
||||||
|
*(.rela.got)
|
||||||
|
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
|
||||||
|
*(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
|
||||||
|
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
|
||||||
|
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
|
||||||
|
*(.rela.ifunc)
|
||||||
|
}
|
||||||
|
.rela.plt :
|
||||||
|
{
|
||||||
|
*(.rela.plt)
|
||||||
|
PROVIDE_HIDDEN (__rela_iplt_start = .);
|
||||||
|
*(.rela.iplt)
|
||||||
|
PROVIDE_HIDDEN (__rela_iplt_end = .);
|
||||||
|
}
|
||||||
|
. = ALIGN(CONSTANT (MAXPAGESIZE));
|
||||||
|
.init :
|
||||||
|
{
|
||||||
|
KEEP (*(SORT_NONE(.init)))
|
||||||
|
}
|
||||||
|
.plt : { *(.plt) *(.iplt) }
|
||||||
|
.plt.got : { *(.plt.got) }
|
||||||
|
.plt.sec : { *(.plt.sec) }
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
|
||||||
|
*(.text.exit .text.exit.*)
|
||||||
|
*(.text.startup .text.startup.*)
|
||||||
|
*(.text.hot .text.hot.*)
|
||||||
|
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||||
|
/* .gnu.warning sections are handled specially by elf.em. */
|
||||||
|
*(.gnu.warning)
|
||||||
|
}
|
||||||
|
.fini :
|
||||||
|
{
|
||||||
|
KEEP (*(SORT_NONE(.fini)))
|
||||||
|
}
|
||||||
|
PROVIDE (__etext = .);
|
||||||
|
PROVIDE (_etext = .);
|
||||||
|
PROVIDE (etext = .);
|
||||||
|
. = ALIGN(CONSTANT (MAXPAGESIZE));
|
||||||
|
/* Adjust the address for the rodata segment. We want to adjust up to
|
||||||
|
the same address within the page on the next page up. */
|
||||||
|
. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
|
||||||
|
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
|
||||||
|
.rodata1 : { *(.rodata1) }
|
||||||
|
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
|
||||||
|
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
|
||||||
|
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
|
||||||
|
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
|
||||||
|
/* These sections are generated by the Sun/Oracle C++ compiler. */
|
||||||
|
.exception_ranges : ONLY_IF_RO { *(.exception_ranges*) }
|
||||||
|
/* Adjust the address for the data segment. We want to adjust up to
|
||||||
|
the same address within the page on the next page up. */
|
||||||
|
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
|
||||||
|
/* Exception handling */
|
||||||
|
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
|
||||||
|
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
|
||||||
|
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
|
||||||
|
.exception_ranges : ONLY_IF_RW { *(.exception_ranges*) }
|
||||||
|
/* Thread Local Storage sections */
|
||||||
|
/* .tdata : ALIGN(4K)
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__tdata_start = .);
|
||||||
|
*(.tdata .tdata.* .gnu.linkonce.td.*)
|
||||||
|
}
|
||||||
|
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } */
|
||||||
|
.preinit_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||||
|
KEEP (*(.preinit_array))
|
||||||
|
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||||
|
}
|
||||||
|
/* .init_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__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))
|
||||||
|
PROVIDE_HIDDEN (__init_array_end = .);
|
||||||
|
} */
|
||||||
|
.fini_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||||
|
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
|
||||||
|
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
|
||||||
|
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||||
|
}
|
||||||
|
.ctors :
|
||||||
|
{
|
||||||
|
/* gcc uses crtbegin.o to find the start of
|
||||||
|
the constructors, so we make sure it is
|
||||||
|
first. Because this is a wildcard, it
|
||||||
|
doesn't matter if the user does not
|
||||||
|
actually link against crtbegin.o; the
|
||||||
|
linker won't look for a file to match a
|
||||||
|
wildcard. The wildcard also means that it
|
||||||
|
doesn't matter which directory crtbegin.o
|
||||||
|
is in. */
|
||||||
|
KEEP (*crtbegin.o(.ctors))
|
||||||
|
KEEP (*crtbegin?.o(.ctors))
|
||||||
|
/* We don't want to include the .ctor section from
|
||||||
|
the crtend.o file until after the sorted ctors.
|
||||||
|
The .ctor section from the crtend file contains the
|
||||||
|
end of ctors marker and it must be last */
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
|
||||||
|
KEEP (*(SORT(.ctors.*)))
|
||||||
|
KEEP (*(.ctors))
|
||||||
|
}
|
||||||
|
.dtors :
|
||||||
|
{
|
||||||
|
KEEP (*crtbegin.o(.dtors))
|
||||||
|
KEEP (*crtbegin?.o(.dtors))
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
|
||||||
|
KEEP (*(SORT(.dtors.*)))
|
||||||
|
KEEP (*(.dtors))
|
||||||
|
}
|
||||||
|
.jcr : { KEEP (*(.jcr)) }
|
||||||
|
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
|
||||||
|
.dynamic : { *(.dynamic) }
|
||||||
|
.got : { *(.got) *(.igot) }
|
||||||
|
. = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
|
||||||
|
.got.plt : { *(.got.plt) *(.igot.plt) }
|
||||||
|
.data :
|
||||||
|
{
|
||||||
|
*(.data .data.* .gnu.linkonce.d.*)
|
||||||
|
SORT(CONSTRUCTORS)
|
||||||
|
}
|
||||||
|
.data1 : { *(.data1) }
|
||||||
|
_edata = .; PROVIDE (edata = .);
|
||||||
|
. = .;
|
||||||
|
__bss_start = .;
|
||||||
|
.bss :
|
||||||
|
{
|
||||||
|
*(.dynbss)
|
||||||
|
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||||
|
*(COMMON)
|
||||||
|
/* Align here to ensure that the .bss section occupies space up to
|
||||||
|
_end. Align after .bss to ensure correct alignment even if the
|
||||||
|
.bss section disappears because there are no input sections.
|
||||||
|
FIXME: Why do we need it? When there is no .bss section, we do not
|
||||||
|
pad the .data section. */
|
||||||
|
. = ALIGN(. != 0 ? 64 / 8 : 1);
|
||||||
|
}
|
||||||
|
.lbss :
|
||||||
|
{
|
||||||
|
*(.dynlbss)
|
||||||
|
*(.lbss .lbss.* .gnu.linkonce.lb.*)
|
||||||
|
*(LARGE_COMMON)
|
||||||
|
}
|
||||||
|
. = ALIGN(64 / 8);
|
||||||
|
. = SEGMENT_START("ldata-segment", .);
|
||||||
|
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
|
||||||
|
{
|
||||||
|
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
|
||||||
|
}
|
||||||
|
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
|
||||||
|
{
|
||||||
|
*(.ldata .ldata.* .gnu.linkonce.l.*)
|
||||||
|
. = ALIGN(. != 0 ? 64 / 8 : 1);
|
||||||
|
}
|
||||||
|
. = ALIGN(64 / 8);
|
||||||
|
_end = .; PROVIDE (end = .);
|
||||||
|
. = DATA_SEGMENT_END (.);
|
||||||
|
/* Stabs debugging sections. */
|
||||||
|
.stab 0 : { *(.stab) }
|
||||||
|
.stabstr 0 : { *(.stabstr) }
|
||||||
|
.stab.excl 0 : { *(.stab.excl) }
|
||||||
|
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||||
|
.stab.index 0 : { *(.stab.index) }
|
||||||
|
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||||
|
.comment 0 : { *(.comment) }
|
||||||
|
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
|
||||||
|
/* DWARF debug sections.
|
||||||
|
Symbols in the DWARF debugging sections are relative to the beginning
|
||||||
|
of the section so we begin them at 0. */
|
||||||
|
/* DWARF 1 */
|
||||||
|
.debug 0 : { *(.debug) }
|
||||||
|
.line 0 : { *(.line) }
|
||||||
|
/* GNU DWARF 1 extensions */
|
||||||
|
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||||
|
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||||
|
/* DWARF 1.1 and DWARF 2 */
|
||||||
|
.debug_aranges 0 : { *(.debug_aranges) }
|
||||||
|
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||||
|
/* DWARF 2 */
|
||||||
|
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||||
|
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||||
|
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
|
||||||
|
.debug_frame 0 : { *(.debug_frame) }
|
||||||
|
.debug_str 0 : { *(.debug_str) }
|
||||||
|
.debug_loc 0 : { *(.debug_loc) }
|
||||||
|
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||||
|
/* SGI/MIPS DWARF 2 extensions */
|
||||||
|
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||||
|
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||||
|
.debug_typenames 0 : { *(.debug_typenames) }
|
||||||
|
.debug_varnames 0 : { *(.debug_varnames) }
|
||||||
|
/* DWARF 3 */
|
||||||
|
.debug_pubtypes 0 : { *(.debug_pubtypes) }
|
||||||
|
.debug_ranges 0 : { *(.debug_ranges) }
|
||||||
|
/* DWARF Extension. */
|
||||||
|
.debug_macro 0 : { *(.debug_macro) }
|
||||||
|
.debug_addr 0 : { *(.debug_addr) }
|
||||||
|
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
|
||||||
|
/DISCARD/ : {
|
||||||
|
*(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*)
|
||||||
|
/*
|
||||||
|
* XXX: As of now, ld.so links with relibc which has the main functionality. In the next refactor,
|
||||||
|
* ld.so will be moved out of relibc. So, till that time, we have to discard any sections
|
||||||
|
* that may reference use thread local storage.
|
||||||
|
*
|
||||||
|
* .init_array also depends on TLS and is discarded as we don't need it.
|
||||||
|
*/
|
||||||
|
*(.gnu.linkonce.tb.*) *(.tcommon)
|
||||||
|
*(.init_array)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,256 @@
|
|||||||
|
/* Script for -z combreloc */
|
||||||
|
/* Copyright (C) 2014-2020 Free Software Foundation, Inc.
|
||||||
|
Copying and distribution of this script, with or without modification,
|
||||||
|
are permitted in any medium without royalty provided the copyright
|
||||||
|
notice and this notice are preserved. */
|
||||||
|
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64",
|
||||||
|
"elf64-x86-64")
|
||||||
|
OUTPUT_ARCH(i386:x86-64)
|
||||||
|
ENTRY(_start)
|
||||||
|
SEARCH_DIR("/x86_64-unknown-redox/lib");
|
||||||
|
SEARCH_DIR("/usr/local/lib64");
|
||||||
|
SEARCH_DIR("/lib64");
|
||||||
|
SEARCH_DIR("/usr/lib64");
|
||||||
|
SEARCH_DIR("/usr/local/lib");
|
||||||
|
SEARCH_DIR("/lib");
|
||||||
|
SEARCH_DIR("/usr/lib");
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
/* Read-only sections, merged into text segment: */
|
||||||
|
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x20000000) + SIZEOF_HEADERS;
|
||||||
|
.interp : { *(.interp) }
|
||||||
|
.note.gnu.build-id : { *(.note.gnu.build-id) }
|
||||||
|
.hash : { *(.hash) }
|
||||||
|
.gnu.hash : { *(.gnu.hash) }
|
||||||
|
.dynsym : { *(.dynsym) }
|
||||||
|
.dynstr : { *(.dynstr) }
|
||||||
|
.gnu.version : { *(.gnu.version) }
|
||||||
|
.gnu.version_d : { *(.gnu.version_d) }
|
||||||
|
.gnu.version_r : { *(.gnu.version_r) }
|
||||||
|
.rela.dyn :
|
||||||
|
{
|
||||||
|
*(.rela.init)
|
||||||
|
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
|
||||||
|
*(.rela.fini)
|
||||||
|
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
|
||||||
|
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
|
||||||
|
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
|
||||||
|
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
|
||||||
|
*(.rela.ctors)
|
||||||
|
*(.rela.dtors)
|
||||||
|
*(.rela.got)
|
||||||
|
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
|
||||||
|
*(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
|
||||||
|
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
|
||||||
|
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
|
||||||
|
*(.rela.ifunc)
|
||||||
|
}
|
||||||
|
.rela.plt :
|
||||||
|
{
|
||||||
|
*(.rela.plt)
|
||||||
|
PROVIDE_HIDDEN (__rela_iplt_start = .);
|
||||||
|
*(.rela.iplt)
|
||||||
|
PROVIDE_HIDDEN (__rela_iplt_end = .);
|
||||||
|
}
|
||||||
|
. = ALIGN(CONSTANT (MAXPAGESIZE));
|
||||||
|
.init :
|
||||||
|
{
|
||||||
|
KEEP (*(SORT_NONE(.init)))
|
||||||
|
}
|
||||||
|
.plt : { *(.plt) *(.iplt) }
|
||||||
|
.plt.got : { *(.plt.got) }
|
||||||
|
.plt.sec : { *(.plt.sec) }
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
|
||||||
|
*(.text.exit .text.exit.*)
|
||||||
|
*(.text.startup .text.startup.*)
|
||||||
|
*(.text.hot .text.hot.*)
|
||||||
|
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||||
|
/* .gnu.warning sections are handled specially by elf.em. */
|
||||||
|
*(.gnu.warning)
|
||||||
|
}
|
||||||
|
.fini :
|
||||||
|
{
|
||||||
|
KEEP (*(SORT_NONE(.fini)))
|
||||||
|
}
|
||||||
|
PROVIDE (__etext = .);
|
||||||
|
PROVIDE (_etext = .);
|
||||||
|
PROVIDE (etext = .);
|
||||||
|
. = ALIGN(CONSTANT (MAXPAGESIZE));
|
||||||
|
/* Adjust the address for the rodata segment. We want to adjust up to
|
||||||
|
the same address within the page on the next page up. */
|
||||||
|
. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
|
||||||
|
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
|
||||||
|
.rodata1 : { *(.rodata1) }
|
||||||
|
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
|
||||||
|
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
|
||||||
|
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
|
||||||
|
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
|
||||||
|
/* These sections are generated by the Sun/Oracle C++ compiler. */
|
||||||
|
.exception_ranges : ONLY_IF_RO { *(.exception_ranges*) }
|
||||||
|
/* Adjust the address for the data segment. We want to adjust up to
|
||||||
|
the same address within the page on the next page up. */
|
||||||
|
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
|
||||||
|
/* Exception handling */
|
||||||
|
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
|
||||||
|
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
|
||||||
|
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
|
||||||
|
.exception_ranges : ONLY_IF_RW { *(.exception_ranges*) }
|
||||||
|
/* Thread Local Storage sections */
|
||||||
|
/* .tdata : ALIGN(4K)
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__tdata_start = .);
|
||||||
|
*(.tdata .tdata.* .gnu.linkonce.td.*)
|
||||||
|
}
|
||||||
|
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } */
|
||||||
|
.preinit_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||||
|
KEEP (*(.preinit_array))
|
||||||
|
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||||
|
}
|
||||||
|
/* .init_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__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))
|
||||||
|
PROVIDE_HIDDEN (__init_array_end = .);
|
||||||
|
} */
|
||||||
|
.fini_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||||
|
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
|
||||||
|
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
|
||||||
|
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||||
|
}
|
||||||
|
.ctors :
|
||||||
|
{
|
||||||
|
/* gcc uses crtbegin.o to find the start of
|
||||||
|
the constructors, so we make sure it is
|
||||||
|
first. Because this is a wildcard, it
|
||||||
|
doesn't matter if the user does not
|
||||||
|
actually link against crtbegin.o; the
|
||||||
|
linker won't look for a file to match a
|
||||||
|
wildcard. The wildcard also means that it
|
||||||
|
doesn't matter which directory crtbegin.o
|
||||||
|
is in. */
|
||||||
|
KEEP (*crtbegin.o(.ctors))
|
||||||
|
KEEP (*crtbegin?.o(.ctors))
|
||||||
|
/* We don't want to include the .ctor section from
|
||||||
|
the crtend.o file until after the sorted ctors.
|
||||||
|
The .ctor section from the crtend file contains the
|
||||||
|
end of ctors marker and it must be last */
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
|
||||||
|
KEEP (*(SORT(.ctors.*)))
|
||||||
|
KEEP (*(.ctors))
|
||||||
|
}
|
||||||
|
.dtors :
|
||||||
|
{
|
||||||
|
KEEP (*crtbegin.o(.dtors))
|
||||||
|
KEEP (*crtbegin?.o(.dtors))
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
|
||||||
|
KEEP (*(SORT(.dtors.*)))
|
||||||
|
KEEP (*(.dtors))
|
||||||
|
}
|
||||||
|
.jcr : { KEEP (*(.jcr)) }
|
||||||
|
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
|
||||||
|
.dynamic : { *(.dynamic) }
|
||||||
|
.got : { *(.got) *(.igot) }
|
||||||
|
. = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
|
||||||
|
.got.plt : { *(.got.plt) *(.igot.plt) }
|
||||||
|
.data :
|
||||||
|
{
|
||||||
|
*(.data .data.* .gnu.linkonce.d.*)
|
||||||
|
SORT(CONSTRUCTORS)
|
||||||
|
}
|
||||||
|
.data1 : { *(.data1) }
|
||||||
|
_edata = .; PROVIDE (edata = .);
|
||||||
|
. = .;
|
||||||
|
__bss_start = .;
|
||||||
|
.bss :
|
||||||
|
{
|
||||||
|
*(.dynbss)
|
||||||
|
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||||
|
*(COMMON)
|
||||||
|
/* Align here to ensure that the .bss section occupies space up to
|
||||||
|
_end. Align after .bss to ensure correct alignment even if the
|
||||||
|
.bss section disappears because there are no input sections.
|
||||||
|
FIXME: Why do we need it? When there is no .bss section, we do not
|
||||||
|
pad the .data section. */
|
||||||
|
. = ALIGN(. != 0 ? 64 / 8 : 1);
|
||||||
|
}
|
||||||
|
.lbss :
|
||||||
|
{
|
||||||
|
*(.dynlbss)
|
||||||
|
*(.lbss .lbss.* .gnu.linkonce.lb.*)
|
||||||
|
*(LARGE_COMMON)
|
||||||
|
}
|
||||||
|
. = ALIGN(64 / 8);
|
||||||
|
. = SEGMENT_START("ldata-segment", .);
|
||||||
|
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
|
||||||
|
{
|
||||||
|
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
|
||||||
|
}
|
||||||
|
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
|
||||||
|
{
|
||||||
|
*(.ldata .ldata.* .gnu.linkonce.l.*)
|
||||||
|
. = ALIGN(. != 0 ? 64 / 8 : 1);
|
||||||
|
}
|
||||||
|
. = ALIGN(64 / 8);
|
||||||
|
_end = .; PROVIDE (end = .);
|
||||||
|
. = DATA_SEGMENT_END (.);
|
||||||
|
/* Stabs debugging sections. */
|
||||||
|
.stab 0 : { *(.stab) }
|
||||||
|
.stabstr 0 : { *(.stabstr) }
|
||||||
|
.stab.excl 0 : { *(.stab.excl) }
|
||||||
|
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||||
|
.stab.index 0 : { *(.stab.index) }
|
||||||
|
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||||
|
.comment 0 : { *(.comment) }
|
||||||
|
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
|
||||||
|
/* DWARF debug sections.
|
||||||
|
Symbols in the DWARF debugging sections are relative to the beginning
|
||||||
|
of the section so we begin them at 0. */
|
||||||
|
/* DWARF 1 */
|
||||||
|
.debug 0 : { *(.debug) }
|
||||||
|
.line 0 : { *(.line) }
|
||||||
|
/* GNU DWARF 1 extensions */
|
||||||
|
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||||
|
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||||
|
/* DWARF 1.1 and DWARF 2 */
|
||||||
|
.debug_aranges 0 : { *(.debug_aranges) }
|
||||||
|
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||||
|
/* DWARF 2 */
|
||||||
|
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||||
|
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||||
|
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
|
||||||
|
.debug_frame 0 : { *(.debug_frame) }
|
||||||
|
.debug_str 0 : { *(.debug_str) }
|
||||||
|
.debug_loc 0 : { *(.debug_loc) }
|
||||||
|
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||||
|
/* SGI/MIPS DWARF 2 extensions */
|
||||||
|
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||||
|
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||||
|
.debug_typenames 0 : { *(.debug_typenames) }
|
||||||
|
.debug_varnames 0 : { *(.debug_varnames) }
|
||||||
|
/* DWARF 3 */
|
||||||
|
.debug_pubtypes 0 : { *(.debug_pubtypes) }
|
||||||
|
.debug_ranges 0 : { *(.debug_ranges) }
|
||||||
|
/* DWARF Extension. */
|
||||||
|
.debug_macro 0 : { *(.debug_macro) }
|
||||||
|
.debug_addr 0 : { *(.debug_addr) }
|
||||||
|
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
|
||||||
|
/DISCARD/ : {
|
||||||
|
*(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*)
|
||||||
|
/*
|
||||||
|
* XXX: As of now, ld.so links with relibc which has the main functionality. In the next refactor,
|
||||||
|
* ld.so will be moved out of relibc. So, till that time, we have to discard any sections
|
||||||
|
* that may reference use thread local storage.
|
||||||
|
*
|
||||||
|
* .init_array also depends on TLS and is discarded as we don't need it.
|
||||||
|
*/
|
||||||
|
*(.gnu.linkonce.tb.*) *(.tcommon)
|
||||||
|
*(.init_array)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![feature(linkage)]
|
||||||
|
#![deny(unsafe_op_in_unsafe_fn)]
|
||||||
|
|
||||||
|
use core::arch::global_asm;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
global_asm!(
|
||||||
|
"
|
||||||
|
.weak _DYNAMIC
|
||||||
|
.hidden _DYNAMIC
|
||||||
|
|
||||||
|
.global _start
|
||||||
|
_start:
|
||||||
|
mov x28, sp
|
||||||
|
// align stack to 16 bytes
|
||||||
|
and sp, x28, #0xfffffffffffffff0
|
||||||
|
adr x1, _start
|
||||||
|
mov x0, x28
|
||||||
|
adrp x2, _DYNAMIC
|
||||||
|
add x2, x2, #:lo12:_DYNAMIC
|
||||||
|
// ld_so_start(stack=x0, ld_entry=x1, dynamic=x2)
|
||||||
|
bl relibc_ld_so_start
|
||||||
|
// restore original stack, clear registers, and jump to the new start function
|
||||||
|
mov sp, x28
|
||||||
|
mov x1, xzr
|
||||||
|
mov x2, xzr
|
||||||
|
mov x3, xzr
|
||||||
|
mov x4, xzr
|
||||||
|
mov x5, xzr
|
||||||
|
mov x6, xzr
|
||||||
|
mov x7, xzr
|
||||||
|
mov x8, xzr
|
||||||
|
mov x9, xzr
|
||||||
|
mov x10, xzr
|
||||||
|
mov x11, xzr
|
||||||
|
mov x12, xzr
|
||||||
|
mov x13, xzr
|
||||||
|
mov x14, xzr
|
||||||
|
mov x15, xzr
|
||||||
|
mov x16, xzr
|
||||||
|
mov x17, xzr
|
||||||
|
mov x18, xzr
|
||||||
|
mov x19, xzr
|
||||||
|
mov x20, xzr
|
||||||
|
mov x21, xzr
|
||||||
|
mov x22, xzr
|
||||||
|
mov x23, xzr
|
||||||
|
mov x24, xzr
|
||||||
|
mov x25, xzr
|
||||||
|
mov x26, xzr
|
||||||
|
mov x27, xzr
|
||||||
|
mov x28, xzr
|
||||||
|
mov x29, xzr
|
||||||
|
mov x30, xzr
|
||||||
|
br x0
|
||||||
|
udf #0
|
||||||
|
"
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86")]
|
||||||
|
global_asm!(
|
||||||
|
"
|
||||||
|
.globl _start
|
||||||
|
_start:
|
||||||
|
push esp
|
||||||
|
call relibc_ld_so_start
|
||||||
|
pop esp
|
||||||
|
# TODO: x86
|
||||||
|
ud2
|
||||||
|
"
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
global_asm!(
|
||||||
|
"
|
||||||
|
.weak _DYNAMIC
|
||||||
|
.hidden _DYNAMIC
|
||||||
|
|
||||||
|
.globl _start
|
||||||
|
_start:
|
||||||
|
lea rsi, [rip + _start]
|
||||||
|
|
||||||
|
# Save original stack and align stack to 16 bytes
|
||||||
|
mov rbp, rsp
|
||||||
|
and rsp, 0xfffffffffffffff0
|
||||||
|
|
||||||
|
# Call ld_so_start(stack=rdi, ld_entry=rsi, dynamic=rdx)
|
||||||
|
mov rdi, rbp
|
||||||
|
lea rdx, [rip + _DYNAMIC]
|
||||||
|
call relibc_ld_so_start
|
||||||
|
|
||||||
|
# Restore original stack, clear registers, and jump to new start function
|
||||||
|
mov rsp, rbp
|
||||||
|
xor rcx, rcx
|
||||||
|
xor rdx, rdx
|
||||||
|
xor rdi, rdi
|
||||||
|
xor rsi, rsi
|
||||||
|
xor r8, r8
|
||||||
|
xor r9, r9
|
||||||
|
xor r10, r10
|
||||||
|
xor r11, r11
|
||||||
|
fninit
|
||||||
|
jmp rax
|
||||||
|
ud2
|
||||||
|
"
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
global_asm!(
|
||||||
|
"
|
||||||
|
.globl _start
|
||||||
|
_start:
|
||||||
|
mv a0, sp
|
||||||
|
jal relibc_ld_so_start
|
||||||
|
unimp
|
||||||
|
"
|
||||||
|
);
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn main(_argc: isize, _argv: *const *const i8) -> usize {
|
||||||
|
// LD
|
||||||
|
0x1D
|
||||||
|
}
|
||||||
|
|
||||||
|
#[linkage = "weak"]
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
extern "C" fn relibc_panic(_pi: &::core::panic::PanicInfo) -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
#[linkage = "weak"]
|
||||||
|
pub unsafe fn rust_begin_unwind(pi: &::core::panic::PanicInfo) -> ! {
|
||||||
|
relibc_panic(pi)
|
||||||
|
}
|
||||||
Submodule
+1
Submodule openlibm added at e2da0dafd3
@@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "redox-ioctl"
|
||||||
|
authors = ["bjorn3 <bjorn3_gh@protonmail.com>"]
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
license = "MIT"
|
||||||
|
description = "Ioctl definitions and (de)serialization for Redox"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
drm-sys = "0.8.0"
|
||||||
|
redox_syscall = { path = "../../syscall" }
|
||||||
|
|
||||||
|
[features]
|
||||||
@@ -0,0 +1,319 @@
|
|||||||
|
use alloc::vec::Vec;
|
||||||
|
use core::{
|
||||||
|
cmp,
|
||||||
|
ffi::{c_char, c_int, c_uint},
|
||||||
|
iter, mem, slice,
|
||||||
|
};
|
||||||
|
use drm_sys::drm_clip_rect;
|
||||||
|
|
||||||
|
pub use drm_sys::{
|
||||||
|
__kernel_size_t, DRM_PROP_NAME_LEN, drm_get_cap, drm_mode_card_res,
|
||||||
|
drm_mode_connector_set_property, drm_mode_create_dumb, drm_mode_crtc,
|
||||||
|
drm_mode_crtc_page_flip_target, drm_mode_cursor, drm_mode_cursor2, drm_mode_destroy_dumb,
|
||||||
|
drm_mode_fb_cmd, drm_mode_fb_cmd2, drm_mode_fb_dirty_cmd, drm_mode_get_blob,
|
||||||
|
drm_mode_get_connector, drm_mode_get_encoder, drm_mode_get_plane, drm_mode_get_plane_res,
|
||||||
|
drm_mode_get_property, drm_mode_map_dumb, drm_mode_modeinfo, drm_mode_obj_get_properties,
|
||||||
|
drm_mode_property_enum, drm_mode_set_plane, drm_set_client_cap, drm_version,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const VERSION: u64 = 0;
|
||||||
|
define_ioctl_data! {
|
||||||
|
struct drm_version, DrmVersion {
|
||||||
|
version_major: c_int,
|
||||||
|
version_minor: c_int,
|
||||||
|
version_patchlevel: c_int,
|
||||||
|
name_len: __kernel_size_t,
|
||||||
|
name: *mut c_char [array<c_char, name_len>],
|
||||||
|
date_len: __kernel_size_t,
|
||||||
|
date: *mut c_char [array<c_char, date_len>],
|
||||||
|
desc_len: __kernel_size_t,
|
||||||
|
desc: *mut c_char [array<c_char, desc_len>],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const GET_CAP: u64 = 0x0C;
|
||||||
|
pub use drm_sys::DRM_CAP_DUMB_BUFFER;
|
||||||
|
define_ioctl_data! {
|
||||||
|
struct drm_get_cap, DrmGetCap {
|
||||||
|
capability: u64,
|
||||||
|
value: u64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const SET_CLIENT_CAP: u64 = 0x0D;
|
||||||
|
pub use drm_sys::DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT;
|
||||||
|
define_ioctl_data! {
|
||||||
|
struct drm_set_client_cap, DrmSetClientCap {
|
||||||
|
capability: u64,
|
||||||
|
value: u64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MODE_CARD_RES: u64 = 0xA0;
|
||||||
|
define_ioctl_data! {
|
||||||
|
struct drm_mode_card_res, DrmModeCardRes {
|
||||||
|
fb_id_ptr: u64 [array<u32, count_fbs>],
|
||||||
|
crtc_id_ptr: u64 [array<u32, count_crtcs>],
|
||||||
|
connector_id_ptr: u64 [array<u32, count_connectors>],
|
||||||
|
encoder_id_ptr: u64 [array<u32, count_encoders>],
|
||||||
|
count_fbs: u32,
|
||||||
|
count_crtcs: u32,
|
||||||
|
count_connectors: u32,
|
||||||
|
count_encoders: u32,
|
||||||
|
min_width: u32,
|
||||||
|
max_width: u32,
|
||||||
|
min_height: u32,
|
||||||
|
max_height: u32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MODE_GET_CRTC: u64 = 0xA1;
|
||||||
|
pub const MODE_SET_CRTC: u64 = 0xA2;
|
||||||
|
define_ioctl_data! {
|
||||||
|
struct drm_mode_crtc, DrmModeCrtc {
|
||||||
|
set_connectors_ptr: u64 [array<u32, count_connectors>],
|
||||||
|
count_connectors: u32,
|
||||||
|
crtc_id: u32,
|
||||||
|
fb_id: u32,
|
||||||
|
x: u32,
|
||||||
|
y: u32,
|
||||||
|
gamma_size: u32,
|
||||||
|
mode_valid: u32,
|
||||||
|
mode: drm_mode_modeinfo,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MODE_CURSOR: u64 = 0xA3;
|
||||||
|
define_ioctl_data! {
|
||||||
|
struct drm_mode_cursor, DrmModeCursor {
|
||||||
|
flags: u32,
|
||||||
|
crtc_id: u32,
|
||||||
|
x: i32,
|
||||||
|
y:i32,
|
||||||
|
width:u32,
|
||||||
|
height:u32,
|
||||||
|
handle:u32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MODE_GET_ENCODER: u64 = 0xA6;
|
||||||
|
define_ioctl_data! {
|
||||||
|
struct drm_mode_get_encoder, DrmModeGetEncoder {
|
||||||
|
encoder_id: u32,
|
||||||
|
encoder_type: u32,
|
||||||
|
crtc_id: u32,
|
||||||
|
possible_crtcs: u32,
|
||||||
|
possible_clones: u32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MODE_GET_CONNECTOR: u64 = 0xA7;
|
||||||
|
define_ioctl_data! {
|
||||||
|
struct drm_mode_get_connector, DrmModeGetConnector {
|
||||||
|
encoders_ptr: u64 [array<u32, count_encoders>],
|
||||||
|
modes_ptr: u64 [array<drm_mode_modeinfo, count_modes>],
|
||||||
|
props_ptr: u64 [array<u32, count_props>],
|
||||||
|
prop_values_ptr: u64 [array<u64, count_props>],
|
||||||
|
count_modes: u32,
|
||||||
|
count_props: u32,
|
||||||
|
count_encoders: u32,
|
||||||
|
encoder_id: u32,
|
||||||
|
connector_id: u32,
|
||||||
|
connector_type: u32,
|
||||||
|
connector_type_id: u32,
|
||||||
|
connection: u32,
|
||||||
|
mm_width: u32,
|
||||||
|
mm_height: u32,
|
||||||
|
subpixel: u32,
|
||||||
|
pad: u32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MODE_GET_PROPERTY: u64 = 0xAA;
|
||||||
|
define_ioctl_data! {
|
||||||
|
struct drm_mode_get_property, DrmModeGetProperty {
|
||||||
|
values_ptr: u64 [array<u64, count_values>],
|
||||||
|
enum_blob_ptr: u64 [array<drm_mode_property_enum, count_enum_blobs>],
|
||||||
|
prop_id: u32,
|
||||||
|
flags: u32,
|
||||||
|
name: [c_char; DRM_PROP_NAME_LEN as usize],
|
||||||
|
count_values: u32,
|
||||||
|
count_enum_blobs: u32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MODE_SET_PROPERTY: u64 = 0xAB;
|
||||||
|
define_ioctl_data! {
|
||||||
|
struct drm_mode_connector_set_property, DrmModeConnectorSetProperty {
|
||||||
|
value: u64,
|
||||||
|
prop_id: u32,
|
||||||
|
connector_id: u32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MODE_GET_PROP_BLOB: u64 = 0xAC;
|
||||||
|
define_ioctl_data! {
|
||||||
|
struct drm_mode_get_blob, DrmModeGetBlob {
|
||||||
|
blob_id: u32,
|
||||||
|
length: u32,
|
||||||
|
data: u64 [array<u8, length>],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MODE_GET_FB: u64 = 0xAD;
|
||||||
|
pub const MODE_ADD_FB: u64 = 0xAE;
|
||||||
|
define_ioctl_data! {
|
||||||
|
struct drm_mode_fb_cmd, DrmModeFbCmd {
|
||||||
|
fb_id: u32,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
pitch: u32,
|
||||||
|
bpp: u32,
|
||||||
|
depth: u32,
|
||||||
|
handle: u32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MODE_RM_FB: u64 = 0xAF;
|
||||||
|
define_ioctl_data! {
|
||||||
|
struct standin_for_uint, StandinForUint {
|
||||||
|
inner: c_uint,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub struct standin_for_uint {
|
||||||
|
pub inner: c_uint,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MODE_PAGE_FLIP: u64 = 0xB0;
|
||||||
|
define_ioctl_data! {
|
||||||
|
struct drm_mode_crtc_page_flip_target, DrmModeCrtcPageFlipTarget {
|
||||||
|
crtc_id: u32,
|
||||||
|
fb_id: u32,
|
||||||
|
flags: u32,
|
||||||
|
sequence: u32,
|
||||||
|
user_data: u64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MODE_DIRTYFB: u64 = 0xB1;
|
||||||
|
define_ioctl_data! {
|
||||||
|
struct drm_mode_fb_dirty_cmd, DrmModeFbDirtyCmd {
|
||||||
|
fb_id: u32,
|
||||||
|
flags: u32,
|
||||||
|
color: u32,
|
||||||
|
num_clips: u32,
|
||||||
|
clips_ptr: u64 [array<drm_clip_rect, num_clips>],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MODE_CREATE_DUMB: u64 = 0xB2;
|
||||||
|
define_ioctl_data! {
|
||||||
|
struct drm_mode_create_dumb, DrmModeCreateDumb {
|
||||||
|
height: u32,
|
||||||
|
width: u32,
|
||||||
|
bpp: u32,
|
||||||
|
flags: u32,
|
||||||
|
handle: u32,
|
||||||
|
pitch: u32,
|
||||||
|
size: u64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MODE_MAP_DUMB: u64 = 0xB3;
|
||||||
|
define_ioctl_data! {
|
||||||
|
struct drm_mode_map_dumb, DrmModeMapDumb {
|
||||||
|
handle: u32,
|
||||||
|
pad: u32,
|
||||||
|
offset: u64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MODE_DESTROY_DUMB: u64 = 0xB4;
|
||||||
|
define_ioctl_data! {
|
||||||
|
struct drm_mode_destroy_dumb, DrmModeDestroyDumb {
|
||||||
|
handle: u32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MODE_GET_PLANE_RES: u64 = 0xB5;
|
||||||
|
define_ioctl_data! {
|
||||||
|
struct drm_mode_get_plane_res, DrmModeGetPlaneRes {
|
||||||
|
plane_id_ptr: u64 [array<u32, count_planes>],
|
||||||
|
count_planes: u32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MODE_GET_PLANE: u64 = 0xB6;
|
||||||
|
define_ioctl_data! {
|
||||||
|
struct drm_mode_get_plane, DrmModeGetPlane {
|
||||||
|
plane_id: u32,
|
||||||
|
crtc_id: u32,
|
||||||
|
fb_id: u32,
|
||||||
|
possible_crtcs: u32,
|
||||||
|
gamma_size: u32,
|
||||||
|
count_format_types: u32,
|
||||||
|
format_type_ptr: u64 [array<u32, count_format_types>],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MODE_SET_PLANE: u64 = 0xB7;
|
||||||
|
define_ioctl_data! {
|
||||||
|
struct drm_mode_set_plane, DrmModeSetPlane {
|
||||||
|
plane_id: u32,
|
||||||
|
crtc_id: u32,
|
||||||
|
fb_id: u32,
|
||||||
|
flags: u32,
|
||||||
|
crtc_x: i32,
|
||||||
|
crtc_y: i32,
|
||||||
|
crtc_w: u32,
|
||||||
|
crtc_h: u32,
|
||||||
|
src_x: u32,
|
||||||
|
src_y: u32,
|
||||||
|
src_h: u32,
|
||||||
|
src_w: u32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MODE_OBJ_GET_PROPERTIES: u64 = 0xB9;
|
||||||
|
define_ioctl_data! {
|
||||||
|
struct drm_mode_obj_get_properties, DrmModeObjGetProperties {
|
||||||
|
props_ptr: u64 [array<u32, count_props>],
|
||||||
|
prop_values_ptr: u64 [array<u64, count_props>],
|
||||||
|
count_props: u32,
|
||||||
|
obj_id: u32,
|
||||||
|
obj_type: u32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MODE_CURSOR2: u64 = 0xBB;
|
||||||
|
define_ioctl_data! {
|
||||||
|
struct drm_mode_cursor2, DrmModeCursor2 {
|
||||||
|
flags: u32,
|
||||||
|
crtc_id: u32,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
handle: u32,
|
||||||
|
hot_x: i32,
|
||||||
|
hot_y: i32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MODE_GET_FB2: u64 = 0xCE;
|
||||||
|
define_ioctl_data! {
|
||||||
|
struct drm_mode_fb_cmd2, DrmModeFbCmd2 {
|
||||||
|
fb_id: u32,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
pixel_format: u32,
|
||||||
|
flags: u32,
|
||||||
|
handles: [u32; 4],
|
||||||
|
pitches: [u32; 4],
|
||||||
|
offsets: [u32; 4],
|
||||||
|
modifier: [u64; 4],
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
pub trait IoctlData {
|
||||||
|
unsafe fn write(&self) -> Vec<u8>;
|
||||||
|
unsafe fn read_from(&mut self, buf: &[u8]);
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! define_ioctl_data {
|
||||||
|
(struct $ioctl_ty:ident, $mem_ty:ident {
|
||||||
|
$($rest:tt)*
|
||||||
|
}) => {
|
||||||
|
define_ioctl_data!(
|
||||||
|
struct $ioctl_ty, $mem_ty { $($rest)* } => (), (), ()
|
||||||
|
);
|
||||||
|
};
|
||||||
|
(struct $ioctl_ty:ident, $mem_ty:ident {
|
||||||
|
$field:ident: $ty:ty,
|
||||||
|
$($rest:tt)*
|
||||||
|
} =>
|
||||||
|
($($ioctl_fields:tt)*),
|
||||||
|
($($counted_fields:tt)*),
|
||||||
|
($($noncounted_fields:tt)*)
|
||||||
|
) => {
|
||||||
|
define_ioctl_data!(
|
||||||
|
struct $ioctl_ty, $mem_ty { $($rest)* } =>
|
||||||
|
($($ioctl_fields)* $field: $ty,),
|
||||||
|
($($counted_fields)*),
|
||||||
|
($($noncounted_fields)* $field: $ty,)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
(struct $ioctl_ty:ident, $mem_ty:ident {
|
||||||
|
$field:ident: $ty:ty [array<$el:ty, $counted_by:ident>],
|
||||||
|
$($rest:tt)*
|
||||||
|
} =>
|
||||||
|
($($ioctl_fields:tt)*),
|
||||||
|
($($counted_fields:tt)*),
|
||||||
|
($($noncounted_fields:tt)*)
|
||||||
|
) => {
|
||||||
|
define_ioctl_data!(
|
||||||
|
struct $ioctl_ty, $mem_ty { $($rest)* } =>
|
||||||
|
($($ioctl_fields)* $field: $ty,),
|
||||||
|
($($counted_fields)* $field: $ty [array<$el, $counted_by>],),
|
||||||
|
($($noncounted_fields)*)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
(struct $ioctl_ty:ident, $mem_ty:ident {} =>
|
||||||
|
($($ioctl_field:ident: $ioctl_field_ty:ty,)*),
|
||||||
|
($($counted_field:ident: $counted_ty:ty [array<$el:ty, $counted_by:ident>],)*),
|
||||||
|
($($noncounted_field:ident: $noncounted_ty:ty,)*)
|
||||||
|
) => {
|
||||||
|
// FIXME check ioctl_ty doesn't have padding
|
||||||
|
const _: $ioctl_ty = $ioctl_ty {
|
||||||
|
$($ioctl_field: unsafe { mem::zeroed::<$ioctl_field_ty>() },)*
|
||||||
|
};
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ${concat(__, $mem_ty, Noncounted)} {
|
||||||
|
$($noncounted_field: $noncounted_ty,)*
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct $mem_ty<'a> {
|
||||||
|
noncounted_fields: &'a mut ${concat(__, $mem_ty, Noncounted)},
|
||||||
|
$($counted_field: &'a mut [$el],)*
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $crate::ioctl_data::IoctlData for $ioctl_ty {
|
||||||
|
unsafe fn write(&self) -> Vec<u8> {
|
||||||
|
let noncounted_fields = ${concat(__, $mem_ty, Noncounted)} {
|
||||||
|
$($noncounted_field: self.$noncounted_field,)*
|
||||||
|
};
|
||||||
|
// FIXME use Vec::with_capacity
|
||||||
|
let mut data = Vec::<u8>::new();
|
||||||
|
data.extend_from_slice(&unsafe {
|
||||||
|
mem::transmute::<
|
||||||
|
${concat(__, $mem_ty, Noncounted)},
|
||||||
|
[u8; size_of::<${concat(__, $mem_ty, Noncounted)}>()],
|
||||||
|
>(noncounted_fields)
|
||||||
|
});
|
||||||
|
$(
|
||||||
|
let size = self.$counted_by as usize * size_of::<$el>();
|
||||||
|
if self.$counted_field as usize != 0 {
|
||||||
|
let $counted_field = unsafe {
|
||||||
|
slice::from_raw_parts(self.$counted_field as *const u8, size)
|
||||||
|
};
|
||||||
|
data.extend_from_slice(&$counted_field);
|
||||||
|
} else {
|
||||||
|
data.extend(iter::repeat(0u8).take(size));
|
||||||
|
};
|
||||||
|
|
||||||
|
)*
|
||||||
|
data
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn read_from(&mut self, mut buf: &[u8]) {
|
||||||
|
// FIXME be robust against malicious scheme implementations by returning an error
|
||||||
|
// when the buf is the wrong size
|
||||||
|
let noncounted_fields = buf.split_off(..size_of::<${concat(__, $mem_ty, Noncounted)}>()).unwrap();
|
||||||
|
|
||||||
|
$(
|
||||||
|
let size = self.$counted_by as usize * size_of::<$el>();
|
||||||
|
let $counted_field = buf.split_off(..size).unwrap();
|
||||||
|
if self.$counted_field as usize != 0 {
|
||||||
|
unsafe {
|
||||||
|
slice::from_raw_parts_mut(self.$counted_field as *mut u8, size).copy_from_slice($counted_field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
|
||||||
|
assert!(buf.is_empty());
|
||||||
|
|
||||||
|
let noncounted_fields = unsafe { &*(noncounted_fields as *const _ as *const ${concat(__, $mem_ty, Noncounted)}) };
|
||||||
|
$(self.$noncounted_field = noncounted_fields.$noncounted_field;)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> $mem_ty<'a> {
|
||||||
|
pub fn with(
|
||||||
|
mut buf: &'a mut [u8],
|
||||||
|
f: impl FnOnce($mem_ty<'a>) -> syscall::Result<usize>,
|
||||||
|
) -> syscall::Result<usize> {
|
||||||
|
let noncounted_fields = buf.split_off_mut(..size_of::<${concat(__, $mem_ty, Noncounted)}>())
|
||||||
|
.ok_or(syscall::Error::new(syscall::EINVAL))?;
|
||||||
|
let noncounted_fields = unsafe { &mut *(noncounted_fields as *mut _ as *mut ${concat(__, $mem_ty, Noncounted)}) };
|
||||||
|
|
||||||
|
$(
|
||||||
|
let $counted_field = buf.split_off_mut(..noncounted_fields.$counted_by as usize * size_of::<$el>())
|
||||||
|
.ok_or(syscall::Error::new(syscall::EINVAL))?;
|
||||||
|
let $counted_field = unsafe {
|
||||||
|
slice::from_raw_parts_mut($counted_field as *mut _ as *mut $el, noncounted_fields.$counted_by as usize)
|
||||||
|
};
|
||||||
|
)*
|
||||||
|
|
||||||
|
if !buf.is_empty() {
|
||||||
|
return Err(syscall::Error::new(syscall::EINVAL));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Ok( f($mem_ty {
|
||||||
|
noncounted_fields,
|
||||||
|
$($counted_field,)*
|
||||||
|
})?)
|
||||||
|
}
|
||||||
|
|
||||||
|
$(
|
||||||
|
pub fn $noncounted_field(&self) -> $noncounted_ty {
|
||||||
|
self.noncounted_fields.$noncounted_field
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Should not be called for fields used as array length
|
||||||
|
pub fn ${concat(set_, $noncounted_field)}(&mut self, data: $noncounted_ty) {
|
||||||
|
self.noncounted_fields.$noncounted_field = data;
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
|
||||||
|
$(
|
||||||
|
pub fn $counted_field(&self) -> &[$el] {
|
||||||
|
self.$counted_field
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ${concat(set_, $counted_field)}(&mut self, data: &[$el]) {
|
||||||
|
let copied_count = cmp::min(data.len(), self.$counted_field.len());
|
||||||
|
self.$counted_field[..copied_count].copy_from_slice(&data[..copied_count]);
|
||||||
|
self.noncounted_fields.$counted_by = data.len() as _;
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#![feature(macro_metavar_expr_concat)]
|
||||||
|
#![deny(unsafe_op_in_unsafe_fn)]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod ioctl_data;
|
||||||
|
pub use ioctl_data::IoctlData;
|
||||||
|
|
||||||
|
pub mod drm;
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
[package]
|
||||||
|
name = "redox-rt"
|
||||||
|
authors = ["4lDO2 <4lDO2@protonmail.com>"]
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
license = "MIT"
|
||||||
|
description = "Libc-independent runtime for Redox"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bitflags.workspace = true
|
||||||
|
goblin = { version = "0.10", default-features = false, features = ["elf32", "elf64", "endian_fd"] }
|
||||||
|
plain.workspace = true
|
||||||
|
ioslice.workspace = true
|
||||||
|
redox_syscall.workspace = true
|
||||||
|
redox-path.workspace = true
|
||||||
|
redox_protocols.workspace = true
|
||||||
|
|
||||||
|
generic-rt = { path = "../generic-rt" }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
proc = []
|
||||||
|
default = ["proc"]
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
@@ -0,0 +1,485 @@
|
|||||||
|
use core::{cell::SyncUnsafeCell, mem::offset_of, ptr::NonNull};
|
||||||
|
|
||||||
|
use syscall::{data::*, error::*};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
Tcb,
|
||||||
|
proc::{FdGuard, FdGuardUpper, ForkArgs, fork_inner},
|
||||||
|
signal::{PosixStackt, RtSigarea, SigStack, inner_c},
|
||||||
|
};
|
||||||
|
use redox_protocols::protocol::{ProcCall, RtSigInfo};
|
||||||
|
|
||||||
|
use super::ForkScratchpad;
|
||||||
|
|
||||||
|
// Setup a stack starting from the very end of the address space, and then growing downwards.
|
||||||
|
pub const STACK_TOP: usize = 1 << 47;
|
||||||
|
pub const STACK_SIZE: usize = 1024 * 1024;
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct SigArea {
|
||||||
|
pub altstack_top: usize,
|
||||||
|
pub altstack_bottom: usize,
|
||||||
|
pub tmp_x1_x2: [usize; 2],
|
||||||
|
pub tmp_x3_x4: [usize; 2],
|
||||||
|
pub tmp_x5_x6: [usize; 2],
|
||||||
|
pub tmp_x7_x8: [usize; 2],
|
||||||
|
pub tmp_sp: usize,
|
||||||
|
pub onstack: u64,
|
||||||
|
pub disable_signals_depth: u64,
|
||||||
|
pub pctl: usize, // TODO: remove
|
||||||
|
pub last_sig_was_restart: bool,
|
||||||
|
pub last_sigstack: Option<NonNull<SigStack>>,
|
||||||
|
pub tmp_rt_inf: RtSigInfo,
|
||||||
|
pub tmp_id_inf: u64,
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct ArchIntRegs {
|
||||||
|
pub x30: usize,
|
||||||
|
pub x29: usize,
|
||||||
|
pub x28: usize,
|
||||||
|
pub x27: usize,
|
||||||
|
pub x26: usize,
|
||||||
|
pub x25: usize,
|
||||||
|
pub x24: usize,
|
||||||
|
pub x23: usize,
|
||||||
|
pub x22: usize,
|
||||||
|
pub x21: usize,
|
||||||
|
pub x20: usize,
|
||||||
|
pub x19: usize,
|
||||||
|
pub x18: usize,
|
||||||
|
pub x17: usize,
|
||||||
|
pub x16: usize,
|
||||||
|
pub x15: usize,
|
||||||
|
pub x14: usize,
|
||||||
|
pub x13: usize,
|
||||||
|
pub x12: usize,
|
||||||
|
pub x11: usize,
|
||||||
|
pub x10: usize,
|
||||||
|
pub x9: usize,
|
||||||
|
pub x8: usize,
|
||||||
|
pub x7: usize,
|
||||||
|
pub x6: usize,
|
||||||
|
pub x5: usize,
|
||||||
|
pub x4: usize,
|
||||||
|
pub x3: usize,
|
||||||
|
pub x2: usize,
|
||||||
|
pub x1: usize,
|
||||||
|
|
||||||
|
pub sp: usize,
|
||||||
|
pub nzcv: usize, // user-accessible PSTATE bits
|
||||||
|
|
||||||
|
pub pc: usize,
|
||||||
|
pub x0: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS
|
||||||
|
/// is already initialized as if it was a thread.
|
||||||
|
pub unsafe fn deactivate_tcb(open_via_dup: &FdGuardUpper) -> Result<()> {
|
||||||
|
let mut env = syscall::EnvRegisters::default();
|
||||||
|
|
||||||
|
let file = open_via_dup.dup(b"regs/env")?;
|
||||||
|
|
||||||
|
env.tpidr_el0 = 0;
|
||||||
|
|
||||||
|
file.write(&mut env)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn fork_impl(args: &ForkArgs, initial_rsp: *mut usize) -> usize {
|
||||||
|
Error::mux(fork_inner(initial_rsp, args))
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn child_hook(scratchpad: &ForkScratchpad) {
|
||||||
|
//let _ = syscall::write(1, alloc::format!("CUR{cur_filetable_fd}PROC{new_proc_fd}THR{new_thr_fd}\n").as_bytes());
|
||||||
|
let _ = syscall::close(scratchpad.cur_filetable_fd);
|
||||||
|
unsafe {
|
||||||
|
crate::child_hook_common(crate::ChildHookCommonArgs {
|
||||||
|
new_thr_fd: FdGuard::new(scratchpad.new_thr_fd),
|
||||||
|
new_proc_fd: if scratchpad.new_proc_fd == usize::MAX {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(FdGuard::new(scratchpad.new_proc_fd))
|
||||||
|
},
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
asmfunction!(__relibc_internal_fork_wrapper (usize) -> usize: ["
|
||||||
|
stp x29, x30, [sp, #-16]!
|
||||||
|
stp x27, x28, [sp, #-16]!
|
||||||
|
stp x25, x26, [sp, #-16]!
|
||||||
|
stp x23, x24, [sp, #-16]!
|
||||||
|
stp x21, x22, [sp, #-16]!
|
||||||
|
stp x19, x20, [sp, #-16]!
|
||||||
|
|
||||||
|
//TODO: store floating point regs
|
||||||
|
|
||||||
|
// x0: &ForkArgs
|
||||||
|
mov x1, sp
|
||||||
|
bl {fork_impl}
|
||||||
|
|
||||||
|
ldp x19, x20, [sp], #16
|
||||||
|
ldp x21, x22, [sp], #16
|
||||||
|
ldp x23, x24, [sp], #16
|
||||||
|
ldp x25, x26, [sp], #16
|
||||||
|
ldp x27, x28, [sp], #16
|
||||||
|
ldp x29, x30, [sp], #16
|
||||||
|
ret
|
||||||
|
"] <= [fork_impl = sym fork_impl]);
|
||||||
|
|
||||||
|
asmfunction!(__relibc_internal_fork_ret: ["
|
||||||
|
# scratchpad is in x1, move to x0 for child_hook
|
||||||
|
mov x0, x1
|
||||||
|
|
||||||
|
bl {child_hook}
|
||||||
|
|
||||||
|
//TODO: load floating point regs
|
||||||
|
|
||||||
|
mov x0, xzr
|
||||||
|
|
||||||
|
ldp x19, x20, [sp], #16
|
||||||
|
ldp x21, x22, [sp], #16
|
||||||
|
ldp x23, x24, [sp], #16
|
||||||
|
ldp x25, x26, [sp], #16
|
||||||
|
ldp x27, x28, [sp], #16
|
||||||
|
ldp x29, x30, [sp], #16
|
||||||
|
|
||||||
|
ret
|
||||||
|
"] <= [child_hook = sym child_hook]);
|
||||||
|
|
||||||
|
// https://devblogs.microsoft.com/oldnewthing/20220811-00/?p=106963
|
||||||
|
asmfunction!(__relibc_internal_sigentry: ["
|
||||||
|
// Clear any active reservation.
|
||||||
|
clrex
|
||||||
|
|
||||||
|
// The old pc and x0 are saved in the sigcontrol struct.
|
||||||
|
mrs x0, tpidr_el0 // ABI ptr
|
||||||
|
ldr x0, [x0] // TCB ptr
|
||||||
|
|
||||||
|
// Save x1-x6 and sp
|
||||||
|
stp x1, x2, [x0, #{tcb_sa_off} + {sa_tmp_x1_x2}]
|
||||||
|
stp x3, x4, [x0, #{tcb_sa_off} + {sa_tmp_x3_x4}]
|
||||||
|
stp x5, x6, [x0, #{tcb_sa_off} + {sa_tmp_x5_x6}]
|
||||||
|
stp x7, x8, [x0, #{tcb_sa_off} + {sa_tmp_x7_x8}]
|
||||||
|
mov x1, sp
|
||||||
|
str x1, [x0, #{tcb_sa_off} + {sa_tmp_sp}]
|
||||||
|
|
||||||
|
ldr x6, [x0, #{tcb_sa_off} + {sa_pctl}]
|
||||||
|
1:
|
||||||
|
// Load x1 with the thread's bits
|
||||||
|
add x5, x0, #{tcb_sc_off} + {sc_word}
|
||||||
|
ldaxr x1, [x5]
|
||||||
|
|
||||||
|
// First check if there are standard thread signals,
|
||||||
|
and x4, x1, x1, lsr #32 // x4 := x1 & (x1 >> 32)
|
||||||
|
cbnz x4, 3f // jump if x4 != 0
|
||||||
|
clrex
|
||||||
|
|
||||||
|
// and if not, load process pending bitset.
|
||||||
|
add x5, x6, #{pctl_pending}
|
||||||
|
ldaxr x2, [x5]
|
||||||
|
|
||||||
|
// Check if there are standard proc signals:
|
||||||
|
lsr x3, x1, #32 // mask
|
||||||
|
and w3, w2, w3 // pending unblocked proc
|
||||||
|
cbz w3, 4f // skip 'fetch_andn' step if zero
|
||||||
|
|
||||||
|
// If there was one, find which one, and try clearing the bit (last value in x3, addr in x6)
|
||||||
|
// this picks the MSB rather than the LSB, unlike x86. POSIX does not require any specific
|
||||||
|
// ordering though.
|
||||||
|
clz w3, w3
|
||||||
|
mov w4, #31
|
||||||
|
sub w3, w4, w3
|
||||||
|
// x3 now contains the sig_idx
|
||||||
|
|
||||||
|
mov x4, #1
|
||||||
|
lsl x4, x4, x3 // bit to remove
|
||||||
|
|
||||||
|
sub x4, x2, x4 // bit was certainly set, so sub is allowed
|
||||||
|
// x4 is now the new mask to be set
|
||||||
|
add x5, x6, #{pctl_pending}
|
||||||
|
|
||||||
|
add x2, x5, #{pctl_sender_infos}
|
||||||
|
add x2, x2, w3, uxtb 3
|
||||||
|
ldar x2, [x2]
|
||||||
|
|
||||||
|
// Try clearing the bit, retrying on failure.
|
||||||
|
stxr w1, x4, [x5] // try setting pending set to x4, set w1 := 0 on success
|
||||||
|
cbnz w1, 1b // retry everything if this fails
|
||||||
|
mov x1, x3
|
||||||
|
b 2f
|
||||||
|
4:
|
||||||
|
// Check for realtime signals, thread/proc.
|
||||||
|
clrex
|
||||||
|
|
||||||
|
// Load the pending set again. TODO: optimize this?
|
||||||
|
// Process pending - realtime
|
||||||
|
add x1, x6, #{pctl_pending}
|
||||||
|
ldaxr x2, [x1]
|
||||||
|
lsr x2, x2, #32
|
||||||
|
|
||||||
|
// Thread pending - realtime and allowset
|
||||||
|
add x5, x0, #{tcb_sc_off} + {sc_word} + 8
|
||||||
|
ldar x1, [x5]
|
||||||
|
|
||||||
|
orr x2, x1, x2 // combine proc and thread pending
|
||||||
|
and x2, x2, x2, lsr #32 // AND pending with allowset
|
||||||
|
cbz x2, 7f // spurious signal if realtime is clear
|
||||||
|
|
||||||
|
rbit x2, x2
|
||||||
|
clz x2, x2
|
||||||
|
// x2 now contains sig_idx - 32
|
||||||
|
|
||||||
|
// If realtime signal was directed at thread, handle it as an idempotent signal.
|
||||||
|
lsr x3, x1, x2 // x3 := x1 >> x2; x1 is thread pending
|
||||||
|
tbnz x3, #0, 5f // jump if bit is nonzero
|
||||||
|
|
||||||
|
// SYS_CALL(fd, payload_base, payload_len, metadata_len, metadata_base | (flags << 8))
|
||||||
|
// x8 x0 x1 x2 x3 x4
|
||||||
|
|
||||||
|
mov x5, x0 // save TCB pointer
|
||||||
|
mov x6, x2
|
||||||
|
ldr x8, ={SYS_CALL}
|
||||||
|
adrp x0, {proc_fd}
|
||||||
|
ldr x0, [x0, #:lo12:{proc_fd}]
|
||||||
|
add x1, x5, #{tcb_sa_off} + {sa_tmp_rt_inf}
|
||||||
|
str x6, [x1]
|
||||||
|
mov x2, #{RTINF_SIZE}
|
||||||
|
adrp x4, {proc_call}
|
||||||
|
add x4, x4, :lo12:{proc_call}
|
||||||
|
mov x3, #1
|
||||||
|
svc 0
|
||||||
|
mov x3, x0
|
||||||
|
mov x0, x5 // restore TCB pointer
|
||||||
|
mov x2, x6 // restore signal number - 32
|
||||||
|
add x1, x2, #32 // signal number
|
||||||
|
cbnz x3, 1b
|
||||||
|
b 2f
|
||||||
|
5:
|
||||||
|
// A realtime signal was sent to this thread, try clearing its bit.
|
||||||
|
// x3 contains last rt signal word, x2 contains rt_idx
|
||||||
|
clrex
|
||||||
|
|
||||||
|
// Calculate the absolute sig_idx
|
||||||
|
add x1, x3, 32
|
||||||
|
|
||||||
|
// Load si_pid and si_uid
|
||||||
|
add x2, x0, #{tcb_sc_off} + {sc_sender_infos}
|
||||||
|
add x2, x2, w1, uxtb #3
|
||||||
|
ldar x2, [x2]
|
||||||
|
|
||||||
|
add x3, x0, #{tcb_sc_off} + {sc_word} + 8
|
||||||
|
ldxr x2, [x3]
|
||||||
|
|
||||||
|
// Calculate new mask
|
||||||
|
mov x4, #1
|
||||||
|
lsl x4, x4, x2
|
||||||
|
sub x2, x2, x4 // remove bit
|
||||||
|
|
||||||
|
stxr w5, x2, [x3]
|
||||||
|
cbnz w5, 1b
|
||||||
|
str x2, [x0, #{tcb_sa_off} + {sa_tmp_id_inf}]
|
||||||
|
b 2f
|
||||||
|
3:
|
||||||
|
// A standard signal was sent to this thread, try clearing its bit.
|
||||||
|
clz w1, w1
|
||||||
|
mov x2, #31
|
||||||
|
sub x1, x2, x1
|
||||||
|
|
||||||
|
// Load si_pid and si_uid
|
||||||
|
add x2, x0, #{tcb_sc_off} + {sc_sender_infos}
|
||||||
|
add x2, x2, w1, uxtb #3
|
||||||
|
ldar x2, [x2]
|
||||||
|
|
||||||
|
// Clear bit from mask
|
||||||
|
mov x3, #1
|
||||||
|
lsl x3, x3, x1
|
||||||
|
sub x4, x4, x3
|
||||||
|
|
||||||
|
// Try updating the mask
|
||||||
|
stxr w3, x1, [x5]
|
||||||
|
cbnz w3, 1b
|
||||||
|
|
||||||
|
str x2, [x0, #{tcb_sa_off} + {sa_tmp_id_inf}]
|
||||||
|
2:
|
||||||
|
ldr x3, [x0, #{tcb_sa_off} + {sa_pctl}]
|
||||||
|
add x3, x3, {pctl_actions}
|
||||||
|
add x2, x3, w1, uxtb #4 // actions_base + sig_idx * sizeof Action
|
||||||
|
// TODO: NOT ATOMIC (tearing allowed between regs)!
|
||||||
|
ldxp x2, x3, [x2]
|
||||||
|
clrex
|
||||||
|
|
||||||
|
// Calculate new sp wrt redzone and alignment
|
||||||
|
mov x4, sp
|
||||||
|
sub x4, x4, {REDZONE_SIZE}
|
||||||
|
and x4, x4, -{STACK_ALIGN}
|
||||||
|
mov sp, x4
|
||||||
|
|
||||||
|
// skip sigaltstack step if SA_ONSTACK is clear
|
||||||
|
// tbz x2, #{SA_ONSTACK_BIT}, 2f
|
||||||
|
|
||||||
|
ldr x2, [x0, #{tcb_sc_off} + {sc_saved_pc}]
|
||||||
|
ldr x3, [x0, #{tcb_sc_off} + {sc_saved_x0}]
|
||||||
|
stp x2, x3, [sp, #-16]!
|
||||||
|
|
||||||
|
ldr x2, [x0, #{tcb_sa_off} + {sa_tmp_sp}]
|
||||||
|
mrs x3, nzcv
|
||||||
|
stp x2, x3, [sp, #-16]!
|
||||||
|
|
||||||
|
ldp x2, x3, [x0, #{tcb_sa_off} + {sa_tmp_x1_x2}]
|
||||||
|
stp x2, x3, [sp, #-16]!
|
||||||
|
ldp x3, x4, [x0, #{tcb_sa_off} + {sa_tmp_x3_x4}]
|
||||||
|
stp x4, x3, [sp, #-16]!
|
||||||
|
ldp x5, x6, [x0, #{tcb_sa_off} + {sa_tmp_x5_x6}]
|
||||||
|
stp x6, x5, [sp, #-16]!
|
||||||
|
ldp x7, x8, [x0, #{tcb_sa_off} + {sa_tmp_x7_x8}]
|
||||||
|
stp x8, x7, [sp, #-16]!
|
||||||
|
|
||||||
|
stp x10, x9, [sp, #-16]!
|
||||||
|
stp x12, x11, [sp, #-16]!
|
||||||
|
stp x14, x13, [sp, #-16]!
|
||||||
|
stp x16, x15, [sp, #-16]!
|
||||||
|
stp x18, x17, [sp, #-16]!
|
||||||
|
stp x20, x19, [sp, #-16]!
|
||||||
|
stp x22, x21, [sp, #-16]!
|
||||||
|
stp x24, x23, [sp, #-16]!
|
||||||
|
stp x26, x25, [sp, #-16]!
|
||||||
|
stp x28, x27, [sp, #-16]!
|
||||||
|
stp x30, x29, [sp, #-16]!
|
||||||
|
|
||||||
|
str w1, [sp, #-4]
|
||||||
|
sub sp, sp, #64
|
||||||
|
|
||||||
|
mov x0, sp
|
||||||
|
bl {inner}
|
||||||
|
|
||||||
|
add sp, sp, #64
|
||||||
|
|
||||||
|
ldp x30, x29, [sp], #16
|
||||||
|
ldp x28, x27, [sp], #16
|
||||||
|
ldp x26, x25, [sp], #16
|
||||||
|
ldp x24, x23, [sp], #16
|
||||||
|
ldp x22, x21, [sp], #16
|
||||||
|
ldp x20, x19, [sp], #16
|
||||||
|
ldp x18, x17, [sp], #16
|
||||||
|
ldp x16, x15, [sp], #16
|
||||||
|
ldp x14, x13, [sp], #16
|
||||||
|
ldp x12, x11, [sp], #16
|
||||||
|
ldp x10, x9, [sp], #16
|
||||||
|
ldp x8, x7, [sp], #16
|
||||||
|
ldp x6, x5, [sp], #16
|
||||||
|
ldp x4, x3, [sp], #16
|
||||||
|
ldp x2, x1, [sp], #16
|
||||||
|
|
||||||
|
ldr x0, [sp, #8]
|
||||||
|
msr nzcv, x0
|
||||||
|
|
||||||
|
8:
|
||||||
|
// x18 is reserved by ABI as 'platform register', so clobbering it should be safe.
|
||||||
|
mov x18, sp
|
||||||
|
ldr x0, [x18]
|
||||||
|
mov sp, x0
|
||||||
|
|
||||||
|
ldp x18, x0, [x18, #16]
|
||||||
|
br x18
|
||||||
|
7:
|
||||||
|
// Spurious signal, i.e. all bitsets were 0 at the time they were checked
|
||||||
|
clrex
|
||||||
|
|
||||||
|
ldr x1, [x0, #{tcb_sc_off} + {sc_flags}]
|
||||||
|
and x1, x1, ~1
|
||||||
|
str x1, [x0, #{tcb_sc_off} + {sc_flags}]
|
||||||
|
|
||||||
|
ldp x1, x2, [x0, #{tcb_sa_off} + {sa_tmp_x1_x2}]
|
||||||
|
ldp x3, x4, [x0, #{tcb_sa_off} + {sa_tmp_x3_x4}]
|
||||||
|
ldp x5, x6, [x0, #{tcb_sa_off} + {sa_tmp_x5_x6}]
|
||||||
|
ldr x18, [x0, #{tcb_sc_off} + {sc_saved_pc}]
|
||||||
|
ldr x0, [x0, #{tcb_sc_off} + {sc_saved_x0}]
|
||||||
|
br x18
|
||||||
|
"] <= [
|
||||||
|
pctl_pending = const (offset_of!(SigProcControl, pending)),
|
||||||
|
pctl_actions = const (offset_of!(SigProcControl, actions)),
|
||||||
|
pctl_sender_infos = const (offset_of!(SigProcControl, sender_infos)),
|
||||||
|
tcb_sc_off = const (offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control)),
|
||||||
|
tcb_sa_off = const (offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, arch)),
|
||||||
|
sa_tmp_x1_x2 = const offset_of!(SigArea, tmp_x1_x2),
|
||||||
|
sa_tmp_x3_x4 = const offset_of!(SigArea, tmp_x3_x4),
|
||||||
|
sa_tmp_x5_x6 = const offset_of!(SigArea, tmp_x5_x6),
|
||||||
|
sa_tmp_x7_x8 = const offset_of!(SigArea, tmp_x7_x8),
|
||||||
|
sa_tmp_sp = const offset_of!(SigArea, tmp_sp),
|
||||||
|
sa_tmp_rt_inf = const offset_of!(SigArea, tmp_rt_inf),
|
||||||
|
sa_tmp_id_inf = const offset_of!(SigArea, tmp_id_inf),
|
||||||
|
sa_pctl = const offset_of!(SigArea, pctl),
|
||||||
|
sc_saved_pc = const offset_of!(Sigcontrol, saved_ip),
|
||||||
|
sc_saved_x0 = const offset_of!(Sigcontrol, saved_archdep_reg),
|
||||||
|
sc_sender_infos = const offset_of!(Sigcontrol, sender_infos),
|
||||||
|
sc_word = const offset_of!(Sigcontrol, word),
|
||||||
|
sc_flags = const offset_of!(Sigcontrol, control_flags),
|
||||||
|
proc_fd = sym PROC_FD,
|
||||||
|
inner = sym inner_c,
|
||||||
|
proc_call = sym PROC_CALL,
|
||||||
|
|
||||||
|
SA_ONSTACK_BIT = const 58, // (1 << 58) >> 32 = 0x0400_0000
|
||||||
|
|
||||||
|
SYS_CALL = const syscall::SYS_CALL,
|
||||||
|
|
||||||
|
STACK_ALIGN = const 16,
|
||||||
|
REDZONE_SIZE = const 128,
|
||||||
|
RTINF_SIZE = const size_of::<RtSigInfo>(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
asmfunction!(__relibc_internal_rlct_clone_ret: ["
|
||||||
|
# Load registers
|
||||||
|
ldp x8, x0, [sp], #16
|
||||||
|
ldp x1, x2, [sp], #16
|
||||||
|
ldp x3, x4, [sp], #16
|
||||||
|
|
||||||
|
# Call entry point
|
||||||
|
blr x8
|
||||||
|
|
||||||
|
ret
|
||||||
|
"] <= []);
|
||||||
|
|
||||||
|
pub fn current_sp() -> usize {
|
||||||
|
let sp: usize;
|
||||||
|
unsafe {
|
||||||
|
core::arch::asm!("mov {}, sp", out(reg) sp);
|
||||||
|
}
|
||||||
|
sp
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn manually_enter_trampoline() {
|
||||||
|
let ctl = unsafe { &Tcb::current().unwrap().os_specific.control };
|
||||||
|
|
||||||
|
ctl.saved_archdep_reg.set(0);
|
||||||
|
let ip_location = &ctl.saved_ip as *const _ as usize;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
core::arch::asm!("
|
||||||
|
bl 2f
|
||||||
|
b 3f
|
||||||
|
2:
|
||||||
|
str lr, [x0]
|
||||||
|
b __relibc_internal_sigentry
|
||||||
|
3:
|
||||||
|
",
|
||||||
|
inout("x0") ip_location => _, out("lr") _);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn arch_pre(stack: &mut SigStack, os: &mut SigArea) -> PosixStackt {
|
||||||
|
PosixStackt {
|
||||||
|
sp: core::ptr::null_mut(), // TODO
|
||||||
|
size: 0, // TODO
|
||||||
|
flags: 0, // TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn arch_ret_to_sig(stack: &mut SigStack, control: &Sigcontrol) {
|
||||||
|
let orig_pc = core::mem::replace(&mut stack.regs.pc, __relibc_internal_sigentry as usize);
|
||||||
|
control.saved_ip.set(orig_pc);
|
||||||
|
control.saved_archdep_reg.set(stack.regs.x0);
|
||||||
|
}
|
||||||
|
pub(crate) static PROC_FD: SyncUnsafeCell<usize> = SyncUnsafeCell::new(usize::MAX);
|
||||||
|
static PROC_CALL: [usize; 1] = [ProcCall::Sigdeq as usize];
|
||||||
@@ -0,0 +1,411 @@
|
|||||||
|
use core::{cell::SyncUnsafeCell, mem::offset_of, ptr::NonNull, sync::atomic::Ordering};
|
||||||
|
|
||||||
|
use syscall::*;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
proc::{FdGuard, FdGuardUpper, ForkArgs, fork_inner},
|
||||||
|
signal::{PROC_CONTROL_STRUCT, PosixStackt, RtSigarea, SigStack, inner_fastcall},
|
||||||
|
};
|
||||||
|
use redox_protocols::protocol::{ProcCall, RtSigInfo};
|
||||||
|
|
||||||
|
use super::ForkScratchpad;
|
||||||
|
|
||||||
|
// Setup a stack starting from the very end of the address space, and then growing downwards.
|
||||||
|
pub const STACK_TOP: usize = 1 << 31;
|
||||||
|
pub const STACK_SIZE: usize = 1024 * 1024;
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct SigArea {
|
||||||
|
pub altstack_top: usize,
|
||||||
|
pub altstack_bottom: usize,
|
||||||
|
pub tmp_eip: usize,
|
||||||
|
pub tmp_esp: usize,
|
||||||
|
pub tmp_eax: usize,
|
||||||
|
pub tmp_ebx: usize,
|
||||||
|
pub tmp_ecx: usize,
|
||||||
|
pub tmp_edx: usize,
|
||||||
|
pub tmp_edi: usize,
|
||||||
|
pub tmp_esi: usize,
|
||||||
|
pub tmp_rt_inf: RtSigInfo,
|
||||||
|
pub tmp_signo: usize,
|
||||||
|
pub tmp_id_inf: u64,
|
||||||
|
pub tmp_mm0: u64,
|
||||||
|
pub disable_signals_depth: u64,
|
||||||
|
pub last_sig_was_restart: bool,
|
||||||
|
pub last_sigstack: Option<NonNull<SigStack>>,
|
||||||
|
}
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
#[repr(C, align(16))]
|
||||||
|
pub struct ArchIntRegs {
|
||||||
|
pub fxsave: [u16; 29],
|
||||||
|
|
||||||
|
// ensure fxsave region is 16 byte aligned
|
||||||
|
pub _pad: [usize; 2], // fxsave "available" +0
|
||||||
|
|
||||||
|
pub ebp: usize, // fxsave "available" +8
|
||||||
|
pub esi: usize, // avail +12
|
||||||
|
pub edi: usize, // avail +16
|
||||||
|
pub ebx: usize, // avail +20
|
||||||
|
pub eax: usize, // avail +24
|
||||||
|
pub ecx: usize, // avail +28
|
||||||
|
pub edx: usize, // avail +32
|
||||||
|
|
||||||
|
pub eflags: usize, // avail +36
|
||||||
|
pub eip: usize, // avail +40
|
||||||
|
pub esp: usize, // avail +44
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS
|
||||||
|
/// is already initialized as if it was a thread.
|
||||||
|
pub unsafe fn deactivate_tcb(open_via_dup: &FdGuardUpper) -> Result<()> {
|
||||||
|
let mut env = syscall::EnvRegisters::default();
|
||||||
|
|
||||||
|
let file = open_via_dup.dup(b"regs/env")?;
|
||||||
|
|
||||||
|
env.fsbase = 0;
|
||||||
|
env.gsbase = 0;
|
||||||
|
|
||||||
|
file.write(&mut env)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "fastcall" fn fork_impl(args: &ForkArgs, initial_rsp: *mut usize) -> usize {
|
||||||
|
Error::mux(fork_inner(initial_rsp, args))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: duplicate code with x86_64
|
||||||
|
unsafe extern "cdecl" fn child_hook(scratchpad: ForkScratchpad) {
|
||||||
|
let _ = syscall::close(scratchpad.cur_filetable_fd);
|
||||||
|
unsafe {
|
||||||
|
crate::child_hook_common(crate::ChildHookCommonArgs {
|
||||||
|
new_thr_fd: FdGuard::new(scratchpad.new_thr_fd),
|
||||||
|
new_proc_fd: if scratchpad.new_proc_fd == usize::MAX {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(FdGuard::new(scratchpad.new_proc_fd))
|
||||||
|
},
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
asmfunction!(__relibc_internal_fork_wrapper (usize) -> usize: ["
|
||||||
|
mov ecx, [esp+4]
|
||||||
|
|
||||||
|
push ebp
|
||||||
|
mov ebp, esp
|
||||||
|
|
||||||
|
// Push preserved registers
|
||||||
|
push ebx
|
||||||
|
push edi
|
||||||
|
push esi
|
||||||
|
push ebp
|
||||||
|
|
||||||
|
sub esp, 32
|
||||||
|
|
||||||
|
//TODO stmxcsr [esp+16]
|
||||||
|
fnstcw [esp+24]
|
||||||
|
|
||||||
|
mov edx, esp
|
||||||
|
call {fork_impl}
|
||||||
|
|
||||||
|
jmp 2f
|
||||||
|
"] <= [fork_impl = sym fork_impl]);
|
||||||
|
|
||||||
|
asmfunction!(__relibc_internal_fork_ret: ["
|
||||||
|
// Arguments already on the stack
|
||||||
|
call {child_hook}
|
||||||
|
|
||||||
|
//TODO ldmxcsr [esp+16]
|
||||||
|
fldcw [esp+24]
|
||||||
|
|
||||||
|
xor eax, eax
|
||||||
|
|
||||||
|
.p2align 4
|
||||||
|
2:
|
||||||
|
add esp, 32
|
||||||
|
|
||||||
|
// Pop preserved registers
|
||||||
|
pop ebp
|
||||||
|
pop esi
|
||||||
|
pop edi
|
||||||
|
pop ebx
|
||||||
|
|
||||||
|
pop ebp
|
||||||
|
|
||||||
|
ret
|
||||||
|
"] <= [child_hook = sym child_hook]);
|
||||||
|
asmfunction!(__relibc_internal_sigentry: ["
|
||||||
|
// Save some registers
|
||||||
|
mov gs:[{tcb_sa_off} + {sa_tmp_esp}], esp
|
||||||
|
mov gs:[{tcb_sa_off} + {sa_tmp_eax}], eax
|
||||||
|
mov gs:[{tcb_sa_off} + {sa_tmp_edx}], edx
|
||||||
|
mov gs:[{tcb_sa_off} + {sa_tmp_ecx}], ecx
|
||||||
|
mov gs:[{tcb_sa_off} + {sa_tmp_ebx}], ebx
|
||||||
|
mov gs:[{tcb_sa_off} + {sa_tmp_edi}], edi
|
||||||
|
mov gs:[{tcb_sa_off} + {sa_tmp_esi}], esi
|
||||||
|
1:
|
||||||
|
// Read standard signal word - first for this thread
|
||||||
|
mov edx, gs:[{tcb_sc_off} + {sc_word} + 4]
|
||||||
|
mov eax, gs:[{tcb_sc_off} + {sc_word}]
|
||||||
|
and eax, edx
|
||||||
|
bsf eax, eax
|
||||||
|
jnz 9f
|
||||||
|
|
||||||
|
// Read standard signal word - for the process
|
||||||
|
lea ecx, [{pctl}]
|
||||||
|
mov eax, [ecx + {pctl_pending}]
|
||||||
|
and eax, edx
|
||||||
|
bsf eax, eax
|
||||||
|
jz 3f
|
||||||
|
|
||||||
|
// Read si_pid and si_uid, atomically.
|
||||||
|
movq gs:[{tcb_sa_off} + {sa_tmp_mm0}], mm0
|
||||||
|
movq mm0, [ecx + {pctl_sender_infos} + eax * 8]
|
||||||
|
movq gs:[{tcb_sa_off} + {sa_tmp_id_inf}], mm0
|
||||||
|
movq mm0, gs:[{tcb_sa_off} + {sa_tmp_mm0}]
|
||||||
|
|
||||||
|
// Try clearing the pending bit, otherwise retry if another thread did that first
|
||||||
|
lock btr [ecx + {pctl_pending}], eax
|
||||||
|
jnc 1b
|
||||||
|
jmp 2f
|
||||||
|
3:
|
||||||
|
// Read realtime thread and process signal word together
|
||||||
|
mov edx, [ecx + {pctl_pending} + 4]
|
||||||
|
mov eax, gs:[{tcb_sc_off} + {sc_word} + 8]
|
||||||
|
or eax, edx
|
||||||
|
and eax, gs:[{tcb_sc_off} + {sc_word} + 12]
|
||||||
|
bsf eax, eax
|
||||||
|
jz 7f // spurious signal
|
||||||
|
|
||||||
|
// If thread rather than process was specifically targeted, send the signal to it first.
|
||||||
|
bt edx, eax
|
||||||
|
jnc 8f
|
||||||
|
|
||||||
|
// SYS_CALL(fd, payload_base, payload_len, metadata_len, metadata_base)
|
||||||
|
// eax ebx ecx edx esi edi
|
||||||
|
|
||||||
|
mov ebx, [{proc_fd}]
|
||||||
|
mov ecx, gs:[0]
|
||||||
|
add ecx, {tcb_sa_off} + {sa_tmp_rt_inf}
|
||||||
|
mov [ecx], eax
|
||||||
|
mov gs:[{tcb_sa_off} + {sa_tmp_signo}], eax
|
||||||
|
mov edx, {RTINF_SIZE}
|
||||||
|
mov esi, 1
|
||||||
|
lea edi, [{proc_call}]
|
||||||
|
mov eax, {SYS_CALL}
|
||||||
|
int 0x80
|
||||||
|
test eax, eax
|
||||||
|
jnz 1b
|
||||||
|
|
||||||
|
mov eax, gs:[{tcb_sa_off} + {sa_tmp_signo}]
|
||||||
|
add eax, 32
|
||||||
|
jmp 2f
|
||||||
|
8:
|
||||||
|
add eax, 32
|
||||||
|
9:
|
||||||
|
// Read si_pid and si_uid, atomically.
|
||||||
|
movq gs:[{tcb_sa_off} + {sa_tmp_mm0}], mm0
|
||||||
|
movq mm0, gs:[{tcb_sc_off} + {sc_sender_infos} + eax * 8]
|
||||||
|
movq gs:[{tcb_sa_off} + {sa_tmp_id_inf}], mm0
|
||||||
|
movq mm0, gs:[{tcb_sa_off} + {sa_tmp_mm0}]
|
||||||
|
mov edx, eax
|
||||||
|
shr edx, 5
|
||||||
|
mov ecx, eax
|
||||||
|
and ecx, 31
|
||||||
|
lock btr gs:[{tcb_sc_off} + {sc_word} + edx * 8], ecx
|
||||||
|
|
||||||
|
add eax, 64
|
||||||
|
2:
|
||||||
|
and esp, -{STACK_ALIGN}
|
||||||
|
|
||||||
|
mov edx, eax
|
||||||
|
add edx, edx
|
||||||
|
bt dword ptr [{pctl} + {pctl_actions} + edx * 8 + 4], 28
|
||||||
|
jnc 4f
|
||||||
|
|
||||||
|
mov edx, gs:[{tcb_sa_off} + {sa_altstack_top}]
|
||||||
|
cmp esp, edx
|
||||||
|
ja 3f
|
||||||
|
|
||||||
|
cmp esp, gs:[{tcb_sa_off} + {sa_altstack_bottom}]
|
||||||
|
jnbe 4f
|
||||||
|
3:
|
||||||
|
mov esp, edx
|
||||||
|
4:
|
||||||
|
// Now that we have a stack, we can finally start populating the signal stack.
|
||||||
|
push dword ptr gs:[{tcb_sa_off} + {sa_tmp_esp}]
|
||||||
|
push dword ptr gs:[{tcb_sc_off} + {sc_saved_eip}]
|
||||||
|
push dword ptr gs:[{tcb_sc_off} + {sc_saved_eflags}]
|
||||||
|
|
||||||
|
push dword ptr gs:[{tcb_sa_off} + {sa_tmp_edx}]
|
||||||
|
push dword ptr gs:[{tcb_sa_off} + {sa_tmp_ecx}]
|
||||||
|
push dword ptr gs:[{tcb_sa_off} + {sa_tmp_eax}]
|
||||||
|
push dword ptr gs:[{tcb_sa_off} + {sa_tmp_ebx}]
|
||||||
|
push dword ptr gs:[{tcb_sa_off} + {sa_tmp_edi}]
|
||||||
|
push dword ptr gs:[{tcb_sa_off} + {sa_tmp_esi}]
|
||||||
|
push ebp
|
||||||
|
|
||||||
|
sub esp, 2 * 4 + 29 * 16
|
||||||
|
fxsave [esp]
|
||||||
|
|
||||||
|
mov [esp - 4], eax
|
||||||
|
sub esp, 48
|
||||||
|
|
||||||
|
mov ecx, esp
|
||||||
|
call {inner}
|
||||||
|
|
||||||
|
fxrstor [esp + 48]
|
||||||
|
add esp, 48 + 29 * 16 + 2 * 4
|
||||||
|
|
||||||
|
pop ebp
|
||||||
|
pop esi
|
||||||
|
pop edi
|
||||||
|
pop ebx
|
||||||
|
pop eax
|
||||||
|
pop ecx
|
||||||
|
pop edx
|
||||||
|
|
||||||
|
popfd
|
||||||
|
pop dword ptr gs:[{tcb_sa_off} + {sa_tmp_eip}]
|
||||||
|
|
||||||
|
.globl __relibc_internal_sigentry_crit_first
|
||||||
|
__relibc_internal_sigentry_crit_first:
|
||||||
|
pop esp
|
||||||
|
|
||||||
|
.globl __relibc_internal_sigentry_crit_second
|
||||||
|
__relibc_internal_sigentry_crit_second:
|
||||||
|
jmp dword ptr gs:[{tcb_sa_off} + {sa_tmp_eip}]
|
||||||
|
7:
|
||||||
|
mov eax, gs:[0]
|
||||||
|
lea esp, [eax + {tcb_sc_off} + {sc_saved_eflags}]
|
||||||
|
popfd
|
||||||
|
|
||||||
|
mov esp, gs:[{tcb_sa_off} + {sa_tmp_esp}]
|
||||||
|
|
||||||
|
mov eax, gs:[{tcb_sc_off} + {sc_saved_eip}]
|
||||||
|
mov gs:[{tcb_sa_off} + {sa_tmp_eip}], eax
|
||||||
|
|
||||||
|
mov eax, gs:[{tcb_sa_off} + {sa_tmp_eax}]
|
||||||
|
mov ebx, gs:[{tcb_sa_off} + {sa_tmp_ebx}]
|
||||||
|
mov ecx, gs:[{tcb_sa_off} + {sa_tmp_ecx}]
|
||||||
|
mov edx, gs:[{tcb_sa_off} + {sa_tmp_edx}]
|
||||||
|
mov edi, gs:[{tcb_sa_off} + {sa_tmp_edi}]
|
||||||
|
mov esi, gs:[{tcb_sa_off} + {sa_tmp_esi}]
|
||||||
|
|
||||||
|
and dword ptr gs:[{tcb_sc_off} + {sc_control}], ~1
|
||||||
|
.globl __relibc_internal_sigentry_crit_third
|
||||||
|
__relibc_internal_sigentry_crit_third:
|
||||||
|
jmp dword ptr gs:[{tcb_sa_off} + {sa_tmp_eip}]
|
||||||
|
"] <= [
|
||||||
|
inner = sym inner_fastcall,
|
||||||
|
sa_tmp_eip = const offset_of!(SigArea, tmp_eip),
|
||||||
|
sa_tmp_esp = const offset_of!(SigArea, tmp_esp),
|
||||||
|
sa_tmp_eax = const offset_of!(SigArea, tmp_eax),
|
||||||
|
sa_tmp_ebx = const offset_of!(SigArea, tmp_ebx),
|
||||||
|
sa_tmp_ecx = const offset_of!(SigArea, tmp_ecx),
|
||||||
|
sa_tmp_edx = const offset_of!(SigArea, tmp_edx),
|
||||||
|
sa_tmp_edi = const offset_of!(SigArea, tmp_edi),
|
||||||
|
sa_tmp_esi = const offset_of!(SigArea, tmp_esi),
|
||||||
|
sa_tmp_mm0 = const offset_of!(SigArea, tmp_mm0),
|
||||||
|
sa_tmp_rt_inf = const offset_of!(SigArea, tmp_rt_inf),
|
||||||
|
sa_tmp_id_inf = const offset_of!(SigArea, tmp_id_inf),
|
||||||
|
sa_tmp_signo = const offset_of!(SigArea, tmp_signo),
|
||||||
|
sa_altstack_top = const offset_of!(SigArea, altstack_top),
|
||||||
|
sa_altstack_bottom = const offset_of!(SigArea, altstack_bottom),
|
||||||
|
sc_control = const offset_of!(Sigcontrol, control_flags),
|
||||||
|
sc_saved_eflags = const offset_of!(Sigcontrol, saved_archdep_reg),
|
||||||
|
sc_saved_eip = const offset_of!(Sigcontrol, saved_ip),
|
||||||
|
sc_word = const offset_of!(Sigcontrol, word),
|
||||||
|
sc_sender_infos = const offset_of!(Sigcontrol, sender_infos),
|
||||||
|
tcb_sa_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, arch),
|
||||||
|
tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control),
|
||||||
|
pctl_actions = const offset_of!(SigProcControl, actions),
|
||||||
|
pctl_sender_infos = const offset_of!(SigProcControl, sender_infos),
|
||||||
|
pctl_pending = const offset_of!(SigProcControl, pending),
|
||||||
|
pctl = sym PROC_CONTROL_STRUCT,
|
||||||
|
proc_fd = sym PROC_FD,
|
||||||
|
proc_call = sym PROC_CALL,
|
||||||
|
STACK_ALIGN = const 16,
|
||||||
|
SYS_CALL = const syscall::SYS_CALL,
|
||||||
|
RTINF_SIZE = const size_of::<RtSigInfo>(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
asmfunction!(__relibc_internal_rlct_clone_ret -> usize: ["
|
||||||
|
# Load registers
|
||||||
|
pop eax
|
||||||
|
|
||||||
|
sub esp, 8
|
||||||
|
|
||||||
|
mov DWORD PTR [esp], 0x00001F80
|
||||||
|
# TODO: ldmxcsr [esp]
|
||||||
|
mov WORD PTR [esp], 0x037F
|
||||||
|
fldcw [esp]
|
||||||
|
|
||||||
|
add esp, 8
|
||||||
|
|
||||||
|
# Call entry point
|
||||||
|
call eax
|
||||||
|
|
||||||
|
ret
|
||||||
|
"] <= []);
|
||||||
|
unsafe extern "C" {
|
||||||
|
fn __relibc_internal_sigentry_crit_first();
|
||||||
|
fn __relibc_internal_sigentry_crit_second();
|
||||||
|
fn __relibc_internal_sigentry_crit_third();
|
||||||
|
}
|
||||||
|
pub unsafe fn arch_pre(stack: &mut SigStack, area: &mut SigArea) -> PosixStackt {
|
||||||
|
if stack.regs.eip == __relibc_internal_sigentry_crit_first as usize {
|
||||||
|
let stack_ptr = stack.regs.esp as *const usize;
|
||||||
|
stack.regs.esp = unsafe { stack_ptr.read() };
|
||||||
|
stack.regs.eip = unsafe { stack_ptr.sub(1).read() };
|
||||||
|
} else if stack.regs.eip == __relibc_internal_sigentry_crit_second as usize
|
||||||
|
|| stack.regs.eip == __relibc_internal_sigentry_crit_third as usize
|
||||||
|
{
|
||||||
|
stack.regs.eip = area.tmp_eip;
|
||||||
|
}
|
||||||
|
PosixStackt {
|
||||||
|
sp: stack.regs.esp as *mut (),
|
||||||
|
size: 0, // TODO
|
||||||
|
flags: 0, // TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn arch_ret_to_sig(stack: &mut SigStack, control: &Sigcontrol) {
|
||||||
|
let orig_eip = core::mem::replace(&mut stack.regs.eip, __relibc_internal_sigentry as usize);
|
||||||
|
control.saved_ip.set(orig_eip);
|
||||||
|
control.saved_archdep_reg.set(stack.regs.eflags);
|
||||||
|
}
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe fn manually_enter_trampoline() {
|
||||||
|
let c = unsafe { &crate::Tcb::current().unwrap().os_specific.control };
|
||||||
|
c.control_flags.store(
|
||||||
|
c.control_flags.load(Ordering::Relaxed) | syscall::flag::INHIBIT_DELIVERY.bits(),
|
||||||
|
Ordering::Release,
|
||||||
|
);
|
||||||
|
c.saved_archdep_reg.set(0); // TODO: Just reset DF on x86?
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
core::arch::asm!("
|
||||||
|
call 2f
|
||||||
|
jmp 3f
|
||||||
|
2:
|
||||||
|
pop dword ptr gs:[{tcb_sc_off} + {sc_saved_eip}]
|
||||||
|
jmp __relibc_internal_sigentry
|
||||||
|
3:
|
||||||
|
",
|
||||||
|
tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control),
|
||||||
|
sc_saved_eip = const offset_of!(Sigcontrol, saved_ip),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Get current stack pointer, weak granularity guarantees.
|
||||||
|
pub fn current_sp() -> usize {
|
||||||
|
let sp: usize;
|
||||||
|
unsafe {
|
||||||
|
core::arch::asm!("mov {}, esp", out(reg) sp);
|
||||||
|
}
|
||||||
|
sp
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static PROC_FD: SyncUnsafeCell<usize> = SyncUnsafeCell::new(usize::MAX);
|
||||||
|
static PROC_CALL: u64 = ProcCall::Sigdeq as u64;
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
pub use self::aarch64::*;
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
pub mod aarch64;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86")]
|
||||||
|
pub use self::i686::*;
|
||||||
|
#[cfg(target_arch = "x86")]
|
||||||
|
pub mod i686;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
pub use self::x86_64::*;
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
pub mod x86_64;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub use self::riscv64::*;
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub mod riscv64;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ForkScratchpad {
|
||||||
|
pub cur_filetable_fd: usize,
|
||||||
|
pub new_proc_fd: usize,
|
||||||
|
pub new_thr_fd: usize,
|
||||||
|
}
|
||||||
@@ -0,0 +1,654 @@
|
|||||||
|
use core::cell::SyncUnsafeCell;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
Tcb,
|
||||||
|
proc::{FdGuard, FdGuardUpper, ForkArgs, fork_inner},
|
||||||
|
signal::{PosixStackt, RtSigarea, SigStack, get_sigaltstack, inner_c},
|
||||||
|
};
|
||||||
|
use core::{mem::offset_of, ptr::NonNull, sync::atomic::Ordering};
|
||||||
|
use redox_protocols::protocol::{ProcCall, RtSigInfo};
|
||||||
|
use syscall::{data::*, error::*};
|
||||||
|
|
||||||
|
use super::ForkScratchpad;
|
||||||
|
|
||||||
|
// Setup a stack starting from the very end of the address space, and then growing downwards.
|
||||||
|
pub const STACK_TOP: usize = 1 << 38;
|
||||||
|
pub const STACK_SIZE: usize = 1024 * 1024;
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct SigArea {
|
||||||
|
pub tmp_sp: u64,
|
||||||
|
pub tmp_t1: u64,
|
||||||
|
pub tmp_t2: u64,
|
||||||
|
pub tmp_t3: u64,
|
||||||
|
pub tmp_t4: u64,
|
||||||
|
pub tmp_a0: u64,
|
||||||
|
pub tmp_a1: u64,
|
||||||
|
pub tmp_a2: u64,
|
||||||
|
pub tmp_a3: u64,
|
||||||
|
pub tmp_a4: u64,
|
||||||
|
pub tmp_a7: u64,
|
||||||
|
|
||||||
|
pub pctl: usize, // TODO: remove
|
||||||
|
pub tmp_ip: u64,
|
||||||
|
pub tmp_rt_inf: RtSigInfo,
|
||||||
|
pub tmp_id_inf: u64,
|
||||||
|
pub altstack_top: usize,
|
||||||
|
pub altstack_bottom: usize,
|
||||||
|
pub disable_signals_depth: u64,
|
||||||
|
pub last_sig_was_restart: bool,
|
||||||
|
pub last_sigstack: Option<NonNull<SigStack>>,
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct ArchIntRegs {
|
||||||
|
pub int_regs: [u64; 31],
|
||||||
|
pub pc: u64,
|
||||||
|
pub fp_regs: [u64; 32],
|
||||||
|
pub fcsr: u32,
|
||||||
|
_pad: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS
|
||||||
|
/// is already initialized as if it was a thread.
|
||||||
|
pub unsafe fn deactivate_tcb(open_via_dup: &FdGuardUpper) -> Result<()> {
|
||||||
|
let mut env = syscall::EnvRegisters::default();
|
||||||
|
|
||||||
|
let file = open_via_dup.dup(b"regs/env")?;
|
||||||
|
|
||||||
|
env.tp = 0;
|
||||||
|
|
||||||
|
file.write(&mut env)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn fork_impl(args: &ForkArgs, initial_rsp: *mut usize) -> usize {
|
||||||
|
Error::mux(fork_inner(initial_rsp, args))
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn child_hook(scratchpad: &ForkScratchpad) {
|
||||||
|
let _ = syscall::close(scratchpad.cur_filetable_fd);
|
||||||
|
unsafe {
|
||||||
|
crate::child_hook_common(crate::ChildHookCommonArgs {
|
||||||
|
new_thr_fd: FdGuard::new(scratchpad.new_thr_fd),
|
||||||
|
new_proc_fd: if scratchpad.new_proc_fd == usize::MAX {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(FdGuard::new(scratchpad.new_proc_fd))
|
||||||
|
},
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
asmfunction!(__relibc_internal_fork_wrapper (usize) -> usize: ["
|
||||||
|
.attribute arch, \"rv64gc\" # rust bug 80608
|
||||||
|
addi sp, sp, -200
|
||||||
|
sd s0, 0(sp)
|
||||||
|
sd s1, 8(sp)
|
||||||
|
sd s2, 16(sp)
|
||||||
|
sd s3, 24(sp)
|
||||||
|
sd s4, 32(sp)
|
||||||
|
sd s5, 40(sp)
|
||||||
|
sd s6, 48(sp)
|
||||||
|
sd s7, 56(sp)
|
||||||
|
sd s8, 64(sp)
|
||||||
|
sd s9, 72(sp)
|
||||||
|
sd s10, 80(sp)
|
||||||
|
sd s11, 88(sp)
|
||||||
|
sd ra, 96(sp)
|
||||||
|
|
||||||
|
fsd fs0, 104(sp)
|
||||||
|
fsd fs1, 112(sp)
|
||||||
|
fsd fs2, 120(sp)
|
||||||
|
fsd fs3, 128(sp)
|
||||||
|
fsd fs4, 136(sp)
|
||||||
|
fsd fs5, 144(sp)
|
||||||
|
fsd fs6, 152(sp)
|
||||||
|
fsd fs7, 160(sp)
|
||||||
|
fsd fs8, 168(sp)
|
||||||
|
fsd fs9, 176(sp)
|
||||||
|
fsd fs10, 184(sp)
|
||||||
|
fsd fs11, 192(sp)
|
||||||
|
|
||||||
|
// a0 is forwarded from this function
|
||||||
|
mv a1, sp
|
||||||
|
jal {fork_impl}
|
||||||
|
|
||||||
|
ld s0, 0(sp)
|
||||||
|
ld s1, 8(sp)
|
||||||
|
ld s2, 16(sp)
|
||||||
|
ld s3, 24(sp)
|
||||||
|
ld s4, 32(sp)
|
||||||
|
ld s5, 40(sp)
|
||||||
|
ld s6, 48(sp)
|
||||||
|
ld s7, 56(sp)
|
||||||
|
ld s8, 64(sp)
|
||||||
|
ld s9, 72(sp)
|
||||||
|
ld s10, 80(sp)
|
||||||
|
ld s11, 88(sp)
|
||||||
|
ld ra, 96(sp)
|
||||||
|
|
||||||
|
fld fs0, 104(sp)
|
||||||
|
fld fs1, 112(sp)
|
||||||
|
fld fs2, 120(sp)
|
||||||
|
fld fs3, 128(sp)
|
||||||
|
fld fs4, 136(sp)
|
||||||
|
fld fs5, 144(sp)
|
||||||
|
fld fs6, 152(sp)
|
||||||
|
fld fs7, 160(sp)
|
||||||
|
fld fs8, 168(sp)
|
||||||
|
fld fs9, 176(sp)
|
||||||
|
fld fs10, 184(sp)
|
||||||
|
fld fs11, 192(sp)
|
||||||
|
|
||||||
|
addi sp, sp, 200
|
||||||
|
ret
|
||||||
|
"] <= [fork_impl = sym fork_impl]);
|
||||||
|
|
||||||
|
asmfunction!(__relibc_internal_fork_ret: ["
|
||||||
|
.attribute arch, \"rv64gc\" # rust bug 80608
|
||||||
|
|
||||||
|
# scratchpad is in a1, move to a0 for child_hook
|
||||||
|
mv a0, a1
|
||||||
|
|
||||||
|
jal {child_hook}
|
||||||
|
|
||||||
|
mv a0, zero
|
||||||
|
|
||||||
|
ld s0, 0(sp)
|
||||||
|
ld s1, 8(sp)
|
||||||
|
ld s2, 16(sp)
|
||||||
|
ld s3, 24(sp)
|
||||||
|
ld s4, 32(sp)
|
||||||
|
ld s5, 40(sp)
|
||||||
|
ld s6, 48(sp)
|
||||||
|
ld s7, 56(sp)
|
||||||
|
ld s8, 64(sp)
|
||||||
|
ld s9, 72(sp)
|
||||||
|
ld s10, 80(sp)
|
||||||
|
ld s11, 88(sp)
|
||||||
|
ld ra, 96(sp)
|
||||||
|
|
||||||
|
fld fs0, 104(sp)
|
||||||
|
fld fs1, 112(sp)
|
||||||
|
fld fs2, 120(sp)
|
||||||
|
fld fs3, 128(sp)
|
||||||
|
fld fs4, 136(sp)
|
||||||
|
fld fs5, 144(sp)
|
||||||
|
fld fs6, 152(sp)
|
||||||
|
fld fs7, 160(sp)
|
||||||
|
fld fs8, 168(sp)
|
||||||
|
fld fs9, 176(sp)
|
||||||
|
fld fs10, 184(sp)
|
||||||
|
fld fs11, 192(sp)
|
||||||
|
|
||||||
|
addi sp, sp, 200
|
||||||
|
ret
|
||||||
|
"] <= [child_hook = sym child_hook]);
|
||||||
|
|
||||||
|
asmfunction!(__relibc_internal_sigentry: ["
|
||||||
|
.attribute arch, \"rv64gc\" # rust bug 80608
|
||||||
|
// Save some registers
|
||||||
|
ld t0, -8(tp) // Tcb
|
||||||
|
sd sp, ({tcb_sa_off} + {sa_tmp_sp})(t0)
|
||||||
|
sd t1, ({tcb_sa_off} + {sa_tmp_t1})(t0)
|
||||||
|
sd t2, ({tcb_sa_off} + {sa_tmp_t2})(t0)
|
||||||
|
sd t3, ({tcb_sa_off} + {sa_tmp_t3})(t0)
|
||||||
|
sd t4, ({tcb_sa_off} + {sa_tmp_t4})(t0)
|
||||||
|
ld t4, ({tcb_sa_off} + {sa_off_pctl})(t0)
|
||||||
|
|
||||||
|
// First, select signal, always pick first available bit
|
||||||
|
99:
|
||||||
|
// Read first signal word
|
||||||
|
ld t1, ({tcb_sc_off} + {sc_word})(t0)
|
||||||
|
srli t2, t1, 32 // bitset to low word
|
||||||
|
and t1, t1, t2 // masked bitset in low word
|
||||||
|
beqz t1, 3f
|
||||||
|
|
||||||
|
// Found in first thread signal word
|
||||||
|
mv t3, x0
|
||||||
|
2: andi t2, t1, 1
|
||||||
|
bnez t2, 10f
|
||||||
|
addi t3, t3, 1
|
||||||
|
srli t1, t1, 1
|
||||||
|
j 2b
|
||||||
|
|
||||||
|
// If no unblocked thread signal was found, check for process.
|
||||||
|
// This is competitive; we need to atomically check if *we* cleared the process-wide pending
|
||||||
|
// bit, otherwise restart.
|
||||||
|
3: lw t1, {pctl_off_pending}(t4)
|
||||||
|
and t1, t1, t2
|
||||||
|
beqz t1, 3f
|
||||||
|
// Found in first process signal word
|
||||||
|
li t3, -1
|
||||||
|
2: andi t2, t1, 1
|
||||||
|
addi t3, t3, 1
|
||||||
|
srli t1, t1, 1
|
||||||
|
beqz t2, 2b
|
||||||
|
slli t1, t3, 3 // * 8 == size_of SenderInfo
|
||||||
|
add t1, t1, t4
|
||||||
|
ld t1, {pctl_off_sender_infos}(t1)
|
||||||
|
sd t1, ({tcb_sa_off} + {sa_tmp_id_inf})(t0)
|
||||||
|
li t1, 1
|
||||||
|
sll t1, t1, t3
|
||||||
|
not t1, t1
|
||||||
|
addi t2, t4, {pctl_off_pending}
|
||||||
|
amoand.w.aq t2, t1, (t2)
|
||||||
|
and t1, t1, t2
|
||||||
|
bne t1, t2, 9f
|
||||||
|
|
||||||
|
3:
|
||||||
|
// Read second signal word - both process and thread simultaneously.
|
||||||
|
// This must be done since POSIX requires low realtime signals to be picked first.
|
||||||
|
ld t1, ({tcb_sc_off} + {sc_word} + 8)(t0)
|
||||||
|
lw t2, ({pctl_off_pending} + 4)(t4)
|
||||||
|
or t4, t1, t2
|
||||||
|
srli t2, t1, 32
|
||||||
|
and t4, t2, t4
|
||||||
|
beqz t4, 7f
|
||||||
|
li t3, -1
|
||||||
|
2: andi t2, t4, 1
|
||||||
|
addi t3, t3, 1
|
||||||
|
srli t4, t4, 1
|
||||||
|
beqz t2, 2b
|
||||||
|
li t2, 1
|
||||||
|
sll t2, t2, t3
|
||||||
|
and t1, t1, t2
|
||||||
|
addi t3, t3, 32
|
||||||
|
bnez t1, 10f // thread signal
|
||||||
|
|
||||||
|
// otherwise, try (competitively) dequeueing realtime signal
|
||||||
|
|
||||||
|
// SYS_CALL(fd, payload_base, payload_len, metadata_len, metadata_base)
|
||||||
|
// a7 a0 a1 a2 a3 a4
|
||||||
|
|
||||||
|
// TODO: This SYS_CALL invocation has not yet been tested due to toolchain issues.
|
||||||
|
|
||||||
|
sd a0, ({tcb_sa_off} + {sa_tmp_a0})(t0)
|
||||||
|
sd a1, ({tcb_sa_off} + {sa_tmp_a1})(t0)
|
||||||
|
sd a2, ({tcb_sa_off} + {sa_tmp_a2})(t0)
|
||||||
|
sd a3, ({tcb_sa_off} + {sa_tmp_a3})(t0)
|
||||||
|
sd a4, ({tcb_sa_off} + {sa_tmp_a4})(t0)
|
||||||
|
sd a7, ({tcb_sa_off} + {sa_tmp_a7})(t0)
|
||||||
|
li a7, {SYS_CALL}
|
||||||
|
addi a2, t3, -32
|
||||||
|
add a1, t0, {tcb_sa_off} + {sa_tmp_rt_inf} // out pointer of dequeued realtime sig
|
||||||
|
sd a2, (a1)
|
||||||
|
li a2, {RTINF_SIZE}
|
||||||
|
li a3, 1
|
||||||
|
1337:
|
||||||
|
auipc a4, %pcrel_hi({proc_fd})
|
||||||
|
addi a4, a4, %pcrel_lo(1337b)
|
||||||
|
ecall
|
||||||
|
ld a3, ({tcb_sa_off} + {sa_tmp_a3})(t0)
|
||||||
|
ld a4, ({tcb_sa_off} + {sa_tmp_a4})(t0)
|
||||||
|
bnez a0, 99b // assumes error can only be EAGAIN
|
||||||
|
j 9f
|
||||||
|
|
||||||
|
10: // thread signal. t3 holds signal number
|
||||||
|
srli t1, t3, 5
|
||||||
|
bnez t1, 2f // FIXME senderinfo?
|
||||||
|
sll t2, t3, 3 // * 8 == size_of SenderInfo
|
||||||
|
add t2, t2, t0
|
||||||
|
ld t2, ({tcb_sc_off} + {sc_sender_infos})(t2)
|
||||||
|
sd t2, ({tcb_sa_off} + {sa_tmp_id_inf})(t0)
|
||||||
|
2: andi t4, t3, 31
|
||||||
|
li t2, 1
|
||||||
|
sll t2, t2, t4
|
||||||
|
not t2, t2
|
||||||
|
sll t1, t1, 3
|
||||||
|
add t1, t1, t0
|
||||||
|
addi t1, t1, {tcb_sc_off} + {sc_word}
|
||||||
|
amoand.w.aq x0, t2, (t1)
|
||||||
|
addi t3, t3, 64 // indicate signal was targeted at thread
|
||||||
|
|
||||||
|
9: // process signal t3 holds signal number
|
||||||
|
|
||||||
|
// By now we have selected a signal, stored in eax (6-bit). We now need to choose whether or
|
||||||
|
// not to switch to the alternate signal stack. If SA_ONSTACK is clear for this signal, then
|
||||||
|
// skip the sigaltstack logic.
|
||||||
|
ld t4, ({tcb_sa_off} + {sa_off_pctl})(t0)
|
||||||
|
andi t1, t3, 63
|
||||||
|
slli t1, t1, 4 // * 16 == size_of RawAction
|
||||||
|
add t1, t1, t4
|
||||||
|
ld t1, {pctl_off_actions}(t1)
|
||||||
|
slli t1, t1, 63-58 // SA_ONSTACK in sign bit
|
||||||
|
bgez t1, 3f
|
||||||
|
|
||||||
|
// If current RSP is above altstack region, switch to altstack
|
||||||
|
ld t1, ({tcb_sa_off} + {sa_altstack_top})(t0)
|
||||||
|
bgtu sp, t1, 2f
|
||||||
|
ld t2, ({tcb_sa_off} + {sa_altstack_bottom})(t0)
|
||||||
|
bgtu sp, t3, 3f
|
||||||
|
2: mv sp, t1
|
||||||
|
3:
|
||||||
|
// form mcontext on stack
|
||||||
|
addi sp, sp, -33 * 8
|
||||||
|
fsd f0, (0 * 8)(sp)
|
||||||
|
fsd f1, (1 * 8)(sp)
|
||||||
|
fsd f2, (2 * 8)(sp)
|
||||||
|
fsd f3, (3 * 8)(sp)
|
||||||
|
fsd f4, (4 * 8)(sp)
|
||||||
|
fsd f5, (5 * 8)(sp)
|
||||||
|
fsd f6, (6 * 8)(sp)
|
||||||
|
fsd f7, (7 * 8)(sp)
|
||||||
|
fsd f8, (8 * 8)(sp)
|
||||||
|
fsd f9, (9 * 8)(sp)
|
||||||
|
fsd f10, (10 * 8)(sp)
|
||||||
|
fsd f11, (11 * 8)(sp)
|
||||||
|
fsd f12, (12 * 8)(sp)
|
||||||
|
fsd f13, (13 * 8)(sp)
|
||||||
|
fsd f14, (14 * 8)(sp)
|
||||||
|
fsd f15, (15 * 8)(sp)
|
||||||
|
fsd f16, (16 * 8)(sp)
|
||||||
|
fsd f17, (17 * 8)(sp)
|
||||||
|
fsd f18, (18 * 8)(sp)
|
||||||
|
fsd f19, (19 * 8)(sp)
|
||||||
|
fsd f20, (20 * 8)(sp)
|
||||||
|
fsd f21, (21 * 8)(sp)
|
||||||
|
fsd f22, (22 * 8)(sp)
|
||||||
|
fsd f23, (23 * 8)(sp)
|
||||||
|
fsd f24, (24 * 8)(sp)
|
||||||
|
fsd f25, (25 * 8)(sp)
|
||||||
|
fsd f26, (26 * 8)(sp)
|
||||||
|
fsd f27, (27 * 8)(sp)
|
||||||
|
fsd f28, (28 * 8)(sp)
|
||||||
|
fsd f29, (29 * 8)(sp)
|
||||||
|
fsd f30, (30 * 8)(sp)
|
||||||
|
fsd f31, (31 * 8)(sp)
|
||||||
|
csrr t1, fcsr
|
||||||
|
sw t1, (32 * 8)(sp)
|
||||||
|
|
||||||
|
addi sp, sp, -32 * 8
|
||||||
|
sd x1, 0(sp)
|
||||||
|
ld t1, ({tcb_sa_off} + {sa_tmp_sp})(t0)
|
||||||
|
sd t1, (1 * 8)(sp) // x2 is sp
|
||||||
|
sd x3, (2 * 8)(sp)
|
||||||
|
sd x4, (3 * 8)(sp)
|
||||||
|
ld t1, ({tcb_sc_off} + {sc_saved_t0})(t0)
|
||||||
|
sd t1, (4 * 8)(sp) // x5 is t0
|
||||||
|
ld t1, ({tcb_sa_off} + {sa_tmp_t1})(t0)
|
||||||
|
sd t1, (5 * 8)(sp) // x6 is t1
|
||||||
|
ld t1, ({tcb_sa_off} + {sa_tmp_t2})(t0)
|
||||||
|
sd t1, (6 * 8)(sp) // x7 is t2
|
||||||
|
sd x8, (7 * 8)(sp)
|
||||||
|
sd x9, (8 * 8)(sp)
|
||||||
|
sd x10, (9 * 8)(sp)
|
||||||
|
sd x11, (10 * 8)(sp)
|
||||||
|
sd x12, (11 * 8)(sp)
|
||||||
|
sd x13, (12 * 8)(sp)
|
||||||
|
sd x14, (13 * 8)(sp)
|
||||||
|
sd x15, (14 * 8)(sp)
|
||||||
|
sd x16, (15 * 8)(sp)
|
||||||
|
sd x17, (16 * 8)(sp)
|
||||||
|
sd x18, (17 * 8)(sp)
|
||||||
|
sd x19, (18 * 8)(sp)
|
||||||
|
sd x20, (19 * 8)(sp)
|
||||||
|
sd x21, (20 * 8)(sp)
|
||||||
|
sd x22, (21 * 8)(sp)
|
||||||
|
sd x23, (22 * 8)(sp)
|
||||||
|
sd x24, (23 * 8)(sp)
|
||||||
|
sd x25, (24 * 8)(sp)
|
||||||
|
sd x26, (25 * 8)(sp)
|
||||||
|
sd x27, (26 * 8)(sp)
|
||||||
|
ld t1, ({tcb_sa_off} + {sa_tmp_t3})(t0)
|
||||||
|
sd t1, (27 * 8)(sp) // t3 is x28
|
||||||
|
ld t1, ({tcb_sa_off} + {sa_tmp_t4})(t0)
|
||||||
|
sd t1, (28 * 8)(sp) // t4 is x29
|
||||||
|
sd x30, (29 * 8)(sp)
|
||||||
|
sd x31, (30 * 8)(sp)
|
||||||
|
ld t1, ({tcb_sc_off} + {sc_saved_ip})(t0)
|
||||||
|
sd t1, (31 * 8)(sp)
|
||||||
|
|
||||||
|
// form ucontext
|
||||||
|
addi sp, sp, -64
|
||||||
|
sw t3, 60(sp)
|
||||||
|
|
||||||
|
mv t0, sp
|
||||||
|
jal {inner}
|
||||||
|
|
||||||
|
addi sp, sp, 64
|
||||||
|
|
||||||
|
addi t0, sp, 32 * 8
|
||||||
|
fld f0, (0 * 8)(t0)
|
||||||
|
fld f1, (1 * 8)(t0)
|
||||||
|
fld f2, (2 * 8)(t0)
|
||||||
|
fld f3, (3 * 8)(t0)
|
||||||
|
fld f4, (4 * 8)(t0)
|
||||||
|
fld f5, (5 * 8)(t0)
|
||||||
|
fld f6, (6 * 8)(t0)
|
||||||
|
fld f7, (7 * 8)(t0)
|
||||||
|
fld f8, (8 * 8)(t0)
|
||||||
|
fld f9, (9 * 8)(t0)
|
||||||
|
fld f10, (10 * 8)(t0)
|
||||||
|
fld f11, (11 * 8)(t0)
|
||||||
|
fld f12, (12 * 8)(t0)
|
||||||
|
fld f13, (13 * 8)(t0)
|
||||||
|
fld f14, (14 * 8)(t0)
|
||||||
|
fld f15, (15 * 8)(t0)
|
||||||
|
fld f16, (16 * 8)(t0)
|
||||||
|
fld f17, (17 * 8)(t0)
|
||||||
|
fld f18, (18 * 8)(t0)
|
||||||
|
fld f19, (19 * 8)(t0)
|
||||||
|
fld f20, (20 * 8)(t0)
|
||||||
|
fld f21, (21 * 8)(t0)
|
||||||
|
fld f22, (22 * 8)(t0)
|
||||||
|
fld f23, (23 * 8)(t0)
|
||||||
|
fld f24, (24 * 8)(t0)
|
||||||
|
fld f25, (25 * 8)(t0)
|
||||||
|
fld f26, (26 * 8)(t0)
|
||||||
|
fld f27, (27 * 8)(t0)
|
||||||
|
fld f28, (28 * 8)(t0)
|
||||||
|
fld f29, (29 * 8)(t0)
|
||||||
|
fld f30, (30 * 8)(t0)
|
||||||
|
fld f31, (31 * 8)(t0)
|
||||||
|
lw t1, (32 * 8)(t0)
|
||||||
|
csrw fcsr, t1
|
||||||
|
|
||||||
|
ld x1, 0(sp)
|
||||||
|
// skip sp
|
||||||
|
// skip gp
|
||||||
|
ld x4, (3 * 8)(sp)
|
||||||
|
ld x5, (4 * 8)(sp)
|
||||||
|
ld x6, (5 * 8)(sp)
|
||||||
|
ld x7, (6 * 8)(sp)
|
||||||
|
ld x8, (7 * 8)(sp)
|
||||||
|
ld x9, (8 * 8)(sp)
|
||||||
|
ld x10, (9 * 8)(sp)
|
||||||
|
ld x11, (10 * 8)(sp)
|
||||||
|
ld x12, (11 * 8)(sp)
|
||||||
|
ld x13, (12 * 8)(sp)
|
||||||
|
ld x14, (13 * 8)(sp)
|
||||||
|
ld x15, (14 * 8)(sp)
|
||||||
|
ld x16, (15 * 8)(sp)
|
||||||
|
ld x17, (16 * 8)(sp)
|
||||||
|
ld x18, (17 * 8)(sp)
|
||||||
|
ld x19, (18 * 8)(sp)
|
||||||
|
ld x20, (19 * 8)(sp)
|
||||||
|
ld x21, (20 * 8)(sp)
|
||||||
|
ld x22, (21 * 8)(sp)
|
||||||
|
ld x23, (22 * 8)(sp)
|
||||||
|
ld x24, (23 * 8)(sp)
|
||||||
|
ld x25, (24 * 8)(sp)
|
||||||
|
ld x26, (25 * 8)(sp)
|
||||||
|
ld x27, (26 * 8)(sp)
|
||||||
|
ld x28, (27 * 8)(sp)
|
||||||
|
ld x29, (28 * 8)(sp)
|
||||||
|
ld x30, (29 * 8)(sp)
|
||||||
|
ld x31, (30 * 8)(sp)
|
||||||
|
ld gp, (31 * 8)(sp) // new IP; this clobbers register x3/gp which is ABI reserved
|
||||||
|
.global __relibc_internal_sigentry_crit_first
|
||||||
|
__relibc_internal_sigentry_crit_first:
|
||||||
|
ld sp, (1 * 8)(sp)
|
||||||
|
.global __relibc_internal_sigentry_crit_second
|
||||||
|
__relibc_internal_sigentry_crit_second:
|
||||||
|
jr gp
|
||||||
|
7:
|
||||||
|
// A spurious signal occurred. Signals are still disabled here, but will need to be re-enabled.
|
||||||
|
|
||||||
|
// restore stack
|
||||||
|
ld sp, ({tcb_sa_off} + {sa_tmp_sp})(t0)
|
||||||
|
|
||||||
|
// move saved IP away from control, allowing arch_pre to save us if interrupted.
|
||||||
|
ld t1, ({tcb_sc_off} + {sc_saved_ip})(t0)
|
||||||
|
sd t1, ({tcb_sa_off} + {sa_tmp_ip})(t0)
|
||||||
|
|
||||||
|
// restore regs
|
||||||
|
ld t2, ({tcb_sa_off} + {sa_tmp_t2})(t0)
|
||||||
|
ld t3, ({tcb_sa_off} + {sa_tmp_t3})(t0)
|
||||||
|
ld t4, ({tcb_sa_off} + {sa_tmp_t4})(t0)
|
||||||
|
|
||||||
|
// move saved t0 away from control as well
|
||||||
|
mv t1, t0
|
||||||
|
ld t0, ({tcb_sc_off} + {sc_saved_t0})(t0)
|
||||||
|
|
||||||
|
// Re-enable signals. This code can be interrupted after this signal, so we need to define
|
||||||
|
// 'crit_third'.
|
||||||
|
ld gp, ({tcb_sc_off} + {sc_control})(t1)
|
||||||
|
andi gp, gp, ~1
|
||||||
|
sd gp, ({tcb_sc_off} + {sc_control})(t1)
|
||||||
|
|
||||||
|
.globl __relibc_internal_sigentry_crit_third
|
||||||
|
__relibc_internal_sigentry_crit_third:
|
||||||
|
ld gp, ({tcb_sa_off} + {sa_tmp_ip})(t1)
|
||||||
|
.globl __relibc_internal_sigentry_crit_fourth
|
||||||
|
__relibc_internal_sigentry_crit_fourth:
|
||||||
|
ld t1, ({tcb_sa_off} + {sa_tmp_t1})(t1)
|
||||||
|
.globl __relibc_internal_sigentry_crit_fifth
|
||||||
|
__relibc_internal_sigentry_crit_fifth:
|
||||||
|
jr gp
|
||||||
|
"] <= [
|
||||||
|
tcb_sc_off = const (offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control)),
|
||||||
|
sc_word = const offset_of!(Sigcontrol, word),
|
||||||
|
sc_saved_t0 = const offset_of!(Sigcontrol, saved_archdep_reg),
|
||||||
|
sc_saved_ip = const offset_of!(Sigcontrol, saved_ip),
|
||||||
|
sc_sender_infos = const offset_of!(Sigcontrol, sender_infos),
|
||||||
|
sc_control = const offset_of!(Sigcontrol, control_flags),
|
||||||
|
|
||||||
|
tcb_sa_off = const (offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, arch)),
|
||||||
|
sa_off_pctl = const offset_of!(SigArea, pctl),
|
||||||
|
sa_tmp_sp = const offset_of!(SigArea, tmp_sp),
|
||||||
|
sa_tmp_t1 = const offset_of!(SigArea, tmp_t1),
|
||||||
|
sa_tmp_t2 = const offset_of!(SigArea, tmp_t2),
|
||||||
|
sa_tmp_t3 = const offset_of!(SigArea, tmp_t3),
|
||||||
|
sa_tmp_t4 = const offset_of!(SigArea, tmp_t4),
|
||||||
|
sa_tmp_a0 = const offset_of!(SigArea, tmp_a0),
|
||||||
|
sa_tmp_a1 = const offset_of!(SigArea, tmp_a1),
|
||||||
|
sa_tmp_a2 = const offset_of!(SigArea, tmp_a2),
|
||||||
|
sa_tmp_a3 = const offset_of!(SigArea, tmp_a3),
|
||||||
|
sa_tmp_a4 = const offset_of!(SigArea, tmp_a4),
|
||||||
|
sa_tmp_a7 = const offset_of!(SigArea, tmp_a7),
|
||||||
|
sa_tmp_ip = const offset_of!(SigArea, tmp_ip),
|
||||||
|
sa_tmp_id_inf = const offset_of!(SigArea, tmp_id_inf),
|
||||||
|
sa_tmp_rt_inf = const offset_of!(SigArea, tmp_rt_inf),
|
||||||
|
sa_altstack_top = const offset_of!(SigArea, altstack_top),
|
||||||
|
sa_altstack_bottom = const offset_of!(SigArea, altstack_bottom),
|
||||||
|
|
||||||
|
pctl_off_actions = const offset_of!(SigProcControl, actions),
|
||||||
|
inner = sym inner_c,
|
||||||
|
pctl_off_pending = const offset_of!(SigProcControl, pending),
|
||||||
|
pctl_off_sender_infos = const offset_of!(SigProcControl, sender_infos),
|
||||||
|
SYS_CALL = const syscall::SYS_CALL,
|
||||||
|
RTINF_SIZE = const size_of::<RtSigInfo>(),
|
||||||
|
proc_fd = sym PROC_FD,
|
||||||
|
]);
|
||||||
|
|
||||||
|
asmfunction!(__relibc_internal_rlct_clone_ret: ["
|
||||||
|
ld t0, 0(sp)
|
||||||
|
ld a0, 8(sp)
|
||||||
|
ld a1, 16(sp)
|
||||||
|
ld a2, 24(sp)
|
||||||
|
ld a3, 32(sp)
|
||||||
|
ld a4, 40(sp)
|
||||||
|
ld a5, 48(sp)
|
||||||
|
addi sp, sp, 56
|
||||||
|
|
||||||
|
jalr t0
|
||||||
|
ret
|
||||||
|
"] <= []);
|
||||||
|
|
||||||
|
pub fn current_sp() -> usize {
|
||||||
|
let sp: usize;
|
||||||
|
unsafe {
|
||||||
|
core::arch::asm!(
|
||||||
|
"mv {}, sp",
|
||||||
|
out(reg) sp,
|
||||||
|
options(nomem));
|
||||||
|
}
|
||||||
|
sp
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn manually_enter_trampoline() {
|
||||||
|
let ctl = unsafe { &Tcb::current().unwrap().os_specific.control };
|
||||||
|
|
||||||
|
ctl.control_flags.store(
|
||||||
|
ctl.control_flags.load(Ordering::Relaxed) | syscall::flag::INHIBIT_DELIVERY.bits(),
|
||||||
|
Ordering::Release,
|
||||||
|
);
|
||||||
|
ctl.saved_archdep_reg.set(0);
|
||||||
|
let ip_location = &ctl.saved_ip as *const _ as usize;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
core::arch::asm!("
|
||||||
|
jal 2f
|
||||||
|
j 3f
|
||||||
|
2:
|
||||||
|
sd ra, 0(t0)
|
||||||
|
la t0, __relibc_internal_sigentry
|
||||||
|
jalr x0, t0
|
||||||
|
3:
|
||||||
|
",
|
||||||
|
inout("t0") ip_location => _, out("ra") _);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" {
|
||||||
|
fn __relibc_internal_sigentry_crit_first();
|
||||||
|
fn __relibc_internal_sigentry_crit_second();
|
||||||
|
fn __relibc_internal_sigentry_crit_third();
|
||||||
|
fn __relibc_internal_sigentry_crit_fourth();
|
||||||
|
fn __relibc_internal_sigentry_crit_fifth();
|
||||||
|
}
|
||||||
|
pub unsafe fn arch_pre(stack: &mut SigStack, area: &mut SigArea) -> PosixStackt {
|
||||||
|
// It is impossible to update SP and PC atomically. Instead, we abuse the fact that
|
||||||
|
// signals are disabled in the prologue of the signal trampoline, which allows us to emulate
|
||||||
|
// atomicity inside the critical section, consisting of one instruction at 'crit_first', and
|
||||||
|
// one at 'crit_second', see asm.
|
||||||
|
|
||||||
|
if stack.regs.pc == __relibc_internal_sigentry_crit_first as u64 {
|
||||||
|
// Reexecute 'ld sp, (1 * 8)(sp)'
|
||||||
|
let stack_ptr = stack.regs.int_regs[1] as *const u64; // x2
|
||||||
|
stack.regs.int_regs[1] = unsafe { stack_ptr.add(1).read() };
|
||||||
|
// and 'jr gp' steps.
|
||||||
|
stack.regs.pc = stack.regs.int_regs[2];
|
||||||
|
} else if stack.regs.pc == __relibc_internal_sigentry_crit_second as u64
|
||||||
|
|| stack.regs.pc == __relibc_internal_sigentry_crit_fifth as u64
|
||||||
|
{
|
||||||
|
// just reexecute the jump
|
||||||
|
stack.regs.pc = stack.regs.int_regs[2];
|
||||||
|
} else if stack.regs.pc == __relibc_internal_sigentry_crit_third as u64 {
|
||||||
|
// ld gp, ({tcb_sa_off} + {sa_tmp_ip})(t1)
|
||||||
|
stack.regs.int_regs[2] = area.tmp_ip;
|
||||||
|
// ld t1, ({tcb_sa_off} + {sa_tmp_t1})(t1)
|
||||||
|
stack.regs.int_regs[5] = area.tmp_t1;
|
||||||
|
// j gp
|
||||||
|
stack.regs.pc = stack.regs.int_regs[2];
|
||||||
|
} else if stack.regs.pc == __relibc_internal_sigentry_crit_fourth as u64 {
|
||||||
|
// ld t1, ({tcb_sa_off} + {sa_tmp_t1})(t1)
|
||||||
|
stack.regs.int_regs[5] = area.tmp_t1;
|
||||||
|
// jr gp
|
||||||
|
stack.regs.pc = stack.regs.int_regs[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
get_sigaltstack(area, stack.regs.int_regs[1] as usize).into()
|
||||||
|
}
|
||||||
|
pub fn arch_ret_to_sig(stack: &mut SigStack, control: &Sigcontrol) {
|
||||||
|
let orig_pc = core::mem::replace(&mut stack.regs.pc, __relibc_internal_sigentry as u64);
|
||||||
|
control.saved_ip.set(orig_pc as usize);
|
||||||
|
control
|
||||||
|
.saved_archdep_reg
|
||||||
|
.set(stack.regs.int_regs[4] as usize); // t0
|
||||||
|
}
|
||||||
|
pub(crate) static PROC_FD: SyncUnsafeCell<usize> = SyncUnsafeCell::new(usize::MAX);
|
||||||
|
static PROC_CALL: [usize; 1] = [ProcCall::Sigdeq as usize];
|
||||||
@@ -0,0 +1,528 @@
|
|||||||
|
use core::{
|
||||||
|
cell::SyncUnsafeCell,
|
||||||
|
mem::offset_of,
|
||||||
|
ptr::NonNull,
|
||||||
|
sync::atomic::{AtomicU8, Ordering},
|
||||||
|
};
|
||||||
|
|
||||||
|
use syscall::{
|
||||||
|
data::{SigProcControl, Sigcontrol},
|
||||||
|
error::*,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
Tcb,
|
||||||
|
proc::{FdGuard, FdGuardUpper, ForkArgs, fork_inner},
|
||||||
|
signal::{PROC_CONTROL_STRUCT, PosixStackt, RtSigarea, SigStack, get_sigaltstack, inner_c},
|
||||||
|
};
|
||||||
|
use redox_protocols::protocol::{ProcCall, RtSigInfo};
|
||||||
|
|
||||||
|
use super::ForkScratchpad;
|
||||||
|
|
||||||
|
// Setup a stack starting from the very end of the address space, and then growing downwards.
|
||||||
|
pub const STACK_TOP: usize = 1 << 47;
|
||||||
|
pub const STACK_SIZE: usize = 8 * 1024 * 1024;
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct SigArea {
|
||||||
|
pub tmp_rip: usize,
|
||||||
|
pub tmp_rsp: usize,
|
||||||
|
pub tmp_rax: usize,
|
||||||
|
pub tmp_rdx: usize,
|
||||||
|
pub tmp_rdi: usize,
|
||||||
|
pub tmp_rsi: usize,
|
||||||
|
pub tmp_r8: usize,
|
||||||
|
pub tmp_r10: usize,
|
||||||
|
pub tmp_r12: usize,
|
||||||
|
pub tmp_rt_inf: RtSigInfo,
|
||||||
|
pub tmp_id_inf: u64,
|
||||||
|
|
||||||
|
pub altstack_top: usize,
|
||||||
|
pub altstack_bottom: usize,
|
||||||
|
pub disable_signals_depth: u64,
|
||||||
|
pub last_sig_was_restart: bool,
|
||||||
|
pub last_sigstack: Option<NonNull<SigStack>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C, align(16))]
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct ArchIntRegs {
|
||||||
|
pub ymm_upper: [u128; 16],
|
||||||
|
pub fxsave: [u128; 29],
|
||||||
|
pub r15: usize, // fxsave "available" +0
|
||||||
|
pub r14: usize, // available +8
|
||||||
|
pub r13: usize, // available +16
|
||||||
|
pub r12: usize, // available +24
|
||||||
|
pub rbp: usize, // available +32
|
||||||
|
pub rbx: usize, // available +40
|
||||||
|
pub r11: usize, // outside fxsave, and so on
|
||||||
|
pub r10: usize,
|
||||||
|
pub r9: usize,
|
||||||
|
pub r8: usize,
|
||||||
|
pub rax: usize,
|
||||||
|
pub rcx: usize,
|
||||||
|
pub rdx: usize,
|
||||||
|
pub rsi: usize,
|
||||||
|
pub rdi: usize,
|
||||||
|
pub rflags: usize,
|
||||||
|
pub rip: usize,
|
||||||
|
pub rsp: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS
|
||||||
|
/// is already initialized as if it was a thread.
|
||||||
|
pub unsafe fn deactivate_tcb(open_via_dup: &FdGuardUpper) -> Result<()> {
|
||||||
|
let mut env = syscall::EnvRegisters::default();
|
||||||
|
|
||||||
|
let file = open_via_dup.dup(b"regs/env")?;
|
||||||
|
|
||||||
|
env.fsbase = 0;
|
||||||
|
env.gsbase = 0;
|
||||||
|
|
||||||
|
file.write(&mut env)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "sysv64" fn fork_impl(args: &ForkArgs, initial_rsp: *mut usize) -> usize {
|
||||||
|
Error::mux(fork_inner(initial_rsp, args))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unsafe_op_in_unsafe_fn)]
|
||||||
|
unsafe extern "sysv64" fn child_hook(scratchpad: &ForkScratchpad) {
|
||||||
|
let _ = syscall::close(scratchpad.cur_filetable_fd);
|
||||||
|
crate::child_hook_common(crate::ChildHookCommonArgs {
|
||||||
|
new_thr_fd: FdGuard::new(scratchpad.new_thr_fd),
|
||||||
|
new_proc_fd: if scratchpad.new_proc_fd == usize::MAX {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(FdGuard::new(scratchpad.new_proc_fd))
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
asmfunction!(__relibc_internal_fork_wrapper (usize) -> usize: ["
|
||||||
|
push rbp
|
||||||
|
mov rbp, rsp
|
||||||
|
|
||||||
|
push rbx
|
||||||
|
push rbp
|
||||||
|
push r12
|
||||||
|
push r13
|
||||||
|
push r14
|
||||||
|
push r15
|
||||||
|
|
||||||
|
sub rsp, 16
|
||||||
|
|
||||||
|
stmxcsr [rsp+16]
|
||||||
|
fnstcw [rsp+8]
|
||||||
|
|
||||||
|
// rdi: &ForkArgs
|
||||||
|
// rsi: initial_rsp
|
||||||
|
mov rsi, rsp
|
||||||
|
call {fork_impl}
|
||||||
|
|
||||||
|
add rsp, 64
|
||||||
|
|
||||||
|
pop rbp
|
||||||
|
ret
|
||||||
|
|
||||||
|
"] <= [fork_impl = sym fork_impl]);
|
||||||
|
asmfunction!(__relibc_internal_fork_ret: ["
|
||||||
|
# scratchpad is in rsi, move to rdi for child_hook
|
||||||
|
mov rdi, rsi
|
||||||
|
|
||||||
|
call {child_hook}
|
||||||
|
|
||||||
|
ldmxcsr [rsp + 16]
|
||||||
|
mov rcx, [rsp + 8]
|
||||||
|
|
||||||
|
xor rax, rax
|
||||||
|
|
||||||
|
add rsp, 16
|
||||||
|
pop r15
|
||||||
|
pop r14
|
||||||
|
pop r13
|
||||||
|
pop r12
|
||||||
|
pop rbp
|
||||||
|
pop rbx
|
||||||
|
|
||||||
|
pop rbp
|
||||||
|
ret
|
||||||
|
"] <= [child_hook = sym child_hook]);
|
||||||
|
asmfunction!(__relibc_internal_rlct_clone_ret: ["
|
||||||
|
# Load registers
|
||||||
|
pop rax
|
||||||
|
pop rdi
|
||||||
|
pop rsi
|
||||||
|
pop rdx
|
||||||
|
pop rcx
|
||||||
|
pop r8
|
||||||
|
pop r9
|
||||||
|
|
||||||
|
mov DWORD PTR [rsp - 8], 0x00001F80
|
||||||
|
ldmxcsr [rsp - 8]
|
||||||
|
mov WORD PTR [rsp - 8], 0x037F
|
||||||
|
fldcw [rsp - 8]
|
||||||
|
|
||||||
|
# Call entry point
|
||||||
|
call rax
|
||||||
|
|
||||||
|
ret
|
||||||
|
"] <= []);
|
||||||
|
|
||||||
|
asmfunction!(__relibc_internal_sigentry: ["
|
||||||
|
// Save some registers
|
||||||
|
mov fs:[{tcb_sa_off} + {sa_tmp_rsp}], rsp
|
||||||
|
mov fs:[{tcb_sa_off} + {sa_tmp_rax}], rax
|
||||||
|
mov fs:[{tcb_sa_off} + {sa_tmp_rdx}], rdx
|
||||||
|
mov fs:[{tcb_sa_off} + {sa_tmp_rdi}], rdi
|
||||||
|
mov fs:[{tcb_sa_off} + {sa_tmp_rsi}], rsi
|
||||||
|
mov fs:[{tcb_sa_off} + {sa_tmp_r8}], r8
|
||||||
|
mov fs:[{tcb_sa_off} + {sa_tmp_r10}], r10
|
||||||
|
mov fs:[{tcb_sa_off} + {sa_tmp_r12}], r12
|
||||||
|
|
||||||
|
// First, select signal, always pick first available bit
|
||||||
|
1:
|
||||||
|
// Read standard signal word - first targeting this thread
|
||||||
|
mov rax, fs:[{tcb_sc_off} + {sc_word}]
|
||||||
|
mov rdx, rax
|
||||||
|
shr rdx, 32
|
||||||
|
and eax, edx
|
||||||
|
bsf eax, eax
|
||||||
|
jnz 2f
|
||||||
|
|
||||||
|
// If no unblocked thread signal was found, check for process.
|
||||||
|
// This is competitive; we need to atomically check if *we* cleared the process-wide pending
|
||||||
|
// bit, otherwise restart.
|
||||||
|
mov eax, [rip + {pctl} + {pctl_off_pending}]
|
||||||
|
and eax, edx
|
||||||
|
bsf eax, eax
|
||||||
|
jz 8f
|
||||||
|
lea rdi, [rip + {pctl} + {pctl_off_sender_infos}]
|
||||||
|
mov rdi, [rdi + rax * 8]
|
||||||
|
lock btr [rip + {pctl} + {pctl_off_pending}], eax
|
||||||
|
mov fs:[{tcb_sa_off} + {sa_tmp_id_inf}], rdi
|
||||||
|
jc 9f
|
||||||
|
8:
|
||||||
|
// Read second signal word - both process and thread simultaneously.
|
||||||
|
// This must be done since POSIX requires low realtime signals to be picked first.
|
||||||
|
mov edx, fs:[{tcb_sc_off} + {sc_word} + 8]
|
||||||
|
mov eax, [rip + {pctl} + {pctl_off_pending} + 4]
|
||||||
|
or eax, edx
|
||||||
|
and eax, fs:[{tcb_sc_off} + {sc_word} + 12]
|
||||||
|
bsf eax, eax
|
||||||
|
jz 7f
|
||||||
|
|
||||||
|
bt edx, eax // check if signal was sent to thread specifically
|
||||||
|
jnc 81f
|
||||||
|
// if so, continue as usual
|
||||||
|
add eax, 32
|
||||||
|
jmp 2f
|
||||||
|
81:
|
||||||
|
// otherwise, try (competitively) dequeueing realtime signal
|
||||||
|
|
||||||
|
// SYS_CALL(fd, payload_base, payload_len, metadata_len | (flags << 8), metadata_base)
|
||||||
|
// rax rdi rsi rdx r10 r8
|
||||||
|
|
||||||
|
mov r12d, eax
|
||||||
|
mov rsi, fs:[0]
|
||||||
|
mov rdi, [rip+{proc_fd}]
|
||||||
|
add rsi, {tcb_sa_off} + {sa_tmp_rt_inf} // out pointer of dequeued realtime sig
|
||||||
|
mov rdx, {RTINF_SIZE}
|
||||||
|
mov [rsi], eax
|
||||||
|
lea r8, [rip + {proc_call_sigdeq}]
|
||||||
|
mov r10, 1
|
||||||
|
mov eax, {SYS_CALL}
|
||||||
|
syscall
|
||||||
|
test eax, eax
|
||||||
|
jnz 1b // assumes error can only be EAGAIN
|
||||||
|
lea eax, [r12d + 32]
|
||||||
|
jmp 9f
|
||||||
|
2:
|
||||||
|
mov edx, eax
|
||||||
|
shr edx, 5
|
||||||
|
mov rdi, fs:[{tcb_sc_off} + {sc_sender_infos} + eax * 8]
|
||||||
|
lock btr fs:[{tcb_sc_off} + {sc_word} + edx * 4], eax
|
||||||
|
mov fs:[{tcb_sa_off} + {sa_tmp_id_inf}], rdi
|
||||||
|
add eax, 64 // indicate signal was targeted at thread
|
||||||
|
9:
|
||||||
|
sub rsp, {REDZONE_SIZE}
|
||||||
|
and rsp, -{STACK_ALIGN}
|
||||||
|
|
||||||
|
// By now we have selected a signal, stored in eax (6-bit). We now need to choose whether or
|
||||||
|
// not to switch to the alternate signal stack. If SA_ONSTACK is clear for this signal, then
|
||||||
|
// skip the sigaltstack logic.
|
||||||
|
lea rdx, [rip + {pctl} + {pctl_off_actions}]
|
||||||
|
|
||||||
|
mov ecx, eax
|
||||||
|
and ecx, 63
|
||||||
|
|
||||||
|
// LEA doesn't support 16x, so just do two x8s.
|
||||||
|
lea rdx, [rdx + 8 * rcx]
|
||||||
|
lea rdx, [rdx + 8 * rcx]
|
||||||
|
|
||||||
|
bt qword ptr [rdx], {SA_ONSTACK_BIT}
|
||||||
|
jnc 4f
|
||||||
|
|
||||||
|
// Otherwise, the altstack is already active. The sigaltstack being disabled, is equivalent
|
||||||
|
// to setting 'top' to usize::MAX and 'bottom' to 0.
|
||||||
|
|
||||||
|
// If current RSP is above altstack region, switch to altstack
|
||||||
|
mov rdx, fs:[{tcb_sa_off} + {sa_altstack_top}]
|
||||||
|
cmp rsp, rdx
|
||||||
|
cmova rsp, rdx
|
||||||
|
|
||||||
|
// If current RSP is below altstack region, also switch to altstack
|
||||||
|
cmp rsp, fs:[{tcb_sa_off} + {sa_altstack_bottom}]
|
||||||
|
cmovbe rsp, rdx
|
||||||
|
|
||||||
|
.p2align 4
|
||||||
|
4:
|
||||||
|
// Now that we have a stack, we can finally start initializing the signal stack!
|
||||||
|
|
||||||
|
push fs:[{tcb_sa_off} + {sa_tmp_rsp}]
|
||||||
|
push fs:[{tcb_sc_off} + {sc_saved_rip}]
|
||||||
|
push fs:[{tcb_sc_off} + {sc_saved_rflags}]
|
||||||
|
|
||||||
|
push fs:[{tcb_sa_off} + {sa_tmp_rdi}]
|
||||||
|
push fs:[{tcb_sa_off} + {sa_tmp_rsi}]
|
||||||
|
push fs:[{tcb_sa_off} + {sa_tmp_rdx}]
|
||||||
|
push rcx
|
||||||
|
push fs:[{tcb_sa_off} + {sa_tmp_rax}]
|
||||||
|
push fs:[{tcb_sa_off} + {sa_tmp_r8}]
|
||||||
|
push r9
|
||||||
|
push fs:[{tcb_sa_off} + {sa_tmp_r10}]
|
||||||
|
push r11
|
||||||
|
push rbx
|
||||||
|
push rbp
|
||||||
|
push fs:[{tcb_sa_off} + {sa_tmp_r12}]
|
||||||
|
push r13
|
||||||
|
push r14
|
||||||
|
push r15
|
||||||
|
sub rsp, (29 + 16) * 16 // fxsave region minus available bytes
|
||||||
|
fxsave64 [rsp + 16 * 16]
|
||||||
|
|
||||||
|
// TODO: self-modifying?
|
||||||
|
cmp byte ptr [rip + {supports_avx}], 0
|
||||||
|
je 5f
|
||||||
|
|
||||||
|
// Prefer vextractf128 over vextracti128 since the former only requires AVX version 1.
|
||||||
|
vextractf128 [rsp + 15 * 16], ymm0, 1
|
||||||
|
vextractf128 [rsp + 14 * 16], ymm1, 1
|
||||||
|
vextractf128 [rsp + 13 * 16], ymm2, 1
|
||||||
|
vextractf128 [rsp + 12 * 16], ymm3, 1
|
||||||
|
vextractf128 [rsp + 11 * 16], ymm4, 1
|
||||||
|
vextractf128 [rsp + 10 * 16], ymm5, 1
|
||||||
|
vextractf128 [rsp + 9 * 16], ymm6, 1
|
||||||
|
vextractf128 [rsp + 8 * 16], ymm7, 1
|
||||||
|
vextractf128 [rsp + 7 * 16], ymm8, 1
|
||||||
|
vextractf128 [rsp + 6 * 16], ymm9, 1
|
||||||
|
vextractf128 [rsp + 5 * 16], ymm10, 1
|
||||||
|
vextractf128 [rsp + 4 * 16], ymm11, 1
|
||||||
|
vextractf128 [rsp + 3 * 16], ymm12, 1
|
||||||
|
vextractf128 [rsp + 2 * 16], ymm13, 1
|
||||||
|
vextractf128 [rsp + 16], ymm14, 1
|
||||||
|
vextractf128 [rsp], ymm15, 1
|
||||||
|
5:
|
||||||
|
mov [rsp - 4], eax
|
||||||
|
sub rsp, 64 // alloc space for ucontext fields
|
||||||
|
|
||||||
|
mov rdi, rsp
|
||||||
|
call {inner}
|
||||||
|
|
||||||
|
add rsp, 64
|
||||||
|
|
||||||
|
fxrstor64 [rsp + 16 * 16]
|
||||||
|
|
||||||
|
cmp byte ptr [rip + {supports_avx}], 0
|
||||||
|
je 6f
|
||||||
|
|
||||||
|
vinsertf128 ymm0, ymm0, [rsp + 15 * 16], 1
|
||||||
|
vinsertf128 ymm1, ymm1, [rsp + 14 * 16], 1
|
||||||
|
vinsertf128 ymm2, ymm2, [rsp + 13 * 16], 1
|
||||||
|
vinsertf128 ymm2, ymm2, [rsp + 12 * 16], 1
|
||||||
|
vinsertf128 ymm2, ymm2, [rsp + 11 * 16], 1
|
||||||
|
vinsertf128 ymm2, ymm2, [rsp + 10 * 16], 1
|
||||||
|
vinsertf128 ymm2, ymm2, [rsp + 9 * 16], 1
|
||||||
|
vinsertf128 ymm2, ymm2, [rsp + 8 * 16], 1
|
||||||
|
vinsertf128 ymm2, ymm2, [rsp + 7 * 16], 1
|
||||||
|
vinsertf128 ymm2, ymm2, [rsp + 6 * 16], 1
|
||||||
|
vinsertf128 ymm2, ymm2, [rsp + 5 * 16], 1
|
||||||
|
vinsertf128 ymm2, ymm2, [rsp + 4 * 16], 1
|
||||||
|
vinsertf128 ymm2, ymm2, [rsp + 3 * 16], 1
|
||||||
|
vinsertf128 ymm2, ymm2, [rsp + 2 * 16], 1
|
||||||
|
vinsertf128 ymm2, ymm2, [rsp + 16], 1
|
||||||
|
vinsertf128 ymm2, ymm2, [rsp], 1
|
||||||
|
6:
|
||||||
|
add rsp, (29 + 16) * 16
|
||||||
|
|
||||||
|
pop r15
|
||||||
|
pop r14
|
||||||
|
pop r13
|
||||||
|
pop r12
|
||||||
|
pop rbp
|
||||||
|
pop rbx
|
||||||
|
pop r11
|
||||||
|
pop r10
|
||||||
|
pop r9
|
||||||
|
pop r8
|
||||||
|
pop rax
|
||||||
|
pop rcx
|
||||||
|
pop rdx
|
||||||
|
pop rsi
|
||||||
|
pop rdi
|
||||||
|
|
||||||
|
popfq
|
||||||
|
pop qword ptr fs:[{tcb_sa_off} + {sa_tmp_rip}]
|
||||||
|
|
||||||
|
// x86 lacks atomic instructions for setting both the stack and instruction pointer
|
||||||
|
// simultaneously, except the slow microcoded IRETQ instruction. Thus, we let the arch_pre
|
||||||
|
// function emulate atomicity between the pop rsp and indirect jump.
|
||||||
|
|
||||||
|
.globl __relibc_internal_sigentry_crit_first
|
||||||
|
__relibc_internal_sigentry_crit_first:
|
||||||
|
|
||||||
|
pop rsp
|
||||||
|
|
||||||
|
.globl __relibc_internal_sigentry_crit_second
|
||||||
|
__relibc_internal_sigentry_crit_second:
|
||||||
|
jmp qword ptr fs:[{tcb_sa_off} + {sa_tmp_rip}]
|
||||||
|
7:
|
||||||
|
// A spurious signal occurred. Signals are still disabled here, but will need to be re-enabled.
|
||||||
|
|
||||||
|
// restore flags
|
||||||
|
mov rax, fs:[0] // load FS base
|
||||||
|
// TODO: Use lahf/sahf rather than pushfq/popfq?
|
||||||
|
lea rsp, [rax + {tcb_sc_off} + {sc_saved_rflags}]
|
||||||
|
popfq
|
||||||
|
|
||||||
|
// restore stack
|
||||||
|
mov rsp, fs:[{tcb_sa_off} + {sa_tmp_rsp}]
|
||||||
|
|
||||||
|
// move saved RIP away from control, allowing arch_pre to save us if interrupted.
|
||||||
|
mov rax, fs:[{tcb_sc_off} + {sc_saved_rip}]
|
||||||
|
mov fs:[{tcb_sa_off} + {sa_tmp_rip}], rax
|
||||||
|
|
||||||
|
// restore regs
|
||||||
|
mov rax, fs:[{tcb_sa_off} + {sa_tmp_rax}]
|
||||||
|
mov rdx, fs:[{tcb_sa_off} + {sa_tmp_rdx}]
|
||||||
|
|
||||||
|
// Re-enable signals. This code can be interrupted after this signal, so we need to define
|
||||||
|
// 'crit_third'.
|
||||||
|
and qword ptr fs:[{tcb_sc_off} + {sc_control}], ~1
|
||||||
|
|
||||||
|
.globl __relibc_internal_sigentry_crit_third
|
||||||
|
__relibc_internal_sigentry_crit_third:
|
||||||
|
jmp qword ptr fs:[{tcb_sa_off} + {sa_tmp_rip}]
|
||||||
|
"] <= [
|
||||||
|
inner = sym inner_c,
|
||||||
|
sa_tmp_rip = const offset_of!(SigArea, tmp_rip),
|
||||||
|
sa_tmp_rsp = const offset_of!(SigArea, tmp_rsp),
|
||||||
|
sa_tmp_rax = const offset_of!(SigArea, tmp_rax),
|
||||||
|
sa_tmp_rdx = const offset_of!(SigArea, tmp_rdx),
|
||||||
|
sa_tmp_rdi = const offset_of!(SigArea, tmp_rdi),
|
||||||
|
sa_tmp_rsi = const offset_of!(SigArea, tmp_rsi),
|
||||||
|
sa_tmp_r8 = const offset_of!(SigArea, tmp_r8),
|
||||||
|
sa_tmp_r10 = const offset_of!(SigArea, tmp_r10),
|
||||||
|
sa_tmp_r12 = const offset_of!(SigArea, tmp_r12),
|
||||||
|
sa_tmp_rt_inf = const offset_of!(SigArea, tmp_rt_inf),
|
||||||
|
sa_tmp_id_inf = const offset_of!(SigArea, tmp_id_inf),
|
||||||
|
sa_altstack_top = const offset_of!(SigArea, altstack_top),
|
||||||
|
sa_altstack_bottom = const offset_of!(SigArea, altstack_bottom),
|
||||||
|
sc_saved_rflags = const offset_of!(Sigcontrol, saved_archdep_reg),
|
||||||
|
sc_saved_rip = const offset_of!(Sigcontrol, saved_ip),
|
||||||
|
sc_word = const offset_of!(Sigcontrol, word),
|
||||||
|
sc_sender_infos = const offset_of!(Sigcontrol, sender_infos),
|
||||||
|
sc_control = const offset_of!(Sigcontrol, control_flags),
|
||||||
|
tcb_sa_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, arch),
|
||||||
|
tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control),
|
||||||
|
pctl_off_actions = const offset_of!(SigProcControl, actions),
|
||||||
|
pctl_off_pending = const offset_of!(SigProcControl, pending),
|
||||||
|
pctl_off_sender_infos = const offset_of!(SigProcControl, sender_infos),
|
||||||
|
pctl = sym PROC_CONTROL_STRUCT,
|
||||||
|
supports_avx = sym SUPPORTS_AVX,
|
||||||
|
REDZONE_SIZE = const 128,
|
||||||
|
STACK_ALIGN = const 16,
|
||||||
|
SA_ONSTACK_BIT = const 58, // (1 << 58) >> 32 = 0x0400_0000
|
||||||
|
SYS_CALL = const syscall::SYS_CALL,
|
||||||
|
proc_call_sigdeq = sym PROC_CALL_SIGDEQ,
|
||||||
|
RTINF_SIZE = const size_of::<RtSigInfo>(),
|
||||||
|
proc_fd = sym PROC_FD,
|
||||||
|
]);
|
||||||
|
|
||||||
|
unsafe extern "C" {
|
||||||
|
fn __relibc_internal_sigentry_crit_first();
|
||||||
|
fn __relibc_internal_sigentry_crit_second();
|
||||||
|
fn __relibc_internal_sigentry_crit_third();
|
||||||
|
}
|
||||||
|
/// Fixes some edge cases, and calculates the value for uc_stack.
|
||||||
|
pub unsafe fn arch_pre(stack: &mut SigStack, area: &mut SigArea) -> PosixStackt {
|
||||||
|
// It is impossible to update RSP and RIP atomically on x86_64, without using IRETQ, which is
|
||||||
|
// almost as slow as calling a SIGRETURN syscall would be. Instead, we abuse the fact that
|
||||||
|
// signals are disabled in the prologue of the signal trampoline, which allows us to emulate
|
||||||
|
// atomicity inside the critical section, consisting of one instruction at 'crit_first', one at
|
||||||
|
// 'crit_second', and one at 'crit_third', see asm.
|
||||||
|
|
||||||
|
if stack.regs.rip == __relibc_internal_sigentry_crit_first as usize {
|
||||||
|
// Reexecute pop rsp and jump steps. This case needs to be different from the one below,
|
||||||
|
// since rsp has not been overwritten with the previous context's stack, just yet. At this
|
||||||
|
// point, we know [rsp+0] contains the saved RSP, and [rsp-8] contains the saved RIP.
|
||||||
|
let stack_ptr = stack.regs.rsp as *const usize;
|
||||||
|
stack.regs.rsp = unsafe { stack_ptr.read() };
|
||||||
|
stack.regs.rip = unsafe { stack_ptr.sub(1).read() };
|
||||||
|
} else if stack.regs.rip == __relibc_internal_sigentry_crit_second as usize
|
||||||
|
|| stack.regs.rip == __relibc_internal_sigentry_crit_third as usize
|
||||||
|
{
|
||||||
|
// Almost finished, just reexecute the jump before tmp_rip is overwritten by this
|
||||||
|
// deeper-level signal.
|
||||||
|
stack.regs.rip = area.tmp_rip;
|
||||||
|
}
|
||||||
|
|
||||||
|
get_sigaltstack(area, stack.regs.rsp).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rearrange the restore-stack and sigarea in a way that makes it look like a new signal was
|
||||||
|
/// immediately delivered after restoring the allowset to what it was prior to the original signal delivery.
|
||||||
|
pub fn arch_ret_to_sig(stack: &mut SigStack, control: &Sigcontrol) {
|
||||||
|
let orig_rip = core::mem::replace(&mut stack.regs.rip, __relibc_internal_sigentry as usize);
|
||||||
|
control.saved_ip.set(orig_rip);
|
||||||
|
control.saved_archdep_reg.set(stack.regs.rflags);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) static SUPPORTS_AVX: AtomicU8 = AtomicU8::new(0);
|
||||||
|
|
||||||
|
// __relibc will be prepended to the name, so no_mangle is fine
|
||||||
|
#[allow(unsafe_op_in_unsafe_fn)]
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe fn manually_enter_trampoline() {
|
||||||
|
let c = &Tcb::current().unwrap().os_specific.control;
|
||||||
|
c.control_flags.store(
|
||||||
|
c.control_flags.load(Ordering::Relaxed) | syscall::flag::INHIBIT_DELIVERY.bits(),
|
||||||
|
Ordering::Release,
|
||||||
|
);
|
||||||
|
c.saved_archdep_reg.set(0); // TODO: Just reset DF on x86?
|
||||||
|
|
||||||
|
core::arch::asm!("
|
||||||
|
lea rax, [rip + 2f]
|
||||||
|
mov fs:[{tcb_sc_off} + {sc_saved_rip}], rax
|
||||||
|
jmp __relibc_internal_sigentry
|
||||||
|
2:
|
||||||
|
",
|
||||||
|
out("rax") _,
|
||||||
|
tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control),
|
||||||
|
sc_saved_rip = const offset_of!(Sigcontrol, saved_ip),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get current stack pointer, weak granularity guarantees.
|
||||||
|
pub fn current_sp() -> usize {
|
||||||
|
let sp: usize;
|
||||||
|
unsafe {
|
||||||
|
core::arch::asm!("mov {}, rsp", out(reg) sp);
|
||||||
|
}
|
||||||
|
sp
|
||||||
|
}
|
||||||
|
|
||||||
|
static PROC_CALL_SIGDEQ: u64 = ProcCall::Sigdeq as u64;
|
||||||
|
pub(crate) static PROC_FD: SyncUnsafeCell<usize> = SyncUnsafeCell::new(usize::MAX);
|
||||||
@@ -0,0 +1,313 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![allow(internal_features)]
|
||||||
|
#![deny(unsafe_op_in_unsafe_fn)]
|
||||||
|
#![feature(core_intrinsics, int_roundings, slice_ptr_get, sync_unsafe_cell)]
|
||||||
|
#![forbid(unreachable_patterns)]
|
||||||
|
|
||||||
|
use core::cell::UnsafeCell;
|
||||||
|
|
||||||
|
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
|
||||||
|
use generic_rt::ExpectTlsFree; // not used on aarch64 or riscv64
|
||||||
|
use generic_rt::GenericTcb;
|
||||||
|
use redox_protocols::protocol::ProcMeta;
|
||||||
|
use syscall::Sigcontrol;
|
||||||
|
|
||||||
|
use self::{
|
||||||
|
proc::{FdGuard, FdGuardUpper, STATIC_PROC_INFO},
|
||||||
|
sync::Mutex,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! asmfunction(
|
||||||
|
($name:ident $(($($arg:ty),*))? $(-> $ret:ty)? : [$($asmstmt:expr),*$(,)?] <= [$($decl:ident = $(sym $symname:ident)?$(const $constval:expr)?),*$(,)?]$(,)? ) => {
|
||||||
|
::core::arch::global_asm!(concat!("
|
||||||
|
.p2align 4
|
||||||
|
.section .text.", stringify!($name), ", \"ax\", @progbits
|
||||||
|
.globl ", stringify!($name), "
|
||||||
|
.type ", stringify!($name), ", @function
|
||||||
|
", stringify!($name), ":
|
||||||
|
", $($asmstmt, "\n",)* "
|
||||||
|
.size ", stringify!($name), ", . - ", stringify!($name), "
|
||||||
|
"), $($decl = $(sym $symname)?$(const $constval)?),*);
|
||||||
|
|
||||||
|
unsafe extern "C" {
|
||||||
|
pub fn $name($($(_: $arg),*)?) $(-> $ret)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
pub mod arch;
|
||||||
|
pub mod proc;
|
||||||
|
|
||||||
|
// TODO: Replace auxvs with a non-stack-based interface, but keep getauxval for compatibility
|
||||||
|
#[path = "../../src/platform/auxv_defs.rs"]
|
||||||
|
pub mod auxv_defs;
|
||||||
|
|
||||||
|
pub mod signal;
|
||||||
|
pub mod sync;
|
||||||
|
pub mod sys;
|
||||||
|
pub mod thread;
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct RtTcb {
|
||||||
|
pub control: Sigcontrol,
|
||||||
|
pub arch: UnsafeCell<crate::arch::SigArea>,
|
||||||
|
pub thr_fd: UnsafeCell<Option<FdGuardUpper>>,
|
||||||
|
}
|
||||||
|
impl RtTcb {
|
||||||
|
pub fn current() -> &'static Self {
|
||||||
|
unsafe { &Tcb::current().unwrap().os_specific }
|
||||||
|
}
|
||||||
|
pub fn thread_fd(&self) -> &FdGuardUpper {
|
||||||
|
unsafe { (&*self.thr_fd.get()).as_ref().unwrap() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Tcb = GenericTcb<RtTcb>;
|
||||||
|
|
||||||
|
/// OS and architecture specific code to activate TLS - Redox aarch64
|
||||||
|
#[allow(unsafe_op_in_unsafe_fn)]
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
pub unsafe fn tcb_activate(_tcb: &RtTcb, tls_end: usize, tls_len: usize) {
|
||||||
|
// Uses ABI page
|
||||||
|
let abi_ptr = tls_end - tls_len - 16;
|
||||||
|
core::ptr::write(abi_ptr as *mut usize, tls_end);
|
||||||
|
core::arch::asm!(
|
||||||
|
"msr tpidr_el0, {}",
|
||||||
|
in(reg) abi_ptr,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// OS and architecture specific code to activate TLS - Redox x86
|
||||||
|
#[allow(unsafe_op_in_unsafe_fn)]
|
||||||
|
#[cfg(target_arch = "x86")]
|
||||||
|
pub unsafe fn tcb_activate(tcb: &RtTcb, tls_end: usize, _tls_len: usize) {
|
||||||
|
let mut env = syscall::EnvRegisters::default();
|
||||||
|
|
||||||
|
let file = tcb
|
||||||
|
.thread_fd()
|
||||||
|
.dup(b"regs/env")
|
||||||
|
.expect_notls("failed to open handle for process registers");
|
||||||
|
|
||||||
|
file.read(&mut env).expect_notls("failed to read gsbase");
|
||||||
|
|
||||||
|
env.gsbase = tls_end as u32;
|
||||||
|
|
||||||
|
file.write(&env).expect_notls("failed to write gsbase");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// OS and architecture specific code to activate TLS - Redox x86_64
|
||||||
|
#[allow(unsafe_op_in_unsafe_fn)]
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
pub unsafe fn tcb_activate(tcb: &RtTcb, tls_end_and_tcb_start: usize, _tls_len: usize) {
|
||||||
|
let mut env = syscall::EnvRegisters::default();
|
||||||
|
|
||||||
|
let file = tcb
|
||||||
|
.thread_fd()
|
||||||
|
.dup(b"regs/env")
|
||||||
|
.expect_notls("failed to open handle for process registers");
|
||||||
|
|
||||||
|
file.read(&mut env).expect_notls("failed to read fsbase");
|
||||||
|
|
||||||
|
env.fsbase = tls_end_and_tcb_start as u64;
|
||||||
|
|
||||||
|
file.write(&env).expect_notls("failed to write fsbase");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// OS and architecture specific code to activate TLS - Redox riscv64
|
||||||
|
#[allow(unsafe_op_in_unsafe_fn)]
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub unsafe fn tcb_activate(_tcb: &RtTcb, tls_end: usize, tls_len: usize) {
|
||||||
|
// tp points to static tls block
|
||||||
|
// FIXME limited to a single initial master
|
||||||
|
let tls_start = tls_end - tls_len;
|
||||||
|
let abi_ptr = tls_start - 8;
|
||||||
|
core::ptr::write(abi_ptr as *mut usize, tls_end);
|
||||||
|
core::arch::asm!(
|
||||||
|
"mv tp, {}",
|
||||||
|
in(reg) tls_start
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize redox-rt in situations where relibc is not used
|
||||||
|
#[allow(unsafe_op_in_unsafe_fn)]
|
||||||
|
#[cfg(not(feature = "proc"))]
|
||||||
|
pub unsafe fn initialize_freestanding(this_thr_fd: FdGuardUpper) -> &'static FdGuardUpper {
|
||||||
|
// TODO: This code is a hack! Integrate the ld_so TCB code into generic-rt, and then use that
|
||||||
|
// (this function will need pointers to the ELF structs normally passed in auxvs), so the TCB
|
||||||
|
// is initialized properly.
|
||||||
|
|
||||||
|
// TODO: TLS
|
||||||
|
let page = {
|
||||||
|
&mut *(syscall::fmap(
|
||||||
|
!0,
|
||||||
|
&syscall::Map {
|
||||||
|
offset: 0,
|
||||||
|
size: syscall::PAGE_SIZE,
|
||||||
|
flags: syscall::MapFlags::PROT_READ
|
||||||
|
| syscall::MapFlags::PROT_WRITE
|
||||||
|
| syscall::MapFlags::MAP_PRIVATE,
|
||||||
|
address: 0,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap() as *mut Tcb)
|
||||||
|
};
|
||||||
|
page.tcb_ptr = page;
|
||||||
|
page.tcb_len = syscall::PAGE_SIZE;
|
||||||
|
page.tls_end = (page as *mut Tcb).cast();
|
||||||
|
|
||||||
|
// Make sure to use ptr::write to prevent dropping the existing FdGuard
|
||||||
|
page.os_specific.thr_fd.get().write(Some(this_thr_fd));
|
||||||
|
|
||||||
|
#[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))]
|
||||||
|
unsafe {
|
||||||
|
let tcb_addr = page as *mut Tcb as usize;
|
||||||
|
tcb_activate(&page.os_specific, tcb_addr, 0)
|
||||||
|
}
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
unsafe {
|
||||||
|
let abi_ptr = core::ptr::addr_of_mut!(page.tcb_ptr);
|
||||||
|
core::arch::asm!("msr tpidr_el0, {}", in(reg) abi_ptr);
|
||||||
|
}
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
unsafe {
|
||||||
|
let abi_ptr = core::ptr::addr_of_mut!(page.tcb_ptr) as usize;
|
||||||
|
core::arch::asm!("mv tp, {}", in(reg) (abi_ptr + 8));
|
||||||
|
}
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
(*page.os_specific.thr_fd.get()).as_ref().unwrap()
|
||||||
|
}
|
||||||
|
pub(crate) fn read_proc_meta(proc: &FdGuardUpper) -> syscall::Result<ProcMeta> {
|
||||||
|
let mut bytes = [0_u8; size_of::<ProcMeta>()];
|
||||||
|
proc.read(&mut bytes)?;
|
||||||
|
Ok(*plain::from_bytes::<ProcMeta>(&bytes).unwrap())
|
||||||
|
}
|
||||||
|
pub unsafe fn initialize(
|
||||||
|
#[cfg(feature = "proc")] proc_fd: FdGuardUpper,
|
||||||
|
#[cfg(feature = "proc")] ns_fd: Option<FdGuardUpper>,
|
||||||
|
) {
|
||||||
|
#[cfg(feature = "proc")]
|
||||||
|
let metadata = read_proc_meta(&proc_fd).unwrap();
|
||||||
|
|
||||||
|
#[cfg(not(feature = "proc"))]
|
||||||
|
// Bootstrap mode, don't associate proc fds with PIDs
|
||||||
|
let metadata = ProcMeta::default();
|
||||||
|
|
||||||
|
#[cfg(feature = "proc")]
|
||||||
|
{
|
||||||
|
unsafe { crate::arch::PROC_FD.get().write(proc_fd.as_raw_fd()) };
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
STATIC_PROC_INFO.get().write(StaticProcInfo {
|
||||||
|
pid: metadata.pid,
|
||||||
|
|
||||||
|
#[cfg(feature = "proc")]
|
||||||
|
proc_fd: Some(proc_fd),
|
||||||
|
|
||||||
|
#[cfg(not(feature = "proc"))]
|
||||||
|
proc_fd: None,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "proc")]
|
||||||
|
{
|
||||||
|
*DYNAMIC_PROC_INFO.lock() = DynamicProcInfo {
|
||||||
|
pgid: metadata.pgid,
|
||||||
|
ruid: metadata.ruid,
|
||||||
|
euid: metadata.euid,
|
||||||
|
suid: metadata.suid,
|
||||||
|
egid: metadata.egid,
|
||||||
|
rgid: metadata.rgid,
|
||||||
|
sgid: metadata.sgid,
|
||||||
|
ns_fd,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct StaticProcInfo {
|
||||||
|
pid: u32,
|
||||||
|
proc_fd: Option<FdGuardUpper>,
|
||||||
|
}
|
||||||
|
pub struct DynamicProcInfo {
|
||||||
|
pub pgid: u32,
|
||||||
|
pub euid: u32,
|
||||||
|
pub suid: u32,
|
||||||
|
pub ruid: u32,
|
||||||
|
pub egid: u32,
|
||||||
|
pub rgid: u32,
|
||||||
|
pub sgid: u32,
|
||||||
|
pub ns_fd: Option<FdGuardUpper>,
|
||||||
|
}
|
||||||
|
|
||||||
|
static DYNAMIC_PROC_INFO: Mutex<DynamicProcInfo> = Mutex::new(DynamicProcInfo {
|
||||||
|
pgid: u32::MAX,
|
||||||
|
ruid: u32::MAX,
|
||||||
|
euid: u32::MAX,
|
||||||
|
suid: u32::MAX,
|
||||||
|
rgid: u32::MAX,
|
||||||
|
egid: u32::MAX,
|
||||||
|
sgid: u32::MAX,
|
||||||
|
ns_fd: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn static_proc_info() -> &'static StaticProcInfo {
|
||||||
|
unsafe { &*STATIC_PROC_INFO.get() }
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn current_proc_fd() -> &'static FdGuardUpper {
|
||||||
|
let info = static_proc_info();
|
||||||
|
info.proc_fd.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn current_namespace_fd() -> syscall::Result<usize> {
|
||||||
|
DYNAMIC_PROC_INFO
|
||||||
|
.lock()
|
||||||
|
.ns_fd
|
||||||
|
.as_ref()
|
||||||
|
.map(|g| g.as_raw_fd())
|
||||||
|
.ok_or(syscall::Error::new(syscall::ENOENT))
|
||||||
|
}
|
||||||
|
struct ChildHookCommonArgs {
|
||||||
|
new_thr_fd: FdGuard,
|
||||||
|
new_proc_fd: Option<FdGuard>,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn child_hook_common(args: ChildHookCommonArgs) {
|
||||||
|
let new_thr_fd = args.new_thr_fd.to_upper().unwrap();
|
||||||
|
let new_proc_fd = args.new_proc_fd.map(|x| x.to_upper().unwrap());
|
||||||
|
|
||||||
|
// TODO: just pass PID to child rather than obtaining it via IPC?
|
||||||
|
#[cfg(feature = "proc")]
|
||||||
|
let metadata = read_proc_meta(
|
||||||
|
new_proc_fd
|
||||||
|
.as_ref()
|
||||||
|
.expect("must be present with proc feature"),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
#[cfg(not(feature = "proc"))]
|
||||||
|
let metadata = ProcMeta::default();
|
||||||
|
|
||||||
|
if let Some(proc_fd) = &new_proc_fd {
|
||||||
|
unsafe { crate::arch::PROC_FD.get().write(proc_fd.as_raw_fd()) };
|
||||||
|
}
|
||||||
|
|
||||||
|
let old_proc_fd = unsafe {
|
||||||
|
STATIC_PROC_INFO
|
||||||
|
.get()
|
||||||
|
.replace(StaticProcInfo {
|
||||||
|
pid: metadata.pid,
|
||||||
|
proc_fd: new_proc_fd,
|
||||||
|
})
|
||||||
|
.proc_fd
|
||||||
|
};
|
||||||
|
drop(old_proc_fd);
|
||||||
|
|
||||||
|
let old_thr_fd = unsafe { RtTcb::current().thr_fd.get().replace(Some(new_thr_fd)) };
|
||||||
|
drop(old_thr_fd);
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,68 @@
|
|||||||
|
// TODO: Share code for simple futex-based mutex between relibc's Mutex<()> and this.
|
||||||
|
|
||||||
|
use core::{
|
||||||
|
cell::UnsafeCell,
|
||||||
|
ops::{Deref, DerefMut},
|
||||||
|
sync::atomic::{AtomicU32, Ordering},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Mutex<T> {
|
||||||
|
pub lockword: AtomicU32,
|
||||||
|
pub inner: UnsafeCell<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T: Send> Send for Mutex<T> {}
|
||||||
|
unsafe impl<T: Send> Sync for Mutex<T> {}
|
||||||
|
|
||||||
|
impl<T> Mutex<T> {
|
||||||
|
/// Represents an unlocked [Mutex].
|
||||||
|
pub const UNLOCKED: u32 = 0;
|
||||||
|
/// Represents a locked [Mutex].
|
||||||
|
pub const LOCKED: u32 = 1;
|
||||||
|
/// Represents a waiting [Mutex].
|
||||||
|
pub const WAITING: u32 = 2;
|
||||||
|
|
||||||
|
pub const fn new(t: T) -> Self {
|
||||||
|
Self {
|
||||||
|
lockword: AtomicU32::new(0),
|
||||||
|
inner: UnsafeCell::new(t),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn lock(&self) -> MutexGuard<'_, T> {
|
||||||
|
while self
|
||||||
|
.lockword
|
||||||
|
.compare_exchange(
|
||||||
|
Self::UNLOCKED,
|
||||||
|
Self::LOCKED,
|
||||||
|
Ordering::Acquire,
|
||||||
|
Ordering::Relaxed,
|
||||||
|
)
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
core::hint::spin_loop();
|
||||||
|
}
|
||||||
|
MutexGuard { lock: self }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub struct MutexGuard<'l, T> {
|
||||||
|
lock: &'l Mutex<T>,
|
||||||
|
}
|
||||||
|
impl<T> Deref for MutexGuard<'_, T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &T {
|
||||||
|
unsafe { &*self.lock.inner.get() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> DerefMut for MutexGuard<'_, T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut T {
|
||||||
|
unsafe { &mut *self.lock.inner.get() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> Drop for MutexGuard<'_, T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.lock
|
||||||
|
.lockword
|
||||||
|
.store(Mutex::<T>::UNLOCKED, Ordering::Release);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,569 @@
|
|||||||
|
use core::{
|
||||||
|
mem::{replace, size_of},
|
||||||
|
ptr::addr_of,
|
||||||
|
sync::atomic::{AtomicU32, Ordering},
|
||||||
|
};
|
||||||
|
|
||||||
|
use ioslice::IoSlice;
|
||||||
|
use syscall::{
|
||||||
|
CallFlags, EINVAL, ERESTART, StdFsCallKind, TimeSpec,
|
||||||
|
data::StdFsCallMeta,
|
||||||
|
error::{self, EINTR, ENODEV, ESRCH, Error, Result},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
DYNAMIC_PROC_INFO, DynamicProcInfo, RtTcb, Tcb,
|
||||||
|
arch::manually_enter_trampoline,
|
||||||
|
proc::{FdGuard, FdGuardUpper},
|
||||||
|
read_proc_meta,
|
||||||
|
signal::tmp_disable_signals,
|
||||||
|
};
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use redox_protocols::protocol::{
|
||||||
|
NsDup, ProcCall, ProcKillTarget, RtSigInfo, ThreadCall, WaitFlags,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn wrapper<T>(restart: bool, erestart: bool, mut f: impl FnMut() -> Result<T>) -> Result<T> {
|
||||||
|
loop {
|
||||||
|
let _guard = tmp_disable_signals();
|
||||||
|
let rt_sigarea = unsafe { &Tcb::current().unwrap().os_specific };
|
||||||
|
let res = f();
|
||||||
|
let code = if erestart { ERESTART } else { EINTR };
|
||||||
|
|
||||||
|
if let Err(err) = res
|
||||||
|
&& err == Error::new(code)
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
manually_enter_trampoline();
|
||||||
|
}
|
||||||
|
if restart && unsafe { (*rt_sigarea.arch.get()).last_sig_was_restart } {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: uninitialized memory?
|
||||||
|
#[inline]
|
||||||
|
pub fn posix_read(fd: usize, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
wrapper(true, false, || syscall::read(fd, buf))
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn posix_write(fd: usize, buf: &[u8]) -> Result<usize> {
|
||||||
|
wrapper(true, false, || syscall::write(fd, buf))
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn posix_kill(target: ProcKillTarget, sig: usize) -> Result<()> {
|
||||||
|
if sig > 64 {
|
||||||
|
return Err(Error::new(EINVAL));
|
||||||
|
}
|
||||||
|
|
||||||
|
match wrapper(false, true, || {
|
||||||
|
this_proc_call(
|
||||||
|
&mut [],
|
||||||
|
CallFlags::empty(),
|
||||||
|
&[ProcCall::Kill as u64, target.raw() as u64, sig as u64],
|
||||||
|
)
|
||||||
|
}) {
|
||||||
|
Ok(_) | Err(Error { errno: ERESTART }) => Ok(()),
|
||||||
|
Err(error) => Err(error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn posix_sigqueue(pid: usize, sig: usize, arg: usize) -> Result<()> {
|
||||||
|
let target = ProcKillTarget::from_raw(pid);
|
||||||
|
if !matches!(target, ProcKillTarget::SingleProc(_)) {
|
||||||
|
return Err(Error::new(ESRCH));
|
||||||
|
}
|
||||||
|
if sig <= 32 {
|
||||||
|
return posix_kill(target, sig);
|
||||||
|
}
|
||||||
|
let mut siginf = RtSigInfo {
|
||||||
|
arg,
|
||||||
|
code: -1, // TODO: SI_QUEUE constant
|
||||||
|
uid: 0, // TODO
|
||||||
|
pid: posix_getpid(),
|
||||||
|
};
|
||||||
|
match wrapper(false, true, || {
|
||||||
|
this_proc_call(
|
||||||
|
unsafe { plain::as_mut_bytes(&mut siginf) },
|
||||||
|
CallFlags::empty(),
|
||||||
|
&[ProcCall::Sigq as u64, pid as u64, sig as u64],
|
||||||
|
)
|
||||||
|
}) {
|
||||||
|
Ok(_)
|
||||||
|
| Err(Error {
|
||||||
|
errno: error::ERESTART,
|
||||||
|
}) => Ok(()),
|
||||||
|
Err(error) => Err(error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn posix_getpid() -> u32 {
|
||||||
|
// SAFETY: read-only except during program/fork child initialization
|
||||||
|
unsafe { addr_of!((*crate::STATIC_PROC_INFO.get()).pid).read() }
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn posix_getppid() -> u32 {
|
||||||
|
this_proc_call(&mut [], CallFlags::empty(), &[ProcCall::Getppid as u64]).expect("cannot fail")
|
||||||
|
as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn posix_setpriority(which: i32, who: u32, prio: u32) -> Result<(), syscall::Error> {
|
||||||
|
if which != 0 {
|
||||||
|
return Err(syscall::Error::new(syscall::EINVAL)); // TODO: Add support for PRIO_PGRP and PRIO_PROCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
this_proc_call(
|
||||||
|
&mut [],
|
||||||
|
CallFlags::empty(),
|
||||||
|
&[ProcCall::SetProcPriority as u64, who as u64, prio as u64],
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn posix_getpriority(which: i32, who: u32) -> Result<u32, syscall::Error> {
|
||||||
|
if which != 0 {
|
||||||
|
return Err(syscall::Error::new(syscall::EINVAL));
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = this_proc_call(
|
||||||
|
&mut [],
|
||||||
|
CallFlags::empty(),
|
||||||
|
&[ProcCall::GetProcPriority as u64, who as u64],
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(res as u32)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn sys_futex_wait(addr: *mut u32, val: u32, deadline: Option<&TimeSpec>) -> Result<()> {
|
||||||
|
wrapper(true, false, || {
|
||||||
|
unsafe {
|
||||||
|
syscall::syscall5(
|
||||||
|
syscall::SYS_FUTEX,
|
||||||
|
addr as usize,
|
||||||
|
syscall::FUTEX_WAIT,
|
||||||
|
val as usize,
|
||||||
|
deadline.map_or(0, |d| d as *const _ as usize),
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.map(|_| ())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn sys_futex_wake(addr: *mut u32, num: u32) -> Result<u32> {
|
||||||
|
unsafe {
|
||||||
|
syscall::syscall5(
|
||||||
|
syscall::SYS_FUTEX,
|
||||||
|
addr as usize,
|
||||||
|
syscall::FUTEX_WAKE,
|
||||||
|
num as usize,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.map(|awoken| awoken as u32)
|
||||||
|
}
|
||||||
|
unsafe fn raw_sys_call(
|
||||||
|
fd: usize,
|
||||||
|
payload_ptr: *const u8,
|
||||||
|
len: usize,
|
||||||
|
flags: CallFlags,
|
||||||
|
metadata: &[u64],
|
||||||
|
) -> Result<usize> {
|
||||||
|
unsafe {
|
||||||
|
syscall::syscall5(
|
||||||
|
syscall::SYS_CALL,
|
||||||
|
fd,
|
||||||
|
payload_ptr as usize,
|
||||||
|
len,
|
||||||
|
metadata.len() | flags.bits(),
|
||||||
|
metadata.as_ptr() as usize,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn sys_call_ro(
|
||||||
|
fd: usize,
|
||||||
|
payload: &mut [u8],
|
||||||
|
flags: CallFlags,
|
||||||
|
metadata: &[u64],
|
||||||
|
) -> Result<usize> {
|
||||||
|
unsafe {
|
||||||
|
raw_sys_call(
|
||||||
|
fd,
|
||||||
|
payload.as_mut_ptr(),
|
||||||
|
payload.len(),
|
||||||
|
flags | CallFlags::READ,
|
||||||
|
metadata,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn sys_call_wo(fd: usize, payload: &[u8], flags: CallFlags, metadata: &[u64]) -> Result<usize> {
|
||||||
|
unsafe {
|
||||||
|
raw_sys_call(
|
||||||
|
fd,
|
||||||
|
payload.as_ptr(),
|
||||||
|
payload.len(),
|
||||||
|
flags | CallFlags::WRITE,
|
||||||
|
metadata,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn sys_call_rw(
|
||||||
|
fd: usize,
|
||||||
|
payload: &mut [u8],
|
||||||
|
flags: CallFlags,
|
||||||
|
metadata: &[u64],
|
||||||
|
) -> Result<usize> {
|
||||||
|
unsafe {
|
||||||
|
raw_sys_call(
|
||||||
|
fd,
|
||||||
|
payload.as_mut_ptr(),
|
||||||
|
payload.len(),
|
||||||
|
flags | CallFlags::READ | CallFlags::WRITE,
|
||||||
|
metadata,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn sys_call(
|
||||||
|
fd: usize,
|
||||||
|
payload: &mut [u8],
|
||||||
|
flags: CallFlags,
|
||||||
|
metadata: &[u64],
|
||||||
|
) -> Result<usize> {
|
||||||
|
unsafe { raw_sys_call(fd, payload.as_mut_ptr(), payload.len(), flags, metadata) }
|
||||||
|
}
|
||||||
|
pub fn this_proc_call(payload: &mut [u8], flags: CallFlags, metadata: &[u64]) -> Result<usize> {
|
||||||
|
proc_call(
|
||||||
|
crate::current_proc_fd().as_raw_fd(),
|
||||||
|
payload,
|
||||||
|
flags,
|
||||||
|
metadata,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn proc_call(
|
||||||
|
proc_fd: usize,
|
||||||
|
payload: &mut [u8],
|
||||||
|
flags: CallFlags,
|
||||||
|
metadata: &[u64],
|
||||||
|
) -> Result<usize> {
|
||||||
|
sys_call(proc_fd, payload, flags, metadata)
|
||||||
|
}
|
||||||
|
pub fn thread_call(
|
||||||
|
thread_fd: usize,
|
||||||
|
payload: &mut [u8],
|
||||||
|
flags: CallFlags,
|
||||||
|
metadata: &[u64],
|
||||||
|
) -> Result<usize> {
|
||||||
|
sys_call(thread_fd, payload, flags, metadata)
|
||||||
|
}
|
||||||
|
pub fn this_thread_call(payload: &mut [u8], flags: CallFlags, metadata: &[u64]) -> Result<usize> {
|
||||||
|
thread_call(
|
||||||
|
RtTcb::current().thread_fd().as_raw_fd(),
|
||||||
|
payload,
|
||||||
|
flags,
|
||||||
|
metadata,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum WaitpidTarget {
|
||||||
|
AnyChild,
|
||||||
|
AnyGroupMember,
|
||||||
|
SingleProc { pid: usize },
|
||||||
|
ProcGroup { pgid: usize },
|
||||||
|
}
|
||||||
|
impl WaitpidTarget {
|
||||||
|
pub fn from_posix_arg(raw: isize) -> Self {
|
||||||
|
match raw {
|
||||||
|
0 => Self::AnyGroupMember,
|
||||||
|
-1 => Self::AnyChild,
|
||||||
|
1.. => Self::SingleProc { pid: raw as usize },
|
||||||
|
..-1 => Self::ProcGroup {
|
||||||
|
pgid: -raw as usize,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_waitpid(target: WaitpidTarget, status: &mut usize, flags: WaitFlags) -> Result<usize> {
|
||||||
|
let (call, pid) = match target {
|
||||||
|
WaitpidTarget::AnyChild => (ProcCall::Waitpid, 0),
|
||||||
|
WaitpidTarget::SingleProc { pid } => (ProcCall::Waitpid, pid),
|
||||||
|
WaitpidTarget::AnyGroupMember => (ProcCall::Waitpgid, 0),
|
||||||
|
WaitpidTarget::ProcGroup { pgid } => (ProcCall::Waitpgid, pgid),
|
||||||
|
};
|
||||||
|
wrapper(true, false, || {
|
||||||
|
this_proc_call(
|
||||||
|
unsafe { plain::as_mut_bytes(status) },
|
||||||
|
CallFlags::empty(),
|
||||||
|
&[call as u64, pid as u64, flags.bits() as u64],
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn posix_kill_thread(thread_fd: usize, signal: u32) -> Result<()> {
|
||||||
|
// TODO: don't hardcode?
|
||||||
|
if signal > 64 {
|
||||||
|
return Err(Error::new(EINVAL));
|
||||||
|
}
|
||||||
|
|
||||||
|
match wrapper(false, true, || {
|
||||||
|
thread_call(
|
||||||
|
thread_fd,
|
||||||
|
&mut [],
|
||||||
|
CallFlags::empty(),
|
||||||
|
&[ThreadCall::SignalThread as u64, signal.into()],
|
||||||
|
)
|
||||||
|
}) {
|
||||||
|
Ok(_) | Err(Error { errno: ERESTART }) => Ok(()),
|
||||||
|
Err(error) => Err(error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static UMASK: AtomicU32 = AtomicU32::new(0o022);
|
||||||
|
|
||||||
|
/// Controls the set of bits removed from the `mode` mask when new file descriptors are created.
|
||||||
|
///
|
||||||
|
/// Must be validated by the caller
|
||||||
|
//
|
||||||
|
// TODO: validate here?
|
||||||
|
#[inline]
|
||||||
|
pub fn swap_umask(mask: u32) -> u32 {
|
||||||
|
UMASK.swap(mask, Ordering::AcqRel)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_umask() -> u32 {
|
||||||
|
UMASK.load(Ordering::Acquire)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Real/Effective/Set-User/Group ID
|
||||||
|
pub struct Resugid<T> {
|
||||||
|
pub ruid: T,
|
||||||
|
pub euid: T,
|
||||||
|
pub suid: T,
|
||||||
|
pub rgid: T,
|
||||||
|
pub egid: T,
|
||||||
|
pub sgid: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets [res][ug]id, fields that are None will be unchanged.
|
||||||
|
pub fn posix_setresugid(ids: &Resugid<Option<u32>>) -> Result<()> {
|
||||||
|
// TODO: not sure how "tmp" an IPC call is?
|
||||||
|
let _sig_guard = tmp_disable_signals();
|
||||||
|
let mut guard = DYNAMIC_PROC_INFO.lock();
|
||||||
|
|
||||||
|
let mut buf = [0_u8; size_of::<u32>() * 6];
|
||||||
|
plain::slice_from_mut_bytes(&mut buf)
|
||||||
|
.unwrap()
|
||||||
|
.copy_from_slice(&[
|
||||||
|
ids.ruid.unwrap_or(u32::MAX),
|
||||||
|
ids.euid.unwrap_or(u32::MAX),
|
||||||
|
ids.suid.unwrap_or(u32::MAX),
|
||||||
|
ids.rgid.unwrap_or(u32::MAX),
|
||||||
|
ids.egid.unwrap_or(u32::MAX),
|
||||||
|
ids.sgid.unwrap_or(u32::MAX),
|
||||||
|
]);
|
||||||
|
|
||||||
|
this_proc_call(&mut buf, CallFlags::empty(), &[ProcCall::SetResugid as u64])?;
|
||||||
|
|
||||||
|
if let Some(ruid) = ids.ruid {
|
||||||
|
guard.ruid = ruid;
|
||||||
|
}
|
||||||
|
if let Some(euid) = ids.euid {
|
||||||
|
guard.euid = euid;
|
||||||
|
}
|
||||||
|
if let Some(suid) = ids.suid {
|
||||||
|
guard.suid = suid;
|
||||||
|
}
|
||||||
|
if let Some(rgid) = ids.rgid {
|
||||||
|
guard.rgid = rgid;
|
||||||
|
}
|
||||||
|
if let Some(egid) = ids.egid {
|
||||||
|
guard.egid = egid;
|
||||||
|
}
|
||||||
|
if let Some(sgid) = ids.sgid {
|
||||||
|
guard.sgid = sgid;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn posix_getresugid() -> Resugid<u32> {
|
||||||
|
let _sig_guard = tmp_disable_signals();
|
||||||
|
let DynamicProcInfo {
|
||||||
|
ruid,
|
||||||
|
euid,
|
||||||
|
suid,
|
||||||
|
rgid,
|
||||||
|
egid,
|
||||||
|
sgid,
|
||||||
|
..
|
||||||
|
} = *DYNAMIC_PROC_INFO.lock();
|
||||||
|
Resugid {
|
||||||
|
ruid,
|
||||||
|
euid,
|
||||||
|
suid,
|
||||||
|
rgid,
|
||||||
|
egid,
|
||||||
|
sgid,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn getens() -> Result<usize> {
|
||||||
|
read_proc_meta(crate::current_proc_fd()).map(|meta| meta.ens as usize)
|
||||||
|
}
|
||||||
|
pub fn get_proc_credentials(cap_fd: usize, target_pid: usize, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
if buf.len() < size_of::<redox_protocols::protocol::ProcMeta>() {
|
||||||
|
return Err(Error::new(EINVAL));
|
||||||
|
}
|
||||||
|
proc_call(
|
||||||
|
cap_fd,
|
||||||
|
buf,
|
||||||
|
CallFlags::empty(),
|
||||||
|
&[ProcCall::GetProcCredentials as u64, target_pid as u64],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn posix_exit(status: i32) -> ! {
|
||||||
|
this_proc_call(
|
||||||
|
&mut [],
|
||||||
|
CallFlags::empty(),
|
||||||
|
&[ProcCall::Exit as u64, (status & 0xFF) as u64],
|
||||||
|
)
|
||||||
|
.expect("failed to call proc mgr with Exit");
|
||||||
|
let _ = syscall::write(1, b"redox-rt: ProcCall::Exit FAILED, abort()ing!\n");
|
||||||
|
core::intrinsics::abort();
|
||||||
|
}
|
||||||
|
pub fn posix_getpgid(pid: usize) -> Result<usize> {
|
||||||
|
this_proc_call(
|
||||||
|
&mut [],
|
||||||
|
CallFlags::empty(),
|
||||||
|
&[ProcCall::Setpgid as u64, pid as u64, u64::wrapping_neg(1)],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn posix_setpgid(pid: usize, pgid: usize) -> Result<()> {
|
||||||
|
if pgid == usize::wrapping_neg(1) {
|
||||||
|
return Err(Error::new(EINVAL));
|
||||||
|
}
|
||||||
|
this_proc_call(
|
||||||
|
&mut [],
|
||||||
|
CallFlags::empty(),
|
||||||
|
&[ProcCall::Setpgid as u64, pid as u64, pgid as u64],
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn posix_getsid(pid: usize) -> Result<usize> {
|
||||||
|
this_proc_call(
|
||||||
|
&mut [],
|
||||||
|
CallFlags::empty(),
|
||||||
|
&[ProcCall::Getsid as u64, pid as u64],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn posix_setsid() -> Result<u32> {
|
||||||
|
this_proc_call(&mut [], CallFlags::empty(), &[ProcCall::Setsid as u64])?;
|
||||||
|
Ok(posix_getpid())
|
||||||
|
}
|
||||||
|
pub fn posix_nanosleep(rqtp: &TimeSpec, rmtp: &mut TimeSpec) -> Result<()> {
|
||||||
|
wrapper(false, false, || syscall::nanosleep(rqtp, rmtp))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn setns(fd: usize) -> Option<FdGuardUpper> {
|
||||||
|
let mut info = DYNAMIC_PROC_INFO.lock();
|
||||||
|
let new_fd_guard = FdGuard::new(fd).to_upper().unwrap();
|
||||||
|
let old_fd_guard = replace(&mut info.ns_fd, Some(new_fd_guard));
|
||||||
|
old_fd_guard
|
||||||
|
}
|
||||||
|
pub fn getns() -> Result<usize> {
|
||||||
|
let cur_ns = crate::current_namespace_fd()?;
|
||||||
|
if cur_ns == usize::MAX {
|
||||||
|
Err(Error::new(ENODEV))
|
||||||
|
} else {
|
||||||
|
Ok(cur_ns)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn open<T: AsRef<str>>(path: T, flags: usize) -> Result<usize> {
|
||||||
|
let path = path.as_ref();
|
||||||
|
let fcntl_flags = flags & syscall::O_FCNTL_MASK;
|
||||||
|
unsafe {
|
||||||
|
syscall::syscall5(
|
||||||
|
syscall::SYS_OPENAT,
|
||||||
|
crate::current_namespace_fd()?,
|
||||||
|
path.as_ptr() as usize,
|
||||||
|
path.len(),
|
||||||
|
flags,
|
||||||
|
fcntl_flags,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn openat<T: AsRef<str>>(
|
||||||
|
fd: usize,
|
||||||
|
path: T,
|
||||||
|
flags: usize,
|
||||||
|
fcntl_flags: usize,
|
||||||
|
) -> Result<usize> {
|
||||||
|
let path = path.as_ref();
|
||||||
|
unsafe {
|
||||||
|
syscall::syscall5(
|
||||||
|
syscall::SYS_OPENAT,
|
||||||
|
fd,
|
||||||
|
path.as_ptr() as usize,
|
||||||
|
path.len(),
|
||||||
|
flags,
|
||||||
|
fcntl_flags,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn unlink<T: AsRef<str>>(path: T, flags: usize) -> Result<usize> {
|
||||||
|
let path = path.as_ref();
|
||||||
|
unsafe {
|
||||||
|
syscall::syscall4(
|
||||||
|
syscall::SYS_UNLINKAT,
|
||||||
|
crate::current_namespace_fd()?,
|
||||||
|
path.as_ptr() as usize,
|
||||||
|
path.len(),
|
||||||
|
flags,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn mkns(names: &[IoSlice]) -> Result<FdGuardUpper> {
|
||||||
|
let mut buf = Vec::from((NsDup::ForkNs as usize).to_ne_bytes());
|
||||||
|
for name in names {
|
||||||
|
let name_bytes = name.as_slice();
|
||||||
|
let len = name_bytes.len();
|
||||||
|
let _scheme_name = core::str::from_utf8(name_bytes).map_err(|_| Error::new(EINVAL))?;
|
||||||
|
buf.extend_from_slice(&len.to_ne_bytes());
|
||||||
|
buf.extend_from_slice(name_bytes);
|
||||||
|
}
|
||||||
|
FdGuard::new(syscall::dup(crate::current_namespace_fd()?, &buf)?).to_upper()
|
||||||
|
}
|
||||||
|
pub fn register_scheme_to_ns(ns_fd: usize, name: &str, cap_fd: usize) -> Result<()> {
|
||||||
|
let mut buf = alloc::vec::Vec::from((NsDup::IssueRegister as usize).to_ne_bytes());
|
||||||
|
buf.extend_from_slice(name.as_bytes());
|
||||||
|
let ns_this_scheme = FdGuard::new(syscall::dup(ns_fd, &buf)?);
|
||||||
|
let cap_bytes = cap_fd.to_ne_bytes();
|
||||||
|
ns_this_scheme.call_wo(&cap_bytes, CallFlags::FD, &[])?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn std_fs_call_ro(fd: usize, payload: &mut [u8], metadata: &StdFsCallMeta) -> Result<usize> {
|
||||||
|
sys_call_ro(fd, payload, CallFlags::STD_FS, metadata)
|
||||||
|
}
|
||||||
|
pub fn std_fs_call_wo(fd: usize, payload: &[u8], metadata: &StdFsCallMeta) -> Result<usize> {
|
||||||
|
sys_call_wo(fd, payload, CallFlags::STD_FS, metadata)
|
||||||
|
}
|
||||||
|
pub fn std_fs_call_rw(fd: usize, payload: &mut [u8], metadata: &StdFsCallMeta) -> Result<usize> {
|
||||||
|
sys_call_rw(fd, payload, CallFlags::STD_FS, metadata)
|
||||||
|
}
|
||||||
|
pub fn fstat(fd: usize, stat: &mut syscall::Stat) -> Result<usize> {
|
||||||
|
std_fs_call_ro(fd, stat, &StdFsCallMeta::new(StdFsCallKind::Fstat, 0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fcntl(fd: usize, cmd: usize, arg: usize) -> Result<usize> {
|
||||||
|
let _siglock = tmp_disable_signals();
|
||||||
|
let raw_fd = syscall::fcntl(fd, cmd, arg)?;
|
||||||
|
Ok(FdGuard::new(raw_fd).as_raw_fd())
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
use core::mem::size_of;
|
||||||
|
|
||||||
|
use syscall::Result;
|
||||||
|
|
||||||
|
use crate::{RtTcb, arch::*, proc::*, signal::tmp_disable_signals, static_proc_info};
|
||||||
|
|
||||||
|
/// Spawns a new context sharing the same address space as the current one (i.e. a new thread).
|
||||||
|
pub unsafe fn rlct_clone_impl(stack: *mut usize, tcb: &RtTcb) -> Result<usize> {
|
||||||
|
let proc_info = static_proc_info();
|
||||||
|
let cur_proc_fd = proc_info.proc_fd.as_ref().unwrap();
|
||||||
|
|
||||||
|
let cur_thr_fd = RtTcb::current().thread_fd();
|
||||||
|
let new_thr_fd = cur_proc_fd.dup(b"new-thread")?.to_upper().unwrap();
|
||||||
|
|
||||||
|
// Inherit existing address space
|
||||||
|
{
|
||||||
|
let cur_addr_space_fd = cur_thr_fd.dup(b"addrspace")?;
|
||||||
|
let new_addr_space_sel_fd = new_thr_fd.dup(b"current-addrspace")?;
|
||||||
|
|
||||||
|
let buf = create_set_addr_space_buf(
|
||||||
|
cur_addr_space_fd.as_raw_fd(),
|
||||||
|
__relibc_internal_rlct_clone_ret as *const () as usize,
|
||||||
|
stack as usize,
|
||||||
|
);
|
||||||
|
new_addr_space_sel_fd.write(&buf)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inherit reference to file table
|
||||||
|
{
|
||||||
|
let cur_filetable_fd = cur_thr_fd.dup(b"filetable")?;
|
||||||
|
let new_filetable_sel_fd = new_thr_fd.dup(b"current-filetable")?;
|
||||||
|
|
||||||
|
new_filetable_sel_fd.write(&usize::to_ne_bytes(cur_filetable_fd.as_raw_fd()))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since the signal handler is not yet initialized, signals specifically targeting the thread
|
||||||
|
// (relibc is only required to implement thread-specific signals that already originate from
|
||||||
|
// the same process) will be discarded. Process-specific signals will ignore this new thread,
|
||||||
|
// until it has initialized its own signal handler.
|
||||||
|
|
||||||
|
let start_fd = new_thr_fd.dup(b"start")?;
|
||||||
|
|
||||||
|
let fd = new_thr_fd.as_raw_fd();
|
||||||
|
unsafe {
|
||||||
|
tcb.thr_fd.get().write(Some(new_thr_fd));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unblock context.
|
||||||
|
start_fd.write(&[0])?;
|
||||||
|
|
||||||
|
Ok(fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn exit_this_thread(stack_base: *mut (), stack_size: usize) -> ! {
|
||||||
|
let _guard = tmp_disable_signals();
|
||||||
|
|
||||||
|
let tcb = RtTcb::current();
|
||||||
|
// TODO: modify interface so it writes directly to the thread fd?
|
||||||
|
let status_fd = tcb.thread_fd().dup(b"status").unwrap();
|
||||||
|
|
||||||
|
let _ = unsafe { syscall::funmap(tcb as *const RtTcb as usize, syscall::PAGE_SIZE) };
|
||||||
|
|
||||||
|
let mut buf = [0; size_of::<usize>() * 3];
|
||||||
|
plain::slice_from_mut_bytes(&mut buf)
|
||||||
|
.unwrap()
|
||||||
|
.copy_from_slice(&[usize::MAX, stack_base as usize, stack_size]);
|
||||||
|
// TODO: SYS_CALL w/CONSUME
|
||||||
|
status_fd.write(&buf).unwrap();
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
Executable
+58
@@ -0,0 +1,58 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
target=$1
|
||||||
|
deps_dir=$2
|
||||||
|
|
||||||
|
if [ -z "$target" ] || [ -z "$deps_dir" ]; then
|
||||||
|
echo "Usage:\n\t./renamesyms.sh TARGET DEPS_DIR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$target" ]; then
|
||||||
|
echo "Target file '$target' does not exist"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ ! -d "$deps_dir" ] ; then
|
||||||
|
echo "Deps dir '$deps_dir' does not exist or not a directory"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
symbols_file=`mktemp`
|
||||||
|
special_syms=(
|
||||||
|
__rdl_oom
|
||||||
|
__rg_alloc
|
||||||
|
__rg_alloc_zeroed
|
||||||
|
__rg_dealloc
|
||||||
|
__rg_oom
|
||||||
|
__rg_realloc
|
||||||
|
__rust_alloc
|
||||||
|
__rust_alloc_error_handler
|
||||||
|
__rust_alloc_error_handler_should_panic
|
||||||
|
__rust_alloc_zeroed
|
||||||
|
__rust_dealloc
|
||||||
|
__rust_no_alloc_shim_is_unstable
|
||||||
|
__rust_realloc
|
||||||
|
)
|
||||||
|
|
||||||
|
for dep in `find $deps_dir -type f -name "*.rlib"`; do
|
||||||
|
"${NM}" --format=posix -g "$dep" 2>/dev/null | sed 's/.*:.*//g' | awk '{if ($2 == "T") print $1}' | sed 's/^\(.*\)$/\1 __relibc_\1/g' >> $symbols_file
|
||||||
|
done
|
||||||
|
|
||||||
|
for special_sym in "${special_syms[@]}"; do
|
||||||
|
echo "$special_sym __relibc_$special_sym" >> $symbols_file
|
||||||
|
done
|
||||||
|
|
||||||
|
mangled_alloc_syms=$("${NM}" --format=posix -g "$target" 2>/dev/null | awk '{print $1}' | grep "7___rustc" || true)
|
||||||
|
for sym in $mangled_alloc_syms; do
|
||||||
|
echo "$sym __relibc_$sym" >> $symbols_file
|
||||||
|
done
|
||||||
|
|
||||||
|
sorted_file=`mktemp`
|
||||||
|
sort -u "$symbols_file" > "$sorted_file"
|
||||||
|
rm -f "$symbols_file"
|
||||||
|
|
||||||
|
"${OBJCOPY}" --redefine-syms="$sorted_file" "$target"
|
||||||
|
|
||||||
|
rm -f "$sorted_file"
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
[toolchain]
|
||||||
|
channel = "nightly-2025-11-15"
|
||||||
|
components = ["rust-src"]
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
blank_lines_lower_bound = 0
|
||||||
|
blank_lines_upper_bound = 1
|
||||||
|
brace_style = "SameLineWhere"
|
||||||
|
disable_all_formatting = false
|
||||||
|
edition = "2024"
|
||||||
|
empty_item_single_line = true
|
||||||
|
fn_single_line = false
|
||||||
|
force_explicit_abi = true
|
||||||
|
format_strings = false
|
||||||
|
hard_tabs = false
|
||||||
|
imports_granularity = "Crate"
|
||||||
|
imports_indent = "Block"
|
||||||
|
imports_layout = "Mixed"
|
||||||
|
indent_style = "Block"
|
||||||
|
max_width = 100
|
||||||
|
newline_style = "Unix"
|
||||||
|
show_parse_errors = true
|
||||||
|
skip_children = false
|
||||||
|
tab_spaces = 4
|
||||||
|
trailing_comma = "Vertical"
|
||||||
|
where_single_line = false
|
||||||
@@ -1,207 +0,0 @@
|
|||||||
use core::{
|
|
||||||
mem,
|
|
||||||
ops::{Deref, DerefMut},
|
|
||||||
slice,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::error::{Error, Result};
|
|
||||||
|
|
||||||
pub const PAGE_SIZE: usize = 4096;
|
|
||||||
/// Size of the metadata region used to transfer information from the kernel to the bootstrapper.
|
|
||||||
pub const KERNEL_METADATA_SIZE: usize = 4 * PAGE_SIZE;
|
|
||||||
|
|
||||||
#[cfg(feature = "userspace")]
|
|
||||||
macro_rules! syscall {
|
|
||||||
($($name:ident($a:ident, $($b:ident, $($c:ident, $($d:ident, $($e:ident, $($f:ident, $($g:ident, )?)?)?)?)?)?);)+) => {
|
|
||||||
$(
|
|
||||||
pub unsafe fn $name($a: usize, $($b: usize, $($c: usize, $($d: usize, $($e: usize, $($f: usize, $($g: usize)?)?)?)?)?)?) -> Result<usize> {
|
|
||||||
let ret: usize;
|
|
||||||
|
|
||||||
core::arch::asm!(
|
|
||||||
"svc 0",
|
|
||||||
in("x8") $a,
|
|
||||||
$(
|
|
||||||
in("x0") $b,
|
|
||||||
$(
|
|
||||||
in("x1") $c,
|
|
||||||
$(
|
|
||||||
in("x2") $d,
|
|
||||||
$(
|
|
||||||
in("x3") $e,
|
|
||||||
$(
|
|
||||||
in("x4") $f,
|
|
||||||
$(
|
|
||||||
in("x5") $g,
|
|
||||||
)?
|
|
||||||
)?
|
|
||||||
)?
|
|
||||||
)?
|
|
||||||
)?
|
|
||||||
)?
|
|
||||||
lateout("x0") ret,
|
|
||||||
options(nostack),
|
|
||||||
);
|
|
||||||
|
|
||||||
Error::demux(ret)
|
|
||||||
}
|
|
||||||
)+
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "userspace")]
|
|
||||||
syscall! {
|
|
||||||
syscall0(a,);
|
|
||||||
syscall1(a, b,);
|
|
||||||
syscall2(a, b, c,);
|
|
||||||
syscall3(a, b, c, d,);
|
|
||||||
syscall4(a, b, c, d, e,);
|
|
||||||
syscall5(a, b, c, d, e, f,);
|
|
||||||
syscall6(a, b, c, d, e, f, g,);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Default)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct IntRegisters {
|
|
||||||
pub x30: usize,
|
|
||||||
pub x29: usize,
|
|
||||||
pub x28: usize,
|
|
||||||
pub x27: usize,
|
|
||||||
pub x26: usize,
|
|
||||||
pub x25: usize,
|
|
||||||
pub x24: usize,
|
|
||||||
pub x23: usize,
|
|
||||||
pub x22: usize,
|
|
||||||
pub x21: usize,
|
|
||||||
pub x20: usize,
|
|
||||||
pub x19: usize,
|
|
||||||
pub x18: usize,
|
|
||||||
pub x17: usize,
|
|
||||||
pub x16: usize,
|
|
||||||
pub x15: usize,
|
|
||||||
pub x14: usize,
|
|
||||||
pub x13: usize,
|
|
||||||
pub x12: usize,
|
|
||||||
pub x11: usize,
|
|
||||||
pub x10: usize,
|
|
||||||
pub x9: usize,
|
|
||||||
pub x8: usize,
|
|
||||||
pub x7: usize,
|
|
||||||
pub x6: usize,
|
|
||||||
pub x5: usize,
|
|
||||||
pub x4: usize,
|
|
||||||
pub x3: usize,
|
|
||||||
pub x2: usize,
|
|
||||||
pub x1: usize,
|
|
||||||
pub x0: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for IntRegisters {
|
|
||||||
type Target = [u8];
|
|
||||||
fn deref(&self) -> &[u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts(
|
|
||||||
self as *const IntRegisters as *const u8,
|
|
||||||
mem::size_of::<IntRegisters>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for IntRegisters {
|
|
||||||
fn deref_mut(&mut self) -> &mut [u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts_mut(
|
|
||||||
self as *mut IntRegisters as *mut u8,
|
|
||||||
mem::size_of::<IntRegisters>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
|
||||||
#[repr(C, packed)]
|
|
||||||
pub struct FloatRegisters {
|
|
||||||
pub fp_simd_regs: [u128; 32],
|
|
||||||
pub fpsr: u32,
|
|
||||||
pub fpcr: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for FloatRegisters {
|
|
||||||
type Target = [u8];
|
|
||||||
fn deref(&self) -> &[u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts(
|
|
||||||
self as *const FloatRegisters as *const u8,
|
|
||||||
mem::size_of::<FloatRegisters>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for FloatRegisters {
|
|
||||||
fn deref_mut(&mut self) -> &mut [u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts_mut(
|
|
||||||
self as *mut FloatRegisters as *mut u8,
|
|
||||||
mem::size_of::<FloatRegisters>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
|
||||||
#[repr(C, packed)]
|
|
||||||
pub struct EnvRegisters {
|
|
||||||
pub tpidr_el0: usize,
|
|
||||||
pub tpidrro_el0: usize,
|
|
||||||
}
|
|
||||||
impl Deref for EnvRegisters {
|
|
||||||
type Target = [u8];
|
|
||||||
fn deref(&self) -> &[u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts(
|
|
||||||
self as *const EnvRegisters as *const u8,
|
|
||||||
mem::size_of::<EnvRegisters>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for EnvRegisters {
|
|
||||||
fn deref_mut(&mut self) -> &mut [u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts_mut(
|
|
||||||
self as *mut EnvRegisters as *mut u8,
|
|
||||||
mem::size_of::<EnvRegisters>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
|
||||||
#[repr(C, packed)]
|
|
||||||
pub struct Exception {
|
|
||||||
pub kind: usize,
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
impl Deref for Exception {
|
|
||||||
type Target = [u8];
|
|
||||||
fn deref(&self) -> &[u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts(
|
|
||||||
self as *const Exception as *const u8,
|
|
||||||
mem::size_of::<Exception>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for Exception {
|
|
||||||
fn deref_mut(&mut self) -> &mut [u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts_mut(
|
|
||||||
self as *mut Exception as *mut u8,
|
|
||||||
mem::size_of::<Exception>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,206 +0,0 @@
|
|||||||
use super::error::{Error, Result};
|
|
||||||
use core::arch::asm;
|
|
||||||
use core::{
|
|
||||||
mem,
|
|
||||||
ops::{Deref, DerefMut},
|
|
||||||
slice,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const PAGE_SIZE: usize = 4096;
|
|
||||||
/// Size of the metadata region used to transfer information from the kernel to the bootstrapper.
|
|
||||||
pub const KERNEL_METADATA_SIZE: usize = 4 * PAGE_SIZE;
|
|
||||||
|
|
||||||
#[cfg(feature = "userspace")]
|
|
||||||
macro_rules! syscall {
|
|
||||||
($($name:ident($a:ident, $($b:ident, $($c:ident, $($d:ident, $($e:ident, $($f:ident, $($g:ident, )?)?)?)?)?)?);)+) => {
|
|
||||||
$(
|
|
||||||
pub unsafe fn $name($a: usize, $($b: usize, $($c: usize, $($d: usize, $($e: usize, $($f: usize, $($g: usize)?)?)?)?)?)?) -> Result<usize> {
|
|
||||||
let ret: usize;
|
|
||||||
|
|
||||||
asm!(
|
|
||||||
"ecall",
|
|
||||||
in("a7") $a,
|
|
||||||
$(
|
|
||||||
in("a0") $b,
|
|
||||||
$(
|
|
||||||
in("a1") $c,
|
|
||||||
$(
|
|
||||||
in("a2") $d,
|
|
||||||
$(
|
|
||||||
in("a3") $e,
|
|
||||||
$(
|
|
||||||
in("a4") $f,
|
|
||||||
$(
|
|
||||||
in("a5") $g,
|
|
||||||
)?
|
|
||||||
)?
|
|
||||||
)?
|
|
||||||
)?
|
|
||||||
)?
|
|
||||||
)?
|
|
||||||
lateout("a0") ret,
|
|
||||||
options(nostack),
|
|
||||||
);
|
|
||||||
|
|
||||||
Error::demux(ret)
|
|
||||||
}
|
|
||||||
)+
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "userspace")]
|
|
||||||
syscall! {
|
|
||||||
syscall0(a,);
|
|
||||||
syscall1(a, b,);
|
|
||||||
syscall2(a, b, c,);
|
|
||||||
syscall3(a, b, c, d,);
|
|
||||||
syscall4(a, b, c, d, e,);
|
|
||||||
syscall5(a, b, c, d, e, f,);
|
|
||||||
syscall6(a, b, c, d, e, f, g,);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Default)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct IntRegisters {
|
|
||||||
pub pc: usize,
|
|
||||||
pub x31: usize,
|
|
||||||
pub x30: usize,
|
|
||||||
pub x29: usize,
|
|
||||||
pub x28: usize,
|
|
||||||
pub x27: usize,
|
|
||||||
pub x26: usize,
|
|
||||||
pub x25: usize,
|
|
||||||
pub x24: usize,
|
|
||||||
pub x23: usize,
|
|
||||||
pub x22: usize,
|
|
||||||
pub x21: usize,
|
|
||||||
pub x20: usize,
|
|
||||||
pub x19: usize,
|
|
||||||
pub x18: usize,
|
|
||||||
pub x17: usize,
|
|
||||||
pub x16: usize,
|
|
||||||
pub x15: usize,
|
|
||||||
pub x14: usize,
|
|
||||||
pub x13: usize,
|
|
||||||
pub x12: usize,
|
|
||||||
pub x11: usize,
|
|
||||||
pub x10: usize,
|
|
||||||
pub x9: usize,
|
|
||||||
pub x8: usize,
|
|
||||||
pub x7: usize,
|
|
||||||
pub x6: usize,
|
|
||||||
pub x5: usize,
|
|
||||||
// x4(tp) is in env
|
|
||||||
// x3(gp) is a platform scratch register
|
|
||||||
pub x2: usize,
|
|
||||||
pub x1: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for IntRegisters {
|
|
||||||
type Target = [u8];
|
|
||||||
fn deref(&self) -> &[u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts(
|
|
||||||
self as *const IntRegisters as *const u8,
|
|
||||||
mem::size_of::<IntRegisters>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for IntRegisters {
|
|
||||||
fn deref_mut(&mut self) -> &mut [u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts_mut(
|
|
||||||
self as *mut IntRegisters as *mut u8,
|
|
||||||
mem::size_of::<IntRegisters>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
|
||||||
#[repr(C, packed)]
|
|
||||||
pub struct FloatRegisters {
|
|
||||||
pub fregs: [u64; 32],
|
|
||||||
pub fcsr: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for FloatRegisters {
|
|
||||||
type Target = [u8];
|
|
||||||
fn deref(&self) -> &[u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts(
|
|
||||||
self as *const FloatRegisters as *const u8,
|
|
||||||
mem::size_of::<FloatRegisters>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for FloatRegisters {
|
|
||||||
fn deref_mut(&mut self) -> &mut [u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts_mut(
|
|
||||||
self as *mut FloatRegisters as *mut u8,
|
|
||||||
mem::size_of::<FloatRegisters>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
|
||||||
#[repr(packed)]
|
|
||||||
pub struct EnvRegisters {
|
|
||||||
pub tp: usize,
|
|
||||||
}
|
|
||||||
impl Deref for EnvRegisters {
|
|
||||||
type Target = [u8];
|
|
||||||
fn deref(&self) -> &[u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts(
|
|
||||||
self as *const EnvRegisters as *const u8,
|
|
||||||
mem::size_of::<EnvRegisters>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for EnvRegisters {
|
|
||||||
fn deref_mut(&mut self) -> &mut [u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts_mut(
|
|
||||||
self as *mut EnvRegisters as *mut u8,
|
|
||||||
mem::size_of::<EnvRegisters>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
|
||||||
#[repr(C, packed)]
|
|
||||||
pub struct Exception {
|
|
||||||
pub kind: usize,
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
impl Deref for Exception {
|
|
||||||
type Target = [u8];
|
|
||||||
fn deref(&self) -> &[u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts(
|
|
||||||
self as *const Exception as *const u8,
|
|
||||||
mem::size_of::<Exception>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for Exception {
|
|
||||||
fn deref_mut(&mut self) -> &mut [u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts_mut(
|
|
||||||
self as *mut Exception as *mut u8,
|
|
||||||
mem::size_of::<Exception>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-288
@@ -1,288 +0,0 @@
|
|||||||
use core::{
|
|
||||||
arch::asm,
|
|
||||||
mem,
|
|
||||||
ops::{Deref, DerefMut},
|
|
||||||
slice,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::error::{Error, Result};
|
|
||||||
|
|
||||||
pub const PAGE_SIZE: usize = 4096;
|
|
||||||
/// Size of the metadata region used to transfer information from the kernel to the bootstrapper.
|
|
||||||
pub const KERNEL_METADATA_SIZE: usize = 4 * PAGE_SIZE;
|
|
||||||
|
|
||||||
#[cfg(feature = "userspace")]
|
|
||||||
macro_rules! syscall {
|
|
||||||
($($name:ident($a:ident, $($b:ident, $($c:ident, $($d:ident, $($e:ident, $($f:ident, )?)?)?)?)?);)+) => {
|
|
||||||
$(
|
|
||||||
pub unsafe fn $name(mut $a: usize, $($b: usize, $($c: usize, $($d: usize, $($e: usize, $($f: usize)?)?)?)?)?) -> Result<usize> {
|
|
||||||
asm!(
|
|
||||||
"int 0x80",
|
|
||||||
inout("eax") $a,
|
|
||||||
$(
|
|
||||||
in("ebx") $b,
|
|
||||||
$(
|
|
||||||
in("ecx") $c,
|
|
||||||
$(
|
|
||||||
in("edx") $d,
|
|
||||||
$(
|
|
||||||
in("esi") $e,
|
|
||||||
$(
|
|
||||||
in("edi") $f,
|
|
||||||
)?
|
|
||||||
)?
|
|
||||||
)?
|
|
||||||
)?
|
|
||||||
)?
|
|
||||||
options(nostack),
|
|
||||||
);
|
|
||||||
|
|
||||||
Error::demux($a)
|
|
||||||
}
|
|
||||||
)+
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "userspace")]
|
|
||||||
syscall! {
|
|
||||||
syscall0(a,);
|
|
||||||
syscall1(a, b,);
|
|
||||||
syscall2(a, b, c,);
|
|
||||||
syscall3(a, b, c, d,);
|
|
||||||
// Must be done custom because LLVM reserves ESI
|
|
||||||
//syscall4(a, b, c, d, e,);
|
|
||||||
//syscall5(a, b, c, d, e, f,);
|
|
||||||
//syscall6(a, b, c, d, e, f, g,);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "userspace")]
|
|
||||||
pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result<usize> {
|
|
||||||
asm!(
|
|
||||||
"xchg esi, {e}
|
|
||||||
int 0x80
|
|
||||||
xchg esi, {e}",
|
|
||||||
e = in(reg) e,
|
|
||||||
inout("eax") a,
|
|
||||||
in("ebx") b,
|
|
||||||
in("ecx") c,
|
|
||||||
in("edx") d,
|
|
||||||
options(nostack),
|
|
||||||
);
|
|
||||||
|
|
||||||
Error::demux(a)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "userspace")]
|
|
||||||
pub unsafe fn syscall5(
|
|
||||||
mut a: usize,
|
|
||||||
b: usize,
|
|
||||||
c: usize,
|
|
||||||
d: usize,
|
|
||||||
e: usize,
|
|
||||||
f: usize,
|
|
||||||
) -> Result<usize> {
|
|
||||||
asm!(
|
|
||||||
"xchg esi, {e}
|
|
||||||
int 0x80
|
|
||||||
xchg esi, {e}",
|
|
||||||
e = in(reg) e,
|
|
||||||
inout("eax") a,
|
|
||||||
in("ebx") b,
|
|
||||||
in("ecx") c,
|
|
||||||
in("edx") d,
|
|
||||||
in("edi") f,
|
|
||||||
options(nostack),
|
|
||||||
);
|
|
||||||
|
|
||||||
Error::demux(a)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "userspace")]
|
|
||||||
pub unsafe fn syscall6(
|
|
||||||
mut a: usize,
|
|
||||||
b: usize,
|
|
||||||
c: usize,
|
|
||||||
d: usize,
|
|
||||||
e: usize,
|
|
||||||
f: usize,
|
|
||||||
g: usize,
|
|
||||||
) -> Result<usize> {
|
|
||||||
#[repr(C)]
|
|
||||||
struct PackedArgs {
|
|
||||||
arg4: usize,
|
|
||||||
arg6: usize,
|
|
||||||
nr: usize,
|
|
||||||
}
|
|
||||||
let args = PackedArgs {
|
|
||||||
arg4: e,
|
|
||||||
arg6: g,
|
|
||||||
nr: a,
|
|
||||||
};
|
|
||||||
let args_ptr = &args as *const PackedArgs;
|
|
||||||
asm!(
|
|
||||||
"push ebp",
|
|
||||||
"push esi",
|
|
||||||
"mov esi, [eax + 0]", // arg4 -> esi
|
|
||||||
"mov ebp, [eax + 4]", // arg6 -> ebp
|
|
||||||
"mov eax, [eax + 8]", // nr -> eax
|
|
||||||
"int 0x80",
|
|
||||||
"pop esi",
|
|
||||||
"pop ebp",
|
|
||||||
inout("eax") args_ptr => a,
|
|
||||||
in("ebx") b,
|
|
||||||
in("ecx") c,
|
|
||||||
in("edx") d,
|
|
||||||
in("edi") f,
|
|
||||||
options(nostack),
|
|
||||||
);
|
|
||||||
|
|
||||||
Error::demux(a)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Default)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct IntRegisters {
|
|
||||||
// TODO: Some of these don't get set by Redox yet. Should they?
|
|
||||||
pub ebp: usize,
|
|
||||||
pub esi: usize,
|
|
||||||
pub edi: usize,
|
|
||||||
pub ebx: usize,
|
|
||||||
pub eax: usize,
|
|
||||||
pub ecx: usize,
|
|
||||||
pub edx: usize,
|
|
||||||
// pub orig_rax: usize,
|
|
||||||
pub eip: usize,
|
|
||||||
pub cs: usize,
|
|
||||||
pub eflags: usize,
|
|
||||||
pub esp: usize,
|
|
||||||
pub ss: usize,
|
|
||||||
// pub fs_base: usize,
|
|
||||||
// pub gs_base: usize,
|
|
||||||
// pub ds: usize,
|
|
||||||
// pub es: usize,
|
|
||||||
pub fs: usize,
|
|
||||||
// pub gs: usize
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for IntRegisters {
|
|
||||||
type Target = [u8];
|
|
||||||
fn deref(&self) -> &[u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts(
|
|
||||||
self as *const IntRegisters as *const u8,
|
|
||||||
mem::size_of::<IntRegisters>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for IntRegisters {
|
|
||||||
fn deref_mut(&mut self) -> &mut [u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts_mut(
|
|
||||||
self as *mut IntRegisters as *mut u8,
|
|
||||||
mem::size_of::<IntRegisters>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
|
||||||
#[repr(C, packed)]
|
|
||||||
pub struct FloatRegisters {
|
|
||||||
pub fcw: u16,
|
|
||||||
pub fsw: u16,
|
|
||||||
pub ftw: u8,
|
|
||||||
pub _reserved: u8,
|
|
||||||
pub fop: u16,
|
|
||||||
pub fip: u64,
|
|
||||||
pub fdp: u64,
|
|
||||||
pub mxcsr: u32,
|
|
||||||
pub mxcsr_mask: u32,
|
|
||||||
pub st_space: [u128; 8],
|
|
||||||
pub xmm_space: [u128; 16],
|
|
||||||
// TODO: YMM/ZMM
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for FloatRegisters {
|
|
||||||
type Target = [u8];
|
|
||||||
fn deref(&self) -> &[u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts(
|
|
||||||
self as *const FloatRegisters as *const u8,
|
|
||||||
mem::size_of::<FloatRegisters>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for FloatRegisters {
|
|
||||||
fn deref_mut(&mut self) -> &mut [u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts_mut(
|
|
||||||
self as *mut FloatRegisters as *mut u8,
|
|
||||||
mem::size_of::<FloatRegisters>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
|
||||||
#[repr(C, packed)]
|
|
||||||
pub struct EnvRegisters {
|
|
||||||
pub fsbase: u32,
|
|
||||||
pub gsbase: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for EnvRegisters {
|
|
||||||
type Target = [u8];
|
|
||||||
fn deref(&self) -> &[u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts(
|
|
||||||
self as *const EnvRegisters as *const u8,
|
|
||||||
mem::size_of::<EnvRegisters>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for EnvRegisters {
|
|
||||||
fn deref_mut(&mut self) -> &mut [u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts_mut(
|
|
||||||
self as *mut EnvRegisters as *mut u8,
|
|
||||||
mem::size_of::<EnvRegisters>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
|
||||||
#[repr(C, packed)]
|
|
||||||
pub struct Exception {
|
|
||||||
pub kind: usize,
|
|
||||||
pub code: usize,
|
|
||||||
pub address: usize,
|
|
||||||
}
|
|
||||||
impl Deref for Exception {
|
|
||||||
type Target = [u8];
|
|
||||||
fn deref(&self) -> &[u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts(
|
|
||||||
self as *const Exception as *const u8,
|
|
||||||
mem::size_of::<Exception>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for Exception {
|
|
||||||
fn deref_mut(&mut self) -> &mut [u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts_mut(
|
|
||||||
self as *mut Exception as *mut u8,
|
|
||||||
mem::size_of::<Exception>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,194 +0,0 @@
|
|||||||
use core::{
|
|
||||||
mem,
|
|
||||||
ops::{Deref, DerefMut},
|
|
||||||
slice,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const PAGE_SIZE: usize = 4096;
|
|
||||||
/// Size of the metadata region used to transfer information from the kernel to the bootstrapper.
|
|
||||||
pub const KERNEL_METADATA_SIZE: usize = 4 * PAGE_SIZE;
|
|
||||||
|
|
||||||
#[cfg(feature = "userspace")]
|
|
||||||
macro_rules! syscall {
|
|
||||||
($($name:ident($a:ident, $($b:ident, $($c:ident, $($d:ident, $($e:ident, $($f:ident, $($g:ident, )?)?)?)?)?)?);)+) => {
|
|
||||||
$(
|
|
||||||
pub unsafe fn $name(mut $a: usize, $($b: usize, $($c: usize, $($d: usize, $($e: usize, $($f: usize, $($g: usize)?)?)?)?)?)?) -> crate::error::Result<usize> {
|
|
||||||
core::arch::asm!(
|
|
||||||
"syscall",
|
|
||||||
inout("rax") $a,
|
|
||||||
$(
|
|
||||||
in("rdi") $b,
|
|
||||||
$(
|
|
||||||
in("rsi") $c,
|
|
||||||
$(
|
|
||||||
in("rdx") $d,
|
|
||||||
$(
|
|
||||||
in("r10") $e,
|
|
||||||
$(
|
|
||||||
in("r8") $f,
|
|
||||||
$(
|
|
||||||
in("r9") $g,
|
|
||||||
)?
|
|
||||||
)?
|
|
||||||
)?
|
|
||||||
)?
|
|
||||||
)?
|
|
||||||
)?
|
|
||||||
out("rcx") _,
|
|
||||||
out("r11") _,
|
|
||||||
options(nostack),
|
|
||||||
);
|
|
||||||
|
|
||||||
crate::error::Error::demux($a)
|
|
||||||
}
|
|
||||||
)+
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "userspace")]
|
|
||||||
syscall! {
|
|
||||||
syscall0(a,);
|
|
||||||
syscall1(a, b,);
|
|
||||||
syscall2(a, b, c,);
|
|
||||||
syscall3(a, b, c, d,);
|
|
||||||
syscall4(a, b, c, d, e,);
|
|
||||||
syscall5(a, b, c, d, e, f,);
|
|
||||||
syscall6(a, b, c, d, e, f, g,);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Default)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct IntRegisters {
|
|
||||||
pub r15: usize,
|
|
||||||
pub r14: usize,
|
|
||||||
pub r13: usize,
|
|
||||||
pub r12: usize,
|
|
||||||
pub rbp: usize,
|
|
||||||
pub rbx: usize,
|
|
||||||
pub r11: usize,
|
|
||||||
pub r10: usize,
|
|
||||||
pub r9: usize,
|
|
||||||
pub r8: usize,
|
|
||||||
pub rax: usize,
|
|
||||||
pub rcx: usize,
|
|
||||||
pub rdx: usize,
|
|
||||||
pub rsi: usize,
|
|
||||||
pub rdi: usize,
|
|
||||||
pub rip: usize,
|
|
||||||
pub cs: usize,
|
|
||||||
pub rflags: usize,
|
|
||||||
pub rsp: usize,
|
|
||||||
pub ss: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for IntRegisters {
|
|
||||||
type Target = [u8];
|
|
||||||
fn deref(&self) -> &[u8] {
|
|
||||||
unsafe { slice::from_raw_parts(self as *const Self as *const u8, mem::size_of::<Self>()) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for IntRegisters {
|
|
||||||
fn deref_mut(&mut self) -> &mut [u8] {
|
|
||||||
unsafe { slice::from_raw_parts_mut(self as *mut Self as *mut u8, mem::size_of::<Self>()) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
|
||||||
#[repr(C, packed)]
|
|
||||||
pub struct FloatRegisters {
|
|
||||||
pub fcw: u16,
|
|
||||||
pub fsw: u16,
|
|
||||||
pub ftw: u8,
|
|
||||||
pub _reserved: u8,
|
|
||||||
pub fop: u16,
|
|
||||||
pub fip: u64,
|
|
||||||
pub fdp: u64,
|
|
||||||
pub mxcsr: u32,
|
|
||||||
pub mxcsr_mask: u32,
|
|
||||||
pub st_space: [u128; 8],
|
|
||||||
pub xmm_space: [u128; 16],
|
|
||||||
// TODO: YMM/ZMM
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for FloatRegisters {
|
|
||||||
type Target = [u8];
|
|
||||||
fn deref(&self) -> &[u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts(
|
|
||||||
self as *const FloatRegisters as *const u8,
|
|
||||||
mem::size_of::<FloatRegisters>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for FloatRegisters {
|
|
||||||
fn deref_mut(&mut self) -> &mut [u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts_mut(
|
|
||||||
self as *mut FloatRegisters as *mut u8,
|
|
||||||
mem::size_of::<FloatRegisters>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
|
||||||
#[repr(C, packed)]
|
|
||||||
pub struct EnvRegisters {
|
|
||||||
pub fsbase: u64,
|
|
||||||
pub gsbase: u64,
|
|
||||||
// TODO: PKRU?
|
|
||||||
}
|
|
||||||
impl Deref for EnvRegisters {
|
|
||||||
type Target = [u8];
|
|
||||||
fn deref(&self) -> &[u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts(
|
|
||||||
self as *const EnvRegisters as *const u8,
|
|
||||||
mem::size_of::<EnvRegisters>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for EnvRegisters {
|
|
||||||
fn deref_mut(&mut self) -> &mut [u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts_mut(
|
|
||||||
self as *mut EnvRegisters as *mut u8,
|
|
||||||
mem::size_of::<EnvRegisters>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
|
||||||
#[repr(C, packed)]
|
|
||||||
pub struct Exception {
|
|
||||||
pub kind: usize,
|
|
||||||
pub code: usize,
|
|
||||||
pub address: usize,
|
|
||||||
}
|
|
||||||
impl Deref for Exception {
|
|
||||||
type Target = [u8];
|
|
||||||
fn deref(&self) -> &[u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts(
|
|
||||||
self as *const Exception as *const u8,
|
|
||||||
mem::size_of::<Exception>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for Exception {
|
|
||||||
fn deref_mut(&mut self) -> &mut [u8] {
|
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts_mut(
|
|
||||||
self as *mut Exception as *mut u8,
|
|
||||||
mem::size_of::<Exception>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
double strtod(const char *nptr, char **endptr);
|
||||||
|
|
||||||
|
long double strtold(const char *nptr, char **endptr) {
|
||||||
|
return (long double)strtod(nptr, endptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
double relibc_ldtod(const long double* val) {
|
||||||
|
return (double)(*val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void relibc_dtold(double val, long double* out) {
|
||||||
|
*out = (long double)val;
|
||||||
|
}
|
||||||
+322
@@ -0,0 +1,322 @@
|
|||||||
|
//! Nul-terminated byte strings.
|
||||||
|
|
||||||
|
use core::{marker::PhantomData, ptr::NonNull, str::Utf8Error};
|
||||||
|
|
||||||
|
use alloc::{borrow::Cow, string::String};
|
||||||
|
|
||||||
|
use crate::platform::types::{c_char, wchar_t};
|
||||||
|
|
||||||
|
mod private {
|
||||||
|
pub trait Sealed {}
|
||||||
|
}
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum Thin {}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum Wide {}
|
||||||
|
|
||||||
|
impl private::Sealed for Thin {}
|
||||||
|
impl private::Sealed for Wide {}
|
||||||
|
|
||||||
|
pub trait Kind: private::Sealed + Copy + 'static {
|
||||||
|
/// c_char or wchar_t
|
||||||
|
type C: Copy + 'static;
|
||||||
|
// u8 or u32
|
||||||
|
type Char: Copy + From<u8> + Into<u32> + PartialEq + 'static;
|
||||||
|
|
||||||
|
const NUL: Self::Char;
|
||||||
|
|
||||||
|
const IS_THIN_NOT_WIDE: bool;
|
||||||
|
|
||||||
|
fn r2c(c: Self::Char) -> Self::C;
|
||||||
|
fn c2r(c: Self::C) -> Self::Char;
|
||||||
|
|
||||||
|
fn chars_from_bytes(b: &[u8]) -> Option<&[Self::Char]>;
|
||||||
|
fn chars_to_bytes(c: &[Self::Char]) -> Option<&[u8]>;
|
||||||
|
|
||||||
|
unsafe fn strlen(s: *const Self::C) -> usize;
|
||||||
|
unsafe fn strchr(s: *const Self::C, c: Self::C) -> *const Self::C;
|
||||||
|
unsafe fn strchrnul(s: *const Self::C, c: Self::C) -> *const Self::C;
|
||||||
|
}
|
||||||
|
impl Kind for Thin {
|
||||||
|
type C = c_char;
|
||||||
|
type Char = u8;
|
||||||
|
|
||||||
|
const NUL: Self::Char = 0;
|
||||||
|
const IS_THIN_NOT_WIDE: bool = true;
|
||||||
|
|
||||||
|
unsafe fn strlen(s: *const c_char) -> usize {
|
||||||
|
unsafe { crate::header::string::strlen(s) }
|
||||||
|
}
|
||||||
|
unsafe fn strchr(s: *const c_char, c: c_char) -> *const c_char {
|
||||||
|
unsafe { crate::header::string::strchr(s, c.into()) }
|
||||||
|
}
|
||||||
|
unsafe fn strchrnul(s: *const c_char, c: c_char) -> *const c_char {
|
||||||
|
unsafe { crate::header::string::strchrnul(s, c.into()) }
|
||||||
|
}
|
||||||
|
fn r2c(c: u8) -> c_char {
|
||||||
|
c as _
|
||||||
|
}
|
||||||
|
fn c2r(c: c_char) -> u8 {
|
||||||
|
c as _
|
||||||
|
}
|
||||||
|
fn chars_from_bytes(b: &[u8]) -> Option<&[Self::Char]> {
|
||||||
|
Some(b)
|
||||||
|
}
|
||||||
|
fn chars_to_bytes(c: &[Self::Char]) -> Option<&[u8]> {
|
||||||
|
Some(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Kind for Wide {
|
||||||
|
type C = wchar_t;
|
||||||
|
type Char = u32;
|
||||||
|
|
||||||
|
const NUL: Self::Char = 0;
|
||||||
|
const IS_THIN_NOT_WIDE: bool = false;
|
||||||
|
|
||||||
|
unsafe fn strlen(s: *const Self::C) -> usize {
|
||||||
|
unsafe { crate::header::wchar::wcslen(s) }
|
||||||
|
}
|
||||||
|
unsafe fn strchr(s: *const Self::C, c: Self::C) -> *const Self::C {
|
||||||
|
unsafe { crate::header::wchar::wcschr(s, c) }
|
||||||
|
}
|
||||||
|
unsafe fn strchrnul(mut s: *const Self::C, c: Self::C) -> *const Self::C {
|
||||||
|
// TODO: optimized function
|
||||||
|
while unsafe { s.read() } != c && unsafe { s.read() } != 0 {
|
||||||
|
s = unsafe { s.add(1) };
|
||||||
|
}
|
||||||
|
s
|
||||||
|
}
|
||||||
|
fn r2c(c: Self::Char) -> Self::C {
|
||||||
|
c as _
|
||||||
|
}
|
||||||
|
fn c2r(c: Self::C) -> Self::Char {
|
||||||
|
c as _
|
||||||
|
}
|
||||||
|
fn chars_from_bytes(b: &[u8]) -> Option<&[Self::Char]> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
fn chars_to_bytes(c: &[Self::Char]) -> Option<&[u8]> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Safe wrapper for immutable borrowed C strings, guaranteed to be the same layout as `*const u8`.
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct NulStr<'a, T: Kind> {
|
||||||
|
ptr: NonNull<T::C>,
|
||||||
|
_marker: PhantomData<&'a [u8]>,
|
||||||
|
}
|
||||||
|
pub type CStr<'a> = NulStr<'a, Thin>;
|
||||||
|
pub type WStr<'a> = NulStr<'a, Wide>;
|
||||||
|
|
||||||
|
impl<'a, T: Kind> NulStr<'a, T> {
|
||||||
|
/// Safety
|
||||||
|
///
|
||||||
|
/// The ptr must be valid up to and including the first NUL byte from the base ptr.
|
||||||
|
pub const unsafe fn from_ptr(ptr: *const T::C) -> Self {
|
||||||
|
Self {
|
||||||
|
ptr: unsafe { NonNull::new_unchecked(ptr.cast_mut()) },
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub unsafe fn from_nullable_ptr(ptr: *const T::C) -> Option<Self> {
|
||||||
|
if ptr.is_null() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(unsafe { Self::from_ptr(ptr) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Look for the closest occurence of `c`, and if found, split the string into a slice up to
|
||||||
|
/// that byte and a `CStr` starting at that byte.
|
||||||
|
#[inline]
|
||||||
|
#[doc(alias = "strchrnul")]
|
||||||
|
pub fn find_get_subslice_or_all(
|
||||||
|
self,
|
||||||
|
c: impl Into<T::Char>,
|
||||||
|
) -> Result<(&'a [T::Char], Self), (&'a [T::Char], Self)> {
|
||||||
|
let c = c.into();
|
||||||
|
|
||||||
|
// SAFETY: strchrnul expects self.as_ptr() to be valid up to and including its last NUL
|
||||||
|
// byte
|
||||||
|
let found = unsafe { T::strchrnul(self.as_ptr(), T::r2c(c)) };
|
||||||
|
|
||||||
|
// SAFETY: the pointer returned from strchrnul is always a substring of this string, and
|
||||||
|
// hence always valid as a CStr.
|
||||||
|
let found = unsafe { Self::from_ptr(found) };
|
||||||
|
let until = unsafe { self.slice_until_substr(found) };
|
||||||
|
|
||||||
|
if found.first() == T::NUL {
|
||||||
|
// The character was not found, and we got the end of the string instead.
|
||||||
|
Err((until, found))
|
||||||
|
} else {
|
||||||
|
Ok((until, found))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// `substr` must be contained within `self`
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn slice_until_substr(self, substr: NulStr<'_, T>) -> &'a [T::Char] {
|
||||||
|
let index = unsafe {
|
||||||
|
// SAFETY: the sub-pointer as returned by strchr must be derived from the same
|
||||||
|
// allocation
|
||||||
|
substr.as_ptr().offset_from(self.as_ptr()) as usize
|
||||||
|
};
|
||||||
|
unsafe { core::slice::from_raw_parts(self.as_ptr().cast::<T::Char>(), index) }
|
||||||
|
}
|
||||||
|
/// Look for the closest occurence of `c`, and if found, split the string into a slice up to
|
||||||
|
/// that byte and a `CStr` starting at that byte.
|
||||||
|
#[inline]
|
||||||
|
pub fn find_get_subslice(self, c: T::Char) -> Option<(&'a [T::Char], Self)> {
|
||||||
|
let rest = self.find(c)?;
|
||||||
|
|
||||||
|
// SAFETY: the output of strchr is obviously a substring if it doesn't return NULL
|
||||||
|
Some((unsafe { self.slice_until_substr(rest) }, rest))
|
||||||
|
}
|
||||||
|
/// Look for the closest occurence of `c`, and return a new string starting at that byte if
|
||||||
|
/// found.
|
||||||
|
#[doc(alias = "strchr")]
|
||||||
|
#[doc(alias = "wcschr")]
|
||||||
|
#[inline]
|
||||||
|
pub fn find(self, c: T::Char) -> Option<Self> {
|
||||||
|
unsafe {
|
||||||
|
// SAFETY: the only requirement is for self.as_ptr() to be valid up to and including
|
||||||
|
// the nearest NUL byte, which this type requires
|
||||||
|
let ret = T::strchr(self.as_ptr(), T::r2c(c));
|
||||||
|
// SAFETY: strchr must either return NULL (not found) or a substring of self, which can
|
||||||
|
// never exceed the nearest NUL byte of self
|
||||||
|
Self::from_nullable_ptr(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: strrchr, strchrnul wrappers
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn contains(self, c: T::Char) -> bool {
|
||||||
|
self.find(c).is_some()
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn first(self) -> T::Char {
|
||||||
|
unsafe {
|
||||||
|
// SAFETY: Self must be valid up to and including its nearest NUL byte, which certainly
|
||||||
|
// implies its readable length is nonzero (string is empty if this first byte is 0).
|
||||||
|
T::c2r(self.ptr.read())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn first_char(self) -> Option<char> {
|
||||||
|
char::from_u32(self.first().into())
|
||||||
|
}
|
||||||
|
/// Same as `split_first` except also requires that the first char be convertible into `char`
|
||||||
|
#[inline]
|
||||||
|
pub fn split_first_char(self) -> Option<(char, Self)> {
|
||||||
|
self.split_first()
|
||||||
|
.and_then(|(c, r)| Some((char::from_u32(c.into())?, r)))
|
||||||
|
}
|
||||||
|
/// Split this string into `Some((first_byte, string_after_that))` or `None` if empty.
|
||||||
|
#[inline]
|
||||||
|
pub fn split_first(self) -> Option<(T::Char, Self)> {
|
||||||
|
if self.first() == T::NUL {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some((self.first(), unsafe {
|
||||||
|
Self::from_ptr(self.as_ptr().add(1))
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
pub fn to_chars_with_nul(self) -> &'a [T::Char] {
|
||||||
|
unsafe {
|
||||||
|
// SAFETY: The string must be valid at least until (and including) the NUL byte.
|
||||||
|
let len = T::strlen(self.ptr.as_ptr());
|
||||||
|
core::slice::from_raw_parts(self.ptr.as_ptr().cast(), len + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn to_chars(self) -> &'a [T::Char] {
|
||||||
|
let s = self.to_chars_with_nul();
|
||||||
|
&s[..s.len() - 1]
|
||||||
|
}
|
||||||
|
pub const fn as_ptr(self) -> *const T::C {
|
||||||
|
self.ptr.as_ptr()
|
||||||
|
}
|
||||||
|
pub const unsafe fn from_chars_with_nul_unchecked(chars: &'a [T::Char]) -> Self {
|
||||||
|
unsafe { Self::from_ptr(chars.as_ptr().cast()) }
|
||||||
|
}
|
||||||
|
pub fn from_chars_with_nul(chars: &'a [T::Char]) -> Result<Self, FromCharsWithNulError> {
|
||||||
|
if chars.last() != Some(&T::NUL) || chars[..chars.len() - 1].contains(&T::NUL) {
|
||||||
|
return Err(FromCharsWithNulError);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(unsafe { Self::from_chars_with_nul_unchecked(chars) })
|
||||||
|
}
|
||||||
|
pub fn from_chars_until_nul(chars: &'a [T::Char]) -> Result<Self, FromCharsUntilNulError> {
|
||||||
|
if !chars.contains(&T::NUL) {
|
||||||
|
return Err(FromCharsUntilNulError);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(unsafe { Self::from_chars_with_nul_unchecked(chars) })
|
||||||
|
}
|
||||||
|
/// Scan the string to get its length.
|
||||||
|
#[doc(alias = "strlen")]
|
||||||
|
#[doc(alias = "wcslen")]
|
||||||
|
pub fn len(self) -> usize {
|
||||||
|
self.to_chars().len()
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.first() == T::NUL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a> CStr<'a> {
|
||||||
|
pub fn to_owned_cstring(self) -> CString {
|
||||||
|
CString::from(unsafe { core::ffi::CStr::from_ptr(self.ptr.as_ptr()) })
|
||||||
|
}
|
||||||
|
pub fn borrow(string: &'a CString) -> Self {
|
||||||
|
unsafe { Self::from_ptr(string.as_ptr()) }
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn to_bytes(self) -> &'a [u8] {
|
||||||
|
self.to_chars()
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn to_bytes_with_nul(self) -> &'a [u8] {
|
||||||
|
self.to_chars_with_nul()
|
||||||
|
}
|
||||||
|
pub fn to_str(self) -> Result<&'a str, Utf8Error> {
|
||||||
|
core::str::from_utf8(self.to_bytes())
|
||||||
|
}
|
||||||
|
pub fn to_string_lossy(self) -> Cow<'a, str> {
|
||||||
|
String::from_utf8_lossy(self.to_bytes())
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &'a [u8]) -> Self {
|
||||||
|
unsafe { Self::from_chars_with_nul_unchecked(bytes) }
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn from_bytes_with_nul(bytes: &'a [u8]) -> Result<Self, FromCharsWithNulError> {
|
||||||
|
Self::from_chars_with_nul(bytes)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn from_bytes_until_nul(bytes: &'a [u8]) -> Result<Self, FromCharsUntilNulError> {
|
||||||
|
Self::from_chars_until_nul(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T: Kind> Send for NulStr<'_, T> {}
|
||||||
|
unsafe impl<T: Kind> Sync for NulStr<'_, T> {}
|
||||||
|
|
||||||
|
impl From<&core::ffi::CStr> for CStr<'_> {
|
||||||
|
fn from(s: &core::ffi::CStr) -> Self {
|
||||||
|
// SAFETY:
|
||||||
|
// * We can assume that `s` is valid because the caller should have upheld its
|
||||||
|
// safety concerns when constructing it.
|
||||||
|
unsafe { Self::from_ptr(s.as_ptr()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FromCharsWithNulError;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FromCharsUntilNulError;
|
||||||
|
|
||||||
|
pub use alloc::ffi::CString;
|
||||||
+294
@@ -0,0 +1,294 @@
|
|||||||
|
//! Equivalent of Rust's `Vec<T>`, but using relibc's own allocator.
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
io::{self, Write},
|
||||||
|
platform::{self, WriteByte, types::*},
|
||||||
|
};
|
||||||
|
use core::{
|
||||||
|
cmp, fmt,
|
||||||
|
iter::IntoIterator,
|
||||||
|
mem,
|
||||||
|
ops::{Deref, DerefMut},
|
||||||
|
ptr::{self, NonNull},
|
||||||
|
slice,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Error that occurs when an allocation fails
|
||||||
|
#[derive(Debug, Default, Hash, PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub struct AllocError;
|
||||||
|
|
||||||
|
/// A normal vector allocated in Rust needs to be dropped from Rust
|
||||||
|
/// too, in order to avoid UB. This CVec is an abstraction that works
|
||||||
|
/// using only C allocations functions and can therefore be dropped
|
||||||
|
/// from C. Just like the Rust Vec, this does bounds checks to assure
|
||||||
|
/// you never reach isize::MAX. Unless you need to drop something from
|
||||||
|
/// C, prefer Rust's builtin Vec.
|
||||||
|
pub struct CVec<T> {
|
||||||
|
ptr: NonNull<T>,
|
||||||
|
len: usize,
|
||||||
|
cap: usize,
|
||||||
|
}
|
||||||
|
impl<T> CVec<T> {
|
||||||
|
#[allow(clippy::new_without_default)]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
ptr: NonNull::dangling(),
|
||||||
|
len: 0,
|
||||||
|
cap: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn check_bounds(i: usize) -> Result<usize, AllocError> {
|
||||||
|
if i > isize::MAX as usize {
|
||||||
|
Err(AllocError)
|
||||||
|
} else {
|
||||||
|
Ok(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn check_mul(x: usize, y: usize) -> Result<usize, AllocError> {
|
||||||
|
x.checked_mul(y)
|
||||||
|
.ok_or(AllocError)
|
||||||
|
.and_then(Self::check_bounds)
|
||||||
|
}
|
||||||
|
pub fn with_capacity(cap: usize) -> Result<Self, AllocError> {
|
||||||
|
if cap == 0 {
|
||||||
|
return Ok(Self::new());
|
||||||
|
}
|
||||||
|
let size = Self::check_mul(cap, mem::size_of::<T>())?;
|
||||||
|
let ptr = NonNull::new(unsafe { platform::alloc(size).cast::<T>() }).ok_or(AllocError)?;
|
||||||
|
Ok(Self { ptr, len: 0, cap })
|
||||||
|
}
|
||||||
|
unsafe fn resize(&mut self, cap: usize) -> Result<(), AllocError> {
|
||||||
|
let size = Self::check_mul(cap, mem::size_of::<T>())?;
|
||||||
|
let ptr = if cap == 0 {
|
||||||
|
NonNull::dangling()
|
||||||
|
} else if self.cap > 0 {
|
||||||
|
NonNull::new(
|
||||||
|
unsafe { platform::realloc(self.ptr.as_ptr().cast::<c_void>(), size) }.cast::<T>(),
|
||||||
|
)
|
||||||
|
.ok_or(AllocError)?
|
||||||
|
} else {
|
||||||
|
NonNull::new((unsafe { platform::alloc(size) }).cast::<T>()).ok_or(AllocError)?
|
||||||
|
};
|
||||||
|
self.ptr = ptr;
|
||||||
|
self.cap = cap;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
unsafe fn drop_range(&mut self, start: usize, end: usize) {
|
||||||
|
let mut start = unsafe { self.ptr.as_ptr().add(start) };
|
||||||
|
let end = unsafe { self.ptr.as_ptr().add(end) };
|
||||||
|
while start < end {
|
||||||
|
unsafe { ptr::drop_in_place(start) };
|
||||||
|
start = unsafe { start.add(1) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push stuff
|
||||||
|
|
||||||
|
pub fn reserve(&mut self, required: usize) -> Result<(), AllocError> {
|
||||||
|
let required_len = self
|
||||||
|
.len
|
||||||
|
.checked_add(required)
|
||||||
|
.ok_or(AllocError)
|
||||||
|
.and_then(Self::check_bounds)?;
|
||||||
|
if required_len > self.cap {
|
||||||
|
let new_cap = cmp::min(required_len.next_power_of_two(), isize::MAX as usize);
|
||||||
|
unsafe {
|
||||||
|
self.resize(new_cap)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn push(&mut self, elem: T) -> Result<(), AllocError> {
|
||||||
|
self.reserve(1)?;
|
||||||
|
unsafe {
|
||||||
|
ptr::write(self.ptr.as_ptr().add(self.len), elem);
|
||||||
|
}
|
||||||
|
self.len += 1; // no need to bounds check, as new len <= cap
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn extend_from_slice(&mut self, elems: &[T]) -> Result<(), AllocError>
|
||||||
|
where
|
||||||
|
T: Copy,
|
||||||
|
{
|
||||||
|
self.reserve(elems.len())?;
|
||||||
|
unsafe {
|
||||||
|
ptr::copy_nonoverlapping(elems.as_ptr(), self.ptr.as_ptr().add(self.len), elems.len());
|
||||||
|
}
|
||||||
|
self.len += elems.len(); // no need to bounds check, as new len <= cap
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn append(&mut self, other: &mut Self) -> Result<(), AllocError> {
|
||||||
|
let len = other.len;
|
||||||
|
other.len = 0; // move
|
||||||
|
self.reserve(len)?;
|
||||||
|
unsafe {
|
||||||
|
ptr::copy_nonoverlapping(other.as_ptr(), self.ptr.as_ptr().add(self.len), len);
|
||||||
|
}
|
||||||
|
self.len += other.len(); // no need to bounds check, as new len <= cap
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pop stuff
|
||||||
|
|
||||||
|
pub fn truncate(&mut self, len: usize) {
|
||||||
|
if len < self.len {
|
||||||
|
unsafe {
|
||||||
|
let old_len = self.len;
|
||||||
|
self.drop_range(len, old_len);
|
||||||
|
}
|
||||||
|
self.len = len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn shrink_to_fit(&mut self) -> Result<(), AllocError> {
|
||||||
|
if self.len < self.cap {
|
||||||
|
unsafe {
|
||||||
|
let new_cap = self.len;
|
||||||
|
self.resize(new_cap)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn pop(&mut self) -> Option<T> {
|
||||||
|
if self.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let elem = unsafe { ptr::read(self.as_ptr().add(self.len - 1)) };
|
||||||
|
self.len -= 1;
|
||||||
|
Some(elem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Misc stuff
|
||||||
|
|
||||||
|
pub fn capacity(&self) -> usize {
|
||||||
|
self.cap
|
||||||
|
}
|
||||||
|
pub fn as_ptr(&self) -> *const T {
|
||||||
|
self.ptr.as_ptr()
|
||||||
|
}
|
||||||
|
pub fn as_mut_ptr(&mut self) -> *mut T {
|
||||||
|
self.ptr.as_ptr()
|
||||||
|
}
|
||||||
|
/// Leaks the inner data. This is safe to drop from C!
|
||||||
|
pub fn leak(mut self) -> *mut T {
|
||||||
|
let ptr = self.as_mut_ptr();
|
||||||
|
mem::forget(self);
|
||||||
|
ptr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> Deref for CVec<T> {
|
||||||
|
type Target = [T];
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
unsafe { slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> DerefMut for CVec<T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
unsafe { slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> Drop for CVec<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
let len = self.len;
|
||||||
|
self.drop_range(0, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a, T> IntoIterator for &'a CVec<T> {
|
||||||
|
type Item = <&'a [T] as IntoIterator>::Item;
|
||||||
|
type IntoIter = <&'a [T] as IntoIterator>::IntoIter;
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
<&[T]>::into_iter(&*self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a, T> IntoIterator for &'a mut CVec<T> {
|
||||||
|
type Item = <&'a mut [T] as IntoIterator>::Item;
|
||||||
|
type IntoIter = <&'a mut [T] as IntoIterator>::IntoIter;
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
<&mut [T]>::into_iter(&mut *self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Write for CVec<u8> {
|
||||||
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||||
|
self.extend_from_slice(buf).map_err(|err| {
|
||||||
|
io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
"AllocStringWriter::write failed to allocate",
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
Ok(buf.len())
|
||||||
|
}
|
||||||
|
fn flush(&mut self) -> io::Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl fmt::Write for CVec<u8> {
|
||||||
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||||
|
self.write(s.as_bytes()).map_err(|_| fmt::Error)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl WriteByte for CVec<u8> {
|
||||||
|
fn write_u8(&mut self, byte: u8) -> fmt::Result {
|
||||||
|
self.write(&[byte]).map_err(|_| fmt::Error)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::CVec;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn push_pop() {
|
||||||
|
let mut vec = CVec::new();
|
||||||
|
vec.push(1).unwrap();
|
||||||
|
vec.push(2).unwrap();
|
||||||
|
vec.push(3).unwrap();
|
||||||
|
assert_eq!(&vec[..], &[1, 2, 3]);
|
||||||
|
assert_eq!(vec.pop().unwrap(), 3);
|
||||||
|
assert_eq!(&vec[..], &[1, 2]);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn extend_from_slice() {
|
||||||
|
use crate::io::Write;
|
||||||
|
|
||||||
|
let mut vec = CVec::new();
|
||||||
|
vec.extend_from_slice(&[1, 2, 3]).unwrap();
|
||||||
|
vec.extend_from_slice(&[4, 5, 6]).unwrap();
|
||||||
|
assert_eq!(&vec[..], &[1, 2, 3, 4, 5, 6]);
|
||||||
|
assert_eq!(vec.write(&[7, 8, 9]).unwrap(), 3);
|
||||||
|
assert_eq!(&vec[..], &[1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn dropped() {
|
||||||
|
use alloc::rc::Rc;
|
||||||
|
|
||||||
|
let counter = Rc::new(());
|
||||||
|
let mut vec = CVec::with_capacity(3).unwrap();
|
||||||
|
vec.push(Rc::clone(&counter)).unwrap();
|
||||||
|
vec.push(Rc::clone(&counter)).unwrap();
|
||||||
|
vec.push(Rc::clone(&counter)).unwrap();
|
||||||
|
assert_eq!(Rc::strong_count(&counter), 4);
|
||||||
|
|
||||||
|
let popped = vec.pop().unwrap();
|
||||||
|
assert_eq!(Rc::strong_count(&counter), 4);
|
||||||
|
drop(popped);
|
||||||
|
assert_eq!(Rc::strong_count(&counter), 3);
|
||||||
|
|
||||||
|
vec.push(Rc::clone(&counter)).unwrap();
|
||||||
|
vec.push(Rc::clone(&counter)).unwrap();
|
||||||
|
vec.push(Rc::clone(&counter)).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(vec.len(), 5);
|
||||||
|
assert_eq!(Rc::strong_count(&counter), 6);
|
||||||
|
vec.truncate(1);
|
||||||
|
assert_eq!(Rc::strong_count(&counter), 2);
|
||||||
|
|
||||||
|
drop(vec);
|
||||||
|
assert_eq!(Rc::strong_count(&counter), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
-425
@@ -1,425 +0,0 @@
|
|||||||
use super::{
|
|
||||||
arch::*,
|
|
||||||
data::{Map, Stat, StatVfs, StdFsCallMeta, TimeSpec},
|
|
||||||
error::Result,
|
|
||||||
flag::*,
|
|
||||||
number::*,
|
|
||||||
};
|
|
||||||
|
|
||||||
use core::mem;
|
|
||||||
|
|
||||||
/// Close a file descriptor
|
|
||||||
pub fn close(fd: usize) -> Result<usize> {
|
|
||||||
unsafe { syscall1(SYS_CLOSE, fd) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the current system time
|
|
||||||
pub fn clock_gettime(clock: usize, tp: &mut TimeSpec) -> Result<usize> {
|
|
||||||
unsafe { syscall2(SYS_CLOCK_GETTIME, clock, tp as *mut TimeSpec as usize) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Copy and transform a file descriptor into specified fd number
|
|
||||||
pub fn dup_into(fd: usize, out: usize, buf: &[u8]) -> Result<usize> {
|
|
||||||
unsafe { syscall4(SYS_DUP_INTO, fd, buf.as_ptr() as usize, buf.len(), out) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Copy and transform a file descriptor, letting the kernel allocate the new fd
|
|
||||||
pub fn dup(fd: usize, buf: &[u8]) -> Result<usize> {
|
|
||||||
unsafe { syscall3(SYS_DUP, fd, buf.as_ptr() as usize, buf.len()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Copy and transform a file descriptor
|
|
||||||
pub fn dup2(fd: usize, newfd: usize, buf: &[u8]) -> Result<usize> {
|
|
||||||
unsafe { syscall4(SYS_DUP2, fd, newfd, buf.as_ptr() as usize, buf.len()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Change file permissions
|
|
||||||
pub fn fchmod(fd: usize, mode: u16) -> Result<usize> {
|
|
||||||
unsafe { syscall2(SYS_FCHMOD, fd, mode as usize) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Change file ownership
|
|
||||||
pub fn fchown(fd: usize, uid: u32, gid: u32) -> Result<usize> {
|
|
||||||
unsafe { syscall3(SYS_FCHOWN, fd, uid as usize, gid as usize) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Change file descriptor flags
|
|
||||||
pub fn fcntl(fd: usize, cmd: usize, arg: usize) -> Result<usize> {
|
|
||||||
unsafe { syscall3(SYS_FCNTL, fd, cmd, arg) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Map a file into memory, but with the ability to set the address to map into, either as a hint
|
|
||||||
/// or as a requirement of the map.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
/// `EACCES` - the file descriptor was not open for reading
|
|
||||||
/// `EBADF` - if the file descriptor was invalid
|
|
||||||
/// `ENODEV` - mmapping was not supported
|
|
||||||
/// `EINVAL` - invalid combination of flags
|
|
||||||
/// `EEXIST` - if [`MapFlags::MAP_FIXED`] was set, and the address specified was already in use.
|
|
||||||
///
|
|
||||||
pub unsafe fn fmap(fd: usize, map: &Map) -> Result<usize> {
|
|
||||||
syscall3(
|
|
||||||
SYS_FMAP,
|
|
||||||
fd,
|
|
||||||
map as *const Map as usize,
|
|
||||||
mem::size_of::<Map>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unmap whole (or partial) continous memory-mapped files
|
|
||||||
pub unsafe fn funmap(addr: usize, len: usize) -> Result<usize> {
|
|
||||||
syscall2(SYS_FUNMAP, addr, len)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieve the canonical path of a file
|
|
||||||
pub fn fpath(fd: usize, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
unsafe { syscall3(SYS_FPATH, fd, buf.as_mut_ptr() as usize, buf.len()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a link to a file
|
|
||||||
pub fn flink<T: AsRef<str>>(fd: usize, path: T) -> Result<usize> {
|
|
||||||
let path = path.as_ref();
|
|
||||||
unsafe { syscall3(SYS_FLINK, fd, path.as_ptr() as usize, path.len()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Rename a file
|
|
||||||
pub fn frename<T: AsRef<str>>(fd: usize, path: T) -> Result<usize> {
|
|
||||||
let path = path.as_ref();
|
|
||||||
unsafe { syscall3(SYS_FRENAME, fd, path.as_ptr() as usize, path.len()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get metadata about a file
|
|
||||||
pub fn fstat(fd: usize, stat: &mut Stat) -> Result<usize> {
|
|
||||||
unsafe {
|
|
||||||
syscall3(
|
|
||||||
SYS_FSTAT,
|
|
||||||
fd,
|
|
||||||
stat as *mut Stat as usize,
|
|
||||||
mem::size_of::<Stat>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get metadata about a filesystem
|
|
||||||
pub fn fstatvfs(fd: usize, stat: &mut StatVfs) -> Result<usize> {
|
|
||||||
unsafe {
|
|
||||||
syscall3(
|
|
||||||
SYS_FSTATVFS,
|
|
||||||
fd,
|
|
||||||
stat as *mut StatVfs as usize,
|
|
||||||
mem::size_of::<StatVfs>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sync a file descriptor to its underlying medium
|
|
||||||
pub fn fsync(fd: usize) -> Result<usize> {
|
|
||||||
unsafe { syscall1(SYS_FSYNC, fd) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Truncate or extend a file to a specified length
|
|
||||||
pub fn ftruncate(fd: usize, len: usize) -> Result<usize> {
|
|
||||||
unsafe { syscall2(SYS_FTRUNCATE, fd, len) }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Change modify and/or access times
|
|
||||||
pub fn futimens(fd: usize, times: &[TimeSpec]) -> Result<usize> {
|
|
||||||
unsafe {
|
|
||||||
syscall3(
|
|
||||||
SYS_FUTIMENS,
|
|
||||||
fd,
|
|
||||||
times.as_ptr() as usize,
|
|
||||||
mem::size_of_val(times),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Fast userspace mutex
|
|
||||||
pub unsafe fn futex(
|
|
||||||
addr: *mut i32,
|
|
||||||
op: usize,
|
|
||||||
val: i32,
|
|
||||||
val2: usize,
|
|
||||||
addr2: *mut i32,
|
|
||||||
) -> Result<usize> {
|
|
||||||
syscall5(
|
|
||||||
SYS_FUTEX,
|
|
||||||
addr as usize,
|
|
||||||
op,
|
|
||||||
(val as isize) as usize,
|
|
||||||
val2,
|
|
||||||
addr2 as usize,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Seek to `offset` bytes in a file descriptor
|
|
||||||
pub fn lseek(fd: usize, offset: isize, whence: usize) -> Result<usize> {
|
|
||||||
unsafe { syscall3(SYS_LSEEK, fd, offset as usize, whence) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Make a new scheme namespace
|
|
||||||
pub fn mkns(schemes: &[[usize; 2]]) -> Result<usize> {
|
|
||||||
unsafe { syscall2(SYS_MKNS, schemes.as_ptr() as usize, schemes.len()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Change mapping flags
|
|
||||||
pub unsafe fn mprotect(addr: usize, size: usize, flags: MapFlags) -> Result<usize> {
|
|
||||||
syscall3(SYS_MPROTECT, addr, size, flags.bits())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sleep for the time specified in `req`
|
|
||||||
pub fn nanosleep(req: &TimeSpec, rem: &mut TimeSpec) -> Result<usize> {
|
|
||||||
unsafe {
|
|
||||||
syscall2(
|
|
||||||
SYS_NANOSLEEP,
|
|
||||||
req as *const TimeSpec as usize,
|
|
||||||
rem as *mut TimeSpec as usize,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Open a file at a specific path into specified fd number
|
|
||||||
pub fn openat_into<T: AsRef<str>>(
|
|
||||||
fd: usize,
|
|
||||||
out: usize,
|
|
||||||
path: T,
|
|
||||||
flags: usize,
|
|
||||||
fcntl_flags: usize,
|
|
||||||
) -> Result<usize> {
|
|
||||||
let path = path.as_ref();
|
|
||||||
unsafe {
|
|
||||||
syscall6(
|
|
||||||
SYS_OPENAT_INTO,
|
|
||||||
fd,
|
|
||||||
path.as_ptr() as usize,
|
|
||||||
path.len(),
|
|
||||||
flags,
|
|
||||||
fcntl_flags,
|
|
||||||
out,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Open a file at a specific path, letting the kernel allocate the new fd
|
|
||||||
pub fn openat<T: AsRef<str>>(fd: usize, path: T, flags: usize, fcntl_flags: usize) -> Result<usize> {
|
|
||||||
let path = path.as_ref();
|
|
||||||
unsafe {
|
|
||||||
syscall5(
|
|
||||||
SYS_OPENAT,
|
|
||||||
fd,
|
|
||||||
path.as_ptr() as usize,
|
|
||||||
path.len(),
|
|
||||||
flags,
|
|
||||||
fcntl_flags,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Open a file at a specific path with uid/gid filtering.
|
|
||||||
/// Red Bear: legacy wrapper preserved for bootstrap namespace capability checks.
|
|
||||||
pub fn openat_with_filter<T: AsRef<str>>(
|
|
||||||
fd: usize,
|
|
||||||
path: T,
|
|
||||||
flags: usize,
|
|
||||||
fcntl_flags: usize,
|
|
||||||
uid: u32,
|
|
||||||
gid: u32,
|
|
||||||
) -> Result<usize> {
|
|
||||||
let path = path.as_ref();
|
|
||||||
unsafe {
|
|
||||||
syscall6(
|
|
||||||
SYS_OPENAT_WITH_FILTER,
|
|
||||||
fd,
|
|
||||||
path.as_ptr() as usize,
|
|
||||||
path.len(),
|
|
||||||
flags | fcntl_flags,
|
|
||||||
uid as usize,
|
|
||||||
gid as usize,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Send a file descriptor to another process via a socket
|
|
||||||
pub fn sendfd(receiver_socket: usize, fd: usize, flags: usize, arg: u64) -> Result<usize> {
|
|
||||||
#[cfg(target_pointer_width = "32")]
|
|
||||||
unsafe {
|
|
||||||
syscall5(
|
|
||||||
SYS_SENDFD,
|
|
||||||
receiver_socket,
|
|
||||||
fd,
|
|
||||||
flags,
|
|
||||||
arg as u32 as usize,
|
|
||||||
(arg >> 32) as usize,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
#[cfg(target_pointer_width = "64")]
|
|
||||||
unsafe {
|
|
||||||
syscall4(SYS_SENDFD, receiver_socket, fd, flags, arg as usize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Remove a file at at specific path
|
|
||||||
pub fn unlinkat<T: AsRef<str>>(fd: usize, path: T, flags: usize) -> Result<usize> {
|
|
||||||
let path = path.as_ref();
|
|
||||||
unsafe { syscall4(SYS_UNLINKAT, fd, path.as_ptr() as usize, path.len(), flags) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Remove a file at a specific path with uid/gid filtering.
|
|
||||||
/// Red Bear: legacy wrapper preserved for bootstrap namespace capability checks.
|
|
||||||
pub fn unlinkat_with_filter<T: AsRef<str>>(
|
|
||||||
fd: usize,
|
|
||||||
path: T,
|
|
||||||
flags: usize,
|
|
||||||
uid: u32,
|
|
||||||
gid: u32,
|
|
||||||
) -> Result<usize> {
|
|
||||||
let path = path.as_ref();
|
|
||||||
unsafe {
|
|
||||||
syscall6(
|
|
||||||
SYS_UNLINKAT_WITH_FILTER,
|
|
||||||
fd,
|
|
||||||
path.as_ptr() as usize,
|
|
||||||
path.len(),
|
|
||||||
flags,
|
|
||||||
uid as usize,
|
|
||||||
gid as usize,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Read from a file descriptor into a buffer
|
|
||||||
pub fn read(fd: usize, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
unsafe { syscall3(SYS_READ, fd, buf.as_mut_ptr() as usize, buf.len()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Write a buffer to a file descriptor
|
|
||||||
///
|
|
||||||
/// The kernel will attempt to write the bytes in `buf` to the file descriptor `fd`, returning
|
|
||||||
/// either an `Err`, explained below, or `Ok(count)` where `count` is the number of bytes which
|
|
||||||
/// were written.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// * `EAGAIN` - the file descriptor was opened with `O_NONBLOCK` and writing would block
|
|
||||||
/// * `EBADF` - the file descriptor is not valid or is not open for writing
|
|
||||||
/// * `EFAULT` - `buf` does not point to the process's addressible memory
|
|
||||||
/// * `EIO` - an I/O error occurred
|
|
||||||
/// * `ENOSPC` - the device containing the file descriptor has no room for data
|
|
||||||
/// * `EPIPE` - the file descriptor refers to a pipe or socket whose reading end is closed
|
|
||||||
pub fn write(fd: usize, buf: &[u8]) -> Result<usize> {
|
|
||||||
unsafe { syscall3(SYS_WRITE, fd, buf.as_ptr() as usize, buf.len()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Yield the process's time slice to the kernel
|
|
||||||
///
|
|
||||||
/// This function will return Ok(0) on success
|
|
||||||
pub fn sched_yield() -> Result<usize> {
|
|
||||||
unsafe { syscall0(SYS_YIELD) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Call {
|
|
||||||
unsafe fn raw_call(
|
|
||||||
&self,
|
|
||||||
payload_ptr: *const u8,
|
|
||||||
len: usize,
|
|
||||||
flags: CallFlags,
|
|
||||||
metadata: &[u64],
|
|
||||||
) -> Result<usize>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Call for usize {
|
|
||||||
unsafe fn raw_call(
|
|
||||||
&self,
|
|
||||||
payload_ptr: *const u8,
|
|
||||||
len: usize,
|
|
||||||
flags: CallFlags,
|
|
||||||
metadata: &[u64],
|
|
||||||
) -> Result<usize> {
|
|
||||||
unsafe {
|
|
||||||
syscall5(
|
|
||||||
SYS_CALL,
|
|
||||||
*self,
|
|
||||||
payload_ptr as usize,
|
|
||||||
len,
|
|
||||||
metadata.len() | flags.bits(),
|
|
||||||
metadata.as_ptr() as usize,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Call for &[usize] {
|
|
||||||
unsafe fn raw_call(
|
|
||||||
&self,
|
|
||||||
payload_ptr: *const u8,
|
|
||||||
len: usize,
|
|
||||||
flags: CallFlags,
|
|
||||||
metadata: &[u64],
|
|
||||||
) -> Result<usize> {
|
|
||||||
let combined_flags = flags | CallFlags::MULTIPLE_FDS;
|
|
||||||
unsafe {
|
|
||||||
syscall6(
|
|
||||||
SYS_CALL,
|
|
||||||
self.as_ptr() as usize,
|
|
||||||
payload_ptr as usize,
|
|
||||||
len,
|
|
||||||
metadata.len() | combined_flags.bits(),
|
|
||||||
metadata.as_ptr() as usize,
|
|
||||||
self.len() * mem::size_of::<usize>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// SYS_CALL interface, read-only variant
|
|
||||||
pub fn call_ro<T: Call>(
|
|
||||||
fd: T,
|
|
||||||
payload: &mut [u8],
|
|
||||||
flags: CallFlags,
|
|
||||||
metadata: &[u64],
|
|
||||||
) -> Result<usize> {
|
|
||||||
unsafe {
|
|
||||||
fd.raw_call(
|
|
||||||
payload.as_mut_ptr(),
|
|
||||||
payload.len(),
|
|
||||||
flags | CallFlags::READ,
|
|
||||||
metadata,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// SYS_CALL interface, write-only variant
|
|
||||||
pub fn call_wo<T: Call>(
|
|
||||||
fd: T,
|
|
||||||
payload: &[u8],
|
|
||||||
flags: CallFlags,
|
|
||||||
metadata: &[u64],
|
|
||||||
) -> Result<usize> {
|
|
||||||
unsafe {
|
|
||||||
fd.raw_call(
|
|
||||||
payload.as_ptr(),
|
|
||||||
payload.len(),
|
|
||||||
flags | CallFlags::WRITE,
|
|
||||||
metadata,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// SYS_CALL interface, read-write variant
|
|
||||||
pub fn call_rw<T: Call>(
|
|
||||||
fd: T,
|
|
||||||
payload: &mut [u8],
|
|
||||||
flags: CallFlags,
|
|
||||||
metadata: &[u64],
|
|
||||||
) -> Result<usize> {
|
|
||||||
unsafe {
|
|
||||||
fd.raw_call(
|
|
||||||
payload.as_mut_ptr(),
|
|
||||||
payload.len(),
|
|
||||||
flags | CallFlags::READ | CallFlags::WRITE,
|
|
||||||
metadata,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn std_fs_call<T: Call>(fd: T, payload: &mut [u8], metadata: &StdFsCallMeta) -> Result<usize> {
|
|
||||||
call_rw(fd, payload, CallFlags::STD_FS, metadata)
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user