Compare commits
1028 Commits
pmsf/relen
...
pmsf-relea
| Author | SHA1 | Date | |
|---|---|---|---|
| 536ed76d5a | |||
| c4c3f5009e | |||
| 2da36731da | |||
| 206829415a | |||
| bb93064d78 | |||
| 669f61117d | |||
| 2e0a8f9b37 | |||
| 569255e6c4 | |||
| 576bee9a37 | |||
| 3e4c296eba | |||
| e209b7dac4 | |||
| 5f33d313c8 | |||
| 399237850d | |||
| 5286529632 | |||
| 2d3b9559bf | |||
| f34b1feaca | |||
| 096125d963 | |||
| 39b2afeb7c | |||
| 9bd04fa000 | |||
| 86e3cd0c5a | |||
| f33801e25e | |||
| d61985b37a | |||
| 7b99c3ac2c | |||
| 67fe371f84 | |||
| 5550e4336f | |||
| 43d9a7de9b | |||
| 13056da039 | |||
| a4a20360e9 | |||
| 9817204d8a | |||
| ec6a997f80 | |||
| 417a1ed384 | |||
| 983520d721 | |||
| 15f990bf71 | |||
| ee5425fe95 | |||
| 362cafb471 | |||
| 910a6bc859 | |||
| 5efa75d9b8 | |||
| aa0a45be05 | |||
| e596b871a9 | |||
| 90316c7c26 | |||
| 68666eee2a | |||
| f077d16c20 | |||
| 3b84e61ead | |||
| 85fca9e924 | |||
| ea2c36c5a9 | |||
| 5420bb8a67 | |||
| 5d1bc3fbd4 | |||
| 0486939291 | |||
| 9b3e4c5895 | |||
| 71c5ce5ced | |||
| 4beb469c91 | |||
| 42e2a67f23 | |||
| 559ee1e940 | |||
| d2332396e4 | |||
| a1c12b9fb9 | |||
| f7fc4f02cf | |||
| e5efd18435 | |||
| f843cadb6b | |||
| 77d7ea04ac | |||
| cd9514abc4 | |||
| 3980e07fe5 | |||
| b155432b65 | |||
| b5b12b89a0 | |||
| f5ae4daa5f | |||
| 8859dc9e6d | |||
| d815a0f658 | |||
| 23b257a8d2 | |||
| ed680da951 | |||
| bd69bce20f | |||
| 78c7096162 | |||
| ddecb0e685 | |||
| 5d6a9e797a | |||
| 22f5fccc2c | |||
| 3e77bfb6e9 | |||
| 3db037387c | |||
| d042e71e9f | |||
| 7ae35bf1bb | |||
| a158260e84 | |||
| 235711f3d3 | |||
| a2a596e767 | |||
| ddd461dcc8 | |||
| f081acbfba | |||
| 3bc9c325c5 | |||
| 0b0e64c2c9 | |||
| 7ab35c6265 | |||
| 0bca6cab06 | |||
| ad723a419f | |||
| b5669a952b | |||
| 975c74c1f5 | |||
| ad8e14b740 | |||
| ce55d03eef | |||
| fb933ae0eb | |||
| ca435dc2e3 | |||
| 31c7ea0165 | |||
| b303a00ce0 | |||
| d4d3144e75 | |||
| 892c3d996f | |||
| 1602998751 | |||
| f2a071e808 | |||
| 9656560f14 | |||
| 49bb5a7e06 | |||
| 5bd8aeb917 | |||
| dd57a34866 | |||
| e7ef087598 | |||
| 372f4b6a4e | |||
| d720865fb6 | |||
| be6d8ffc10 | |||
| d0d25ec7df | |||
| 0381387640 | |||
| 9e0af6d2b5 | |||
| ca8c1cd643 | |||
| 9ae10cad1f | |||
| c4edfb4e08 | |||
| 34fc6435ee | |||
| b1a906b970 | |||
| c0368604e1 | |||
| 45b24c37a0 | |||
| 4e46c22d5c | |||
| 4cb7047f0f | |||
| 8765826465 | |||
| b7ca74577b | |||
| 9e86ebee94 | |||
| 21da73c383 | |||
| 7bf323843e | |||
| ed7d54651d | |||
| 968bccdd2a | |||
| 5d0c16a884 | |||
| 662338f116 | |||
| e034853b38 | |||
| b7e0b693a6 | |||
| 8a1a2a6033 | |||
| 10e4db45dc | |||
| 5692716770 | |||
| e3f2a68311 | |||
| 6a5ec8cb3c | |||
| d9d029006c | |||
| 75e8df126f | |||
| f6c1eb10e2 | |||
| 2b618c1ab4 | |||
| 7e51546624 | |||
| e5f4f8d0e7 | |||
| bbce31552e | |||
| f9423ff3fa | |||
| 10c3514889 | |||
| 920474115c | |||
| 1a5eacb445 | |||
| ff5561ff7d | |||
| 253afeed1e | |||
| 63e3ff7cca | |||
| 8e4da42384 | |||
| c82e52d55b | |||
| 6763b02abc | |||
| d5d881d9e9 | |||
| 8531de319a | |||
| b6799ccd2e | |||
| 2b3c7d2287 | |||
| b285fc50f3 | |||
| 9285149548 | |||
| 21d2b71b5c | |||
| 38e5cf0983 | |||
| 8080401ab0 | |||
| e2f489aaff | |||
| 4094f7c5fc | |||
| 58963828ab | |||
| 5a222588a8 | |||
| 8a10a442ff | |||
| bde802df29 | |||
| 4af6e087dd | |||
| ed35ac841b | |||
| 2b7ee000cd | |||
| ca92bfc3c6 | |||
| fe6453f8f0 | |||
| d31226c873 | |||
| ee2108d07d | |||
| 11747fe5d0 | |||
| dfed9babfc | |||
| 0bf262864c | |||
| e0fe69050d | |||
| 2372639e9d | |||
| 3811794048 | |||
| e22249b81c | |||
| 557c5c1f11 | |||
| 59391d5520 | |||
| 097cf3aa5e | |||
| c4bec037be | |||
| 25927df3b7 | |||
| 2c38800bbe | |||
| a11b0a67e3 | |||
| 1c811a4d1d | |||
| 523b55d82d | |||
| 6cd23d1d8c | |||
| cb273fdad8 | |||
| 60374d01ae | |||
| f924d0ca96 | |||
| 64b5ee2dea | |||
| 9e6610b0aa | |||
| e9769a7249 | |||
| bf692af31b | |||
| ccf9ed7d54 | |||
| ed99f3608d | |||
| d2e2f42382 | |||
| 3c68a8c6c0 | |||
| 0d14e7e698 | |||
| a52a39179a | |||
| 4a3741bf02 | |||
| 47fd807f9b | |||
| 4af25aed92 | |||
| 59216d3db0 | |||
| 7c28c9b13f | |||
| 7e7f2e5d1b | |||
| 550e861bf7 | |||
| cdf715a0b5 | |||
| 3054a76249 | |||
| 02642bc94c | |||
| bfd1c08d6c | |||
| 02919cd275 | |||
| 0be098929a | |||
| 6fbcc14a5d | |||
| 68a7af632c | |||
| d9b7f018ce | |||
| 6245db9fca | |||
| 4ac0e1971e | |||
| 06db384f8a | |||
| f7bfa0970e | |||
| f3c1ea6c2d | |||
| 4d247c00a3 | |||
| 3e32479594 | |||
| 70dec93f2b | |||
| 36759ddacf | |||
| 18a5d8188a | |||
| 383f568a64 | |||
| 682ecc1745 | |||
| 7600b03f35 | |||
| c232af7ddb | |||
| ed15cddacd | |||
| 8986bc8af4 | |||
| 07ca2df588 | |||
| 7bd30a488a | |||
| 7dddd65b46 | |||
| 94d8d12c26 | |||
| 5a0ca53a4a | |||
| 35b7bf9382 | |||
| 07818ec6a7 | |||
| 61894e17cd | |||
| 71b16f4e18 | |||
| 78c08898ae | |||
| bf10bca192 | |||
| 52a152235e | |||
| 6775c7cb3a | |||
| c09b6ce975 | |||
| 3dfee1d290 | |||
| b42cb16b65 | |||
| b691585785 | |||
| 1c4cf18556 | |||
| 5805b07218 | |||
| 78f1c10e0f | |||
| f795e1be83 | |||
| da63695cf3 | |||
| c2ad11ac70 | |||
| f350487e1e | |||
| 49d3118621 | |||
| d25948c5a7 | |||
| e03306d170 | |||
| 332cf5327f | |||
| 5a23a72aed | |||
| 8afb8ccba2 | |||
| c5b9ae4e3f | |||
| 643a1b8848 | |||
| afdbc5b815 | |||
| 0a624782df | |||
| 6d2be31b93 | |||
| 0d9f88ea67 | |||
| 2f1174550e | |||
| 2d6aa65067 | |||
| 9c5bb16447 | |||
| acac35c125 | |||
| 8637c1d0ad | |||
| 766ba3694d | |||
| eacdc426d7 | |||
| 09a487eb2b | |||
| e630113771 | |||
| 3ddbfe1a82 | |||
| 07e47b3dd6 | |||
| cf32bb8812 | |||
| e238e6521b | |||
| fc0fc6aba3 | |||
| d5a1e32ac3 | |||
| beab3f8c71 | |||
| 889ee28ed5 | |||
| 08335c1548 | |||
| e037fd3364 | |||
| 6db7a2157b | |||
| 30238b1ebd | |||
| ff158bffe6 | |||
| e38f49e32a | |||
| c1b101cbaf | |||
| e91ce66dad | |||
| c948732efa | |||
| 0373fe0e2a | |||
| 71b6220963 | |||
| 0a402f6e91 | |||
| 41349948f8 | |||
| 0360905124 | |||
| 1751588435 | |||
| 3f21d81073 | |||
| ab8422c8e7 | |||
| b67951bed4 | |||
| 100f94be99 | |||
| 1ca685f887 | |||
| 9e0e05eb4e | |||
| bab4519617 | |||
| d0e48c51c7 | |||
| 18cbe62e69 | |||
| 824b1b582f | |||
| 778ec44adc | |||
| 4e7a8906a1 | |||
| 19a169ceb8 | |||
| 1339d04759 | |||
| 3f233ab127 | |||
| f2a4cb0a0e | |||
| 0f36f60faa | |||
| a37f8cfc80 | |||
| 9d679e3916 | |||
| 7cfd21440b | |||
| 4f27e217a8 | |||
| 080ec9fadd | |||
| 5e4d0718ff | |||
| a66ba1f2a1 | |||
| 6bd8c936e3 | |||
| b9f01dffc6 | |||
| f3cee9ceff | |||
| 55bd08c5ae | |||
| f0fa5603cf | |||
| 4d68828259 | |||
| 613962e353 | |||
| bd93dc6923 | |||
| 9645b62a65 | |||
| 5e47b08dc8 | |||
| f5f82abc99 | |||
| 75243f744c | |||
| a94e8d439a | |||
| d48662d496 | |||
| fe845cf53d | |||
| caebbc3ee1 | |||
| 0fbc77cac6 | |||
| a348513569 | |||
| 6015840583 | |||
| 07d896c8e5 | |||
| 2bfedb1867 | |||
| 78e4ee55b7 | |||
| 78ee3759b8 | |||
| d1515a0536 | |||
| 6afe668ec7 | |||
| 09a78412f0 | |||
| 3283c26827 | |||
| a1c139063b | |||
| 256078933c | |||
| 68ce8639bb | |||
| b4125ba0c1 | |||
| 1f49441a27 | |||
| edcb15c31f | |||
| 8db7a0f7af | |||
| d25f67ec12 | |||
| cdc16d428f | |||
| 224236f57c | |||
| acc8f602e5 | |||
| f021a7cd94 | |||
| 587aacedf3 | |||
| e010b1396b | |||
| 5ee097fce9 | |||
| c6dc756d4e | |||
| 16cbca281f | |||
| 5fb57bead4 | |||
| 34feee0ed6 | |||
| cb5f6b063b | |||
| b3782c3cf5 | |||
| 98ffeaa0c5 | |||
| 810a677d32 | |||
| 6a49afb3ed | |||
| 989b5ee8ae | |||
| a1a5c81e6c | |||
| 52d194a1e6 | |||
| b5b3e89f9e | |||
| b0296139a8 | |||
| f869dfb47f | |||
| 131d776d66 | |||
| 174d06a3ff | |||
| e946eb2a41 | |||
| 0691b7630b | |||
| effc7d9ed4 | |||
| 983c40f58b | |||
| 936819a1b9 | |||
| c9473a7529 | |||
| 5a704457e2 | |||
| d3e85e80fd | |||
| 21665f4338 | |||
| 5278d217ff | |||
| 41785a0bf9 | |||
| 2bf43b5483 | |||
| 80343ab7d8 | |||
| 8fc5a6a2a4 | |||
| f85db99ff0 | |||
| aa1ed616eb | |||
| 05ec6654a7 | |||
| 17395ea507 | |||
| fa2472c172 | |||
| 5175b1ad87 | |||
| 712eca44d5 | |||
| 9d778c7bb6 | |||
| 32755dbea9 | |||
| d715ebdae0 | |||
| 95aac21130 | |||
| 2dc7161453 | |||
| 8e4d64be2f | |||
| ceccd3ead3 | |||
| 7e0ad4fdd2 | |||
| f75f89fc8f | |||
| 541b33591c | |||
| 933c2235e5 | |||
| f15c0a9333 | |||
| e264243adc | |||
| c4d0498b3a | |||
| d1e15514aa | |||
| 1c2dfa1f4b | |||
| 4886d2c640 | |||
| 99372bb1d3 | |||
| 51c3465a49 | |||
| 7301b42e36 | |||
| 737f984213 | |||
| cfef9ac3f5 | |||
| dd40d6a068 | |||
| 5bd5fd488d | |||
| 3ff77a1d6f | |||
| c7067aeb84 | |||
| 4ae626451e | |||
| 8dd1859176 | |||
| 0b3612631f | |||
| 54cf57ab1a | |||
| 992cbda8d0 | |||
| 30c54c9d43 | |||
| 58a34d22c9 | |||
| ba99a70cd8 | |||
| 553242c18a | |||
| 5d496b1695 | |||
| 569fba6db9 | |||
| 3712c958f4 | |||
| c39bc9caa7 | |||
| a7334f791d | |||
| c52128c581 | |||
| 951c23f257 | |||
| 37e815eee1 | |||
| 763dd22b35 | |||
| ec67dc482f | |||
| acbab220c8 | |||
| 9d33388b29 | |||
| 9c52ba48b3 | |||
| 6e261a107c | |||
| 7307a6a3cb | |||
| 8fc9c79705 | |||
| 7cb921a44b | |||
| eb00777309 | |||
| 7f0b798418 | |||
| 97916c9d04 | |||
| 41408f2104 | |||
| 0ad87a094c | |||
| a6276b7a78 | |||
| 45bc505968 | |||
| f7dd3d49cc | |||
| 24308fd292 | |||
| 20f0c179da | |||
| b051549f2e | |||
| 8eab556ac5 | |||
| 9bf0e57509 | |||
| f4082851ea | |||
| 35e715a1e3 | |||
| c07785a1ea | |||
| 12f94f2770 | |||
| f3ce1be333 | |||
| 003c532bf3 | |||
| ad1c01f96c | |||
| 6b9490b6ff | |||
| ad524bb6c7 | |||
| 285292992f | |||
| c3975cf27c | |||
| f0b7566181 | |||
| 743684fe39 | |||
| c899659d39 | |||
| eafd7a7d3b | |||
| a16f862cf6 | |||
| 6cb74ecacf | |||
| 5860b639c6 | |||
| 00ba4b7625 | |||
| 8077f0acc7 | |||
| e7e7a0d301 | |||
| eb870b006c | |||
| 8f620c8af8 | |||
| ef3d38c5c9 | |||
| 89ad24e7d6 | |||
| 5a16f5ea98 | |||
| 7f5b95ea32 | |||
| 271abe7117 | |||
| 770fd39bd1 | |||
| 07c6263732 | |||
| e667d0cc9c | |||
| 47e06c6d4e | |||
| 694d0fdade | |||
| 9e1b6bf517 | |||
| d6b64e2574 | |||
| 41031221c8 | |||
| 5e67f24e6b | |||
| 4e04f67c94 | |||
| 101cc8747f | |||
| 80322adaa0 | |||
| cf92f7aacb | |||
| 06e0753fce | |||
| 1234beccb8 | |||
| c52e1a9af5 | |||
| 121e95d115 | |||
| a98fd13090 | |||
| ae09051c81 | |||
| cb7e820eae | |||
| ff06d4258e | |||
| c497f9c82c | |||
| 87a0109604 | |||
| 30df3189b1 | |||
| 70a6c4601e | |||
| c75d0deecf | |||
| 999274ca90 | |||
| fca58734fb | |||
| 576aeb3aa9 | |||
| 2ba219f781 | |||
| 929d171f47 | |||
| 27ec4f67a3 | |||
| 3b4c42c3c0 | |||
| 823d0583dc | |||
| 2f90db434e | |||
| 2f50cefbd4 | |||
| a6e6a954f5 | |||
| 0877ba7cbf | |||
| a3d78b95d7 | |||
| 1e878200f7 | |||
| 3a922ad2ba | |||
| a6b94eff79 | |||
| 951a43ea6c | |||
| 2e04fa8872 | |||
| 4126056fbe | |||
| 44c330d647 | |||
| d2dd6fdbfb | |||
| bd489a4815 | |||
| bbcb54a1f4 | |||
| 2e51f0ee63 | |||
| 1351de6ad1 | |||
| 2df290073b | |||
| 2d3458363e | |||
| 8d44851d65 | |||
| 1dd3f88f3b | |||
| 9cbab3630e | |||
| 72e8ff11e9 | |||
| 7c27186a83 | |||
| 059aea5d35 | |||
| aacf65bbfa | |||
| b08ce88082 | |||
| 0c8447db79 | |||
| 5e8fb713c4 | |||
| 5ce2154c74 | |||
| 9336fa7ae5 | |||
| b472d53672 | |||
| aeaff94ec1 | |||
| e50d68e417 | |||
| 8615bb40fb | |||
| a13f183e4c | |||
| 0536407204 | |||
| dcb36587b5 | |||
| e8ad336ac5 | |||
| e7a60e4d01 | |||
| 4bb9dd44f1 | |||
| 5c9dde7255 | |||
| 92efee6e52 | |||
| d81611b641 | |||
| 8037a1ce39 | |||
| 70dbe169b2 | |||
| 559675b90a | |||
| e92dc595cd | |||
| 7e7e6148fd | |||
| 5cd4393a54 | |||
| 089ce6235c | |||
| 3c372b4c8a | |||
| dec959358a | |||
| 9fc3d66f1b | |||
| aa6946b92c | |||
| 50fc86a447 | |||
| 2ba7542e4b | |||
| fa0eff949d | |||
| 96debc72f8 | |||
| db08122d31 | |||
| d80593bc4d | |||
| f2cfc07554 | |||
| 3b7f5008fd | |||
| acef4ff244 | |||
| 548a55eda5 | |||
| a105837aae | |||
| cde79a805e | |||
| 724425addf | |||
| 8f6390061d | |||
| 8dbe129ab7 | |||
| c2efd7c53b | |||
| bd531ec1fd | |||
| 367bb6f4b7 | |||
| aba2d648f4 | |||
| b5d25654d8 | |||
| 63d068d3f2 | |||
| 78c076a70f | |||
| e3851d233f | |||
| cfaa165e62 | |||
| 3dba9cc13d | |||
| e2650608cd | |||
| aa812e8745 | |||
| 5de8b5638f | |||
| 0e79df499a | |||
| 5bcc3eed7b | |||
| 68605ab4d4 | |||
| 4ba7e5dc5a | |||
| 896a0c881a | |||
| 87ec08ecc8 | |||
| 25b2779c3d | |||
| 2eb4f4a3ba | |||
| 0ecee0072d | |||
| 50899e30ab | |||
| d73b488401 | |||
| 03303628c7 | |||
| d854dede03 | |||
| ac70e6b840 | |||
| 9163393476 | |||
| 8d4c861144 | |||
| 238e760a29 | |||
| 8764993c0d | |||
| 65a4fbd1d4 | |||
| 883aafc6bb | |||
| d9b87c087c | |||
| 4b92dbf923 | |||
| 44c6e992bd | |||
| 3fb8b14806 | |||
| 664c19ad5e | |||
| bfb7b0d959 | |||
| 48d12e42ad | |||
| 76af948623 | |||
| 54fc439e9e | |||
| 1cbb4d322b | |||
| 7ed4341538 | |||
| 7ec39e2288 | |||
| 149c2a9cc9 | |||
| d972472c53 | |||
| f1e4b2b7f3 | |||
| b8925960ec | |||
| 7b96ddd045 | |||
| 351e2ec334 | |||
| 4b61f7f04b | |||
| dfbb00c106 | |||
| 859ce5e47f | |||
| 2e6626a4b3 | |||
| d70440b406 | |||
| 43e4a406b4 | |||
| 774f0611cc | |||
| 6cbf4fb740 | |||
| cd4f3d962d | |||
| 2d83ec7aa3 | |||
| b5f88b593a | |||
| 7f36abd3f2 | |||
| e374a733d6 | |||
| 4c8ffb353d | |||
| 20074d8862 | |||
| 2437ccdc76 | |||
| c45a8695eb | |||
| 6fd4e5bace | |||
| 09feeca5df | |||
| 1a1e9548fb | |||
| bbf8221ec3 | |||
| a429d40f06 | |||
| e2a8fd4520 | |||
| 8d10c5788f | |||
| 09d4e4f408 | |||
| 252a151fc6 | |||
| b7b9f9f511 | |||
| 50cdccf3ef | |||
| 40418f87c7 | |||
| 5e3e321474 | |||
| 1706d2254b | |||
| 1d41da9590 | |||
| 86e8dcd5e2 | |||
| 883fd365c7 | |||
| fc119f9840 | |||
| 8329facdfa | |||
| a4d43618fb | |||
| 36bb8994dd | |||
| 97e08be344 | |||
| 40f7e11c53 | |||
| 6d055312a2 | |||
| b14ef0e24b | |||
| 738606dbd5 | |||
| 86c850fc58 | |||
| ff3f9aa6ba | |||
| a6c3ce6ec0 | |||
| ff783b94c7 | |||
| fb6331e0fa | |||
| a6149c6dbb | |||
| ae09558d71 | |||
| e260b03686 | |||
| c334b59142 | |||
| b93179f3c0 | |||
| 524abd46b4 | |||
| 77ef3b2929 | |||
| 5a76c5d2f3 | |||
| 20a5845a47 | |||
| f1703e2b2f | |||
| 4bf3f6c965 | |||
| 73e8f6b60a | |||
| 4ae462b668 | |||
| 9b14e8715a | |||
| f40b82295e | |||
| 1e07ea71d3 | |||
| 26b26f355f | |||
| 9d7fb33360 | |||
| 87d879aa7b | |||
| 63376d7712 | |||
| b84cdf6214 | |||
| 178275dc0c | |||
| 14745bdeb7 | |||
| 12f43953ed | |||
| 73a7dd79af | |||
| 7c474b4da3 | |||
| f2ee6b1759 | |||
| 8257829623 | |||
| 89000c18dc | |||
| b31e80a43a | |||
| a3fc543459 | |||
| 799512388c | |||
| 6e0a658e96 | |||
| f26fdaefd8 | |||
| 1fa0fe2786 | |||
| 7a3f6d4941 | |||
| d316836008 | |||
| 89134dd7b0 | |||
| 698b16960a | |||
| bcf60562e0 | |||
| 9c78da8a32 | |||
| 3d608d4b54 | |||
| 0199123dd7 | |||
| f8b4f59f8b | |||
| e5e7f488e2 | |||
| a94ed43094 | |||
| 196c999515 | |||
| 276553c6b2 | |||
| 52891b6ff6 | |||
| 5a514107c4 | |||
| 5d0785d0e1 | |||
| fcb3772a34 | |||
| 07614b5e22 | |||
| c6345b5a8a | |||
| 72f466c24c | |||
| 8d5e0cf083 | |||
| 03687729ec | |||
| 14d0aa450f | |||
| 0f51ccd4e4 | |||
| ad787abea6 | |||
| 899d26605c | |||
| 5e56fb635a | |||
| 089dea355a | |||
| a0d45c1bcd | |||
| 6755b4a3de | |||
| e647c3137d | |||
| 6c8207633f | |||
| 5b52a44b52 | |||
| ee99fd45ab | |||
| 504d40a328 | |||
| 59a22d59a2 | |||
| 2742fbcf95 | |||
| 87a850f553 | |||
| 9e3713facd | |||
| 2b2e7f85d7 | |||
| ba61fd9cd1 | |||
| 5af0ea7fb8 | |||
| 9ff288648b | |||
| 515169f21b | |||
| 2a8905c93b | |||
| 02e2fe3c26 | |||
| e20c1eb99e | |||
| 89f7aea980 | |||
| deaee6c249 | |||
| 857f7dbfa6 | |||
| 4b50557553 | |||
| 2ac238fc50 | |||
| 6b7a6fcbc8 | |||
| 356c6f6293 | |||
| e69c506617 | |||
| a9fda392a0 | |||
| fbda78aefe | |||
| 112148172b | |||
| aa255f37f2 | |||
| 0a51386960 | |||
| 0e3d2e0bea | |||
| 6e56bb387d | |||
| 9714d2e75f | |||
| 469ae3a7e5 | |||
| b8eb7dd8e8 | |||
| 8d3e0b3080 | |||
| 5f7cdd29b6 | |||
| df0267b287 | |||
| bba1c381f4 | |||
| 822f4630e3 | |||
| a715d7143d | |||
| 91d4db600b | |||
| c2422ba87f | |||
| 3e9a7e9d69 | |||
| d09a46d655 | |||
| f90bad0925 | |||
| 76accfb8d5 | |||
| f01373765b | |||
| 0961a38493 | |||
| 0e43f3aef4 | |||
| 6a947d9d26 | |||
| 01c0419234 | |||
| 9750d0b725 | |||
| c4427747e6 | |||
| b0f8ca5e03 | |||
| 3d18c9aa64 | |||
| 0688afdd34 | |||
| 5879c854fb | |||
| 2024c44541 | |||
| f2c8491fc0 | |||
| a913ee6082 | |||
| ea2805f097 | |||
| 3e56584223 | |||
| a620b12dc1 | |||
| 01cf514e59 | |||
| 0bd1282059 | |||
| 080ad7e62a | |||
| 5a5fee867a | |||
| 80811671d4 | |||
| fdc31e152b | |||
| 3900b235e0 | |||
| 0ac8aaab1b | |||
| 1075087241 | |||
| f272407353 | |||
| b018bac9c8 | |||
| b125743323 | |||
| 9a6ee577f6 | |||
| 5c233f2cf3 | |||
| c025478d7c | |||
| 700c2f769b | |||
| 0ba7c8670c | |||
| 14bb8302c4 | |||
| 4bc83ac393 | |||
| aa561d7011 | |||
| bed865275d | |||
| ad9568060e | |||
| dc8ea93b13 | |||
| 078ba241d9 | |||
| f1f45a47ef | |||
| 6f6ed8acc7 | |||
| b8610f14b0 | |||
| b68499e971 | |||
| ec1c83081d | |||
| 40e3859739 | |||
| b2192fc50b | |||
| d3d89900f6 | |||
| 62d1da1b3e | |||
| 98afe11c85 | |||
| 73ac39c317 | |||
| e50f08faa1 | |||
| 33cea54dc7 | |||
| fdb3b10d06 | |||
| ba286136bf | |||
| 361ec4f98e | |||
| c6017182f6 | |||
| 497f9393e0 | |||
| b46f7461a3 | |||
| d0dae7f241 | |||
| b0b5165d16 | |||
| e571850d79 | |||
| 4aec2902ca | |||
| 55f751ac6d | |||
| 88c9f1bb4e | |||
| d029507494 | |||
| 0ab07f39a6 | |||
| 02d2ca8ac7 | |||
| 17314a1fb3 | |||
| 4e5f15c685 | |||
| 1415d7e6b6 | |||
| 4760804dba | |||
| 9fc57302f8 | |||
| 2eb844f8b5 | |||
| e5a706a091 | |||
| f62e97e0ed | |||
| 8635939b8d | |||
| b5b82df3e3 | |||
| 3cbc7a2dcc | |||
| 599677a5e2 | |||
| 3d4b57ffe3 | |||
| 6f3569e4e2 | |||
| c88c2706a2 | |||
| 5cbe03b9c4 | |||
| fad8e13ccd | |||
| 32a4962593 | |||
| 48ad93983f | |||
| 75118780da | |||
| 262eec3e83 | |||
| 8e724128e8 | |||
| f42a02efda | |||
| 05c9b76131 | |||
| 9c6ddbfe90 | |||
| 9e11476e15 | |||
| 80b36ab628 | |||
| fdf9fba578 | |||
| ea7b17f641 | |||
| 935d8169b8 | |||
| 767410b875 | |||
| da0601e490 | |||
| bf2854d2a2 | |||
| 3352cb8aef | |||
| 32734680cb | |||
| 28f0286479 | |||
| b6247d1f3c | |||
| 70a088af87 | |||
| 58f3b7781b | |||
| 99851b0d9e | |||
| 3fe2a95d7f | |||
| 2bd0daabbe | |||
| d443644de3 | |||
| 4ad186c5ef | |||
| 8efaa71190 | |||
| bcc1904f9c | |||
| a01d83d783 | |||
| 5078a06e91 | |||
| eda2c756ed | |||
| c634c797c5 | |||
| 9e9e5c2929 | |||
| 3eed3506b4 | |||
| 0382131c6f | |||
| 9e79b18bca | |||
| e0e9a2a295 | |||
| 59b8007f98 | |||
| fbc8810334 | |||
| 46dd2971ab | |||
| a24e31e85d | |||
| f2dbcf7594 | |||
| 389c25c4b9 | |||
| 3676f61983 | |||
| 5919da6f05 | |||
| 4260ce1889 | |||
| 82b257c29c | |||
| 48fc746652 | |||
| dcec8673f2 | |||
| d9d60a1ebd | |||
| 63a84713ee | |||
| c3e7c725b5 | |||
| 41ce391c86 | |||
| 1b606d1884 | |||
| 0c40bc8982 | |||
| 1528a08540 | |||
| 0650ab01c8 | |||
| fbb4841606 | |||
| b7d017dec8 | |||
| cf02f920c1 | |||
| 1c4afd1350 | |||
| 3b07a15fd1 | |||
| d0c2f00df2 | |||
| 385a86b000 | |||
| 0f5942c6b3 | |||
| a1a691a030 | |||
| 45b35a3d66 | |||
| 673befd2d7 | |||
| 82969f045c | |||
| 0f522fb32a | |||
| a465b7f58f | |||
| 642b6d0f50 | |||
| 76cb1144ef | |||
| 13b997668e | |||
| 235a65033f | |||
| 9382d6f1a0 | |||
| 73faaea227 | |||
| 69c2e7f96c | |||
| 8c033a1461 | |||
| 37b0348993 | |||
| f6b50558fc | |||
| 807dc7c8de | |||
| d0c4138ac2 | |||
| 47d9f08c6f | |||
| 47305d427d | |||
| 6f512a7f1c | |||
| e670435500 | |||
| 4d86b20701 | |||
| be1b6ba7b7 | |||
| 41b3c7a507 | |||
| 6ee366e765 | |||
| 41d76e1fcb | |||
| ae2ece93da | |||
| 1caee8ab3b | |||
| e7a7efed11 | |||
| 5c35ba66c5 | |||
| 8a81f9e103 | |||
| 05fa2e754b | |||
| 23f73e92f3 | |||
| cbce6d2bac | |||
| 946afd2343 | |||
| 0e17671f72 | |||
| b961ba5396 | |||
| 55ea6d3fc1 | |||
| 3f1d900007 | |||
| 2bbfaf436f | |||
| ce5e12c2f9 | |||
| e31579b076 | |||
| 1d673cbfd6 | |||
| 1ef95ea342 | |||
| 0de6fe6c41 | |||
| c68af2db9d | |||
| 6ed6a36a51 | |||
| d9dfd9cded | |||
| c219a53402 | |||
| 243c699009 | |||
| 183b2ab14c | |||
| 0ad857c80e | |||
| 0db7f616ad | |||
| 5d6cfe855a | |||
| e946c3583f | |||
| 322743eef8 | |||
| 3ad64ffe2e | |||
| fe64a4d005 | |||
| 0bdbd49eac |
100
.gitignore
vendored
100
.gitignore
vendored
@ -1,58 +1,56 @@
|
||||
*~
|
||||
\#*
|
||||
.#*
|
||||
*.o
|
||||
*.a
|
||||
*.exe
|
||||
*.dll
|
||||
*.obj
|
||||
*.pdb
|
||||
*.lib
|
||||
*.exp
|
||||
*.log
|
||||
*.bz2
|
||||
*.zip
|
||||
.gdb_history
|
||||
a.out
|
||||
tcc_g
|
||||
tcc
|
||||
/*-tcc
|
||||
tc2.c
|
||||
doc
|
||||
tc3s.c
|
||||
p3.c
|
||||
tc1.c
|
||||
error.c
|
||||
i386-gen1.c
|
||||
test.out1
|
||||
test.out1b
|
||||
test.out2
|
||||
test.out2b
|
||||
test.out3
|
||||
test.out3b
|
||||
web.sh
|
||||
memdebug.c
|
||||
bench
|
||||
Makefile.uClibc
|
||||
boundtest
|
||||
prog.ref
|
||||
test.ref
|
||||
test.out
|
||||
tcc-doc.html
|
||||
ideas
|
||||
tcctest.ref
|
||||
linux.tcc
|
||||
ldtest
|
||||
libtcc_test
|
||||
instr.S
|
||||
p.c
|
||||
p2.c
|
||||
tcctest[1234]
|
||||
test[1234].out
|
||||
tests/tcclib.h
|
||||
tests/tcctest.gcc
|
||||
tests/weaktest.*.o.txt
|
||||
tests2/fred.txt
|
||||
.gdb_history
|
||||
*-tcc
|
||||
libtcc*.def
|
||||
|
||||
config*.h
|
||||
config*.mak
|
||||
config.texi
|
||||
conftest*
|
||||
tags
|
||||
TAGS
|
||||
tcc.1
|
||||
tcc.pod
|
||||
config.h
|
||||
config.mak
|
||||
config.texi
|
||||
tags
|
||||
.DS_Store
|
||||
*.swp
|
||||
lib/x86_64
|
||||
lib/i386
|
||||
lib/x86_64-win32
|
||||
lib/i386-win32
|
||||
tcc-doc.html
|
||||
tcc-doc.info
|
||||
conftest*
|
||||
tiny_libmaker
|
||||
*.dSYM
|
||||
|
||||
win32/doc
|
||||
win32/libtcc
|
||||
win32/lib/32
|
||||
win32/lib/64
|
||||
win32/include/float.h
|
||||
win32/include/stdarg.h
|
||||
win32/include/stdbool.h
|
||||
win32/include/stddef.h
|
||||
win32/include/varargs.h
|
||||
win32/include/tcclib.h
|
||||
|
||||
tests/test.out*
|
||||
tests/test*.out
|
||||
tests/tcctest[1234]
|
||||
tests/tcctest.gcc
|
||||
tests/*.ref
|
||||
tests/*.txt
|
||||
tests/*.gcc
|
||||
tests/*-cc*
|
||||
tests/*-tcc*
|
||||
tests/libtcc_test
|
||||
tests/vla_test
|
||||
tests/hello
|
||||
tests/tests2/fred.txt
|
||||
|
||||
45
Changelog
45
Changelog
@ -1,3 +1,44 @@
|
||||
Version 0.9.27:
|
||||
|
||||
User interface:
|
||||
- -x[c|a|n] filetype option (Sergey Korshunoff)
|
||||
- -P[1], -dD, -dM preprocessor options (Sergey Korshunoff)
|
||||
- -Wl,-(no-)whole-archive linker option (Reuben Thomas)
|
||||
- -mms-bitfields option (David Mertens)
|
||||
- -include <file> option (Michael Matz)
|
||||
- -mno-sse on x86-64 disables use of SSE instructions
|
||||
- @listfile support (Vlad Vissoultchev)
|
||||
- tcc -ar/-impdef - formerly tiny_xxx tools integrated (grischka)
|
||||
- CPATH, C_INCLUDE_PATH and LD_LIBRARY_PATH environment variables support
|
||||
(Andrew Aladjev, Urs Janssen)
|
||||
|
||||
Platforms:
|
||||
- Bootstrap native Windows 32/64 compiler using Cygwin+gcc (Christian Jullien)
|
||||
- new AARCH64 (arm64) target (Edmund Grimley Evans)
|
||||
- vastly improved support for ARM hard float calling convention
|
||||
(Thomas Preud'homme, Daniel Glöckner)
|
||||
- provide a runtime library for ARM (Thomas Preud'homme)
|
||||
- many x86_64 ABI fixes incl. XMM register passing and tests (James Lyon)
|
||||
- ABI tests with native compiler using libtcc (James Lyon)
|
||||
- UNICODE startup code supports wmain and wWinMain (YX Hao)
|
||||
- shared libraries for x86_64 (Michael Matz)
|
||||
|
||||
Features:
|
||||
- VLA (variable length array) improved (James Lyon, Pip Cet)
|
||||
- import functions by ordinal in .def files on windows (YX Hao)
|
||||
- x86/x86_64 assembler much improved (Michael Matz)
|
||||
- simple dead code suppression (Edmund Grimley Evans, Michael Matz, grischka)
|
||||
- implement round/fmin/fmax etc. math on windows (Avi Halachmi)
|
||||
- #pragma once support (Sergey Korshunoff, Vlad Vissoultchev, ...)
|
||||
- switch/case code improved (Zdenek Pavlas)
|
||||
- ~15% faster by TinyAlloc fast memory allocator (Vlad Vissoultchev)
|
||||
- standard conforming (and GCC compatible) struct initialization
|
||||
(Michael Matz)
|
||||
- bit-field layout made compatible with GCC (Michael Matz)
|
||||
|
||||
Licensing:
|
||||
- TinyCC partly relicensed to MIT license (See RELICENSING file).
|
||||
|
||||
version 0.9.26:
|
||||
|
||||
User interface:
|
||||
@ -10,7 +51,7 @@ User interface:
|
||||
Platforms:
|
||||
- Many improvements for x86-64 target (Shinichiro Hamaji, Michael Matz, grischka)
|
||||
- x86-64 assembler (Frederic Feret)
|
||||
- Many improvements for ARM target (Daniel Gl<EFBFBD>ckner, Thomas Preud'homme)
|
||||
- Many improvements for ARM target (Daniel Glöckner, Thomas Preud'homme)
|
||||
- Support WinCE PE ARM (Timo VJ Lahde)
|
||||
- Support ARM hardfloat calling convention (Thomas Preud'homme)
|
||||
- Support SELinux (Security-Enhanced Linux) (Henry Kroll III)
|
||||
@ -29,7 +70,7 @@ Features:
|
||||
version 0.9.25:
|
||||
|
||||
- first support for x86-64 target (Shinichiro Hamaji)
|
||||
- support <EFBFBD>Clibc
|
||||
- support µClibc
|
||||
- split tcc.c into tcc.h libtcc.c tccpp.c tccgen.c tcc.c
|
||||
- improved preprocess output with linenumbers and spaces preserved
|
||||
- tcc_relocate now copies code into user buffer
|
||||
|
||||
71
CodingStyle
Normal file
71
CodingStyle
Normal file
@ -0,0 +1,71 @@
|
||||
|
||||
In general, use the same coding style as the surrounding code.
|
||||
|
||||
However, do not make any unnecessary changes as that complicates
|
||||
the VCS (git) history and makes it harder to merge patches. So
|
||||
do not modify code just to make it conform to a coding style.
|
||||
|
||||
Indentation
|
||||
|
||||
Turn on a "fill tabs with spaces" option in your editor.
|
||||
|
||||
Remove tabs and trailing spaces from any lines that are modified.
|
||||
|
||||
Note that some files are indented with 2 spaces (when they
|
||||
have large indentation) while most are indented with 4 spaces.
|
||||
|
||||
Language
|
||||
|
||||
TCC is mostly implemented in C90. Do not use any non-C90 features
|
||||
that are not already in use.
|
||||
|
||||
Non-C90 features currently in use, as revealed by
|
||||
./configure --extra-cflags="-std=c90 -Wpedantic":
|
||||
|
||||
- long long (including "LL" constants)
|
||||
- inline
|
||||
- very long string constants
|
||||
- assignment between function pointer and 'void *'
|
||||
- "//" comments
|
||||
- empty macro arguments (DEF_ASMTEST in i386-tok.h)
|
||||
- unnamed struct and union fields (in struct Sym), a C11 feature
|
||||
|
||||
Testing
|
||||
|
||||
A simple "make test" is sufficient for some simple changes. However,
|
||||
before committing a change consider performing some of the following
|
||||
additional tests:
|
||||
|
||||
- Build and run "make test" on several architectures.
|
||||
|
||||
- Build with ./configure --enable-cross.
|
||||
|
||||
- If the generation of relocations has been changed, try compiling
|
||||
with TCC and linking with GCC/Clang. If the linker has been
|
||||
modified, try compiling with GCC/Clang and linking with TCC.
|
||||
|
||||
- Test with ASan/UBSan to detect memory corruption and undefined behaviour:
|
||||
|
||||
make clean
|
||||
./configure
|
||||
make
|
||||
make test
|
||||
cp libtcc.a libtcc.a.hide
|
||||
|
||||
make clean
|
||||
./configure --extra-cflags="-fsanitize=address,undefined -g"
|
||||
make
|
||||
cp libtcc.a.hide libtcc.a
|
||||
make test
|
||||
|
||||
- Test with Valgrind to detect some uses of uninitialised values:
|
||||
|
||||
make clean
|
||||
./configure
|
||||
make
|
||||
# On Intel, because Valgrind does floating-point arithmetic differently:
|
||||
( cd tests && gcc -I.. tcctest.c && valgrind -q ./a.out > test.ref )
|
||||
make test TCC="valgrind -q --leak-check=full `pwd`/tcc -B`pwd` -I`pwd`"
|
||||
|
||||
(Because of how VLAs are implemented, invalid reads are expected
|
||||
with 79_vla_continue.)
|
||||
600
Makefile
600
Makefile
@ -1,337 +1,328 @@
|
||||
# --------------------------------------------------------------------------
|
||||
#
|
||||
# Tiny C Compiler Makefile
|
||||
#
|
||||
|
||||
TOP ?= .
|
||||
include $(TOP)/config.mak
|
||||
VPATH = $(top_srcdir)
|
||||
ifndef TOP
|
||||
TOP = .
|
||||
INCLUDED = no
|
||||
endif
|
||||
|
||||
CPPFLAGS = -I$(TOP) # for config.h
|
||||
include $(TOP)/config.mak
|
||||
|
||||
ifeq (-$(findstring gcc,$(CC))-,-gcc-)
|
||||
ifeq (-$(findstring $(GCC_MAJOR),01)-,--)
|
||||
CFLAGS+=-fno-strict-aliasing
|
||||
ifeq (-$(findstring $(GCC_MAJOR),23)-,--)
|
||||
CFLAGS+=-Wno-pointer-sign -Wno-sign-compare
|
||||
ifeq (-$(GCC_MAJOR)-$(findstring $(GCC_MINOR),56789)-,-4--)
|
||||
CFLAGS+=-D_FORTIFY_SOURCE=0
|
||||
ifeq (-$(GCC_MAJOR)-$(findstring $(GCC_MINOR),56789)-,-4--)
|
||||
CFLAGS += -D_FORTIFY_SOURCE=0
|
||||
endif
|
||||
else
|
||||
CFLAGS+=-Wno-unused-result
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
else # not GCC
|
||||
ifeq (-$(findstring clang,$(CC))-,-clang-)
|
||||
# make clang accept gnuisms in libtcc1.c
|
||||
CFLAGS+=-fheinous-gnu-extensions
|
||||
endif
|
||||
ifeq (-$(findstring clang,$(CC))-,-clang-)
|
||||
# make clang accept gnuisms in libtcc1.c
|
||||
CFLAGS+=-fheinous-gnu-extensions
|
||||
endif
|
||||
endif
|
||||
|
||||
CPPFLAGS_P=$(CPPFLAGS) -DCONFIG_TCC_STATIC
|
||||
CFLAGS_P=$(CFLAGS) -pg -static
|
||||
LIBS_P=
|
||||
LDFLAGS_P=$(LDFLAGS)
|
||||
LIBTCC = libtcc.a
|
||||
LIBTCC1 = libtcc1.a
|
||||
LINK_LIBTCC =
|
||||
LIBS =
|
||||
CFLAGS += -I$(TOP)
|
||||
CFLAGS += $(CPPFLAGS)
|
||||
VPATH = $(TOPSRC)
|
||||
|
||||
ifdef CONFIG_WIN64
|
||||
CONFIG_WIN32=yes
|
||||
endif
|
||||
|
||||
ifndef CONFIG_WIN32
|
||||
LIBS=-lm
|
||||
ifndef CONFIG_NOLDL
|
||||
LIBS+=-ldl
|
||||
endif
|
||||
endif
|
||||
|
||||
# make libtcc as static or dynamic library?
|
||||
ifdef DISABLE_STATIC
|
||||
LIBTCC=libtcc.so.1.0
|
||||
LINK_LIBTCC=-Wl,-rpath,"$(libdir)"
|
||||
ifdef DISABLE_RPATH
|
||||
LINK_LIBTCC=
|
||||
endif
|
||||
ifdef CONFIG_WIN32
|
||||
ifneq ($(DISABLE_STATIC),no)
|
||||
LIBTCC = libtcc.dll
|
||||
LIBTCCDEF = libtcc.def
|
||||
endif
|
||||
CFGWIN = -win
|
||||
NATIVE_TARGET = $(ARCH)-$(if $(eq $(ARCH),arm),wince,win32)
|
||||
else
|
||||
LIBTCC=libtcc.a
|
||||
LINK_LIBTCC=
|
||||
endif
|
||||
|
||||
CONFIG_$(ARCH) = yes
|
||||
NATIVE_DEFINES_$(CONFIG_i386) += -DTCC_TARGET_I386
|
||||
NATIVE_DEFINES_$(CONFIG_x86-64) += -DTCC_TARGET_X86_64
|
||||
NATIVE_DEFINES_$(CONFIG_WIN32) += -DTCC_TARGET_PE
|
||||
NATIVE_DEFINES_$(CONFIG_uClibc) += -DTCC_UCLIBC
|
||||
NATIVE_DEFINES_$(CONFIG_arm) += -DTCC_TARGET_ARM -DWITHOUT_LIBTCC
|
||||
NATIVE_DEFINES_$(CONFIG_arm_eabihf) += -DTCC_ARM_EABI -DTCC_ARM_HARDFLOAT
|
||||
NATIVE_DEFINES_$(CONFIG_arm_eabi) += -DTCC_ARM_EABI
|
||||
NATIVE_DEFINES_$(CONFIG_arm_vfp) += -DTCC_ARM_VFP
|
||||
NATIVE_DEFINES += $(NATIVE_DEFINES_yes)
|
||||
|
||||
ifeq ($(TOP),.)
|
||||
|
||||
PROGS=tcc$(EXESUF)
|
||||
I386_CROSS = i386-tcc$(EXESUF)
|
||||
WIN32_CROSS = i386-win32-tcc$(EXESUF)
|
||||
WIN64_CROSS = x86_64-win32-tcc$(EXESUF)
|
||||
WINCE_CROSS = arm-win32-tcc$(EXESUF)
|
||||
X64_CROSS = x86_64-tcc$(EXESUF)
|
||||
ARM_FPA_CROSS = arm-fpa-tcc$(EXESUF)
|
||||
ARM_FPA_LD_CROSS = arm-fpa-ld-tcc$(EXESUF)
|
||||
ARM_VFP_CROSS = arm-vfp-tcc$(EXESUF)
|
||||
ARM_EABI_CROSS = arm-eabi-tcc$(EXESUF)
|
||||
ARM_CROSS = $(ARM_FPA_CROSS) $(ARM_FPA_LD_CROSS) $(ARM_VFP_CROSS) $(ARM_EABI_CROSS)
|
||||
C67_CROSS = c67-tcc$(EXESUF)
|
||||
|
||||
CORE_FILES = tcc.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c tccrun.c
|
||||
CORE_FILES += tcc.h config.h libtcc.h tcctok.h
|
||||
I386_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h i386-tok.h
|
||||
WIN32_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h i386-tok.h tccpe.c
|
||||
WIN64_FILES = $(CORE_FILES) x86_64-gen.c i386-asm.c x86_64-asm.h tccpe.c
|
||||
WINCE_FILES = $(CORE_FILES) arm-gen.c tccpe.c
|
||||
X86_64_FILES = $(CORE_FILES) x86_64-gen.c i386-asm.c x86_64-asm.h
|
||||
ARM_FILES = $(CORE_FILES) arm-gen.c
|
||||
C67_FILES = $(CORE_FILES) c67-gen.c tcccoff.c
|
||||
|
||||
ifdef CONFIG_WIN64
|
||||
PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF)
|
||||
NATIVE_FILES=$(WIN64_FILES)
|
||||
PROGS_CROSS=$(WIN32_CROSS) $(I386_CROSS) $(X64_CROSS) $(ARM_CROSS) $(C67_CROSS)
|
||||
LIBTCC1_CROSS=lib/i386-win32/libtcc1.a
|
||||
LIBTCC1=libtcc1.a
|
||||
else ifdef CONFIG_WIN32
|
||||
PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF)
|
||||
NATIVE_FILES=$(WIN32_FILES)
|
||||
PROGS_CROSS=$(WIN64_CROSS) $(I386_CROSS) $(X64_CROSS) $(ARM_CROSS) $(C67_CROSS)
|
||||
LIBTCC1_CROSS=lib/x86_64-win32/libtcc1.a
|
||||
LIBTCC1=libtcc1.a
|
||||
else ifeq ($(ARCH),i386)
|
||||
NATIVE_FILES=$(I386_FILES)
|
||||
PROGS_CROSS=$(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(C67_CROSS)
|
||||
LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a
|
||||
LIBTCC1=libtcc1.a
|
||||
else ifeq ($(ARCH),x86-64)
|
||||
NATIVE_FILES=$(X86_64_FILES)
|
||||
PROGS_CROSS=$(I386_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(C67_CROSS)
|
||||
LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a lib/i386/libtcc1.a
|
||||
LIBTCC1=libtcc1.a
|
||||
else ifeq ($(ARCH),arm)
|
||||
NATIVE_FILES=$(ARM_FILES)
|
||||
PROGS_CROSS=$(I386_CROSS) $(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(C67_CROSS)
|
||||
LIBS=-lm
|
||||
ifndef CONFIG_NOLDL
|
||||
LIBS+=-ldl
|
||||
endif
|
||||
# make libtcc as static or dynamic library?
|
||||
ifeq ($(DISABLE_STATIC),yes)
|
||||
LIBTCC=libtcc.so
|
||||
ifndef DISABLE_RPATH
|
||||
LINK_LIBTCC += -Wl,-rpath,"$(libdir)"
|
||||
export LD_LIBRARY_PATH := $(CURDIR)/$(TOP)
|
||||
endif
|
||||
endif
|
||||
CFGWIN =-unx
|
||||
NATIVE_TARGET = $(ARCH)
|
||||
endif
|
||||
|
||||
ifeq ($(TARGETOS),Darwin)
|
||||
PROGS+=tiny_libmaker$(EXESUF)
|
||||
CFLAGS += -Wl,-flat_namespace,-undefined,warning
|
||||
export MACOSX_DEPLOYMENT_TARGET:=10.2
|
||||
endif
|
||||
|
||||
ifdef CONFIG_USE_LIBGCC
|
||||
LIBTCC1=
|
||||
endif
|
||||
# run local version of tcc with local libraries and includes
|
||||
TCCFLAGS-unx = -B$(TOP) -I$(TOPSRC)/include -I$(TOPSRC) -I$(TOP)
|
||||
TCCFLAGS-win = -B$(TOPSRC)/win32 -I$(TOPSRC)/include -I$(TOPSRC) -I$(TOP) -L$(TOP)
|
||||
TCCFLAGS = $(TCCFLAGS$(CFGWIN))
|
||||
TCC = $(TOP)/tcc$(EXESUF) $(TCCFLAGS)
|
||||
|
||||
TCCLIBS = $(LIBTCC1) $(LIBTCC)
|
||||
CFLAGS_P = $(CFLAGS) -pg -static -DCONFIG_TCC_STATIC -DTCC_PROFILE
|
||||
LIBS_P= $(LIBS)
|
||||
LDFLAGS_P = $(LDFLAGS)
|
||||
|
||||
CONFIG_$(ARCH) = yes
|
||||
NATIVE_DEFINES_$(CONFIG_i386) += -DTCC_TARGET_I386
|
||||
NATIVE_DEFINES_$(CONFIG_x86_64) += -DTCC_TARGET_X86_64
|
||||
NATIVE_DEFINES_$(CONFIG_WIN32) += -DTCC_TARGET_PE
|
||||
NATIVE_DEFINES_$(CONFIG_uClibc) += -DTCC_UCLIBC
|
||||
NATIVE_DEFINES_$(CONFIG_arm) += -DTCC_TARGET_ARM
|
||||
NATIVE_DEFINES_$(CONFIG_arm_eabihf) += -DTCC_ARM_EABI -DTCC_ARM_HARDFLOAT
|
||||
NATIVE_DEFINES_$(CONFIG_arm_eabi) += -DTCC_ARM_EABI
|
||||
NATIVE_DEFINES_$(CONFIG_arm_vfp) += -DTCC_ARM_VFP
|
||||
NATIVE_DEFINES_$(CONFIG_arm64) += -DTCC_TARGET_ARM64
|
||||
NATIVE_DEFINES += $(NATIVE_DEFINES_yes)
|
||||
|
||||
ifeq ($(INCLUDED),no)
|
||||
# --------------------------------------------------------------------------
|
||||
# running top Makefile
|
||||
|
||||
PROGS = tcc$(EXESUF)
|
||||
TCCLIBS = $(LIBTCC1) $(LIBTCC) $(LIBTCCDEF)
|
||||
TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info
|
||||
|
||||
ifdef CONFIG_CROSS
|
||||
PROGS+=$(PROGS_CROSS)
|
||||
TCCLIBS+=$(LIBTCC1_CROSS)
|
||||
endif
|
||||
|
||||
all: $(PROGS) $(TCCLIBS) $(TCCDOCS)
|
||||
|
||||
# Host Tiny C Compiler
|
||||
tcc$(EXESUF): tcc.o $(LIBTCC)
|
||||
$(CC) -o $@ $^ $(LIBS) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(LINK_LIBTCC)
|
||||
# cross compiler targets to build
|
||||
TCC_X = i386 x86_64 i386-win32 x86_64-win32 arm arm64 arm-wince c67
|
||||
# TCC_X += arm-fpa arm-fpa-ld arm-vfp arm-eabi
|
||||
|
||||
# Cross Tiny C Compilers
|
||||
%-tcc$(EXESUF): tcc.c
|
||||
$(CC) -o $@ $< -DONE_SOURCE $(DEFINES) $(CPPFLAGS) $(CFLAGS) $(LIBS) $(LDFLAGS)
|
||||
# cross libtcc1.a targets to build
|
||||
LIBTCC1_X = i386 x86_64 i386-win32 x86_64-win32 arm arm64 arm-wince
|
||||
|
||||
# profiling version
|
||||
tcc_p$(EXESUF): $(NATIVE_FILES)
|
||||
$(CC) -o $@ $< -DONE_SOURCE $(NATIVE_DEFINES) $(CPPFLAGS_P) $(CFLAGS_P) $(LIBS_P) $(LDFLAGS_P)
|
||||
PROGS_CROSS = $(foreach X,$(TCC_X),$X-tcc$(EXESUF))
|
||||
LIBTCC1_CROSS = $(foreach X,$(LIBTCC1_X),libtcc1-$X.a)
|
||||
|
||||
$(I386_CROSS): DEFINES = -DTCC_TARGET_I386 \
|
||||
-DCONFIG_TCCDIR="\"$(tccdir)/i386\""
|
||||
$(X64_CROSS): DEFINES = -DTCC_TARGET_X86_64
|
||||
$(WIN32_CROSS): DEFINES = -DTCC_TARGET_I386 -DTCC_TARGET_PE \
|
||||
-DCONFIG_TCCDIR="\"$(tccdir)/win32\"" \
|
||||
-DCONFIG_TCC_LIBPATHS="\"{B}/lib/32;{B}/lib\""
|
||||
$(WIN64_CROSS): DEFINES = -DTCC_TARGET_X86_64 -DTCC_TARGET_PE \
|
||||
-DCONFIG_TCCDIR="\"$(tccdir)/win32\"" \
|
||||
-DCONFIG_TCC_LIBPATHS="\"{B}/lib/64;{B}/lib\""
|
||||
$(WINCE_CROSS): DEFINES = -DTCC_TARGET_PE
|
||||
$(C67_CROSS): DEFINES = -DTCC_TARGET_C67
|
||||
$(ARM_FPA_CROSS): DEFINES = -DTCC_TARGET_ARM
|
||||
$(ARM_FPA_LD_CROSS)$(EXESUF): DEFINES = -DTCC_TARGET_ARM -DLDOUBLE_SIZE=12
|
||||
$(ARM_VFP_CROSS): DEFINES = -DTCC_TARGET_ARM -DTCC_ARM_VFP
|
||||
$(ARM_EABI_CROSS): DEFINES = -DTCC_TARGET_ARM -DTCC_ARM_EABI
|
||||
|
||||
$(I386_CROSS): $(I386_FILES)
|
||||
$(X64_CROSS): $(X86_64_FILES)
|
||||
$(WIN32_CROSS): $(WIN32_FILES)
|
||||
$(WIN64_CROSS): $(WIN64_FILES)
|
||||
$(WINCE_CROSS): $(WINCE_FILES)
|
||||
$(C67_CROSS): $(C67_FILES)
|
||||
$(ARM_FPA_CROSS) $(ARM_FPA_LD_CROSS) $(ARM_VFP_CROSS) $(ARM_EABI_CROSS): $(ARM_FILES)
|
||||
|
||||
# libtcc generation and test
|
||||
ifndef ONE_SOURCE
|
||||
LIBTCC_OBJ = $(filter-out tcc.o,$(patsubst %.c,%.o,$(filter %.c,$(NATIVE_FILES))))
|
||||
LIBTCC_INC = $(filter %.h,$(CORE_FILES)) $(filter-out $(CORE_FILES),$(NATIVE_FILES))
|
||||
else
|
||||
LIBTCC_OBJ = libtcc.o
|
||||
LIBTCC_INC = $(NATIVE_FILES)
|
||||
libtcc.o : NATIVE_DEFINES += -DONE_SOURCE
|
||||
ifdef CONFIG_CROSS
|
||||
all : $(LIBTCC1_CROSS) $(PROGS_CROSS)
|
||||
endif
|
||||
|
||||
$(LIBTCC_OBJ) tcc.o : %.o : %.c $(LIBTCC_INC)
|
||||
$(CC) -o $@ -c $< $(NATIVE_DEFINES) $(CPPFLAGS) $(CFLAGS)
|
||||
# build cross compilers & libs
|
||||
cross: all $(LIBTCC1_CROSS) $(PROGS_CROSS)
|
||||
|
||||
# build specific cross compiler & lib
|
||||
cross-%: %-tcc$(EXESUF) libtcc1-%.a ;
|
||||
|
||||
install: install$(CFGWIN)
|
||||
uninstall: uninstall$(CFGWIN)
|
||||
|
||||
# --------------------------------------------
|
||||
|
||||
T = $(or $(CROSS_TARGET),$(NATIVE_TARGET),unknown)
|
||||
X = $(if $(CROSS_TARGET),$(CROSS_TARGET)-)
|
||||
|
||||
DEF-i386 = -DTCC_TARGET_I386
|
||||
DEF-x86_64 = -DTCC_TARGET_X86_64
|
||||
DEF-i386-win32 = -DTCC_TARGET_PE -DTCC_TARGET_I386
|
||||
DEF-x86_64-win32= -DTCC_TARGET_PE -DTCC_TARGET_X86_64
|
||||
DEF-arm-wince = -DTCC_TARGET_PE -DTCC_TARGET_ARM -DTCC_ARM_EABI -DTCC_ARM_VFP -DTCC_ARM_HARDFLOAT
|
||||
DEF-arm64 = -DTCC_TARGET_ARM64
|
||||
DEF-c67 = -DTCC_TARGET_C67 -w # disable warnigs
|
||||
DEF-arm-fpa = -DTCC_TARGET_ARM
|
||||
DEF-arm-fpa-ld = -DTCC_TARGET_ARM -DLDOUBLE_SIZE=12
|
||||
DEF-arm-vfp = -DTCC_TARGET_ARM -DTCC_ARM_VFP
|
||||
DEF-arm-eabi = -DTCC_TARGET_ARM -DTCC_ARM_VFP -DTCC_ARM_EABI
|
||||
DEF-arm-eabihf = -DTCC_TARGET_ARM -DTCC_ARM_VFP -DTCC_ARM_EABI -DTCC_ARM_HARDFLOAT
|
||||
DEF-arm = $(DEF-arm-eabihf)
|
||||
DEF-$(NATIVE_TARGET) = $(NATIVE_DEFINES)
|
||||
|
||||
DEFINES += $(DEF-$T) $(DEF-all)
|
||||
DEFINES += $(if $(ROOT-$T),-DCONFIG_SYSROOT="\"$(ROOT-$T)\"")
|
||||
DEFINES += $(if $(CRT-$T),-DCONFIG_TCC_CRTPREFIX="\"$(CRT-$T)\"")
|
||||
DEFINES += $(if $(LIB-$T),-DCONFIG_TCC_LIBPATHS="\"$(LIB-$T)\"")
|
||||
DEFINES += $(if $(INC-$T),-DCONFIG_TCC_SYSINCLUDEPATHS="\"$(INC-$T)\"")
|
||||
DEFINES += $(DEF-$(or $(findstring win,$T),unx))
|
||||
|
||||
ifneq ($(X),)
|
||||
ifeq ($(CONFIG_WIN32),yes)
|
||||
DEF-win += -DTCC_LIBTCC1="\"libtcc1-$T.a\""
|
||||
DEF-unx += -DTCC_LIBTCC1="\"lib/libtcc1-$T.a\""
|
||||
else
|
||||
DEF-all += -DTCC_LIBTCC1="\"libtcc1-$T.a\""
|
||||
DEF-win += -DCONFIG_TCCDIR="\"$(tccdir)/win32\""
|
||||
endif
|
||||
endif
|
||||
|
||||
# include custom cross-compiler configuration (see make help)
|
||||
-include config-cross.mak
|
||||
|
||||
CORE_FILES = tcc.c tcctools.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c tccrun.c
|
||||
CORE_FILES += tcc.h config.h libtcc.h tcctok.h
|
||||
i386_FILES = $(CORE_FILES) i386-gen.c i386-link.c i386-asm.c i386-asm.h i386-tok.h
|
||||
i386-win32_FILES = $(i386_FILES) tccpe.c
|
||||
x86_64_FILES = $(CORE_FILES) x86_64-gen.c x86_64-link.c i386-asm.c x86_64-asm.h
|
||||
x86_64-win32_FILES = $(x86_64_FILES) tccpe.c
|
||||
arm_FILES = $(CORE_FILES) arm-gen.c arm-link.c arm-asm.c
|
||||
arm-wince_FILES = $(arm_FILES) tccpe.c
|
||||
arm64_FILES = $(CORE_FILES) arm64-gen.c arm64-link.c
|
||||
c67_FILES = $(CORE_FILES) c67-gen.c c67-link.c tcccoff.c
|
||||
|
||||
# libtcc sources
|
||||
LIBTCC_SRC = $(filter-out tcc.c tcctools.c arm-asm.c,$(filter %.c,$($T_FILES)))
|
||||
|
||||
ifeq ($(ONE_SOURCE),yes)
|
||||
LIBTCC_OBJ = $(X)libtcc.o
|
||||
LIBTCC_INC = $($T_FILES)
|
||||
TCC_FILES = tcc.c
|
||||
$(X)libtcc.o $T-tcc$(EXESUF) : DEFINES += -DONE_SOURCE
|
||||
else
|
||||
LIBTCC_OBJ = $(patsubst %.c,$(X)%.o,$(LIBTCC_SRC))
|
||||
LIBTCC_INC = $(filter %.h %-gen.c %-link.c,$($T_FILES))
|
||||
TCC_FILES = $(X)tcc.o $(LIBTCC_OBJ)
|
||||
endif
|
||||
|
||||
# target specific object rule
|
||||
$(X)%.o : %.c $(LIBTCC_INC)
|
||||
$(CC) -o $@ -c $< $(DEFINES) $(CFLAGS)
|
||||
|
||||
# additional dependencies
|
||||
$(X)tcc.o : tcctools.c
|
||||
$(X)arm-gen.o : arm-asm.c
|
||||
|
||||
# Host Tiny C Compiler
|
||||
tcc$(EXESUF): $(X)tcc.o $(LIBTCC)
|
||||
$(CC) -o $@ $^ $(DEFINES) $(CFLAGS) $(LIBS) $(LDFLAGS) $(LINK_LIBTCC)
|
||||
|
||||
# Cross Tiny C Compilers
|
||||
%-tcc$(EXESUF): FORCE
|
||||
@$(MAKE) --no-print-directory $@ CROSS_TARGET=$* ONE_SOURCE=$(or $(ONE_SOURCE),yes)
|
||||
|
||||
$(CROSS_TARGET)-tcc$(EXESUF): $(TCC_FILES)
|
||||
$(CC) -o $@ $^ $(DEFINES) $(CFLAGS) $(LIBS) $(LDFLAGS)
|
||||
|
||||
# profiling version
|
||||
tcc_p$(EXESUF): $($T_FILES)
|
||||
$(CC) -o $@ $< -$(DEFINES) $(CFLAGS_P) $(LIBS_P) $(LDFLAGS_P)
|
||||
|
||||
# static libtcc library
|
||||
libtcc.a: $(LIBTCC_OBJ)
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
libtcc.so.1.0: $(LIBTCC_OBJ)
|
||||
# dynamic libtcc library
|
||||
libtcc.so: $(LIBTCC_OBJ)
|
||||
$(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LDFLAGS)
|
||||
|
||||
libtcc.so.1.0: CFLAGS+=-fPIC
|
||||
libtcc.so: CFLAGS+=-fPIC
|
||||
|
||||
# windows utilities
|
||||
tiny_impdef$(EXESUF): win32/tools/tiny_impdef.c
|
||||
$(CC) -o $@ $< $(CPPFLAGS) $(CFLAGS) $(LDFLAGS)
|
||||
tiny_libmaker$(EXESUF): win32/tools/tiny_libmaker.c
|
||||
$(CC) -o $@ $< $(CPPFLAGS) $(CFLAGS) $(LDFLAGS)
|
||||
# windows dynamic libtcc library
|
||||
libtcc.dll : $(LIBTCC_OBJ)
|
||||
$(CC) -shared $(LIBTCC_OBJ) -o $@ $(LDFLAGS)
|
||||
|
||||
libtcc.def : libtcc.dll tcc$(EXESUF)
|
||||
./tcc$(EXESUF) -impdef $< -o $@
|
||||
|
||||
libtcc.dll : DEFINES += -DLIBTCC_AS_DLL
|
||||
|
||||
# TinyCC runtime libraries
|
||||
libtcc1.a : FORCE
|
||||
$(MAKE) -C lib native
|
||||
lib/%/libtcc1.a : FORCE $(PROGS_CROSS)
|
||||
$(MAKE) -C lib cross TARGET=$*
|
||||
libtcc1.a : tcc$(EXESUF) FORCE
|
||||
@$(MAKE) -f lib/Makefile BIN=$@ $@ TOP=. --no-print-directory
|
||||
|
||||
# Cross libtcc1.a
|
||||
libtcc1-%.a : %-tcc$(EXESUF) FORCE
|
||||
@$(MAKE) -f lib/Makefile BIN=$@ $@ CROSS_TARGET=$* TOP=. --no-print-directory
|
||||
|
||||
FORCE:
|
||||
|
||||
# install
|
||||
TCC_INCLUDES = stdarg.h stddef.h stdbool.h float.h varargs.h tcclib.h
|
||||
INSTALL=install
|
||||
ifdef STRIP_BINARIES
|
||||
INSTALLBIN=$(INSTALL) -s
|
||||
else
|
||||
INSTALLBIN=$(INSTALL)
|
||||
endif
|
||||
|
||||
ifndef CONFIG_WIN32
|
||||
install: $(PROGS) $(TCCLIBS) $(TCCDOCS)
|
||||
mkdir -p "$(bindir)"
|
||||
ifeq ($(CC),tcc)
|
||||
$(INSTALL) -m755 $(PROGS) "$(bindir)"
|
||||
else
|
||||
$(INSTALLBIN) -m755 $(PROGS) "$(bindir)"
|
||||
endif
|
||||
mkdir -p "$(mandir)/man1"
|
||||
-$(INSTALL) tcc.1 "$(mandir)/man1"
|
||||
mkdir -p "$(infodir)"
|
||||
-$(INSTALL) tcc-doc.info "$(infodir)"
|
||||
mkdir -p "$(tccdir)"
|
||||
mkdir -p "$(tccdir)/include"
|
||||
ifneq ($(LIBTCC1),)
|
||||
$(INSTALL) -m644 $(LIBTCC1) "$(tccdir)"
|
||||
endif
|
||||
$(INSTALL) -m644 $(addprefix $(top_srcdir)/include/,$(TCC_INCLUDES)) "$(tccdir)/include"
|
||||
mkdir -p "$(libdir)"
|
||||
$(INSTALL) -m755 $(LIBTCC) "$(libdir)"
|
||||
ifdef DISABLE_STATIC
|
||||
ln -sf "$(ln_libdir)/libtcc.so.1.0" "$(libdir)/libtcc.so.1"
|
||||
ln -sf "$(ln_libdir)/libtcc.so.1.0" "$(libdir)/libtcc.so"
|
||||
endif
|
||||
mkdir -p "$(includedir)"
|
||||
$(INSTALL) -m644 $(top_srcdir)/libtcc.h "$(includedir)"
|
||||
mkdir -p "$(docdir)"
|
||||
-$(INSTALL) -m644 tcc-doc.html "$(docdir)"
|
||||
ifdef CONFIG_CROSS
|
||||
mkdir -p "$(tccdir)/win32/lib/32"
|
||||
mkdir -p "$(tccdir)/win32/lib/64"
|
||||
ifeq ($(ARCH),x86-64)
|
||||
mkdir -p "$(tccdir)/i386"
|
||||
$(INSTALL) -m644 lib/i386/libtcc1.a "$(tccdir)/i386"
|
||||
cp -r "$(tccdir)/include" "$(tccdir)/i386"
|
||||
endif
|
||||
$(INSTALL) -m644 win32/lib/*.def "$(tccdir)/win32/lib"
|
||||
$(INSTALL) -m644 lib/i386-win32/libtcc1.a "$(tccdir)/win32/lib/32"
|
||||
$(INSTALL) -m644 lib/x86_64-win32/libtcc1.a "$(tccdir)/win32/lib/64"
|
||||
cp -r win32/include/. "$(tccdir)/win32/include"
|
||||
cp -r include/. "$(tccdir)/win32/include"
|
||||
endif
|
||||
|
||||
uninstall:
|
||||
rm -fv $(foreach P,$(PROGS),"$(bindir)/$P")
|
||||
rm -fv $(foreach P,$(LIBTCC1),"$(tccdir)/$P")
|
||||
rm -fv $(foreach P,$(TCC_INCLUDES),"$(tccdir)/include/$P")
|
||||
rm -fv "$(docdir)/tcc-doc.html" "$(mandir)/man1/tcc.1" "$(infodir)/tcc-doc.info"
|
||||
rm -fv "$(libdir)/$(LIBTCC)" "$(includedir)/libtcc.h"
|
||||
rm -fv "$(libdir)/libtcc.so*"
|
||||
rm -rf "$(tccdir)/win32"
|
||||
-rmdir $(tccdir)/include
|
||||
ifeq ($(ARCH),x86-64)
|
||||
rm -rf "$(tccdir)/i386"
|
||||
endif
|
||||
else
|
||||
# on windows
|
||||
install: $(PROGS) $(TCCLIBS) $(TCCDOCS)
|
||||
mkdir -p "$(tccdir)"
|
||||
mkdir -p "$(tccdir)/lib"
|
||||
mkdir -p "$(tccdir)/include"
|
||||
mkdir -p "$(tccdir)/examples"
|
||||
mkdir -p "$(tccdir)/doc"
|
||||
mkdir -p "$(tccdir)/libtcc"
|
||||
$(INSTALLBIN) -m755 $(PROGS) "$(tccdir)"
|
||||
$(INSTALL) -m644 $(LIBTCC1) win32/lib/*.def "$(tccdir)/lib"
|
||||
cp -r win32/include/. "$(tccdir)/include"
|
||||
cp -r win32/examples/. "$(tccdir)/examples"
|
||||
$(INSTALL) -m644 $(addprefix include/,$(TCC_INCLUDES)) "$(tccdir)/include"
|
||||
$(INSTALL) -m644 tcc-doc.html win32/tcc-win32.txt "$(tccdir)/doc"
|
||||
$(INSTALL) -m644 $(LIBTCC) libtcc.h "$(tccdir)/libtcc"
|
||||
ifdef CONFIG_CROSS
|
||||
mkdir -p "$(tccdir)/lib/32"
|
||||
mkdir -p "$(tccdir)/lib/64"
|
||||
-$(INSTALL) -m644 lib/i386-win32/libtcc1.a "$(tccdir)/lib/32"
|
||||
-$(INSTALL) -m644 lib/x86_64-win32/libtcc1.a "$(tccdir)/lib/64"
|
||||
endif
|
||||
|
||||
uninstall:
|
||||
rm -rfv "$(tccdir)/*"
|
||||
endif
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# documentation and man page
|
||||
tcc-doc.html: tcc-doc.texi
|
||||
-texi2html -monolithic -number $<
|
||||
-makeinfo --no-split --html --number-sections -o $@ $<
|
||||
|
||||
tcc.1: tcc-doc.texi
|
||||
-$(top_srcdir)/texi2pod.pl $< tcc.pod
|
||||
-pod2man --section=1 --center=" " --release=" " tcc.pod > $@
|
||||
-$(TOPSRC)/texi2pod.pl $< tcc.pod
|
||||
-pod2man --section=1 --center="Tiny C Compiler" --release="$(VERSION)" tcc.pod > $@
|
||||
|
||||
tcc-doc.info: tcc-doc.texi
|
||||
-makeinfo $<
|
||||
|
||||
# in tests subdir
|
||||
export LIBTCC1
|
||||
# --------------------------------------------------------------------------
|
||||
# install
|
||||
|
||||
%est:
|
||||
$(MAKE) -C tests $@
|
||||
INSTALL = install -m644
|
||||
INSTALLBIN = install -m755 $(STRIP_$(STRIP_BINARIES))
|
||||
STRIP_yes = -s
|
||||
install-strip: install
|
||||
install-strip: STRIP_BINARIES = yes
|
||||
|
||||
clean:
|
||||
rm -vf $(PROGS) tcc_p$(EXESUF) tcc.pod *~ *.o *.a *.so* *.out *.exe libtcc_test$(EXESUF)
|
||||
$(MAKE) -C tests $@
|
||||
ifneq ($(LIBTCC1),)
|
||||
$(MAKE) -C lib $@
|
||||
endif
|
||||
TRY-INSTALL = $(if $(wildcard $1),mkdir -p $2 && $(INSTALL) $1 $2)
|
||||
LIBTCC1_W = $(wildcard $(filter %-win32.a %-wince.a,$(LIBTCC1_CROSS)))
|
||||
LIBTCC1_U = $(wildcard $(filter-out $(LIBTCC1_W),$(LIBTCC1_CROSS)))
|
||||
PROGS_X = $(wildcard $(PROGS_CROSS))
|
||||
|
||||
distclean: clean
|
||||
rm -vf config.h config.mak config.texi tcc.1 tcc-doc.info tcc-doc.html
|
||||
# install progs & libs
|
||||
install-unx:
|
||||
mkdir -p "$(bindir)"
|
||||
$(INSTALLBIN) $(PROGS) $(PROGS_X) "$(bindir)"
|
||||
mkdir -p "$(tccdir)"
|
||||
$(INSTALL) $(LIBTCC1) $(LIBTCC1_U) "$(tccdir)"
|
||||
mkdir -p "$(tccdir)/include"
|
||||
$(INSTALL) $(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h "$(tccdir)/include"
|
||||
mkdir -p "$(libdir)"
|
||||
$(INSTALL) $(LIBTCC) "$(libdir)"
|
||||
mkdir -p "$(includedir)"
|
||||
$(INSTALL) $(TOPSRC)/libtcc.h "$(includedir)"
|
||||
$(call TRY-INSTALL,tcc.1,"$(mandir)/man1")
|
||||
$(call TRY-INSTALL,tcc-doc.info,"$(infodir)")
|
||||
$(call TRY-INSTALL,tcc-doc.html,"$(docdir)")
|
||||
mkdir -p "$(tccdir)/win32/include"
|
||||
cp -r $(TOPSRC)/include/. "$(tccdir)/win32/include"
|
||||
cp -r $(TOPSRC)/win32/include/. "$(tccdir)/win32/include"
|
||||
mkdir -p "$(tccdir)/win32/lib"
|
||||
$(INSTALL) $(TOPSRC)/win32/lib/*.def $(LIBTCC1_W) "$(tccdir)/win32/lib"
|
||||
|
||||
config.mak:
|
||||
@echo "Please run ./configure."
|
||||
@exit 1
|
||||
# uninstall
|
||||
uninstall-unx:
|
||||
rm -fv $(foreach P,$(PROGS) $(PROGS_CROSS),"$(bindir)/$P")
|
||||
rm -fv "$(libdir)/$(LIBTCC)" "$(includedir)/libtcc.h"
|
||||
rm -fv "$(mandir)/man1/tcc.1" "$(infodir)/tcc-doc.info"
|
||||
rm -fv "$(docdir)/tcc-doc.html"
|
||||
rm -rv "$(tccdir)"
|
||||
|
||||
# install progs & libs on windows
|
||||
install-win:
|
||||
mkdir -p "$(tccdir)"
|
||||
$(INSTALL) $(PROGS) $(subst libtcc.a,,$(LIBTCC)) $(PROGS_X) "$(tccdir)"
|
||||
mkdir -p "$(tccdir)/lib"
|
||||
$(INSTALL) $(TOPSRC)/win32/lib/*.def "$(tccdir)/lib"
|
||||
$(INSTALL) libtcc1.a $(LIBTCC1_W) $(LIBTCC1_U) "$(tccdir)/lib"
|
||||
mkdir -p "$(tccdir)/include"
|
||||
cp -r $(TOPSRC)/win32/include/. "$(tccdir)/include"
|
||||
$(INSTALL) $(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h "$(tccdir)/include"
|
||||
mkdir -p "$(tccdir)/lib/include";
|
||||
$(INSTALL) $(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h "$(tccdir)/lib/include"
|
||||
mkdir -p "$(tccdir)/examples"
|
||||
cp -r $(TOPSRC)/win32/examples/. "$(tccdir)/examples"
|
||||
$(INSTALL) $(TOPSRC)/tests/libtcc_test.c "$(tccdir)/examples"
|
||||
mkdir -p "$(tccdir)/libtcc"
|
||||
$(INSTALL) $(TOPSRC)/libtcc.h $(subst .dll,.def,$(LIBTCC)) "$(tccdir)/libtcc"
|
||||
mkdir -p "$(tccdir)/doc"
|
||||
$(INSTALL) $(TOPSRC)/win32/tcc-win32.txt $(wildcard tcc-doc.html) "$(tccdir)/doc"
|
||||
|
||||
# the msys-git shell works to configure && make except it does not have install
|
||||
install-win : INSTALL = cp
|
||||
|
||||
# uninstall on windows
|
||||
uninstall-win:
|
||||
rm -rfv "$(tccdir)/"*
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# other stuff
|
||||
|
||||
TAGFILES = *.[ch] include/*.h lib/*.[chS]
|
||||
tags : ; ctags $(TAGFILES)
|
||||
# cannot have both tags and TAGS on windows
|
||||
ETAGS : ; etags $(TAGFILES)
|
||||
|
||||
# create release tarball from *current* git branch (including tcc-doc.html
|
||||
# and converting two files to CRLF)
|
||||
TCC-VERSION := tcc-$(shell cat $(top_srcdir)/VERSION)
|
||||
TCC-VERSION = $(VERSION)
|
||||
tar: tcc-doc.html
|
||||
mkdir $(TCC-VERSION)
|
||||
( cd $(TCC-VERSION) && git --git-dir ../.git checkout -f )
|
||||
@ -343,7 +334,52 @@ tar: tcc-doc.html
|
||||
rm -rf $(TCC-VERSION)
|
||||
git reset
|
||||
|
||||
config.mak:
|
||||
$(if $(wildcard $@),,@echo "Please run ./configure." && exit 1)
|
||||
|
||||
.PHONY: all clean tar distclean install uninstall FORCE
|
||||
# in tests subdir
|
||||
test:
|
||||
$(MAKE) -C tests
|
||||
|
||||
endif # ifeq ($(TOP),.)
|
||||
clean:
|
||||
rm -f $(PROGS) $(PROGS_CROSS) tcc_p$(EXESUF) tcc.pod \
|
||||
*~ *.o *.a *.so* *.out *.log lib*.def *.exe *.dll a.out \
|
||||
tags TAGS libtcc_test$(EXESUF)
|
||||
$(MAKE) -C tests $@
|
||||
$(MAKE) -C lib $@
|
||||
|
||||
distclean: clean
|
||||
rm -f config.h config.mak config.texi tcc.1 tcc-doc.info tcc-doc.html
|
||||
|
||||
.PHONY: all clean test tar tags ETAGS distclean install uninstall FORCE
|
||||
|
||||
help:
|
||||
@echo "make"
|
||||
@echo " build native compiler (from separate objects)"
|
||||
@echo ""
|
||||
@echo "make cross"
|
||||
@echo " build cross compilers (from one source)"
|
||||
@echo ""
|
||||
@echo "make ONE_SOURCE=yes / no"
|
||||
@echo " force building from one source / separate objects"
|
||||
@echo ""
|
||||
@echo "make cross-TARGET"
|
||||
@echo " build one specific cross compiler for 'TARGET', as in"
|
||||
@echo " $(TCC_X)"
|
||||
@echo ""
|
||||
@echo "Cross compiler configuration:"
|
||||
@echo " make will read custom configuration for cross compilers from a file"
|
||||
@echo " 'config-cross.mak' if present. For example for a windows->i386-linux"
|
||||
@echo " cross-compiler that expects the linux files in <prefix>/i386-linux:"
|
||||
@echo ""
|
||||
@echo " ROOT-i386 = {B}/i386-linux"
|
||||
@echo " CRT-i386 = $(ROOT-i386)/usr/lib"
|
||||
@echo " LIB-i386 = $(ROOT-i386)/lib:$(ROOT-i386)/usr/lib"
|
||||
@echo " INC-i386 = {B}/lib/include:$(ROOT-i386)/usr/include"
|
||||
@echo " DEF-i386 += -D__linux__"
|
||||
@echo ""
|
||||
@echo "Other supported make targets:"
|
||||
@echo " install install-strip test tags ETAGS tar clean distclean help"
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
endif # ($(INCLUDED),no)
|
||||
|
||||
18
README
18
README
@ -28,25 +28,19 @@ Features:
|
||||
Documentation:
|
||||
-------------
|
||||
|
||||
1) Installation on a i386 Linux host (for Windows read tcc-win32.txt)
|
||||
1) Installation on a i386/x86_64/arm Linux/OSX/FreeBSD host
|
||||
|
||||
./configure
|
||||
make
|
||||
make test
|
||||
make install
|
||||
|
||||
Alternatively, out-of-tree builds are supported: you may use different
|
||||
directories to hold build objects, kept separate from your source tree:
|
||||
Notes: For OSX and FreeBSD, gmake should be used instead of make.
|
||||
For Windows read tcc-win32.txt.
|
||||
|
||||
mkdir _build
|
||||
cd _build
|
||||
../configure
|
||||
make
|
||||
make test
|
||||
make install
|
||||
|
||||
By default, tcc is installed in /usr/local/bin.
|
||||
./configure --help shows configuration options.
|
||||
makeinfo must be installed to compile the doc. By default, tcc is
|
||||
installed in /usr/local/bin. ./configure --help shows configuration
|
||||
options.
|
||||
|
||||
|
||||
2) Introduction
|
||||
|
||||
60
RELICENSING
Normal file
60
RELICENSING
Normal file
@ -0,0 +1,60 @@
|
||||
|
||||
Relicensing TinyCC
|
||||
------------------
|
||||
|
||||
The authors listed below hereby confirm their agreement to relicense TinyCC
|
||||
including their past contributions under the following terms:
|
||||
|
||||
|
||||
* 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.
|
||||
|
||||
|
||||
Author (name) I agree (YES/NO) Files/Features (optional)
|
||||
------------------------------------------------------------------------------
|
||||
Adam Sampson YES makefiles
|
||||
Daniel Glöckner NO arm-gen.c
|
||||
Daniel Glöckner YES not arm-gen.c
|
||||
Edmund Grimley Evans YES arm64
|
||||
Fabrice Bellard YES original author
|
||||
Frédéric Féret YES x86 64/16 bit asm
|
||||
grischka YES tccpe.c
|
||||
Henry Kroll YES
|
||||
Joe Soroka YES
|
||||
Kirill Smelkov YES
|
||||
mingodad YES
|
||||
Pip Cet YES
|
||||
Shinichiro Hamaji YES x86_64-gen.c
|
||||
Vincent Lefèvre YES
|
||||
Thomas Preud'homme YES arm-gen.c
|
||||
Timo VJ Lähde (Timppa) ? tiny_libmaker.c
|
||||
TK ? tcccoff.c c67-gen.c
|
||||
Urs Janssen YES
|
||||
waddlesplash YES
|
||||
Christian Jullien YES Windows Cygwin build and tests
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Please add yourself to the list above (rsp. replace the question mark)
|
||||
and (after fetching the latest version) commit to the "mob" branch with
|
||||
commit message:
|
||||
|
||||
Relicensing TinyCC
|
||||
|
||||
Thanks.
|
||||
42
TODO
42
TODO
@ -2,17 +2,9 @@ TODO list:
|
||||
|
||||
Bugs:
|
||||
|
||||
- fix macro substitution with nested definitions (ShangHongzhang)
|
||||
- i386 fastcall is mostly wrong
|
||||
- FPU st(0) is left unclean (kwisatz haderach). Incompatible with
|
||||
optimized gcc/msc code
|
||||
|
||||
- constructors
|
||||
- cast bug (Peter Wang)
|
||||
- define incomplete type if defined several times (Peter Wang).
|
||||
- configure --cc=tcc (still one bug in libtcc1.c)
|
||||
- test binutils/gcc compile
|
||||
- tci patch + argument.
|
||||
- see -lxxx bug (Michael Charity).
|
||||
- see transparent union pb in /urs/include/sys/socket.h
|
||||
- precise behaviour of typeof with arrays ? (__put_user macro)
|
||||
but should suffice for most cases)
|
||||
@ -27,13 +19,25 @@ Bugs:
|
||||
- finish varargs.h support (gcc 3.2 testsuite issue)
|
||||
- fix static functions declared inside block
|
||||
- fix multiple unions init
|
||||
- sizeof, alignof, typeof can still generate code in some cases.
|
||||
- Fix the remaining libtcc memory leaks.
|
||||
- make libtcc fully reentrant (except for the compilation stage itself).
|
||||
- struct/union/enum definitions in nested scopes (see also Debian bug #770657)
|
||||
- __STDC_IEC_559__: float f(void) { static float x = 0.0 / 0.0; return x; }
|
||||
- memory may be leaked after errors (longjmp).
|
||||
|
||||
Portability:
|
||||
|
||||
- it is assumed that int is 32-bit and sizeof(int) == 4
|
||||
- int is used when host or target size_t would make more sense
|
||||
- TCC handles target floating-point (fp) values using the host's fp
|
||||
arithmetic, which is simple and fast but may lead to exceptions
|
||||
and inaccuracy and wrong representations when cross-compiling
|
||||
|
||||
Linking:
|
||||
|
||||
- static linking (-static) does not work
|
||||
|
||||
Bound checking:
|
||||
|
||||
- '-b' bug.
|
||||
- fix bound exit on RedHat 7.3
|
||||
- setjmp is not supported properly in bound checking.
|
||||
- fix bound check code with '&' on local variables (currently done
|
||||
@ -45,11 +49,10 @@ Missing features:
|
||||
|
||||
- disable-asm and disable-bcheck options
|
||||
- __builtin_expect()
|
||||
- improve '-E' option.
|
||||
- atexit (Nigel Horne)
|
||||
- packed attribute
|
||||
- C99: add complex types (gcc 3.2 testsuite issue)
|
||||
- postfix compound literals (see 20010124-1.c)
|
||||
- interactive mode / integrated debugger
|
||||
|
||||
Optimizations:
|
||||
|
||||
@ -65,17 +68,17 @@ Not critical:
|
||||
normative example - only relevant when using gotos! -> must add
|
||||
boolean variable to tell if compound literal was already
|
||||
initialized).
|
||||
- add PowerPC or ARM code generator and improve codegen for RISC (need
|
||||
- add PowerPC generator and improve codegen for RISC (need
|
||||
to suppress VT_LOCAL and use a base register instead).
|
||||
- interactive mode / integrated debugger
|
||||
- fix preprocessor symbol redefinition
|
||||
- better constant opt (&&, ||, ?:)
|
||||
- add portable byte code generator and interpreter for other
|
||||
unsupported architectures.
|
||||
- C++: variable declaration in for, minimal 'class' support.
|
||||
- win32: __intxx. use resolve for bchecked malloc et al.
|
||||
check exception code (exception filter func).
|
||||
- handle void (__attribute__() *ptr)()
|
||||
- VLAs are implemented in a way that is not compatible with signals:
|
||||
http://lists.gnu.org/archive/html/tinycc-devel/2015-11/msg00018.html
|
||||
|
||||
Fixed (probably):
|
||||
|
||||
@ -91,3 +94,8 @@ Fixed (probably):
|
||||
- #include_next support for /usr/include/limits ?
|
||||
- function pointers/lvalues in ? : (linux kernel net/core/dev.c)
|
||||
- win32: add __stdcall, check GetModuleHandle for dlls.
|
||||
- macro substitution with nested definitions (ShangHongzhang)
|
||||
- with "-run" and libtcc, a PLT is now built.
|
||||
- '-E' option was improved
|
||||
- packed attribute is now supported
|
||||
- ARM and ARM64 code generators have been added.
|
||||
|
||||
94
arm-asm.c
Normal file
94
arm-asm.c
Normal file
@ -0,0 +1,94 @@
|
||||
/*************************************************************/
|
||||
/*
|
||||
* ARM dummy assembler for TCC
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef TARGET_DEFS_ONLY
|
||||
|
||||
#define CONFIG_TCC_ASM
|
||||
#define NB_ASM_REGS 16
|
||||
|
||||
ST_FUNC void g(int c);
|
||||
ST_FUNC void gen_le16(int c);
|
||||
ST_FUNC void gen_le32(int c);
|
||||
|
||||
/*************************************************************/
|
||||
#else
|
||||
/*************************************************************/
|
||||
|
||||
static void asm_error(void)
|
||||
{
|
||||
tcc_error("ARM asm not implemented.");
|
||||
}
|
||||
|
||||
/* XXX: make it faster ? */
|
||||
ST_FUNC void g(int c)
|
||||
{
|
||||
int ind1;
|
||||
if (nocode_wanted)
|
||||
return;
|
||||
ind1 = ind + 1;
|
||||
if (ind1 > cur_text_section->data_allocated)
|
||||
section_realloc(cur_text_section, ind1);
|
||||
cur_text_section->data[ind] = c;
|
||||
ind = ind1;
|
||||
}
|
||||
|
||||
ST_FUNC void gen_le16 (int i)
|
||||
{
|
||||
g(i);
|
||||
g(i>>8);
|
||||
}
|
||||
|
||||
ST_FUNC void gen_le32 (int i)
|
||||
{
|
||||
gen_le16(i);
|
||||
gen_le16(i>>16);
|
||||
}
|
||||
|
||||
ST_FUNC void gen_expr32(ExprValue *pe)
|
||||
{
|
||||
gen_le32(pe->v);
|
||||
}
|
||||
|
||||
ST_FUNC void asm_opcode(TCCState *s1, int opcode)
|
||||
{
|
||||
asm_error();
|
||||
}
|
||||
|
||||
ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier)
|
||||
{
|
||||
asm_error();
|
||||
}
|
||||
|
||||
/* generate prolog and epilog code for asm statement */
|
||||
ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
|
||||
int nb_outputs, int is_output,
|
||||
uint8_t *clobber_regs,
|
||||
int out_reg)
|
||||
{
|
||||
asm_error();
|
||||
}
|
||||
|
||||
ST_FUNC void asm_compute_constraints(ASMOperand *operands,
|
||||
int nb_operands, int nb_outputs,
|
||||
const uint8_t *clobber_regs,
|
||||
int *pout_reg)
|
||||
{
|
||||
asm_error();
|
||||
}
|
||||
|
||||
ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str)
|
||||
{
|
||||
asm_error();
|
||||
}
|
||||
|
||||
ST_FUNC int asm_parse_regvar (int t)
|
||||
{
|
||||
asm_error();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
#endif /* ndef TARGET_DEFS_ONLY */
|
||||
391
arm-link.c
Normal file
391
arm-link.c
Normal file
@ -0,0 +1,391 @@
|
||||
#ifdef TARGET_DEFS_ONLY
|
||||
|
||||
#define EM_TCC_TARGET EM_ARM
|
||||
|
||||
/* relocation type for 32 bit data relocation */
|
||||
#define R_DATA_32 R_ARM_ABS32
|
||||
#define R_DATA_PTR R_ARM_ABS32
|
||||
#define R_JMP_SLOT R_ARM_JUMP_SLOT
|
||||
#define R_GLOB_DAT R_ARM_GLOB_DAT
|
||||
#define R_COPY R_ARM_COPY
|
||||
|
||||
#define R_NUM R_ARM_NUM
|
||||
|
||||
#define ELF_START_ADDR 0x00008000
|
||||
#define ELF_PAGE_SIZE 0x1000
|
||||
|
||||
#define PCRELATIVE_DLLPLT 1
|
||||
#define RELOCATE_DLLPLT 0
|
||||
|
||||
enum float_abi {
|
||||
ARM_SOFTFP_FLOAT,
|
||||
ARM_HARD_FLOAT,
|
||||
};
|
||||
|
||||
#else /* !TARGET_DEFS_ONLY */
|
||||
|
||||
#include "tcc.h"
|
||||
|
||||
/* Returns 1 for a code relocation, 0 for a data relocation. For unknown
|
||||
relocations, returns -1. */
|
||||
int code_reloc (int reloc_type)
|
||||
{
|
||||
switch (reloc_type) {
|
||||
case R_ARM_MOVT_ABS:
|
||||
case R_ARM_MOVW_ABS_NC:
|
||||
case R_ARM_THM_MOVT_ABS:
|
||||
case R_ARM_THM_MOVW_ABS_NC:
|
||||
case R_ARM_ABS32:
|
||||
case R_ARM_REL32:
|
||||
case R_ARM_GOTPC:
|
||||
case R_ARM_GOTOFF:
|
||||
case R_ARM_GOT32:
|
||||
case R_ARM_COPY:
|
||||
case R_ARM_GLOB_DAT:
|
||||
case R_ARM_NONE:
|
||||
return 0;
|
||||
|
||||
case R_ARM_PC24:
|
||||
case R_ARM_CALL:
|
||||
case R_ARM_JUMP24:
|
||||
case R_ARM_PLT32:
|
||||
case R_ARM_THM_PC22:
|
||||
case R_ARM_THM_JUMP24:
|
||||
case R_ARM_PREL31:
|
||||
case R_ARM_V4BX:
|
||||
case R_ARM_JUMP_SLOT:
|
||||
return 1;
|
||||
}
|
||||
|
||||
tcc_error ("Unknown relocation type: %d", reloc_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Returns an enumerator to describe wether and when the relocation needs a
|
||||
GOT and/or PLT entry to be created. See tcc.h for a description of the
|
||||
different values. */
|
||||
int gotplt_entry_type (int reloc_type)
|
||||
{
|
||||
switch (reloc_type) {
|
||||
case R_ARM_NONE:
|
||||
case R_ARM_COPY:
|
||||
case R_ARM_GLOB_DAT:
|
||||
case R_ARM_JUMP_SLOT:
|
||||
return NO_GOTPLT_ENTRY;
|
||||
|
||||
case R_ARM_PC24:
|
||||
case R_ARM_CALL:
|
||||
case R_ARM_JUMP24:
|
||||
case R_ARM_PLT32:
|
||||
case R_ARM_THM_PC22:
|
||||
case R_ARM_THM_JUMP24:
|
||||
case R_ARM_MOVT_ABS:
|
||||
case R_ARM_MOVW_ABS_NC:
|
||||
case R_ARM_THM_MOVT_ABS:
|
||||
case R_ARM_THM_MOVW_ABS_NC:
|
||||
case R_ARM_PREL31:
|
||||
case R_ARM_ABS32:
|
||||
case R_ARM_REL32:
|
||||
case R_ARM_V4BX:
|
||||
return AUTO_GOTPLT_ENTRY;
|
||||
|
||||
case R_ARM_GOTPC:
|
||||
case R_ARM_GOTOFF:
|
||||
return BUILD_GOT_ONLY;
|
||||
|
||||
case R_ARM_GOT32:
|
||||
return ALWAYS_GOTPLT_ENTRY;
|
||||
}
|
||||
|
||||
tcc_error ("Unknown relocation type: %d", reloc_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr)
|
||||
{
|
||||
Section *plt = s1->plt;
|
||||
uint8_t *p;
|
||||
unsigned plt_offset;
|
||||
|
||||
/* when building a DLL, GOT entry accesses must be done relative to
|
||||
start of GOT (see x86_64 examble above) */
|
||||
if (s1->output_type == TCC_OUTPUT_DLL)
|
||||
tcc_error("DLLs unimplemented!");
|
||||
|
||||
/* empty PLT: create PLT0 entry that push address of call site and
|
||||
jump to ld.so resolution routine (GOT + 8) */
|
||||
if (plt->data_offset == 0) {
|
||||
p = section_ptr_add(plt, 20);
|
||||
write32le(p, 0xe52de004); /* push {lr} */
|
||||
write32le(p+4, 0xe59fe004); /* ldr lr, [pc, #4] */
|
||||
write32le(p+8, 0xe08fe00e); /* add lr, pc, lr */
|
||||
write32le(p+12, 0xe5bef008); /* ldr pc, [lr, #8]! */
|
||||
/* p+16 is set in relocate_plt */
|
||||
}
|
||||
plt_offset = plt->data_offset;
|
||||
|
||||
if (attr->plt_thumb_stub) {
|
||||
p = section_ptr_add(plt, 4);
|
||||
write32le(p, 0x4778); /* bx pc */
|
||||
write32le(p+2, 0x46c0); /* nop */
|
||||
}
|
||||
p = section_ptr_add(plt, 16);
|
||||
/* Jump to GOT entry where ld.so initially put address of PLT0 */
|
||||
write32le(p, 0xe59fc004); /* ldr ip, [pc, #4] */
|
||||
write32le(p+4, 0xe08fc00c); /* add ip, pc, ip */
|
||||
write32le(p+8, 0xe59cf000); /* ldr pc, [ip] */
|
||||
/* p + 12 contains offset to GOT entry once patched by relocate_plt */
|
||||
write32le(p+12, got_offset);
|
||||
return plt_offset;
|
||||
}
|
||||
|
||||
/* relocate the PLT: compute addresses and offsets in the PLT now that final
|
||||
address for PLT and GOT are known (see fill_program_header) */
|
||||
ST_FUNC void relocate_plt(TCCState *s1)
|
||||
{
|
||||
uint8_t *p, *p_end;
|
||||
|
||||
if (!s1->plt)
|
||||
return;
|
||||
|
||||
p = s1->plt->data;
|
||||
p_end = p + s1->plt->data_offset;
|
||||
|
||||
if (p < p_end) {
|
||||
int x = s1->got->sh_addr - s1->plt->sh_addr - 12;
|
||||
write32le(s1->plt->data + 16, x - 16);
|
||||
p += 20;
|
||||
while (p < p_end) {
|
||||
if (read32le(p) == 0x46c04778) /* PLT Thumb stub present */
|
||||
p += 4;
|
||||
add32le(p + 12, x + s1->plt->data - p);
|
||||
p += 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void relocate_init(Section *sr) {}
|
||||
|
||||
void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, addr_t val)
|
||||
{
|
||||
ElfW(Sym) *sym;
|
||||
int sym_index;
|
||||
|
||||
sym_index = ELFW(R_SYM)(rel->r_info);
|
||||
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
||||
|
||||
switch(type) {
|
||||
case R_ARM_PC24:
|
||||
case R_ARM_CALL:
|
||||
case R_ARM_JUMP24:
|
||||
case R_ARM_PLT32:
|
||||
{
|
||||
int x, is_thumb, is_call, h, blx_avail, is_bl, th_ko;
|
||||
x = (*(int *) ptr) & 0xffffff;
|
||||
#ifdef DEBUG_RELOC
|
||||
printf ("reloc %d: x=0x%x val=0x%x ", type, x, val);
|
||||
#endif
|
||||
(*(int *)ptr) &= 0xff000000;
|
||||
if (x & 0x800000)
|
||||
x -= 0x1000000;
|
||||
x <<= 2;
|
||||
blx_avail = (TCC_ARM_VERSION >= 5);
|
||||
is_thumb = val & 1;
|
||||
is_bl = (*(unsigned *) ptr) >> 24 == 0xeb;
|
||||
is_call = (type == R_ARM_CALL || (type == R_ARM_PC24 && is_bl));
|
||||
x += val - addr;
|
||||
#ifdef DEBUG_RELOC
|
||||
printf (" newx=0x%x name=%s\n", x,
|
||||
(char *) symtab_section->link->data + sym->st_name);
|
||||
#endif
|
||||
h = x & 2;
|
||||
th_ko = (x & 3) && (!blx_avail || !is_call);
|
||||
if (th_ko || x >= 0x2000000 || x < -0x2000000)
|
||||
tcc_error("can't relocate value at %x,%d",addr, type);
|
||||
x >>= 2;
|
||||
x &= 0xffffff;
|
||||
/* Only reached if blx is avail and it is a call */
|
||||
if (is_thumb) {
|
||||
x |= h << 24;
|
||||
(*(int *)ptr) = 0xfa << 24; /* bl -> blx */
|
||||
}
|
||||
(*(int *) ptr) |= x;
|
||||
}
|
||||
return;
|
||||
/* Since these relocations only concern Thumb-2 and blx instruction was
|
||||
introduced before Thumb-2, we can assume blx is available and not
|
||||
guard its use */
|
||||
case R_ARM_THM_PC22:
|
||||
case R_ARM_THM_JUMP24:
|
||||
{
|
||||
int x, hi, lo, s, j1, j2, i1, i2, imm10, imm11;
|
||||
int to_thumb, is_call, to_plt, blx_bit = 1 << 12;
|
||||
Section *plt;
|
||||
|
||||
/* weak reference */
|
||||
if (sym->st_shndx == SHN_UNDEF &&
|
||||
ELFW(ST_BIND)(sym->st_info) == STB_WEAK)
|
||||
return;
|
||||
|
||||
/* Get initial offset */
|
||||
hi = (*(uint16_t *)ptr);
|
||||
lo = (*(uint16_t *)(ptr+2));
|
||||
s = (hi >> 10) & 1;
|
||||
j1 = (lo >> 13) & 1;
|
||||
j2 = (lo >> 11) & 1;
|
||||
i1 = (j1 ^ s) ^ 1;
|
||||
i2 = (j2 ^ s) ^ 1;
|
||||
imm10 = hi & 0x3ff;
|
||||
imm11 = lo & 0x7ff;
|
||||
x = (s << 24) | (i1 << 23) | (i2 << 22) |
|
||||
(imm10 << 12) | (imm11 << 1);
|
||||
if (x & 0x01000000)
|
||||
x -= 0x02000000;
|
||||
|
||||
/* Relocation infos */
|
||||
to_thumb = val & 1;
|
||||
plt = s1->plt;
|
||||
to_plt = (val >= plt->sh_addr) &&
|
||||
(val < plt->sh_addr + plt->data_offset);
|
||||
is_call = (type == R_ARM_THM_PC22);
|
||||
|
||||
if (!to_thumb && !to_plt && !is_call) {
|
||||
int index;
|
||||
uint8_t *p;
|
||||
char *name, buf[1024];
|
||||
Section *text_section;
|
||||
|
||||
name = (char *) symtab_section->link->data + sym->st_name;
|
||||
text_section = s1->sections[sym->st_shndx];
|
||||
/* Modify reloc to target a thumb stub to switch to ARM */
|
||||
snprintf(buf, sizeof(buf), "%s_from_thumb", name);
|
||||
index = put_elf_sym(symtab_section,
|
||||
text_section->data_offset + 1,
|
||||
sym->st_size, sym->st_info, 0,
|
||||
sym->st_shndx, buf);
|
||||
to_thumb = 1;
|
||||
val = text_section->data_offset + 1;
|
||||
rel->r_info = ELFW(R_INFO)(index, type);
|
||||
/* Create a thumb stub function to switch to ARM mode */
|
||||
put_elf_reloc(symtab_section, text_section,
|
||||
text_section->data_offset + 4, R_ARM_JUMP24,
|
||||
sym_index);
|
||||
p = section_ptr_add(text_section, 8);
|
||||
write32le(p, 0x4778); /* bx pc */
|
||||
write32le(p+2, 0x46c0); /* nop */
|
||||
write32le(p+4, 0xeafffffe); /* b $sym */
|
||||
}
|
||||
|
||||
/* Compute final offset */
|
||||
x += val - addr;
|
||||
if (!to_thumb && is_call) {
|
||||
blx_bit = 0; /* bl -> blx */
|
||||
x = (x + 3) & -4; /* Compute offset from aligned PC */
|
||||
}
|
||||
|
||||
/* Check that relocation is possible
|
||||
* offset must not be out of range
|
||||
* if target is to be entered in arm mode:
|
||||
- bit 1 must not set
|
||||
- instruction must be a call (bl) or a jump to PLT */
|
||||
if (!to_thumb || x >= 0x1000000 || x < -0x1000000)
|
||||
if (to_thumb || (val & 2) || (!is_call && !to_plt))
|
||||
tcc_error("can't relocate value at %x,%d",addr, type);
|
||||
|
||||
/* Compute and store final offset */
|
||||
s = (x >> 24) & 1;
|
||||
i1 = (x >> 23) & 1;
|
||||
i2 = (x >> 22) & 1;
|
||||
j1 = s ^ (i1 ^ 1);
|
||||
j2 = s ^ (i2 ^ 1);
|
||||
imm10 = (x >> 12) & 0x3ff;
|
||||
imm11 = (x >> 1) & 0x7ff;
|
||||
(*(uint16_t *)ptr) = (uint16_t) ((hi & 0xf800) |
|
||||
(s << 10) | imm10);
|
||||
(*(uint16_t *)(ptr+2)) = (uint16_t) ((lo & 0xc000) |
|
||||
(j1 << 13) | blx_bit | (j2 << 11) |
|
||||
imm11);
|
||||
}
|
||||
return;
|
||||
case R_ARM_MOVT_ABS:
|
||||
case R_ARM_MOVW_ABS_NC:
|
||||
{
|
||||
int x, imm4, imm12;
|
||||
if (type == R_ARM_MOVT_ABS)
|
||||
val >>= 16;
|
||||
imm12 = val & 0xfff;
|
||||
imm4 = (val >> 12) & 0xf;
|
||||
x = (imm4 << 16) | imm12;
|
||||
if (type == R_ARM_THM_MOVT_ABS)
|
||||
*(int *)ptr |= x;
|
||||
else
|
||||
*(int *)ptr += x;
|
||||
}
|
||||
return;
|
||||
case R_ARM_THM_MOVT_ABS:
|
||||
case R_ARM_THM_MOVW_ABS_NC:
|
||||
{
|
||||
int x, i, imm4, imm3, imm8;
|
||||
if (type == R_ARM_THM_MOVT_ABS)
|
||||
val >>= 16;
|
||||
imm8 = val & 0xff;
|
||||
imm3 = (val >> 8) & 0x7;
|
||||
i = (val >> 11) & 1;
|
||||
imm4 = (val >> 12) & 0xf;
|
||||
x = (imm3 << 28) | (imm8 << 16) | (i << 10) | imm4;
|
||||
if (type == R_ARM_THM_MOVT_ABS)
|
||||
*(int *)ptr |= x;
|
||||
else
|
||||
*(int *)ptr += x;
|
||||
}
|
||||
return;
|
||||
case R_ARM_PREL31:
|
||||
{
|
||||
int x;
|
||||
x = (*(int *)ptr) & 0x7fffffff;
|
||||
(*(int *)ptr) &= 0x80000000;
|
||||
x = (x * 2) / 2;
|
||||
x += val - addr;
|
||||
if((x^(x>>1))&0x40000000)
|
||||
tcc_error("can't relocate value at %x,%d",addr, type);
|
||||
(*(int *)ptr) |= x & 0x7fffffff;
|
||||
}
|
||||
case R_ARM_ABS32:
|
||||
*(int *)ptr += val;
|
||||
return;
|
||||
case R_ARM_REL32:
|
||||
*(int *)ptr += val - addr;
|
||||
return;
|
||||
case R_ARM_GOTPC:
|
||||
*(int *)ptr += s1->got->sh_addr - addr;
|
||||
return;
|
||||
case R_ARM_GOTOFF:
|
||||
*(int *)ptr += val - s1->got->sh_addr;
|
||||
return;
|
||||
case R_ARM_GOT32:
|
||||
/* we load the got offset */
|
||||
*(int *)ptr += s1->sym_attrs[sym_index].got_offset;
|
||||
return;
|
||||
case R_ARM_COPY:
|
||||
return;
|
||||
case R_ARM_V4BX:
|
||||
/* trade Thumb support for ARMv4 support */
|
||||
if ((0x0ffffff0 & *(int*)ptr) == 0x012FFF10)
|
||||
*(int*)ptr ^= 0xE12FFF10 ^ 0xE1A0F000; /* BX Rm -> MOV PC, Rm */
|
||||
return;
|
||||
case R_ARM_GLOB_DAT:
|
||||
case R_ARM_JUMP_SLOT:
|
||||
*(addr_t *)ptr = val;
|
||||
return;
|
||||
case R_ARM_NONE:
|
||||
/* Nothing to do. Normally used to indicate a dependency
|
||||
on a certain symbol (like for exception handling under EABI). */
|
||||
return;
|
||||
default:
|
||||
fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n",
|
||||
type, (unsigned)addr, ptr, (unsigned)val);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !TARGET_DEFS_ONLY */
|
||||
1838
arm64-gen.c
Normal file
1838
arm64-gen.c
Normal file
File diff suppressed because it is too large
Load Diff
249
arm64-link.c
Normal file
249
arm64-link.c
Normal file
@ -0,0 +1,249 @@
|
||||
#ifdef TARGET_DEFS_ONLY
|
||||
|
||||
#define EM_TCC_TARGET EM_AARCH64
|
||||
|
||||
#define R_DATA_32 R_AARCH64_ABS32
|
||||
#define R_DATA_PTR R_AARCH64_ABS64
|
||||
#define R_JMP_SLOT R_AARCH64_JUMP_SLOT
|
||||
#define R_GLOB_DAT R_AARCH64_GLOB_DAT
|
||||
#define R_COPY R_AARCH64_COPY
|
||||
|
||||
#define R_NUM R_AARCH64_NUM
|
||||
|
||||
#define ELF_START_ADDR 0x00400000
|
||||
#define ELF_PAGE_SIZE 0x1000
|
||||
|
||||
#define PCRELATIVE_DLLPLT 1
|
||||
#define RELOCATE_DLLPLT 1
|
||||
|
||||
#else /* !TARGET_DEFS_ONLY */
|
||||
|
||||
#include "tcc.h"
|
||||
|
||||
/* Returns 1 for a code relocation, 0 for a data relocation. For unknown
|
||||
relocations, returns -1. */
|
||||
int code_reloc (int reloc_type)
|
||||
{
|
||||
switch (reloc_type) {
|
||||
case R_AARCH64_ABS32:
|
||||
case R_AARCH64_ABS64:
|
||||
case R_AARCH64_PREL32:
|
||||
case R_AARCH64_MOVW_UABS_G0_NC:
|
||||
case R_AARCH64_MOVW_UABS_G1_NC:
|
||||
case R_AARCH64_MOVW_UABS_G2_NC:
|
||||
case R_AARCH64_MOVW_UABS_G3:
|
||||
case R_AARCH64_ADR_PREL_PG_HI21:
|
||||
case R_AARCH64_ADD_ABS_LO12_NC:
|
||||
case R_AARCH64_ADR_GOT_PAGE:
|
||||
case R_AARCH64_LD64_GOT_LO12_NC:
|
||||
case R_AARCH64_GLOB_DAT:
|
||||
case R_AARCH64_COPY:
|
||||
return 0;
|
||||
|
||||
case R_AARCH64_JUMP26:
|
||||
case R_AARCH64_CALL26:
|
||||
case R_AARCH64_JUMP_SLOT:
|
||||
return 1;
|
||||
}
|
||||
|
||||
tcc_error ("Unknown relocation type: %d", reloc_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Returns an enumerator to describe wether and when the relocation needs a
|
||||
GOT and/or PLT entry to be created. See tcc.h for a description of the
|
||||
different values. */
|
||||
int gotplt_entry_type (int reloc_type)
|
||||
{
|
||||
switch (reloc_type) {
|
||||
case R_AARCH64_PREL32:
|
||||
case R_AARCH64_MOVW_UABS_G0_NC:
|
||||
case R_AARCH64_MOVW_UABS_G1_NC:
|
||||
case R_AARCH64_MOVW_UABS_G2_NC:
|
||||
case R_AARCH64_MOVW_UABS_G3:
|
||||
case R_AARCH64_ADR_PREL_PG_HI21:
|
||||
case R_AARCH64_ADD_ABS_LO12_NC:
|
||||
case R_AARCH64_GLOB_DAT:
|
||||
case R_AARCH64_JUMP_SLOT:
|
||||
case R_AARCH64_COPY:
|
||||
return NO_GOTPLT_ENTRY;
|
||||
|
||||
case R_AARCH64_ABS32:
|
||||
case R_AARCH64_ABS64:
|
||||
case R_AARCH64_JUMP26:
|
||||
case R_AARCH64_CALL26:
|
||||
return AUTO_GOTPLT_ENTRY;
|
||||
|
||||
case R_AARCH64_ADR_GOT_PAGE:
|
||||
case R_AARCH64_LD64_GOT_LO12_NC:
|
||||
return ALWAYS_GOTPLT_ENTRY;
|
||||
}
|
||||
|
||||
tcc_error ("Unknown relocation type: %d", reloc_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr)
|
||||
{
|
||||
Section *plt = s1->plt;
|
||||
uint8_t *p;
|
||||
unsigned plt_offset;
|
||||
|
||||
if (s1->output_type == TCC_OUTPUT_DLL)
|
||||
tcc_error("DLLs unimplemented!");
|
||||
|
||||
if (plt->data_offset == 0) {
|
||||
section_ptr_add(plt, 32);
|
||||
}
|
||||
plt_offset = plt->data_offset;
|
||||
|
||||
p = section_ptr_add(plt, 16);
|
||||
write32le(p, got_offset);
|
||||
write32le(p + 4, (uint64_t) got_offset >> 32);
|
||||
return plt_offset;
|
||||
}
|
||||
|
||||
/* relocate the PLT: compute addresses and offsets in the PLT now that final
|
||||
address for PLT and GOT are known (see fill_program_header) */
|
||||
ST_FUNC void relocate_plt(TCCState *s1)
|
||||
{
|
||||
uint8_t *p, *p_end;
|
||||
|
||||
if (!s1->plt)
|
||||
return;
|
||||
|
||||
p = s1->plt->data;
|
||||
p_end = p + s1->plt->data_offset;
|
||||
|
||||
if (p < p_end) {
|
||||
uint64_t plt = s1->plt->sh_addr;
|
||||
uint64_t got = s1->got->sh_addr;
|
||||
uint64_t off = (got >> 12) - (plt >> 12);
|
||||
if ((off + ((uint32_t)1 << 20)) >> 21)
|
||||
tcc_error("Failed relocating PLT (off=0x%lx, got=0x%lx, plt=0x%lx)", off, got, plt);
|
||||
write32le(p, 0xa9bf7bf0); // stp x16,x30,[sp,#-16]!
|
||||
write32le(p + 4, (0x90000010 | // adrp x16,...
|
||||
(off & 0x1ffffc) << 3 | (off & 3) << 29));
|
||||
write32le(p + 8, (0xf9400211 | // ldr x17,[x16,#...]
|
||||
(got & 0xff8) << 7));
|
||||
write32le(p + 12, (0x91000210 | // add x16,x16,#...
|
||||
(got & 0xfff) << 10));
|
||||
write32le(p + 16, 0xd61f0220); // br x17
|
||||
write32le(p + 20, 0xd503201f); // nop
|
||||
write32le(p + 24, 0xd503201f); // nop
|
||||
write32le(p + 28, 0xd503201f); // nop
|
||||
p += 32;
|
||||
while (p < p_end) {
|
||||
uint64_t pc = plt + (p - s1->plt->data);
|
||||
uint64_t addr = got + read64le(p);
|
||||
uint64_t off = (addr >> 12) - (pc >> 12);
|
||||
if ((off + ((uint32_t)1 << 20)) >> 21)
|
||||
tcc_error("Failed relocating PLT (off=0x%lx, addr=0x%lx, pc=0x%lx)", off, addr, pc);
|
||||
write32le(p, (0x90000010 | // adrp x16,...
|
||||
(off & 0x1ffffc) << 3 | (off & 3) << 29));
|
||||
write32le(p + 4, (0xf9400211 | // ldr x17,[x16,#...]
|
||||
(addr & 0xff8) << 7));
|
||||
write32le(p + 8, (0x91000210 | // add x16,x16,#...
|
||||
(addr & 0xfff) << 10));
|
||||
write32le(p + 12, 0xd61f0220); // br x17
|
||||
p += 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void relocate_init(Section *sr) {}
|
||||
|
||||
void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, addr_t val)
|
||||
{
|
||||
int sym_index = ELFW(R_SYM)(rel->r_info);
|
||||
#ifdef DEBUG_RELOC
|
||||
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
||||
#endif
|
||||
|
||||
switch(type) {
|
||||
case R_AARCH64_ABS64:
|
||||
write64le(ptr, val);
|
||||
return;
|
||||
case R_AARCH64_ABS32:
|
||||
write32le(ptr, val);
|
||||
return;
|
||||
case R_AARCH64_PREL32:
|
||||
write32le(ptr, val - addr);
|
||||
return;
|
||||
case R_AARCH64_MOVW_UABS_G0_NC:
|
||||
write32le(ptr, ((read32le(ptr) & 0xffe0001f) |
|
||||
(val & 0xffff) << 5));
|
||||
return;
|
||||
case R_AARCH64_MOVW_UABS_G1_NC:
|
||||
write32le(ptr, ((read32le(ptr) & 0xffe0001f) |
|
||||
(val >> 16 & 0xffff) << 5));
|
||||
return;
|
||||
case R_AARCH64_MOVW_UABS_G2_NC:
|
||||
write32le(ptr, ((read32le(ptr) & 0xffe0001f) |
|
||||
(val >> 32 & 0xffff) << 5));
|
||||
return;
|
||||
case R_AARCH64_MOVW_UABS_G3:
|
||||
write32le(ptr, ((read32le(ptr) & 0xffe0001f) |
|
||||
(val >> 48 & 0xffff) << 5));
|
||||
return;
|
||||
case R_AARCH64_ADR_PREL_PG_HI21: {
|
||||
uint64_t off = (val >> 12) - (addr >> 12);
|
||||
if ((off + ((uint64_t)1 << 20)) >> 21)
|
||||
tcc_error("R_AARCH64_ADR_PREL_PG_HI21 relocation failed");
|
||||
write32le(ptr, ((read32le(ptr) & 0x9f00001f) |
|
||||
(off & 0x1ffffc) << 3 | (off & 3) << 29));
|
||||
return;
|
||||
}
|
||||
case R_AARCH64_ADD_ABS_LO12_NC:
|
||||
write32le(ptr, ((read32le(ptr) & 0xffc003ff) |
|
||||
(val & 0xfff) << 10));
|
||||
return;
|
||||
case R_AARCH64_JUMP26:
|
||||
case R_AARCH64_CALL26:
|
||||
#ifdef DEBUG_RELOC
|
||||
printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, val,
|
||||
(char *) symtab_section->link->data + sym->st_name);
|
||||
#endif
|
||||
if (((val - addr) + ((uint64_t)1 << 27)) & ~(uint64_t)0xffffffc)
|
||||
tcc_error("R_AARCH64_(JUMP|CALL)26 relocation failed"
|
||||
" (val=%lx, addr=%lx)", val, addr);
|
||||
write32le(ptr, (0x14000000 |
|
||||
(uint32_t)(type == R_AARCH64_CALL26) << 31 |
|
||||
((val - addr) >> 2 & 0x3ffffff)));
|
||||
return;
|
||||
case R_AARCH64_ADR_GOT_PAGE: {
|
||||
uint64_t off =
|
||||
(((s1->got->sh_addr +
|
||||
s1->sym_attrs[sym_index].got_offset) >> 12) - (addr >> 12));
|
||||
if ((off + ((uint64_t)1 << 20)) >> 21)
|
||||
tcc_error("R_AARCH64_ADR_GOT_PAGE relocation failed");
|
||||
write32le(ptr, ((read32le(ptr) & 0x9f00001f) |
|
||||
(off & 0x1ffffc) << 3 | (off & 3) << 29));
|
||||
return;
|
||||
}
|
||||
case R_AARCH64_LD64_GOT_LO12_NC:
|
||||
write32le(ptr,
|
||||
((read32le(ptr) & 0xfff803ff) |
|
||||
((s1->got->sh_addr +
|
||||
s1->sym_attrs[sym_index].got_offset) & 0xff8) << 7));
|
||||
return;
|
||||
case R_AARCH64_COPY:
|
||||
return;
|
||||
case R_AARCH64_GLOB_DAT:
|
||||
case R_AARCH64_JUMP_SLOT:
|
||||
/* They don't need addend */
|
||||
#ifdef DEBUG_RELOC
|
||||
printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr,
|
||||
val - rel->r_addend,
|
||||
(char *) symtab_section->link->data + sym->st_name);
|
||||
#endif
|
||||
write64le(ptr, val - rel->r_addend);
|
||||
return;
|
||||
default:
|
||||
fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n",
|
||||
type, (unsigned)addr, ptr, (unsigned)val);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !TARGET_DEFS_ONLY */
|
||||
102
c67-gen.c
102
c67-gen.c
@ -20,7 +20,7 @@
|
||||
|
||||
#ifdef TARGET_DEFS_ONLY
|
||||
|
||||
//#define ASSEMBLY_LISTING_C67
|
||||
/* #define ASSEMBLY_LISTING_C67 */
|
||||
|
||||
/* number of available registers */
|
||||
#define NB_REGS 24
|
||||
@ -93,11 +93,11 @@ enum {
|
||||
#define REG_FRET TREG_C67_A4 /* float return register */
|
||||
|
||||
/* defined if function parameters must be evaluated in reverse order */
|
||||
//#define INVERT_FUNC_PARAMS
|
||||
/* #define INVERT_FUNC_PARAMS */
|
||||
|
||||
/* defined if structures are passed as pointers. Otherwise structures
|
||||
are directly pushed on stack. */
|
||||
//#define FUNC_STRUCT_PARAM_AS_PTR
|
||||
/* #define FUNC_STRUCT_PARAM_AS_PTR */
|
||||
|
||||
/* pointer size, in bytes */
|
||||
#define PTR_SIZE 4
|
||||
@ -108,20 +108,6 @@ enum {
|
||||
/* maximum alignment (for aligned attribute support) */
|
||||
#define MAX_ALIGN 8
|
||||
|
||||
/******************************************************/
|
||||
/* ELF defines */
|
||||
|
||||
#define EM_TCC_TARGET EM_C60
|
||||
|
||||
/* relocation type for 32 bit data relocation */
|
||||
#define R_DATA_32 R_C60_32
|
||||
#define R_DATA_PTR R_C60_32
|
||||
#define R_JMP_SLOT R_C60_JMP_SLOT
|
||||
#define R_COPY R_C60_COPY
|
||||
|
||||
#define ELF_START_ADDR 0x00000400
|
||||
#define ELF_PAGE_SIZE 0x1000
|
||||
|
||||
/******************************************************/
|
||||
#else /* ! TARGET_DEFS_ONLY */
|
||||
/******************************************************/
|
||||
@ -196,7 +182,8 @@ FILE *f = NULL;
|
||||
void C67_g(int c)
|
||||
{
|
||||
int ind1;
|
||||
|
||||
if (nocode_wanted)
|
||||
return;
|
||||
#ifdef ASSEMBLY_LISTING_C67
|
||||
fprintf(f, " %08X", c);
|
||||
#endif
|
||||
@ -245,15 +232,15 @@ void gsym(int t)
|
||||
}
|
||||
|
||||
// these are regs that tcc doesn't really know about,
|
||||
// but asign them unique values so the mapping routines
|
||||
// can distinquish them
|
||||
// but assign them unique values so the mapping routines
|
||||
// can distinguish them
|
||||
|
||||
#define C67_A0 105
|
||||
#define C67_SP 106
|
||||
#define C67_B3 107
|
||||
#define C67_FP 108
|
||||
#define C67_B2 109
|
||||
#define C67_CREG_ZERO -1 // Special code for no condition reg test
|
||||
#define C67_CREG_ZERO -1 /* Special code for no condition reg test */
|
||||
|
||||
|
||||
int ConvertRegToRegClass(int r)
|
||||
@ -1567,14 +1554,14 @@ void load(int r, SValue * sv)
|
||||
|
||||
fr = sv->r;
|
||||
ft = sv->type.t;
|
||||
fc = sv->c.ul;
|
||||
fc = sv->c.i;
|
||||
|
||||
v = fr & VT_VALMASK;
|
||||
if (fr & VT_LVAL) {
|
||||
if (v == VT_LLOCAL) {
|
||||
v1.type.t = VT_INT;
|
||||
v1.r = VT_LOCAL | VT_LVAL;
|
||||
v1.c.ul = fc;
|
||||
v1.c.i = fc;
|
||||
load(r, &v1);
|
||||
fr = r;
|
||||
} else if ((ft & VT_BTYPE) == VT_LDOUBLE) {
|
||||
@ -1726,7 +1713,7 @@ void store(int r, SValue * v)
|
||||
int fr, bt, ft, fc, size, t, element;
|
||||
|
||||
ft = v->type.t;
|
||||
fc = v->c.ul;
|
||||
fc = v->c.i;
|
||||
fr = v->r & VT_VALMASK;
|
||||
bt = ft & VT_BTYPE;
|
||||
/* XXX: incorrect if float reg to reg */
|
||||
@ -1879,6 +1866,13 @@ static void gcall_or_jmp(int is_jmp)
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the number of registers needed to return the struct, or 0 if
|
||||
returning via struct pointer. */
|
||||
ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) {
|
||||
*ret_align = 1; // Never have to re-align return values for x86-64
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* generate function call with address in (vtop->t, vtop->c) and free function
|
||||
context. Stack entry is popped */
|
||||
void gfunc_call(int nb_args)
|
||||
@ -1894,8 +1888,6 @@ void gfunc_call(int nb_args)
|
||||
for (i = 0; i < nb_args; i++) {
|
||||
if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
|
||||
ALWAYS_ASSERT(FALSE);
|
||||
} else if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
|
||||
ALWAYS_ASSERT(FALSE);
|
||||
} else {
|
||||
/* simple type (currently always same size) */
|
||||
/* XXX: implicit cast ? */
|
||||
@ -1964,6 +1956,7 @@ void gfunc_prolog(CType * func_type)
|
||||
/* if the function returns a structure, then add an
|
||||
implicit pointer parameter */
|
||||
func_vt = sym->type;
|
||||
func_var = (sym->c == FUNC_ELLIPSIS);
|
||||
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
|
||||
func_vc = addr;
|
||||
addr += 4;
|
||||
@ -2046,6 +2039,8 @@ void gfunc_epilog(void)
|
||||
int gjmp(int t)
|
||||
{
|
||||
int ind1 = ind;
|
||||
if (nocode_wanted)
|
||||
return t;
|
||||
|
||||
C67_MVKL(C67_A0, t); //r=reg to load, constant
|
||||
C67_MVKH(C67_A0, t); //r=reg to load, constant
|
||||
@ -2078,7 +2073,9 @@ int gtst(int inv, int t)
|
||||
int v, *p;
|
||||
|
||||
v = vtop->r & VT_VALMASK;
|
||||
if (v == VT_CMP) {
|
||||
if (nocode_wanted) {
|
||||
;
|
||||
} else if (v == VT_CMP) {
|
||||
/* fast case : can jump directly since flags are set */
|
||||
// C67 uses B2 sort of as flags register
|
||||
ind1 = ind;
|
||||
@ -2100,13 +2097,12 @@ int gtst(int inv, int t)
|
||||
/* && or || optimization */
|
||||
if ((v & 1) == inv) {
|
||||
/* insert vtop->c jump list in t */
|
||||
p = &vtop->c.i;
|
||||
|
||||
// I guess the idea is to traverse to the
|
||||
// null at the end of the list and store t
|
||||
// there
|
||||
|
||||
n = *p;
|
||||
n = vtop->c.i;
|
||||
while (n != 0) {
|
||||
p = (int *) (cur_text_section->data + n);
|
||||
|
||||
@ -2122,37 +2118,6 @@ int gtst(int inv, int t)
|
||||
t = gjmp(t);
|
||||
gsym(vtop->c.i);
|
||||
}
|
||||
} else {
|
||||
if (is_float(vtop->type.t)) {
|
||||
vpushi(0);
|
||||
gen_op(TOK_NE);
|
||||
}
|
||||
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
|
||||
/* constant jmp optimization */
|
||||
if ((vtop->c.i != 0) != inv)
|
||||
t = gjmp(t);
|
||||
} else {
|
||||
// I think we need to get the value on the stack
|
||||
// into a register, test it, and generate a branch
|
||||
// return the address of the branch, so it can be
|
||||
// later patched
|
||||
|
||||
v = gv(RC_INT); // get value into a reg
|
||||
ind1 = ind;
|
||||
C67_MVKL(C67_A0, t); //r=reg to load, constant
|
||||
C67_MVKH(C67_A0, t); //r=reg to load, constant
|
||||
|
||||
if (v != TREG_EAX && // check if not already in a conditional test reg
|
||||
v != TREG_EDX && v != TREG_ST0 && v != C67_B2) {
|
||||
C67_MV(v, C67_B2);
|
||||
v = C67_B2;
|
||||
}
|
||||
|
||||
C67_IREG_B_REG(inv, v, C67_A0); // [!R] B.S2x A0
|
||||
C67_NOP(5);
|
||||
t = ind1; //return where we need to patch
|
||||
ind1 = ind;
|
||||
}
|
||||
}
|
||||
vtop--;
|
||||
return t;
|
||||
@ -2329,7 +2294,7 @@ void gen_opf(int op)
|
||||
gv2(RC_FLOAT, RC_FLOAT); // make sure src2 is on b side
|
||||
|
||||
ft = vtop->type.t;
|
||||
fc = vtop->c.ul;
|
||||
fc = vtop->c.i;
|
||||
r = vtop->r;
|
||||
fr = vtop[-1].r;
|
||||
|
||||
@ -2554,6 +2519,21 @@ void ggoto(void)
|
||||
vtop--;
|
||||
}
|
||||
|
||||
/* Save the stack pointer onto the stack and return the location of its address */
|
||||
ST_FUNC void gen_vla_sp_save(int addr) {
|
||||
tcc_error("variable length arrays unsupported for this target");
|
||||
}
|
||||
|
||||
/* Restore the SP from a location on the stack */
|
||||
ST_FUNC void gen_vla_sp_restore(int addr) {
|
||||
tcc_error("variable length arrays unsupported for this target");
|
||||
}
|
||||
|
||||
/* Subtract from the stack pointer, and push the resulting value onto the stack */
|
||||
ST_FUNC void gen_vla_alloc(CType *type, int align) {
|
||||
tcc_error("variable length arrays unsupported for this target");
|
||||
}
|
||||
|
||||
/* end of C67 code generator */
|
||||
/*************************************************************/
|
||||
#endif
|
||||
|
||||
130
c67-link.c
Normal file
130
c67-link.c
Normal file
@ -0,0 +1,130 @@
|
||||
#ifdef TARGET_DEFS_ONLY
|
||||
|
||||
#define EM_TCC_TARGET EM_C60
|
||||
|
||||
/* relocation type for 32 bit data relocation */
|
||||
#define R_DATA_32 R_C60_32
|
||||
#define R_DATA_PTR R_C60_32
|
||||
#define R_JMP_SLOT R_C60_JMP_SLOT
|
||||
#define R_GLOB_DAT R_C60_GLOB_DAT
|
||||
#define R_COPY R_C60_COPY
|
||||
|
||||
#define R_NUM R_C60_NUM
|
||||
|
||||
#define ELF_START_ADDR 0x00000400
|
||||
#define ELF_PAGE_SIZE 0x1000
|
||||
|
||||
#define PCRELATIVE_DLLPLT 0
|
||||
#define RELOCATE_DLLPLT 0
|
||||
|
||||
#else /* !TARGET_DEFS_ONLY */
|
||||
|
||||
#include "tcc.h"
|
||||
|
||||
/* Returns 1 for a code relocation, 0 for a data relocation. For unknown
|
||||
relocations, returns -1. */
|
||||
int code_reloc (int reloc_type)
|
||||
{
|
||||
switch (reloc_type) {
|
||||
case R_C60_32:
|
||||
case R_C60LO16:
|
||||
case R_C60HI16:
|
||||
case R_C60_GOT32:
|
||||
case R_C60_GOTOFF:
|
||||
case R_C60_GOTPC:
|
||||
case R_C60_COPY:
|
||||
return 0;
|
||||
|
||||
case R_C60_PLT32:
|
||||
return 1;
|
||||
}
|
||||
|
||||
tcc_error ("Unknown relocation type: %d", reloc_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Returns an enumerator to describe wether and when the relocation needs a
|
||||
GOT and/or PLT entry to be created. See tcc.h for a description of the
|
||||
different values. */
|
||||
int gotplt_entry_type (int reloc_type)
|
||||
{
|
||||
switch (reloc_type) {
|
||||
case R_C60_32:
|
||||
case R_C60LO16:
|
||||
case R_C60HI16:
|
||||
case R_C60_COPY:
|
||||
return NO_GOTPLT_ENTRY;
|
||||
|
||||
case R_C60_GOTOFF:
|
||||
case R_C60_GOTPC:
|
||||
return BUILD_GOT_ONLY;
|
||||
|
||||
case R_C60_PLT32:
|
||||
case R_C60_GOT32:
|
||||
return ALWAYS_GOTPLT_ENTRY;
|
||||
}
|
||||
|
||||
tcc_error ("Unknown relocation type: %d", reloc_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr)
|
||||
{
|
||||
tcc_error("C67 got not implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* relocate the PLT: compute addresses and offsets in the PLT now that final
|
||||
address for PLT and GOT are known (see fill_program_header) */
|
||||
ST_FUNC void relocate_plt(TCCState *s1)
|
||||
{
|
||||
uint8_t *p, *p_end;
|
||||
|
||||
if (!s1->plt)
|
||||
return;
|
||||
|
||||
p = s1->plt->data;
|
||||
p_end = p + s1->plt->data_offset;
|
||||
|
||||
if (p < p_end) {
|
||||
/* XXX: TODO */
|
||||
while (p < p_end) {
|
||||
/* XXX: TODO */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void relocate_init(Section *sr) {}
|
||||
|
||||
void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, addr_t val)
|
||||
{
|
||||
switch(type) {
|
||||
case R_C60_32:
|
||||
*(int *)ptr += val;
|
||||
break;
|
||||
case R_C60LO16:
|
||||
{
|
||||
uint32_t orig;
|
||||
|
||||
/* put the low 16 bits of the absolute address add to what is
|
||||
already there */
|
||||
orig = ((*(int *)(ptr )) >> 7) & 0xffff;
|
||||
orig |= (((*(int *)(ptr+4)) >> 7) & 0xffff) << 16;
|
||||
|
||||
/* patch both at once - assumes always in pairs Low - High */
|
||||
*(int *) ptr = (*(int *) ptr & (~(0xffff << 7)) ) |
|
||||
(((val+orig) & 0xffff) << 7);
|
||||
*(int *)(ptr+4) = (*(int *)(ptr+4) & (~(0xffff << 7)) ) |
|
||||
((((val+orig)>>16) & 0xffff) << 7);
|
||||
}
|
||||
break;
|
||||
case R_C60HI16:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n",
|
||||
type, (unsigned) addr, ptr, (unsigned) val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !TARGET_DEFS_ONLY */
|
||||
6
coff.h
6
coff.h
@ -37,8 +37,8 @@ struct filehdr {
|
||||
#define F_BYTE_ORDER (F_LITTLE | F_BIG)
|
||||
#define FILHDR struct filehdr
|
||||
|
||||
//#define FILHSZ sizeof(FILHDR)
|
||||
#define FILHSZ 22 // above rounds to align on 4 bytes which causes problems
|
||||
/* #define FILHSZ sizeof(FILHDR) */
|
||||
#define FILHSZ 22 /* above rounds to align on 4 bytes which causes problems */
|
||||
|
||||
#define COFF_C67_MAGIC 0x00c2
|
||||
|
||||
@ -150,7 +150,7 @@ struct scnhdr {
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Define constants for names of "special" sections */
|
||||
/*------------------------------------------------------------------------*/
|
||||
//#define _TEXT ".text"
|
||||
/* #define _TEXT ".text" */
|
||||
#define _DATA ".data"
|
||||
#define _BSS ".bss"
|
||||
#define _CINIT ".cinit"
|
||||
|
||||
346
configure
vendored
346
configure
vendored
@ -19,6 +19,7 @@ TMPH=$TMPN.h
|
||||
# default parameters
|
||||
build_cross="no"
|
||||
use_libgcc="no"
|
||||
disable_static=""
|
||||
prefix=""
|
||||
execprefix=""
|
||||
bindir=""
|
||||
@ -30,7 +31,6 @@ infodir=""
|
||||
sysroot=""
|
||||
cross_prefix=""
|
||||
cc="gcc"
|
||||
host_cc="gcc"
|
||||
ar="ar"
|
||||
strip="strip"
|
||||
cygwin="no"
|
||||
@ -39,21 +39,26 @@ bigendian="no"
|
||||
mingw32="no"
|
||||
LIBSUF=".a"
|
||||
EXESUF=""
|
||||
DLLSUF=".so"
|
||||
tcc_sysincludepaths=""
|
||||
tcc_libpaths=""
|
||||
tcc_crtprefix=""
|
||||
tcc_elfinterp=""
|
||||
triplet=
|
||||
tcc_lddir=
|
||||
confvars=
|
||||
|
||||
cpu=`uname -m`
|
||||
cpu=
|
||||
|
||||
# OS specific
|
||||
targetos=`uname -s`
|
||||
targetos=`uname`
|
||||
case $targetos in
|
||||
MINGW32*) mingw32=yes;;
|
||||
MINGW*) mingw32=yes;;
|
||||
MSYS*) mingw32=yes;;
|
||||
CYGWIN*) mingw32=yes; cygwin=yes; cross_prefix="mingw32-";;
|
||||
DragonFly) noldl=yes;;
|
||||
OpenBSD) noldl=yes;;
|
||||
FreeBSD) noldl=yes;;
|
||||
NetBSD) noldl=yes;;
|
||||
*) ;;
|
||||
esac
|
||||
|
||||
@ -66,49 +71,10 @@ source_path_used="yes"
|
||||
if test -z "$source_path" -o "$source_path" = "." ; then
|
||||
source_path=`pwd`
|
||||
source_path_used="no"
|
||||
# mingw compilers might not understand cygwin paths
|
||||
if test $cygwin = "yes"; then source_path="."; fi
|
||||
fi
|
||||
|
||||
case "$cpu" in
|
||||
i386|i486|i586|i686|i86pc|BePC|i686-AT386)
|
||||
cpu="x86"
|
||||
;;
|
||||
x86_64)
|
||||
cpu="x86-64"
|
||||
;;
|
||||
arm*)
|
||||
case "$cpu" in
|
||||
arm|armv4l)
|
||||
cpuver=4
|
||||
;;
|
||||
armv5tel|armv5tejl)
|
||||
cpuver=5
|
||||
;;
|
||||
armv6j|armv6l)
|
||||
cpuver=6
|
||||
;;
|
||||
armv7a|armv7l)
|
||||
cpuver=7
|
||||
;;
|
||||
esac
|
||||
cpu="armv4l"
|
||||
;;
|
||||
alpha)
|
||||
cpu="alpha"
|
||||
;;
|
||||
"Power Macintosh"|ppc|ppc64)
|
||||
cpu="powerpc"
|
||||
;;
|
||||
mips)
|
||||
cpu="mips"
|
||||
;;
|
||||
s390)
|
||||
cpu="s390"
|
||||
;;
|
||||
*)
|
||||
cpu="unknown"
|
||||
;;
|
||||
esac
|
||||
|
||||
for opt do
|
||||
eval opt=\"$opt\"
|
||||
case "$opt" in
|
||||
@ -140,11 +106,13 @@ for opt do
|
||||
;;
|
||||
--cc=*) cc=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--ar=*) ar=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--extra-cflags=*) CFLAGS="${opt#--extra-cflags=}"
|
||||
;;
|
||||
--extra-ldflags=*) LDFLAGS="${opt#--extra-ldflags=}"
|
||||
;;
|
||||
--extra-libs=*) extralibs=${opt#--extra-libs=}
|
||||
--extra-libs=*) extralibs="${opt#--extra-libs=}"
|
||||
;;
|
||||
--sysincludepaths=*) tcc_sysincludepaths=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
@ -154,18 +122,20 @@ for opt do
|
||||
;;
|
||||
--elfinterp=*) tcc_elfinterp=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--triplet=*) triplet=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--cpu=*) cpu=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--enable-gprof) gprof="yes"
|
||||
;;
|
||||
--enable-mingw32) mingw32="yes" ; cross_prefix="i686-pc-mingw32-" ; cpu=x86
|
||||
;;
|
||||
--enable-cygwin) mingw32="yes" ; cygwin="yes" ; cross_prefix="mingw32-" ; cpu=x86
|
||||
;;
|
||||
--enable-cross) build_cross="yes"
|
||||
;;
|
||||
--disable-static) disable_static="yes"
|
||||
;;
|
||||
--enable-static) disable_static="no"
|
||||
;;
|
||||
--disable-rpath) disable_rpath="yes"
|
||||
;;
|
||||
--strip-binaries) strip_binaries="yes"
|
||||
@ -181,6 +151,58 @@ for opt do
|
||||
esac
|
||||
done
|
||||
|
||||
if test -z "$cpu" ; then
|
||||
if test -n "$ARCH" ; then
|
||||
cpu="$ARCH"
|
||||
else
|
||||
cpu=`uname -m`
|
||||
fi
|
||||
fi
|
||||
|
||||
case "$cpu" in
|
||||
x86|i386|i486|i586|i686|i86pc|BePC|i686-AT386)
|
||||
cpu="x86"
|
||||
;;
|
||||
x86_64|amd64|x86-64)
|
||||
cpu="x86_64"
|
||||
;;
|
||||
arm*)
|
||||
case "$cpu" in
|
||||
arm|armv4l)
|
||||
cpuver=4
|
||||
;;
|
||||
armv5tel|armv5tejl)
|
||||
cpuver=5
|
||||
;;
|
||||
armv6j|armv6l)
|
||||
cpuver=6
|
||||
;;
|
||||
armv7a|armv7l)
|
||||
cpuver=7
|
||||
;;
|
||||
esac
|
||||
cpu="armv4l"
|
||||
;;
|
||||
aarch64)
|
||||
cpu="aarch64"
|
||||
;;
|
||||
alpha)
|
||||
cpu="alpha"
|
||||
;;
|
||||
"Power Macintosh"|ppc|ppc64)
|
||||
cpu="powerpc"
|
||||
;;
|
||||
mips)
|
||||
cpu="mips"
|
||||
;;
|
||||
s390)
|
||||
cpu="s390"
|
||||
;;
|
||||
*)
|
||||
cpu="unknown"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Checking for CFLAGS
|
||||
if test -z "$CFLAGS"; then
|
||||
CFLAGS="-Wall -g -O2"
|
||||
@ -188,13 +210,13 @@ fi
|
||||
|
||||
if test "$mingw32" = "yes" ; then
|
||||
if test x"$tccdir" = x""; then
|
||||
tccdir="tcc"
|
||||
tccdir="tcc"
|
||||
fi
|
||||
if test -z "$prefix" ; then
|
||||
prefix="C:/Program Files/${tccdir}"
|
||||
prefix="C:/Program Files/${tccdir}"
|
||||
fi
|
||||
if test -z "$sharedir" ; then
|
||||
sharedir="${prefix}"
|
||||
sharedir="${prefix}"
|
||||
fi
|
||||
execprefix="$prefix"
|
||||
bindir="${prefix}"
|
||||
@ -205,39 +227,39 @@ if test "$mingw32" = "yes" ; then
|
||||
infodir="${sharedir}/info"
|
||||
LIBSUF=".lib"
|
||||
EXESUF=".exe"
|
||||
DLLSUF=".dll"
|
||||
else
|
||||
if test -z "$prefix" ; then
|
||||
prefix="/usr/local"
|
||||
prefix="/usr/local"
|
||||
fi
|
||||
if test -z "$sharedir" ; then
|
||||
sharedir="${prefix}/share"
|
||||
sharedir="${prefix}/share"
|
||||
fi
|
||||
if test x"$execprefix" = x""; then
|
||||
execprefix="${prefix}"
|
||||
execprefix="${prefix}"
|
||||
fi
|
||||
if test x"$libdir" = x""; then
|
||||
libdir="${execprefix}/lib"
|
||||
libdir="${execprefix}/lib"
|
||||
fi
|
||||
if test x"$bindir" = x""; then
|
||||
bindir="${execprefix}/bin"
|
||||
fi
|
||||
if test x"$tccdir" = x""; then
|
||||
tccdir="tcc"
|
||||
bindir="${execprefix}/bin"
|
||||
fi
|
||||
if test x"$docdir" = x""; then
|
||||
docdir="${sharedir}/doc/${tccdir}"
|
||||
docdir="${sharedir}/doc"
|
||||
fi
|
||||
if test x"$mandir" = x""; then
|
||||
mandir="${sharedir}/man"
|
||||
mandir="${sharedir}/man"
|
||||
fi
|
||||
if test x"$infodir" = x""; then
|
||||
infodir="${sharedir}/info"
|
||||
infodir="${sharedir}/info"
|
||||
fi
|
||||
if test x"$tccdir" = x""; then
|
||||
tccdir="${libdir}/tcc"
|
||||
fi
|
||||
tccdir="${libdir}/${tccdir}"
|
||||
fi # mingw32
|
||||
|
||||
if test x"$includedir" = x""; then
|
||||
includedir="${prefix}/include"
|
||||
includedir="${prefix}/include"
|
||||
fi
|
||||
|
||||
if test x"$show_help" = "xyes" ; then
|
||||
@ -249,7 +271,7 @@ Standard options:
|
||||
--help print this message
|
||||
--prefix=PREFIX install in PREFIX [$prefix]
|
||||
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
|
||||
[same as prefix]
|
||||
[same as prefix]
|
||||
--bindir=DIR user executables in DIR [EPREFIX/bin]
|
||||
--libdir=DIR object code libraries in DIR [EPREFIX/lib]
|
||||
--tccdir=DIR installation directory [EPREFIX/lib/tcc]
|
||||
@ -264,20 +286,23 @@ Advanced options (experts only):
|
||||
--cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]
|
||||
--sysroot=PREFIX prepend PREFIX to library/include paths []
|
||||
--cc=CC use C compiler CC [$cc]
|
||||
--ar=AR create archives using AR [$ar]
|
||||
--extra-cflags= specify compiler flags [$CFLAGS]
|
||||
--extra-ldflags= specify linker options []
|
||||
--cpu=CPU CPU [$cpu]
|
||||
--strip-binaries strip symbol tables from resulting binaries
|
||||
--disable-static make libtcc.so instead of libtcc.a
|
||||
--enable-static make libtcc.a instead of libtcc.dll (win32)
|
||||
--disable-rpath disable use of -rpath with the above
|
||||
--with-libgcc use /lib/libgcc_s.so.1 instead of libtcc.a
|
||||
--with-libgcc use libgcc_s.so.1 instead of libtcc1.a in dynamic link
|
||||
--enable-mingw32 build windows version on linux with mingw32
|
||||
--enable-cygwin build windows version on windows with cygwin
|
||||
--enable-cross build cross compilers
|
||||
--with-selinux use mmap for exec mem [needs writable /tmp]
|
||||
--with-selinux use mmap for executable memory (with tcc -run)
|
||||
--sysincludepaths=... specify system include paths, colon separated
|
||||
--libpaths=... specify system library paths, colon separated
|
||||
--crtprefix=... specify locations of crt?.o, colon separated
|
||||
--elfinterp=... specify elf interpreter
|
||||
--triplet=... specify system library/include directory triplet
|
||||
EOF
|
||||
#echo "NOTE: The object files are build at the place where configure is launched"
|
||||
exit 1
|
||||
@ -288,49 +313,46 @@ ar="${cross_prefix}${ar}"
|
||||
strip="${cross_prefix}${strip}"
|
||||
|
||||
CONFTEST=./conftest$EXESUF
|
||||
if ! $cc -o $CONFTEST $source_path/conftest.c 2>/dev/null ; then
|
||||
echo "configure: error: '$cc' failed to compile conftest.c."
|
||||
else
|
||||
gcc_major="$($CONFTEST version)"
|
||||
gcc_minor="$($CONFTEST minor)"
|
||||
fi
|
||||
|
||||
if test -z "$cross_prefix" ; then
|
||||
if ! $cc -o $CONFTEST $source_path/conftest.c 2>/dev/null ; then
|
||||
echo "configure: error: '$cc' failed to compile conftest.c."
|
||||
else
|
||||
bigendian="$($CONFTEST bigendian)"
|
||||
gcc_major="$($CONFTEST version)"
|
||||
gcc_minor="$($CONFTEST minor)"
|
||||
if test "$mingw32" = "no" ; then
|
||||
triplet="$($CONFTEST triplet)"
|
||||
if test -f "/usr/lib/$triplet/crti.o" ; then
|
||||
tcc_lddir="lib/$triplet"
|
||||
multiarch_triplet="$triplet"
|
||||
elif test -f "/usr/lib64/crti.o" ; then
|
||||
tcc_lddir="lib64"
|
||||
bigendian="$($CONFTEST bigendian)"
|
||||
if test "$mingw32" = "no" ; then
|
||||
|
||||
if test -z "$triplet"; then
|
||||
tt="$($CONFTEST triplet)"
|
||||
if test -n "$tt" -a -f "/usr/lib/$tt/crti.o" ; then
|
||||
triplet="$tt"
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$triplet"; then
|
||||
if test $cpu = "x86_64" -o $cpu = "aarch64" ; then
|
||||
if test -f "/usr/lib64/crti.o" ; then
|
||||
tcc_lddir="lib64"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$cpu" = "armv4l" ; then
|
||||
if test "${triplet%eabihf}" != "$triplet" ; then
|
||||
confvars="$confvars arm_eabihf"
|
||||
elif test "${triplet%eabi}" != "$triplet" ; then
|
||||
confvars="$confvars arm_eabi"
|
||||
fi
|
||||
if grep -s -q "^Features.* \(vfp\|iwmmxt\) " /proc/cpuinfo ; then
|
||||
confvars="$confvars arm_vfp"
|
||||
fi
|
||||
if test "${triplet%eabihf}" != "$triplet" ; then
|
||||
confvars="$confvars arm_eabihf"
|
||||
elif test "${triplet%eabi}" != "$triplet" ; then
|
||||
confvars="$confvars arm_eabi"
|
||||
fi
|
||||
if grep -s -q "^Features.* \(vfp\|iwmmxt\) " /proc/cpuinfo ; then
|
||||
confvars="$confvars arm_vfp"
|
||||
fi
|
||||
fi
|
||||
|
||||
# multiarch_triplet=${libc_dir#*/}
|
||||
# multiarch_triplet=${multiarch_triplet%/}
|
||||
# tcc_lddir="${libc_dir%%/*}"
|
||||
# if test -n "$multiarch_triplet" ; then
|
||||
# tcc_lddir="$tcc_lddir/$multiarch_triplet"
|
||||
# fi
|
||||
|
||||
if test -f "/lib/ld-uClibc.so.0" ; then
|
||||
confvars="$confvars uClibc"
|
||||
confvars="$confvars uClibc"
|
||||
fi
|
||||
# gr: maybe for after the release:
|
||||
# tcc_elfinterp="$(ldd $CONFTEST | grep 'ld.*.so' | sed 's,\s*\(\S\+\).*,\1,')"
|
||||
# echo "elfinterp $tcc_elfinterp"
|
||||
|
||||
fi
|
||||
fi
|
||||
else
|
||||
# if cross compiling, cannot launch a program, so make a static guess
|
||||
@ -339,24 +361,44 @@ else
|
||||
esac
|
||||
fi
|
||||
|
||||
cat <<EOF
|
||||
Binary directory $bindir
|
||||
TinyCC directory $tccdir
|
||||
Library directory $libdir
|
||||
Include directory $includedir
|
||||
Manual directory $mandir
|
||||
Info directory $infodir
|
||||
Doc directory $docdir
|
||||
Target root prefix $sysroot
|
||||
Source path $source_path
|
||||
C compiler $cc
|
||||
Target OS $targetos
|
||||
CPU $cpu
|
||||
Big Endian $bigendian
|
||||
gprof enabled $gprof
|
||||
cross compilers $build_cross
|
||||
use libgcc $use_libgcc
|
||||
EOF
|
||||
# a final configuration tuning
|
||||
$cc -v --help > cc_help.txt 2>&1
|
||||
W_OPTIONS="declaration-after-statement"
|
||||
for i in $W_OPTIONS; do
|
||||
O_PRESENT="$(grep -- -W$i cc_help.txt)"
|
||||
if test -n "$O_PRESENT"; then CFLAGS="$CFLAGS -W$i"; fi
|
||||
done
|
||||
W_OPTIONS="pointer-sign sign-compare unused-result"
|
||||
for i in $W_OPTIONS; do
|
||||
O_PRESENT="$(grep -- -W$i cc_help.txt)"
|
||||
if test -n "$O_PRESENT"; then CFLAGS="$CFLAGS -Wno-$i"; fi
|
||||
done
|
||||
F_OPTIONS="strict-aliasing"
|
||||
for i in $F_OPTIONS; do
|
||||
O_PRESENT="$(grep -- -f$i cc_help.txt)"
|
||||
if test -n "$O_PRESENT"; then CFLAGS="$CFLAGS -fno-$i"; fi
|
||||
done
|
||||
rm -f cc_help.txt
|
||||
|
||||
fcho() { if test -n "$2"; then echo "$1$2"; else echo "$1-"; fi }
|
||||
|
||||
echo "Binary directory $bindir"
|
||||
echo "TinyCC directory $tccdir"
|
||||
echo "Library directory $libdir"
|
||||
echo "Include directory $includedir"
|
||||
echo "Manual directory $mandir"
|
||||
echo "Info directory $infodir"
|
||||
echo "Doc directory $docdir"
|
||||
fcho "Target root prefix " "$sysroot"
|
||||
echo "Source path $source_path"
|
||||
echo "C compiler $cc"
|
||||
echo "Target OS $targetos"
|
||||
echo "CPU $cpu"
|
||||
echo "Big Endian $bigendian"
|
||||
echo "Profiling $gprof"
|
||||
echo "Cross compilers $build_cross"
|
||||
echo "Use libgcc $use_libgcc"
|
||||
fcho "Triplet " "$triplet"
|
||||
|
||||
echo "Creating config.mak and config.h"
|
||||
|
||||
@ -366,7 +408,6 @@ prefix=$prefix
|
||||
bindir=\$(DESTDIR)$bindir
|
||||
tccdir=\$(DESTDIR)$tccdir
|
||||
libdir=\$(DESTDIR)$libdir
|
||||
ln_libdir=$libdir
|
||||
includedir=\$(DESTDIR)$includedir
|
||||
mandir=\$(DESTDIR)$mandir
|
||||
infodir=\$(DESTDIR)$infodir
|
||||
@ -374,13 +415,13 @@ docdir=\$(DESTDIR)$docdir
|
||||
CC=$cc
|
||||
GCC_MAJOR=$gcc_major
|
||||
GCC_MINOR=$gcc_minor
|
||||
HOST_CC=$host_cc
|
||||
AR=$ar
|
||||
STRIP=$strip -s -R .comment -R .note
|
||||
CFLAGS=$CFLAGS
|
||||
LDFLAGS=$LDFLAGS
|
||||
LIBSUF=$LIBSUF
|
||||
EXESUF=$EXESUF
|
||||
DLLSUF=$DLLSUF
|
||||
EOF
|
||||
|
||||
print_inc() {
|
||||
@ -405,33 +446,28 @@ print_mak CONFIG_TCC_LIBPATHS "$tcc_libpaths"
|
||||
print_mak CONFIG_TCC_CRTPREFIX "$tcc_crtprefix"
|
||||
print_mak CONFIG_TCC_ELFINTERP "$tcc_elfinterp"
|
||||
print_mak CONFIG_LDDIR "$tcc_lddir"
|
||||
print_mak CONFIG_MULTIARCHDIR "$multiarch_triplet"
|
||||
print_mak CONFIG_TRIPLET "$triplet"
|
||||
|
||||
echo "#define GCC_MAJOR $gcc_major" >> $TMPH
|
||||
echo "#define GCC_MINOR $gcc_minor" >> $TMPH
|
||||
|
||||
if test "$cpu" = "x86" ; then
|
||||
echo "ARCH=i386" >> config.mak
|
||||
echo "#define HOST_I386 1" >> $TMPH
|
||||
elif test "$cpu" = "x86-64" ; then
|
||||
echo "ARCH=x86-64" >> config.mak
|
||||
echo "#define HOST_X86_64 1" >> $TMPH
|
||||
elif test "$cpu" = "x86_64" ; then
|
||||
echo "ARCH=x86_64" >> config.mak
|
||||
elif test "$cpu" = "armv4l" ; then
|
||||
echo "ARCH=arm" >> config.mak
|
||||
echo "#define HOST_ARM 1" >> $TMPH
|
||||
echo "#define TCC_ARM_VERSION $cpuver" >> $TMPH
|
||||
elif test "$cpu" = "aarch64" ; then
|
||||
echo "ARCH=arm64" >> config.mak
|
||||
elif test "$cpu" = "powerpc" ; then
|
||||
echo "ARCH=ppc" >> config.mak
|
||||
echo "#define HOST_PPC 1" >> $TMPH
|
||||
elif test "$cpu" = "mips" ; then
|
||||
echo "ARCH=mips" >> config.mak
|
||||
echo "#define HOST_MIPS 1" >> $TMPH
|
||||
elif test "$cpu" = "s390" ; then
|
||||
echo "ARCH=s390" >> config.mak
|
||||
echo "#define HOST_S390 1" >> $TMPH
|
||||
elif test "$cpu" = "alpha" ; then
|
||||
echo "ARCH=alpha" >> config.mak
|
||||
echo "#define HOST_ALPHA 1" >> $TMPH
|
||||
else
|
||||
echo "Unsupported CPU"
|
||||
exit 1
|
||||
@ -447,13 +483,6 @@ if test "$noldl" = "yes" ; then
|
||||
fi
|
||||
if test "$mingw32" = "yes" ; then
|
||||
echo "CONFIG_WIN32=yes" >> config.mak
|
||||
echo "#define CONFIG_WIN32 1" >> $TMPH
|
||||
fi
|
||||
if test "$cygwin" = "yes" ; then
|
||||
echo "#ifndef _WIN32" >> $TMPH
|
||||
echo "# define _WIN32" >> $TMPH
|
||||
echo "#endif" >> $TMPH
|
||||
echo "AR=ar" >> config.mak
|
||||
fi
|
||||
if test "$bigendian" = "yes" ; then
|
||||
echo "WORDS_BIGENDIAN=yes" >> config.mak
|
||||
@ -466,8 +495,8 @@ fi
|
||||
if test "$build_cross" = "yes" ; then
|
||||
echo "CONFIG_CROSS=yes" >> config.mak
|
||||
fi
|
||||
if test "$disable_static" = "yes" ; then
|
||||
echo "DISABLE_STATIC=yes" >> config.mak
|
||||
if test -n "$disable_static" ; then
|
||||
echo "DISABLE_STATIC=$disable_static" >> config.mak
|
||||
fi
|
||||
if test "$disable_rpath" = "yes" ; then
|
||||
echo "DISABLE_RPATH=yes" >> config.mak
|
||||
@ -485,20 +514,18 @@ if test "$have_selinux" = "yes" ; then
|
||||
fi
|
||||
|
||||
version=`head $source_path/VERSION`
|
||||
echo "VERSION=$version" >>config.mak
|
||||
echo "VERSION = $version" >> config.mak
|
||||
echo "#define TCC_VERSION \"$version\"" >> $TMPH
|
||||
echo "@set VERSION $version" > config.texi
|
||||
echo "SRC_PATH=$source_path" >>config.mak
|
||||
|
||||
if test "$source_path_used" = "yes" ; then
|
||||
case $source_path in
|
||||
/*) echo "top_srcdir=$source_path";;
|
||||
*) echo "top_srcdir=\$(TOP)/$source_path";;
|
||||
/*) echo "TOPSRC=$source_path";;
|
||||
*) echo "TOPSRC=\$(TOP)/$source_path";;
|
||||
esac >>config.mak
|
||||
else
|
||||
echo 'top_srcdir=$(TOP)' >>config.mak
|
||||
echo 'TOPSRC=$(TOP)' >>config.mak
|
||||
fi
|
||||
echo 'top_builddir=$(TOP)' >>config.mak
|
||||
|
||||
diff $TMPH config.h >/dev/null 2>&1
|
||||
if test $? -ne 0 ; then
|
||||
@ -517,21 +544,22 @@ fn_makelink()
|
||||
tgt=$1/$2
|
||||
case $2 in
|
||||
*/*) dn=${2%/*}
|
||||
test -d $dn || mkdir -p $dn
|
||||
case $1 in
|
||||
/*) ;;
|
||||
*) while test $dn ; do
|
||||
tgt=../$tgt; dn=${dn#${dn%%/*}}; dn=${dn#/}
|
||||
done
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
test -d $dn || mkdir -p $dn
|
||||
case $1 in
|
||||
/*) ;;
|
||||
*) while test $dn ; do
|
||||
tgt=../$tgt; dn=${dn#${dn%%/*}}; dn=${dn#/}
|
||||
done
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
ln -sfn $tgt $2
|
||||
|
||||
ln -sfn $tgt $2 || ( echo "ln failed. Using cp instead."; cp -f $1/$2 $2 )
|
||||
}
|
||||
|
||||
if test "$source_path_used" = "yes" ; then
|
||||
FILES="Makefile lib/Makefile tests/Makefile tests/tests2/Makefile"
|
||||
FILES="Makefile lib/Makefile tests/Makefile tests/tests2/Makefile tests/pp/Makefile"
|
||||
for f in $FILES ; do
|
||||
fn_makelink $source_path $f
|
||||
done
|
||||
|
||||
28
conftest.c
28
conftest.c
@ -1,12 +1,14 @@
|
||||
#include <stdio.h>
|
||||
|
||||
/* Define architecture */
|
||||
#if defined(__i386__)
|
||||
#if defined(__i386__) || defined _M_IX86
|
||||
# define TRIPLET_ARCH "i386"
|
||||
#elif defined(__x86_64__)
|
||||
#elif defined(__x86_64__) || defined _M_AMD64
|
||||
# define TRIPLET_ARCH "x86_64"
|
||||
#elif defined(__arm__)
|
||||
# define TRIPLET_ARCH "arm"
|
||||
#elif defined(__aarch64__)
|
||||
# define TRIPLET_ARCH "aarch64"
|
||||
#else
|
||||
# define TRIPLET_ARCH "unknown"
|
||||
#endif
|
||||
@ -16,6 +18,8 @@
|
||||
# define TRIPLET_OS "linux"
|
||||
#elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
|
||||
# define TRIPLET_OS "kfreebsd"
|
||||
#elif defined _WIN32
|
||||
# define TRIPLET_OS "win32"
|
||||
#elif !defined (__GNU__)
|
||||
# define TRIPLET_OS "unknown"
|
||||
#endif
|
||||
@ -31,12 +35,18 @@
|
||||
# define TRIPLET_ABI "gnu"
|
||||
#endif
|
||||
|
||||
#ifdef __GNU__
|
||||
#if defined _WIN32
|
||||
# define TRIPLET TRIPLET_ARCH "-" TRIPLET_OS
|
||||
#elif defined __GNU__
|
||||
# define TRIPLET TRIPLET_ARCH "-" TRIPLET_ABI
|
||||
#else
|
||||
# define TRIPLET TRIPLET_ARCH "-" TRIPLET_OS "-" TRIPLET_ABI
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
int _CRT_glob = 0;
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
switch(argc == 2 ? argv[1][0] : 0) {
|
||||
@ -53,6 +63,13 @@ int main(int argc, char *argv[])
|
||||
case 'v':
|
||||
printf("%d\n", __GNUC__);
|
||||
break;
|
||||
#elif defined __TINYC__
|
||||
case 'v':
|
||||
puts("0");
|
||||
break;
|
||||
case 'm':
|
||||
printf("%d\n", __TINYC__);
|
||||
break;
|
||||
#else
|
||||
case 'm':
|
||||
case 'v':
|
||||
@ -62,9 +79,8 @@ int main(int argc, char *argv[])
|
||||
case 't':
|
||||
puts(TRIPLET);
|
||||
break;
|
||||
case -1:
|
||||
/* to test -Wno-unused-result */
|
||||
fread(NULL, 1, 1, NULL);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <tcclib.h>
|
||||
|
||||
int fib(n)
|
||||
{
|
||||
|
||||
948
i386-asm.c
948
i386-asm.c
File diff suppressed because it is too large
Load Diff
363
i386-asm.h
363
i386-asm.h
@ -38,53 +38,48 @@
|
||||
DEF_ASM_OP0(xlat, 0xd7)
|
||||
|
||||
/* strings */
|
||||
ALT(DEF_ASM_OP0L(cmpsb, 0xa6, 0, OPC_BWL))
|
||||
ALT(DEF_ASM_OP0L(scmpb, 0xa6, 0, OPC_BWL))
|
||||
ALT(DEF_ASM_OP0L(cmpsb, 0xa6, 0, OPC_BWLX))
|
||||
ALT(DEF_ASM_OP0L(scmpb, 0xa6, 0, OPC_BWLX))
|
||||
|
||||
ALT(DEF_ASM_OP0L(insb, 0x6c, 0, OPC_BWL))
|
||||
ALT(DEF_ASM_OP0L(outsb, 0x6e, 0, OPC_BWL))
|
||||
|
||||
ALT(DEF_ASM_OP0L(lodsb, 0xac, 0, OPC_BWL))
|
||||
ALT(DEF_ASM_OP0L(slodb, 0xac, 0, OPC_BWL))
|
||||
ALT(DEF_ASM_OP0L(lodsb, 0xac, 0, OPC_BWLX))
|
||||
ALT(DEF_ASM_OP0L(slodb, 0xac, 0, OPC_BWLX))
|
||||
|
||||
ALT(DEF_ASM_OP0L(movsb, 0xa4, 0, OPC_BWL))
|
||||
ALT(DEF_ASM_OP0L(smovb, 0xa4, 0, OPC_BWL))
|
||||
ALT(DEF_ASM_OP0L(movsb, 0xa4, 0, OPC_BWLX))
|
||||
ALT(DEF_ASM_OP0L(smovb, 0xa4, 0, OPC_BWLX))
|
||||
|
||||
ALT(DEF_ASM_OP0L(scasb, 0xae, 0, OPC_BWL))
|
||||
ALT(DEF_ASM_OP0L(sscab, 0xae, 0, OPC_BWL))
|
||||
ALT(DEF_ASM_OP0L(scasb, 0xae, 0, OPC_BWLX))
|
||||
ALT(DEF_ASM_OP0L(sscab, 0xae, 0, OPC_BWLX))
|
||||
|
||||
ALT(DEF_ASM_OP0L(stosb, 0xaa, 0, OPC_BWL))
|
||||
ALT(DEF_ASM_OP0L(sstob, 0xaa, 0, OPC_BWL))
|
||||
ALT(DEF_ASM_OP0L(stosb, 0xaa, 0, OPC_BWLX))
|
||||
ALT(DEF_ASM_OP0L(sstob, 0xaa, 0, OPC_BWLX))
|
||||
|
||||
/* bits */
|
||||
|
||||
ALT(DEF_ASM_OP2(bsfw, 0x0fbc, 0, OPC_MODRM | OPC_WL, OPT_REGW | OPT_EA, OPT_REGW))
|
||||
ALT(DEF_ASM_OP2(bsrw, 0x0fbd, 0, OPC_MODRM | OPC_WL, OPT_REGW | OPT_EA, OPT_REGW))
|
||||
ALT(DEF_ASM_OP2(bsfw, 0x0fbc, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW))
|
||||
ALT(DEF_ASM_OP2(bsrw, 0x0fbd, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW))
|
||||
|
||||
ALT(DEF_ASM_OP2(btw, 0x0fa3, 0, OPC_MODRM | OPC_WL, OPT_REGW, OPT_REGW | OPT_EA))
|
||||
ALT(DEF_ASM_OP2(btw, 0x0fba, 4, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW | OPT_EA))
|
||||
ALT(DEF_ASM_OP2(btw, 0x0fa3, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA))
|
||||
ALT(DEF_ASM_OP2(btw, 0x0fba, 4, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA))
|
||||
|
||||
ALT(DEF_ASM_OP2(btsw, 0x0fab, 0, OPC_MODRM | OPC_WL, OPT_REGW, OPT_REGW | OPT_EA))
|
||||
ALT(DEF_ASM_OP2(btsw, 0x0fba, 5, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW | OPT_EA))
|
||||
ALT(DEF_ASM_OP2(btsw, 0x0fab, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA))
|
||||
ALT(DEF_ASM_OP2(btsw, 0x0fba, 5, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA))
|
||||
|
||||
ALT(DEF_ASM_OP2(btrw, 0x0fb3, 0, OPC_MODRM | OPC_WL, OPT_REGW, OPT_REGW | OPT_EA))
|
||||
ALT(DEF_ASM_OP2(btrw, 0x0fba, 6, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW | OPT_EA))
|
||||
ALT(DEF_ASM_OP2(btrw, 0x0fb3, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA))
|
||||
ALT(DEF_ASM_OP2(btrw, 0x0fba, 6, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA))
|
||||
|
||||
ALT(DEF_ASM_OP2(btcw, 0x0fbb, 0, OPC_MODRM | OPC_WL, OPT_REGW, OPT_REGW | OPT_EA))
|
||||
ALT(DEF_ASM_OP2(btcw, 0x0fba, 7, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW | OPT_EA))
|
||||
ALT(DEF_ASM_OP2(btcw, 0x0fbb, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA))
|
||||
ALT(DEF_ASM_OP2(btcw, 0x0fba, 7, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA))
|
||||
|
||||
/* prefixes */
|
||||
DEF_ASM_OP0(wait, 0x9b)
|
||||
DEF_ASM_OP0(fwait, 0x9b)
|
||||
#ifdef I386_ASM_16
|
||||
DEF_ASM_OP0(a32, 0x67)
|
||||
DEF_ASM_OP0(o32, 0x66)
|
||||
#else
|
||||
DEF_ASM_OP0(aword, 0x67)
|
||||
DEF_ASM_OP0(addr16, 0x67)
|
||||
ALT(DEF_ASM_OP0(word, 0x66))
|
||||
DEF_ASM_OP0(data16, 0x66)
|
||||
#endif
|
||||
DEF_ASM_OP0(lock, 0xf0)
|
||||
DEF_ASM_OP0(rep, 0xf3)
|
||||
DEF_ASM_OP0(repe, 0xf3)
|
||||
@ -102,43 +97,43 @@ ALT(DEF_ASM_OP2(btcw, 0x0fba, 7, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW | OPT_EA)
|
||||
DEF_ASM_OP0(ud2, 0x0f0b)
|
||||
|
||||
/* NOTE: we took the same order as gas opcode definition order */
|
||||
ALT(DEF_ASM_OP2(movb, 0xa0, 0, OPC_BWL, OPT_ADDR, OPT_EAX))
|
||||
ALT(DEF_ASM_OP2(movb, 0xa2, 0, OPC_BWL, OPT_EAX, OPT_ADDR))
|
||||
ALT(DEF_ASM_OP2(movb, 0x88, 0, OPC_MODRM | OPC_BWL, OPT_REG, OPT_EA | OPT_REG))
|
||||
ALT(DEF_ASM_OP2(movb, 0x8a, 0, OPC_MODRM | OPC_BWL, OPT_EA | OPT_REG, OPT_REG))
|
||||
ALT(DEF_ASM_OP2(movb, 0xb0, 0, OPC_REG | OPC_BWL, OPT_IM, OPT_REG))
|
||||
ALT(DEF_ASM_OP2(movb, 0xc6, 0, OPC_MODRM | OPC_BWL, OPT_IM, OPT_REG | OPT_EA))
|
||||
ALT(DEF_ASM_OP2(movb, 0xa0, 0, OPC_BWLX, OPT_ADDR, OPT_EAX))
|
||||
ALT(DEF_ASM_OP2(movb, 0xa2, 0, OPC_BWLX, OPT_EAX, OPT_ADDR))
|
||||
ALT(DEF_ASM_OP2(movb, 0x88, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG))
|
||||
ALT(DEF_ASM_OP2(movb, 0x8a, 0, OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG))
|
||||
ALT(DEF_ASM_OP2(movb, 0xb0, 0, OPC_REG | OPC_BWLX, OPT_IM, OPT_REG))
|
||||
ALT(DEF_ASM_OP2(movb, 0xc6, 0, OPC_MODRM | OPC_BWLX, OPT_IM, OPT_REG | OPT_EA))
|
||||
|
||||
ALT(DEF_ASM_OP2(movw, 0x8c, 0, OPC_MODRM | OPC_WL, OPT_SEG, OPT_EA | OPT_REG))
|
||||
ALT(DEF_ASM_OP2(movw, 0x8e, 0, OPC_MODRM | OPC_WL, OPT_EA | OPT_REG, OPT_SEG))
|
||||
ALT(DEF_ASM_OP2(movw, 0x8c, 0, OPC_MODRM | OPC_WLX, OPT_SEG, OPT_EA | OPT_REG))
|
||||
ALT(DEF_ASM_OP2(movw, 0x8e, 0, OPC_MODRM | OPC_WLX, OPT_EA | OPT_REG, OPT_SEG))
|
||||
|
||||
ALT(DEF_ASM_OP2(movw, 0x0f20, 0, OPC_MODRM | OPC_WL, OPT_CR, OPT_REG32))
|
||||
ALT(DEF_ASM_OP2(movw, 0x0f21, 0, OPC_MODRM | OPC_WL, OPT_DB, OPT_REG32))
|
||||
ALT(DEF_ASM_OP2(movw, 0x0f24, 0, OPC_MODRM | OPC_WL, OPT_TR, OPT_REG32))
|
||||
ALT(DEF_ASM_OP2(movw, 0x0f22, 0, OPC_MODRM | OPC_WL, OPT_REG32, OPT_CR))
|
||||
ALT(DEF_ASM_OP2(movw, 0x0f23, 0, OPC_MODRM | OPC_WL, OPT_REG32, OPT_DB))
|
||||
ALT(DEF_ASM_OP2(movw, 0x0f26, 0, OPC_MODRM | OPC_WL, OPT_REG32, OPT_TR))
|
||||
ALT(DEF_ASM_OP2(movw, 0x0f20, 0, OPC_MODRM | OPC_WLX, OPT_CR, OPT_REG32))
|
||||
ALT(DEF_ASM_OP2(movw, 0x0f21, 0, OPC_MODRM | OPC_WLX, OPT_DB, OPT_REG32))
|
||||
ALT(DEF_ASM_OP2(movw, 0x0f24, 0, OPC_MODRM | OPC_WLX, OPT_TR, OPT_REG32))
|
||||
ALT(DEF_ASM_OP2(movw, 0x0f22, 0, OPC_MODRM | OPC_WLX, OPT_REG32, OPT_CR))
|
||||
ALT(DEF_ASM_OP2(movw, 0x0f23, 0, OPC_MODRM | OPC_WLX, OPT_REG32, OPT_DB))
|
||||
ALT(DEF_ASM_OP2(movw, 0x0f26, 0, OPC_MODRM | OPC_WLX, OPT_REG32, OPT_TR))
|
||||
|
||||
ALT(DEF_ASM_OP2(movsbl, 0x0fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REG32))
|
||||
ALT(DEF_ASM_OP2(movsbw, 0x0fbe, 0, OPC_MODRM | OPC_D16, OPT_REG8 | OPT_EA, OPT_REG16))
|
||||
ALT(DEF_ASM_OP2(movsbw, 0x660fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REG16))
|
||||
ALT(DEF_ASM_OP2(movswl, 0x0fbf, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32))
|
||||
ALT(DEF_ASM_OP2(movzbw, 0x0fb6, 0, OPC_MODRM | OPC_WL, OPT_REG8 | OPT_EA, OPT_REGW))
|
||||
ALT(DEF_ASM_OP2(movzbw, 0x0fb6, 0, OPC_MODRM | OPC_WLX, OPT_REG8 | OPT_EA, OPT_REGW))
|
||||
ALT(DEF_ASM_OP2(movzwl, 0x0fb7, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32))
|
||||
|
||||
ALT(DEF_ASM_OP1(pushw, 0x50, 0, OPC_REG | OPC_WL, OPT_REGW))
|
||||
ALT(DEF_ASM_OP1(pushw, 0xff, 6, OPC_MODRM | OPC_WL, OPT_REGW | OPT_EA))
|
||||
ALT(DEF_ASM_OP1(pushw, 0x6a, 0, OPC_WL, OPT_IM8S))
|
||||
ALT(DEF_ASM_OP1(pushw, 0x68, 0, OPC_WL, OPT_IM32))
|
||||
ALT(DEF_ASM_OP1(pushw, 0x06, 0, OPC_WL, OPT_SEG))
|
||||
ALT(DEF_ASM_OP1(pushw, 0x50, 0, OPC_REG | OPC_WLX, OPT_REGW))
|
||||
ALT(DEF_ASM_OP1(pushw, 0xff, 6, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA))
|
||||
ALT(DEF_ASM_OP1(pushw, 0x6a, 0, OPC_WLX, OPT_IM8S))
|
||||
ALT(DEF_ASM_OP1(pushw, 0x68, 0, OPC_WLX, OPT_IM32))
|
||||
ALT(DEF_ASM_OP1(pushw, 0x06, 0, OPC_WLX, OPT_SEG))
|
||||
|
||||
ALT(DEF_ASM_OP1(popw, 0x58, 0, OPC_REG | OPC_WL, OPT_REGW))
|
||||
ALT(DEF_ASM_OP1(popw, 0x8f, 0, OPC_MODRM | OPC_WL, OPT_REGW | OPT_EA))
|
||||
ALT(DEF_ASM_OP1(popw, 0x07, 0, OPC_WL, OPT_SEG))
|
||||
ALT(DEF_ASM_OP1(popw, 0x58, 0, OPC_REG | OPC_WLX, OPT_REGW))
|
||||
ALT(DEF_ASM_OP1(popw, 0x8f, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA))
|
||||
ALT(DEF_ASM_OP1(popw, 0x07, 0, OPC_WLX, OPT_SEG))
|
||||
|
||||
ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WL, OPT_REG, OPT_EAX))
|
||||
ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WL, OPT_EAX, OPT_REG))
|
||||
ALT(DEF_ASM_OP2(xchgb, 0x86, 0, OPC_MODRM | OPC_BWL, OPT_REG, OPT_EA | OPT_REG))
|
||||
ALT(DEF_ASM_OP2(xchgb, 0x86, 0, OPC_MODRM | OPC_BWL, OPT_EA | OPT_REG, OPT_REG))
|
||||
ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WLX, OPT_REGW, OPT_EAX))
|
||||
ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WLX, OPT_EAX, OPT_REGW))
|
||||
ALT(DEF_ASM_OP2(xchgb, 0x86, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG))
|
||||
ALT(DEF_ASM_OP2(xchgb, 0x86, 0, OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG))
|
||||
|
||||
ALT(DEF_ASM_OP2(inb, 0xe4, 0, OPC_BWL, OPT_IM8, OPT_EAX))
|
||||
ALT(DEF_ASM_OP1(inb, 0xe4, 0, OPC_BWL, OPT_IM8))
|
||||
@ -150,7 +145,7 @@ ALT(DEF_ASM_OP1(outb, 0xe6, 0, OPC_BWL, OPT_IM8))
|
||||
ALT(DEF_ASM_OP2(outb, 0xee, 0, OPC_BWL, OPT_EAX, OPT_DX))
|
||||
ALT(DEF_ASM_OP1(outb, 0xee, 0, OPC_BWL, OPT_DX))
|
||||
|
||||
ALT(DEF_ASM_OP2(leaw, 0x8d, 0, OPC_MODRM | OPC_WL, OPT_EA, OPT_REG))
|
||||
ALT(DEF_ASM_OP2(leaw, 0x8d, 0, OPC_MODRM | OPC_WLX, OPT_EA, OPT_REG))
|
||||
|
||||
ALT(DEF_ASM_OP2(les, 0xc4, 0, OPC_MODRM, OPT_EA, OPT_REG32))
|
||||
ALT(DEF_ASM_OP2(lds, 0xc5, 0, OPC_MODRM, OPT_EA, OPT_REG32))
|
||||
@ -159,66 +154,64 @@ ALT(DEF_ASM_OP2(lfs, 0x0fb4, 0, OPC_MODRM, OPT_EA, OPT_REG32))
|
||||
ALT(DEF_ASM_OP2(lgs, 0x0fb5, 0, OPC_MODRM, OPT_EA, OPT_REG32))
|
||||
|
||||
/* arith */
|
||||
ALT(DEF_ASM_OP2(addb, 0x00, 0, OPC_ARITH | OPC_MODRM | OPC_BWL, OPT_REG, OPT_EA | OPT_REG)) /* XXX: use D bit ? */
|
||||
ALT(DEF_ASM_OP2(addb, 0x02, 0, OPC_ARITH | OPC_MODRM | OPC_BWL, OPT_EA | OPT_REG, OPT_REG))
|
||||
ALT(DEF_ASM_OP2(addb, 0x04, 0, OPC_ARITH | OPC_BWL, OPT_IM, OPT_EAX))
|
||||
ALT(DEF_ASM_OP2(addb, 0x80, 0, OPC_ARITH | OPC_MODRM | OPC_BWL, OPT_IM, OPT_EA | OPT_REG))
|
||||
ALT(DEF_ASM_OP2(addw, 0x83, 0, OPC_ARITH | OPC_MODRM | OPC_WL, OPT_IM8S, OPT_EA | OPT_REG))
|
||||
ALT(DEF_ASM_OP2(addb, 0x00, 0, OPC_ARITH | OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG)) /* XXX: use D bit ? */
|
||||
ALT(DEF_ASM_OP2(addb, 0x02, 0, OPC_ARITH | OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG))
|
||||
ALT(DEF_ASM_OP2(addb, 0x04, 0, OPC_ARITH | OPC_BWLX, OPT_IM, OPT_EAX))
|
||||
ALT(DEF_ASM_OP2(addw, 0x83, 0, OPC_ARITH | OPC_MODRM | OPC_WLX, OPT_IM8S, OPT_EA | OPT_REGW))
|
||||
ALT(DEF_ASM_OP2(addb, 0x80, 0, OPC_ARITH | OPC_MODRM | OPC_BWLX, OPT_IM, OPT_EA | OPT_REG))
|
||||
|
||||
ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWL, OPT_EA | OPT_REG, OPT_REG))
|
||||
ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWL, OPT_REG, OPT_EA | OPT_REG))
|
||||
ALT(DEF_ASM_OP2(testb, 0xa8, 0, OPC_BWL, OPT_IM, OPT_EAX))
|
||||
ALT(DEF_ASM_OP2(testb, 0xf6, 0, OPC_MODRM | OPC_BWL, OPT_IM, OPT_EA | OPT_REG))
|
||||
ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG))
|
||||
ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG))
|
||||
ALT(DEF_ASM_OP2(testb, 0xa8, 0, OPC_BWLX, OPT_IM, OPT_EAX))
|
||||
ALT(DEF_ASM_OP2(testb, 0xf6, 0, OPC_MODRM | OPC_BWLX, OPT_IM, OPT_EA | OPT_REG))
|
||||
|
||||
ALT(DEF_ASM_OP1(incw, 0x40, 0, OPC_REG | OPC_WL, OPT_REGW))
|
||||
ALT(DEF_ASM_OP1(incb, 0xfe, 0, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
|
||||
ALT(DEF_ASM_OP1(decw, 0x48, 0, OPC_REG | OPC_WL, OPT_REGW))
|
||||
ALT(DEF_ASM_OP1(decb, 0xfe, 1, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
|
||||
ALT(DEF_ASM_OP1(incw, 0x40, 0, OPC_REG | OPC_WLX, OPT_REGW))
|
||||
ALT(DEF_ASM_OP1(incb, 0xfe, 0, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA))
|
||||
ALT(DEF_ASM_OP1(decw, 0x48, 0, OPC_REG | OPC_WLX, OPT_REGW))
|
||||
ALT(DEF_ASM_OP1(decb, 0xfe, 1, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA))
|
||||
|
||||
ALT(DEF_ASM_OP1(notb, 0xf6, 2, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
|
||||
ALT(DEF_ASM_OP1(negb, 0xf6, 3, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
|
||||
ALT(DEF_ASM_OP1(notb, 0xf6, 2, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA))
|
||||
ALT(DEF_ASM_OP1(negb, 0xf6, 3, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA))
|
||||
|
||||
ALT(DEF_ASM_OP1(mulb, 0xf6, 4, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
|
||||
ALT(DEF_ASM_OP1(imulb, 0xf6, 5, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
|
||||
ALT(DEF_ASM_OP1(mulb, 0xf6, 4, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA))
|
||||
ALT(DEF_ASM_OP1(imulb, 0xf6, 5, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA))
|
||||
|
||||
ALT(DEF_ASM_OP2(imulw, 0x0faf, 0, OPC_MODRM | OPC_WL, OPT_REG | OPT_EA, OPT_REG))
|
||||
ALT(DEF_ASM_OP3(imulw, 0x6b, 0, OPC_MODRM | OPC_WL, OPT_IM8S, OPT_REGW | OPT_EA, OPT_REGW))
|
||||
ALT(DEF_ASM_OP2(imulw, 0x6b, 0, OPC_MODRM | OPC_WL, OPT_IM8S, OPT_REGW))
|
||||
ALT(DEF_ASM_OP3(imulw, 0x69, 0, OPC_MODRM | OPC_WL, OPT_IMW, OPT_REGW | OPT_EA, OPT_REGW))
|
||||
ALT(DEF_ASM_OP2(imulw, 0x69, 0, OPC_MODRM | OPC_WL, OPT_IMW, OPT_REGW))
|
||||
ALT(DEF_ASM_OP2(imulw, 0x0faf, 0, OPC_MODRM | OPC_WLX, OPT_REG | OPT_EA, OPT_REG))
|
||||
ALT(DEF_ASM_OP3(imulw, 0x6b, 0, OPC_MODRM | OPC_WLX, OPT_IM8S, OPT_REGW | OPT_EA, OPT_REGW))
|
||||
ALT(DEF_ASM_OP2(imulw, 0x6b, 0, OPC_MODRM | OPC_WLX, OPT_IM8S, OPT_REGW))
|
||||
ALT(DEF_ASM_OP3(imulw, 0x69, 0, OPC_MODRM | OPC_WLX, OPT_IMW, OPT_REGW | OPT_EA, OPT_REGW))
|
||||
ALT(DEF_ASM_OP2(imulw, 0x69, 0, OPC_MODRM | OPC_WLX, OPT_IMW, OPT_REGW))
|
||||
|
||||
ALT(DEF_ASM_OP1(divb, 0xf6, 6, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
|
||||
ALT(DEF_ASM_OP2(divb, 0xf6, 6, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA, OPT_EAX))
|
||||
ALT(DEF_ASM_OP1(idivb, 0xf6, 7, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
|
||||
ALT(DEF_ASM_OP2(idivb, 0xf6, 7, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA, OPT_EAX))
|
||||
ALT(DEF_ASM_OP1(divb, 0xf6, 6, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA))
|
||||
ALT(DEF_ASM_OP2(divb, 0xf6, 6, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA, OPT_EAX))
|
||||
ALT(DEF_ASM_OP1(idivb, 0xf6, 7, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA))
|
||||
ALT(DEF_ASM_OP2(idivb, 0xf6, 7, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA, OPT_EAX))
|
||||
|
||||
/* shifts */
|
||||
ALT(DEF_ASM_OP2(rolb, 0xc0, 0, OPC_MODRM | OPC_BWL | OPC_SHIFT, OPT_IM8, OPT_EA | OPT_REG))
|
||||
ALT(DEF_ASM_OP2(rolb, 0xd2, 0, OPC_MODRM | OPC_BWL | OPC_SHIFT, OPT_CL, OPT_EA | OPT_REG))
|
||||
ALT(DEF_ASM_OP1(rolb, 0xd0, 0, OPC_MODRM | OPC_BWL | OPC_SHIFT, OPT_EA | OPT_REG))
|
||||
ALT(DEF_ASM_OP2(rolb, 0xc0, 0, OPC_MODRM | OPC_BWLX | OPC_SHIFT, OPT_IM8, OPT_EA | OPT_REG))
|
||||
ALT(DEF_ASM_OP2(rolb, 0xd2, 0, OPC_MODRM | OPC_BWLX | OPC_SHIFT, OPT_CL, OPT_EA | OPT_REG))
|
||||
ALT(DEF_ASM_OP1(rolb, 0xd0, 0, OPC_MODRM | OPC_BWLX | OPC_SHIFT, OPT_EA | OPT_REG))
|
||||
|
||||
ALT(DEF_ASM_OP3(shldw, 0x0fa4, 0, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW, OPT_EA | OPT_REGW))
|
||||
ALT(DEF_ASM_OP3(shldw, 0x0fa5, 0, OPC_MODRM | OPC_WL, OPT_CL, OPT_REGW, OPT_EA | OPT_REGW))
|
||||
ALT(DEF_ASM_OP2(shldw, 0x0fa5, 0, OPC_MODRM | OPC_WL, OPT_REGW, OPT_EA | OPT_REGW))
|
||||
ALT(DEF_ASM_OP3(shrdw, 0x0fac, 0, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW, OPT_EA | OPT_REGW))
|
||||
ALT(DEF_ASM_OP3(shrdw, 0x0fad, 0, OPC_MODRM | OPC_WL, OPT_CL, OPT_REGW, OPT_EA | OPT_REGW))
|
||||
ALT(DEF_ASM_OP2(shrdw, 0x0fad, 0, OPC_MODRM | OPC_WL, OPT_REGW, OPT_EA | OPT_REGW))
|
||||
ALT(DEF_ASM_OP3(shldw, 0x0fa4, 0, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW, OPT_EA | OPT_REGW))
|
||||
ALT(DEF_ASM_OP3(shldw, 0x0fa5, 0, OPC_MODRM | OPC_WLX, OPT_CL, OPT_REGW, OPT_EA | OPT_REGW))
|
||||
ALT(DEF_ASM_OP2(shldw, 0x0fa5, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_EA | OPT_REGW))
|
||||
ALT(DEF_ASM_OP3(shrdw, 0x0fac, 0, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW, OPT_EA | OPT_REGW))
|
||||
ALT(DEF_ASM_OP3(shrdw, 0x0fad, 0, OPC_MODRM | OPC_WLX, OPT_CL, OPT_REGW, OPT_EA | OPT_REGW))
|
||||
ALT(DEF_ASM_OP2(shrdw, 0x0fad, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_EA | OPT_REGW))
|
||||
|
||||
ALT(DEF_ASM_OP1(call, 0xff, 2, OPC_MODRM, OPT_INDIR))
|
||||
ALT(DEF_ASM_OP1(call, 0xe8, 0, OPC_JMP, OPT_ADDR))
|
||||
ALT(DEF_ASM_OP1(call, 0xe8, 0, 0, OPT_DISP))
|
||||
ALT(DEF_ASM_OP1(jmp, 0xff, 4, OPC_MODRM, OPT_INDIR))
|
||||
ALT(DEF_ASM_OP1(jmp, 0xeb, 0, OPC_SHORTJMP | OPC_JMP, OPT_ADDR))
|
||||
#ifdef I386_ASM_16
|
||||
ALT(DEF_ASM_OP1(jmp, 0xff, 0, OPC_JMP | OPC_WL, OPT_REGW))
|
||||
#endif
|
||||
ALT(DEF_ASM_OP1(jmp, 0xeb, 0, 0, OPT_DISP8))
|
||||
|
||||
ALT(DEF_ASM_OP2(lcall, 0x9a, 0, 0, OPT_IM16, OPT_IM32))
|
||||
ALT(DEF_ASM_OP1(lcall, 0xff, 3, 0, OPT_EA))
|
||||
ALT(DEF_ASM_OP1(lcall, 0xff, 3, OPC_MODRM, OPT_EA))
|
||||
ALT(DEF_ASM_OP2(ljmp, 0xea, 0, 0, OPT_IM16, OPT_IM32))
|
||||
ALT(DEF_ASM_OP1(ljmp, 0xff, 5, 0, OPT_EA))
|
||||
ALT(DEF_ASM_OP1(ljmp, 0xff, 5, OPC_MODRM, OPT_EA))
|
||||
|
||||
ALT(DEF_ASM_OP1(int, 0xcd, 0, 0, OPT_IM8))
|
||||
ALT(DEF_ASM_OP1(seto, 0x0f90, 0, OPC_MODRM | OPC_TEST, OPT_REG8 | OPT_EA))
|
||||
ALT(DEF_ASM_OP1(setob, 0x0f90, 0, OPC_MODRM | OPC_TEST, OPT_REG8 | OPT_EA))
|
||||
DEF_ASM_OP2(enter, 0xc8, 0, 0, OPT_IM16, OPT_IM8)
|
||||
DEF_ASM_OP0(leave, 0xc9)
|
||||
DEF_ASM_OP0(ret, 0xc3)
|
||||
@ -228,13 +221,13 @@ ALT(DEF_ASM_OP1(ret, 0xc2, 0, 0, OPT_IM16))
|
||||
DEF_ASM_OP0(lret, 0xcb)
|
||||
ALT(DEF_ASM_OP1(lret, 0xca, 0, 0, OPT_IM16))
|
||||
|
||||
ALT(DEF_ASM_OP1(jo, 0x70, 0, OPC_SHORTJMP | OPC_JMP | OPC_TEST, OPT_ADDR))
|
||||
DEF_ASM_OP1(loopne, 0xe0, 0, OPC_SHORTJMP, OPT_ADDR)
|
||||
DEF_ASM_OP1(loopnz, 0xe0, 0, OPC_SHORTJMP, OPT_ADDR)
|
||||
DEF_ASM_OP1(loope, 0xe1, 0, OPC_SHORTJMP, OPT_ADDR)
|
||||
DEF_ASM_OP1(loopz, 0xe1, 0, OPC_SHORTJMP, OPT_ADDR)
|
||||
DEF_ASM_OP1(loop, 0xe2, 0, OPC_SHORTJMP, OPT_ADDR)
|
||||
DEF_ASM_OP1(jecxz, 0xe3, 0, OPC_SHORTJMP, OPT_ADDR)
|
||||
ALT(DEF_ASM_OP1(jo, 0x70, 0, OPC_TEST, OPT_DISP8))
|
||||
DEF_ASM_OP1(loopne, 0xe0, 0, 0, OPT_DISP8)
|
||||
DEF_ASM_OP1(loopnz, 0xe0, 0, 0, OPT_DISP8)
|
||||
DEF_ASM_OP1(loope, 0xe1, 0, 0, OPT_DISP8)
|
||||
DEF_ASM_OP1(loopz, 0xe1, 0, 0, OPT_DISP8)
|
||||
DEF_ASM_OP1(loop, 0xe2, 0, 0, OPT_DISP8)
|
||||
DEF_ASM_OP1(jecxz, 0xe3, 0, 0, OPT_DISP8)
|
||||
|
||||
/* float */
|
||||
/* specific fcomp handling */
|
||||
@ -348,12 +341,12 @@ ALT(DEF_ASM_OP1(fstsw, 0xdd, 7, OPC_MODRM | OPC_FWAIT, OPT_EA ))
|
||||
|
||||
/* segments */
|
||||
DEF_ASM_OP2(arpl, 0x63, 0, OPC_MODRM, OPT_REG16, OPT_REG16 | OPT_EA)
|
||||
DEF_ASM_OP2(lar, 0x0f02, 0, OPC_MODRM, OPT_REG32 | OPT_EA, OPT_REG32)
|
||||
ALT(DEF_ASM_OP2(larw, 0x0f02, 0, OPC_MODRM | OPC_WLX, OPT_REG | OPT_EA, OPT_REG))
|
||||
DEF_ASM_OP1(lgdt, 0x0f01, 2, OPC_MODRM, OPT_EA)
|
||||
DEF_ASM_OP1(lidt, 0x0f01, 3, OPC_MODRM, OPT_EA)
|
||||
DEF_ASM_OP1(lldt, 0x0f00, 2, OPC_MODRM, OPT_EA | OPT_REG)
|
||||
DEF_ASM_OP1(lmsw, 0x0f01, 6, OPC_MODRM, OPT_EA | OPT_REG)
|
||||
ALT(DEF_ASM_OP2(lslw, 0x0f03, 0, OPC_MODRM | OPC_WL, OPT_EA | OPT_REG, OPT_REG))
|
||||
ALT(DEF_ASM_OP2(lslw, 0x0f03, 0, OPC_MODRM | OPC_WLX, OPT_EA | OPT_REG, OPT_REG))
|
||||
DEF_ASM_OP1(ltr, 0x0f00, 3, OPC_MODRM, OPT_EA | OPT_REG)
|
||||
DEF_ASM_OP1(sgdt, 0x0f01, 0, OPC_MODRM, OPT_EA)
|
||||
DEF_ASM_OP1(sidt, 0x0f01, 1, OPC_MODRM, OPT_EA)
|
||||
@ -363,34 +356,20 @@ ALT(DEF_ASM_OP2(lslw, 0x0f03, 0, OPC_MODRM | OPC_WL, OPT_EA | OPT_REG, OPT_REG))
|
||||
DEF_ASM_OP1(verr, 0x0f00, 4, OPC_MODRM, OPT_REG | OPT_EA)
|
||||
DEF_ASM_OP1(verw, 0x0f00, 5, OPC_MODRM, OPT_REG | OPT_EA)
|
||||
|
||||
#ifdef I386_ASM_16
|
||||
/* 386 */
|
||||
DEF_ASM_OP0(loadall386, 0x0f07)
|
||||
#endif
|
||||
|
||||
/* 486 */
|
||||
DEF_ASM_OP1(bswap, 0x0fc8, 0, OPC_REG, OPT_REG32 )
|
||||
ALT(DEF_ASM_OP2(xaddb, 0x0fc0, 0, OPC_MODRM | OPC_BWL, OPT_REG, OPT_REG | OPT_EA ))
|
||||
ALT(DEF_ASM_OP2(cmpxchgb, 0x0fb0, 0, OPC_MODRM | OPC_BWL, OPT_REG, OPT_REG | OPT_EA ))
|
||||
ALT(DEF_ASM_OP2(xaddb, 0x0fc0, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_REG | OPT_EA ))
|
||||
ALT(DEF_ASM_OP2(cmpxchgb, 0x0fb0, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_REG | OPT_EA ))
|
||||
DEF_ASM_OP1(invlpg, 0x0f01, 7, OPC_MODRM, OPT_EA )
|
||||
|
||||
DEF_ASM_OP2(boundl, 0x62, 0, OPC_MODRM, OPT_REG32, OPT_EA)
|
||||
DEF_ASM_OP2(boundw, 0x62, 0, OPC_MODRM | OPC_D16, OPT_REG16, OPT_EA)
|
||||
DEF_ASM_OP2(boundw, 0x6662, 0, OPC_MODRM, OPT_REG16, OPT_EA)
|
||||
|
||||
/* pentium */
|
||||
DEF_ASM_OP1(cmpxchg8b, 0x0fc7, 1, OPC_MODRM, OPT_EA )
|
||||
|
||||
/* pentium pro */
|
||||
ALT(DEF_ASM_OP2(cmovo, 0x0f40, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
|
||||
#ifdef I386_ASM_16
|
||||
ALT(DEF_ASM_OP2(cmovno, 0x0f41, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
|
||||
ALT(DEF_ASM_OP2(cmovc, 0x0f42, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
|
||||
ALT(DEF_ASM_OP2(cmovnc, 0x0f43, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
|
||||
ALT(DEF_ASM_OP2(cmovz, 0x0f44, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
|
||||
ALT(DEF_ASM_OP2(cmovnz, 0x0f45, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
|
||||
ALT(DEF_ASM_OP2(cmovna, 0x0f46, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
|
||||
ALT(DEF_ASM_OP2(cmova, 0x0f47, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
|
||||
#endif
|
||||
ALT(DEF_ASM_OP2(cmovo, 0x0f40, 0, OPC_MODRM | OPC_TEST | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW))
|
||||
DEF_ASM_OP2(fcmovb, 0xdac0, 0, OPC_REG, OPT_ST, OPT_ST0 )
|
||||
DEF_ASM_OP2(fcmove, 0xdac8, 0, OPC_REG, OPT_ST, OPT_ST0 )
|
||||
DEF_ASM_OP2(fcmovbe, 0xdad0, 0, OPC_REG, OPT_ST, OPT_ST0 )
|
||||
@ -407,63 +386,91 @@ ALT(DEF_ASM_OP2(cmova, 0x0f47, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_
|
||||
|
||||
/* mmx */
|
||||
DEF_ASM_OP0(emms, 0x0f77) /* must be last OP0 */
|
||||
|
||||
DEF_ASM_OP2(movd, 0x0f6e, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_MMX )
|
||||
ALT(DEF_ASM_OP2(movd, 0x0f7e, 0, OPC_MODRM, OPT_MMX, OPT_EA | OPT_REG32 ))
|
||||
DEF_ASM_OP2(movd, 0x0f6e, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(movq, 0x0f6f, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
ALT(DEF_ASM_OP2(movd, 0x0f7e, 0, OPC_MODRM, OPT_MMXSSE, OPT_EA | OPT_REG32 ))
|
||||
ALT(DEF_ASM_OP2(movq, 0x0f7f, 0, OPC_MODRM, OPT_MMX, OPT_EA | OPT_MMX ))
|
||||
DEF_ASM_OP2(packssdw, 0x0f6b, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(packsswb, 0x0f63, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(packuswb, 0x0f67, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(paddb, 0x0ffc, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(paddw, 0x0ffd, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(paddd, 0x0ffe, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(paddsb, 0x0fec, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(paddsw, 0x0fed, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(paddusb, 0x0fdc, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(paddusw, 0x0fdd, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(pand, 0x0fdb, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(pandn, 0x0fdf, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(pcmpeqb, 0x0f74, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(pcmpeqw, 0x0f75, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(pcmpeqd, 0x0f76, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(pcmpgtb, 0x0f64, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(pcmpgtw, 0x0f65, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(pcmpgtd, 0x0f66, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(pmaddwd, 0x0ff5, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(pmulhw, 0x0fe5, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(pmullw, 0x0fd5, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(por, 0x0feb, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(psllw, 0x0ff1, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
ALT(DEF_ASM_OP2(psllw, 0x0f71, 6, OPC_MODRM, OPT_IM8, OPT_MMX ))
|
||||
DEF_ASM_OP2(pslld, 0x0ff2, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
ALT(DEF_ASM_OP2(pslld, 0x0f72, 6, OPC_MODRM, OPT_IM8, OPT_MMX ))
|
||||
DEF_ASM_OP2(psllq, 0x0ff3, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
ALT(DEF_ASM_OP2(psllq, 0x0f73, 6, OPC_MODRM, OPT_IM8, OPT_MMX ))
|
||||
DEF_ASM_OP2(psraw, 0x0fe1, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
ALT(DEF_ASM_OP2(psraw, 0x0f71, 4, OPC_MODRM, OPT_IM8, OPT_MMX ))
|
||||
DEF_ASM_OP2(psrad, 0x0fe2, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
ALT(DEF_ASM_OP2(psrad, 0x0f72, 4, OPC_MODRM, OPT_IM8, OPT_MMX ))
|
||||
DEF_ASM_OP2(psrlw, 0x0fd1, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
ALT(DEF_ASM_OP2(psrlw, 0x0f71, 2, OPC_MODRM, OPT_IM8, OPT_MMX ))
|
||||
DEF_ASM_OP2(psrld, 0x0fd2, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
ALT(DEF_ASM_OP2(psrld, 0x0f72, 2, OPC_MODRM, OPT_IM8, OPT_MMX ))
|
||||
DEF_ASM_OP2(psrlq, 0x0fd3, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
ALT(DEF_ASM_OP2(psrlq, 0x0f73, 2, OPC_MODRM, OPT_IM8, OPT_MMX ))
|
||||
DEF_ASM_OP2(psubb, 0x0ff8, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(psubw, 0x0ff9, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(psubd, 0x0ffa, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(psubsb, 0x0fe8, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(psubsw, 0x0fe9, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(psubusb, 0x0fd8, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(psubusw, 0x0fd9, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(punpckhbw, 0x0f68, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(punpckhwd, 0x0f69, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(punpckhdq, 0x0f6a, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(punpcklbw, 0x0f60, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(punpcklwd, 0x0f61, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(punpckldq, 0x0f62, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
DEF_ASM_OP2(pxor, 0x0fef, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||
ALT(DEF_ASM_OP2(movq, 0x660fd6, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_SSE ))
|
||||
ALT(DEF_ASM_OP2(movq, 0xf30f7e, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ))
|
||||
|
||||
DEF_ASM_OP2(packssdw, 0x0f6b, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(packsswb, 0x0f63, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(packuswb, 0x0f67, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(paddb, 0x0ffc, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(paddw, 0x0ffd, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(paddd, 0x0ffe, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(paddsb, 0x0fec, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(paddsw, 0x0fed, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(paddusb, 0x0fdc, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(paddusw, 0x0fdd, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(pand, 0x0fdb, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(pandn, 0x0fdf, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(pcmpeqb, 0x0f74, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(pcmpeqw, 0x0f75, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(pcmpeqd, 0x0f76, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(pcmpgtb, 0x0f64, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(pcmpgtw, 0x0f65, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(pcmpgtd, 0x0f66, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(pmaddwd, 0x0ff5, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(pmulhw, 0x0fe5, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(pmullw, 0x0fd5, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(por, 0x0feb, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(psllw, 0x0ff1, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
ALT(DEF_ASM_OP2(psllw, 0x0f71, 6, OPC_MODRM, OPT_IM8, OPT_MMXSSE ))
|
||||
DEF_ASM_OP2(pslld, 0x0ff2, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
ALT(DEF_ASM_OP2(pslld, 0x0f72, 6, OPC_MODRM, OPT_IM8, OPT_MMXSSE ))
|
||||
DEF_ASM_OP2(psllq, 0x0ff3, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
ALT(DEF_ASM_OP2(psllq, 0x0f73, 6, OPC_MODRM, OPT_IM8, OPT_MMXSSE ))
|
||||
DEF_ASM_OP2(psraw, 0x0fe1, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
ALT(DEF_ASM_OP2(psraw, 0x0f71, 4, OPC_MODRM, OPT_IM8, OPT_MMXSSE ))
|
||||
DEF_ASM_OP2(psrad, 0x0fe2, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
ALT(DEF_ASM_OP2(psrad, 0x0f72, 4, OPC_MODRM, OPT_IM8, OPT_MMXSSE ))
|
||||
DEF_ASM_OP2(psrlw, 0x0fd1, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
ALT(DEF_ASM_OP2(psrlw, 0x0f71, 2, OPC_MODRM, OPT_IM8, OPT_MMXSSE ))
|
||||
DEF_ASM_OP2(psrld, 0x0fd2, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
ALT(DEF_ASM_OP2(psrld, 0x0f72, 2, OPC_MODRM, OPT_IM8, OPT_MMXSSE ))
|
||||
DEF_ASM_OP2(psrlq, 0x0fd3, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
ALT(DEF_ASM_OP2(psrlq, 0x0f73, 2, OPC_MODRM, OPT_IM8, OPT_MMXSSE ))
|
||||
DEF_ASM_OP2(psubb, 0x0ff8, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(psubw, 0x0ff9, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(psubd, 0x0ffa, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(psubsb, 0x0fe8, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(psubsw, 0x0fe9, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(psubusb, 0x0fd8, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(psubusw, 0x0fd9, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(punpckhbw, 0x0f68, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(punpckhwd, 0x0f69, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(punpckhdq, 0x0f6a, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(punpcklbw, 0x0f60, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(punpcklwd, 0x0f61, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(punpckldq, 0x0f62, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(pxor, 0x0fef, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
|
||||
/* sse */
|
||||
DEF_ASM_OP2(movups, 0x0f10, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE )
|
||||
ALT(DEF_ASM_OP2(movups, 0x0f11, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 ))
|
||||
DEF_ASM_OP2(movaps, 0x0f28, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE )
|
||||
ALT(DEF_ASM_OP2(movaps, 0x0f29, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 ))
|
||||
DEF_ASM_OP2(movhps, 0x0f16, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE )
|
||||
ALT(DEF_ASM_OP2(movhps, 0x0f17, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 ))
|
||||
DEF_ASM_OP2(addps, 0x0f58, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
||||
DEF_ASM_OP2(cvtpi2ps, 0x0f2a, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_SSE )
|
||||
DEF_ASM_OP2(cvtps2pi, 0x0f2d, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_MMX )
|
||||
DEF_ASM_OP2(cvttps2pi, 0x0f2c, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_MMX )
|
||||
DEF_ASM_OP2(divps, 0x0f5e, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
||||
DEF_ASM_OP2(maxps, 0x0f5f, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
||||
DEF_ASM_OP2(minps, 0x0f5d, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
||||
DEF_ASM_OP2(mulps, 0x0f59, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
||||
DEF_ASM_OP2(pavgb, 0x0fe0, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
||||
DEF_ASM_OP2(pavgw, 0x0fe3, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
||||
DEF_ASM_OP2(pmaxsw, 0x0fee, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(pmaxub, 0x0fde, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(pminsw, 0x0fea, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(pminub, 0x0fda, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
||||
DEF_ASM_OP2(rcpss, 0x0f53, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
||||
DEF_ASM_OP2(rsqrtps, 0x0f52, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
||||
DEF_ASM_OP2(sqrtps, 0x0f51, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
||||
DEF_ASM_OP2(subps, 0x0f5c, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
||||
|
||||
#undef ALT
|
||||
#undef DEF_ASM_OP0
|
||||
|
||||
405
i386-gen.c
405
i386-gen.c
@ -21,7 +21,7 @@
|
||||
#ifdef TARGET_DEFS_ONLY
|
||||
|
||||
/* number of available registers */
|
||||
#define NB_REGS 4
|
||||
#define NB_REGS 5
|
||||
#define NB_ASM_REGS 8
|
||||
|
||||
/* a register can belong to several classes. The classes must be
|
||||
@ -33,6 +33,8 @@
|
||||
#define RC_ST0 0x0008
|
||||
#define RC_ECX 0x0010
|
||||
#define RC_EDX 0x0020
|
||||
#define RC_EBX 0x0040
|
||||
|
||||
#define RC_IRET RC_EAX /* function return: integer register */
|
||||
#define RC_LRET RC_EDX /* function return: second integer register */
|
||||
#define RC_FRET RC_ST0 /* function return: float register */
|
||||
@ -42,7 +44,9 @@ enum {
|
||||
TREG_EAX = 0,
|
||||
TREG_ECX,
|
||||
TREG_EDX,
|
||||
TREG_EBX,
|
||||
TREG_ST0,
|
||||
TREG_ESP = 4
|
||||
};
|
||||
|
||||
/* return registers for function */
|
||||
@ -55,7 +59,7 @@ enum {
|
||||
|
||||
/* defined if structures are passed as pointers. Otherwise structures
|
||||
are directly pushed on stack. */
|
||||
//#define FUNC_STRUCT_PARAM_AS_PTR
|
||||
/* #define FUNC_STRUCT_PARAM_AS_PTR */
|
||||
|
||||
/* pointer size, in bytes */
|
||||
#define PTR_SIZE 4
|
||||
@ -66,45 +70,35 @@ enum {
|
||||
/* maximum alignment (for aligned attribute support) */
|
||||
#define MAX_ALIGN 8
|
||||
|
||||
|
||||
#define psym oad
|
||||
|
||||
/******************************************************/
|
||||
/* ELF defines */
|
||||
|
||||
#define EM_TCC_TARGET EM_386
|
||||
|
||||
/* relocation type for 32 bit data relocation */
|
||||
#define R_DATA_32 R_386_32
|
||||
#define R_DATA_PTR R_386_32
|
||||
#define R_JMP_SLOT R_386_JMP_SLOT
|
||||
#define R_COPY R_386_COPY
|
||||
|
||||
#define ELF_START_ADDR 0x08048000
|
||||
#define ELF_PAGE_SIZE 0x1000
|
||||
|
||||
/******************************************************/
|
||||
#else /* ! TARGET_DEFS_ONLY */
|
||||
/******************************************************/
|
||||
#include "tcc.h"
|
||||
|
||||
/* define to 1/0 to [not] have EBX as 4th register */
|
||||
#define USE_EBX 0
|
||||
|
||||
ST_DATA const int reg_classes[NB_REGS] = {
|
||||
/* eax */ RC_INT | RC_EAX,
|
||||
/* ecx */ RC_INT | RC_ECX,
|
||||
/* edx */ RC_INT | RC_EDX,
|
||||
/* ebx */ (RC_INT | RC_EBX) * USE_EBX,
|
||||
/* st0 */ RC_FLOAT | RC_ST0,
|
||||
};
|
||||
|
||||
static unsigned long func_sub_sp_offset;
|
||||
static int func_ret_sub;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
static unsigned long func_bound_offset;
|
||||
static addr_t func_bound_offset;
|
||||
static unsigned long func_bound_ind;
|
||||
#endif
|
||||
|
||||
/* XXX: make it faster ? */
|
||||
ST_FUNC void g(int c)
|
||||
{
|
||||
int ind1;
|
||||
if (nocode_wanted)
|
||||
return;
|
||||
ind1 = ind + 1;
|
||||
if (ind1 > cur_text_section->data_allocated)
|
||||
section_realloc(cur_text_section, ind1);
|
||||
@ -137,11 +131,10 @@ ST_FUNC void gen_le32(int c)
|
||||
/* output a symbol and patch all calls to it */
|
||||
ST_FUNC void gsym_addr(int t, int a)
|
||||
{
|
||||
int n, *ptr;
|
||||
while (t) {
|
||||
ptr = (int *)(cur_text_section->data + t);
|
||||
n = *ptr; /* next value */
|
||||
*ptr = a - t - 4;
|
||||
unsigned char *ptr = cur_text_section->data + t;
|
||||
uint32_t n = read32le(ptr); /* next value */
|
||||
write32le(ptr, a - t - 4);
|
||||
t = n;
|
||||
}
|
||||
}
|
||||
@ -151,34 +144,30 @@ ST_FUNC void gsym(int t)
|
||||
gsym_addr(t, ind);
|
||||
}
|
||||
|
||||
/* psym is used to put an instruction with a data field which is a
|
||||
reference to a symbol. It is in fact the same as oad ! */
|
||||
#define psym oad
|
||||
|
||||
/* instruction + 4 bytes data. Return the address of the data */
|
||||
ST_FUNC int oad(int c, int s)
|
||||
static int oad(int c, int s)
|
||||
{
|
||||
int ind1;
|
||||
|
||||
int t;
|
||||
if (nocode_wanted)
|
||||
return s;
|
||||
o(c);
|
||||
ind1 = ind + 4;
|
||||
if (ind1 > cur_text_section->data_allocated)
|
||||
section_realloc(cur_text_section, ind1);
|
||||
*(int *)(cur_text_section->data + ind) = s;
|
||||
s = ind;
|
||||
ind = ind1;
|
||||
return s;
|
||||
t = ind;
|
||||
gen_le32(s);
|
||||
return t;
|
||||
}
|
||||
|
||||
/* generate jmp to a label */
|
||||
#define gjmp2(instr,lbl) oad(instr,lbl)
|
||||
|
||||
/* output constant with relocation if 'r & VT_SYM' is true */
|
||||
ST_FUNC void gen_addr32(int r, Sym *sym, int c)
|
||||
ST_FUNC void gen_addr32(int r, Sym *sym, long c)
|
||||
{
|
||||
if (r & VT_SYM)
|
||||
greloc(cur_text_section, sym, ind, R_386_32);
|
||||
gen_le32(c);
|
||||
}
|
||||
|
||||
ST_FUNC void gen_addrpc32(int r, Sym *sym, int c)
|
||||
ST_FUNC void gen_addrpc32(int r, Sym *sym, long c)
|
||||
{
|
||||
if (r & VT_SYM)
|
||||
greloc(cur_text_section, sym, ind, R_386_PC32);
|
||||
@ -221,14 +210,16 @@ ST_FUNC void load(int r, SValue *sv)
|
||||
|
||||
fr = sv->r;
|
||||
ft = sv->type.t;
|
||||
fc = sv->c.ul;
|
||||
fc = sv->c.i;
|
||||
|
||||
ft &= ~(VT_VOLATILE | VT_CONSTANT);
|
||||
|
||||
v = fr & VT_VALMASK;
|
||||
if (fr & VT_LVAL) {
|
||||
if (v == VT_LLOCAL) {
|
||||
v1.type.t = VT_INT;
|
||||
v1.r = VT_LOCAL | VT_LVAL;
|
||||
v1.c.ul = fc;
|
||||
v1.c.i = fc;
|
||||
fr = r;
|
||||
if (!(reg_classes[fr] & RC_INT))
|
||||
fr = get_reg(RC_INT);
|
||||
@ -243,7 +234,7 @@ ST_FUNC void load(int r, SValue *sv)
|
||||
} else if ((ft & VT_BTYPE) == VT_LDOUBLE) {
|
||||
o(0xdb); /* fldt */
|
||||
r = 5;
|
||||
} else if ((ft & VT_TYPE) == VT_BYTE) {
|
||||
} else if ((ft & VT_TYPE) == VT_BYTE || (ft & VT_TYPE) == VT_BOOL) {
|
||||
o(0xbe0f); /* movsbl */
|
||||
} else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) {
|
||||
o(0xb60f); /* movzbl */
|
||||
@ -296,8 +287,9 @@ ST_FUNC void store(int r, SValue *v)
|
||||
#endif
|
||||
|
||||
ft = v->type.t;
|
||||
fc = v->c.ul;
|
||||
fc = v->c.i;
|
||||
fr = v->r & VT_VALMASK;
|
||||
ft &= ~(VT_VOLATILE | VT_CONSTANT);
|
||||
bt = ft & VT_BTYPE;
|
||||
/* XXX: incorrect if float reg to reg */
|
||||
if (bt == VT_FLOAT) {
|
||||
@ -337,11 +329,21 @@ static void gadd_sp(int val)
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_static_call(int v)
|
||||
{
|
||||
Sym *sym;
|
||||
|
||||
sym = external_global_sym(v, &func_old_type, 0);
|
||||
oad(0xe8, -4);
|
||||
greloc(cur_text_section, sym, ind-4, R_386_PC32);
|
||||
}
|
||||
|
||||
/* 'is_jmp' is '1' if it is a jump */
|
||||
static void gcall_or_jmp(int is_jmp)
|
||||
{
|
||||
int r;
|
||||
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
|
||||
int rt;
|
||||
/* constant case */
|
||||
if (vtop->r & VT_SYM) {
|
||||
/* relocation case */
|
||||
@ -352,7 +354,31 @@ static void gcall_or_jmp(int is_jmp)
|
||||
put_elf_reloc(symtab_section, cur_text_section,
|
||||
ind + 1, R_386_PC32, 0);
|
||||
}
|
||||
oad(0xe8 + is_jmp, vtop->c.ul - 4); /* call/jmp im */
|
||||
oad(0xe8 + is_jmp, vtop->c.i - 4); /* call/jmp im */
|
||||
/* extend the return value to the whole register if necessary
|
||||
visual studio and gcc do not always set the whole eax register
|
||||
when assigning the return value of a function */
|
||||
rt = vtop->type.ref->type.t;
|
||||
switch (rt & VT_BTYPE) {
|
||||
case VT_BYTE:
|
||||
if (rt & VT_UNSIGNED) {
|
||||
o(0xc0b60f); /* movzx %al, %eax */
|
||||
}
|
||||
else {
|
||||
o(0xc0be0f); /* movsx %al, %eax */
|
||||
}
|
||||
break;
|
||||
case VT_SHORT:
|
||||
if (rt & VT_UNSIGNED) {
|
||||
o(0xc0b70f); /* movzx %ax, %eax */
|
||||
}
|
||||
else {
|
||||
o(0xc0bf0f); /* movsx %ax, %eax */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* otherwise, indirect call */
|
||||
r = gv(RC_INT);
|
||||
@ -364,6 +390,33 @@ static void gcall_or_jmp(int is_jmp)
|
||||
static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
|
||||
static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };
|
||||
|
||||
/* Return the number of registers needed to return the struct, or 0 if
|
||||
returning via struct pointer. */
|
||||
ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)
|
||||
{
|
||||
#ifdef TCC_TARGET_PE
|
||||
int size, align;
|
||||
*ret_align = 1; // Never have to re-align return values for x86
|
||||
*regsize = 4;
|
||||
size = type_size(vt, &align);
|
||||
if (size > 8 || (size & (size - 1)))
|
||||
return 0;
|
||||
if (size == 8)
|
||||
ret->t = VT_LLONG;
|
||||
else if (size == 4)
|
||||
ret->t = VT_INT;
|
||||
else if (size == 2)
|
||||
ret->t = VT_SHORT;
|
||||
else
|
||||
ret->t = VT_BYTE;
|
||||
ret->ref = NULL;
|
||||
return 1;
|
||||
#else
|
||||
*ret_align = 1; // Never have to re-align return values for x86
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Generate function call. The function address is pushed first, then
|
||||
all the parameters in call order. This functions pops all the
|
||||
parameters and the function address. */
|
||||
@ -421,7 +474,7 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||
}
|
||||
save_regs(0); /* save used temporary registers */
|
||||
func_sym = vtop->type.ref;
|
||||
func_call = FUNC_CALL(func_sym->r);
|
||||
func_call = func_sym->a.func_call;
|
||||
/* fast call case */
|
||||
if ((func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) ||
|
||||
func_call == FUNC_FASTCALLW) {
|
||||
@ -442,21 +495,21 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||
args_size -= 4;
|
||||
}
|
||||
}
|
||||
gcall_or_jmp(0);
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
if ((func_sym->type.t & VT_BTYPE) == VT_STRUCT)
|
||||
#ifndef TCC_TARGET_PE
|
||||
else if ((vtop->type.ref->type.t & VT_BTYPE) == VT_STRUCT)
|
||||
args_size -= 4;
|
||||
#endif
|
||||
gcall_or_jmp(0);
|
||||
|
||||
if (args_size && func_call != FUNC_STDCALL)
|
||||
gadd_sp(args_size);
|
||||
vtop--;
|
||||
}
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
#define FUNC_PROLOG_SIZE 10
|
||||
#define FUNC_PROLOG_SIZE (10 + USE_EBX)
|
||||
#else
|
||||
#define FUNC_PROLOG_SIZE 9
|
||||
#define FUNC_PROLOG_SIZE (9 + USE_EBX)
|
||||
#endif
|
||||
|
||||
/* generate function prolog of type 't' */
|
||||
@ -469,7 +522,7 @@ ST_FUNC void gfunc_prolog(CType *func_type)
|
||||
CType *type;
|
||||
|
||||
sym = func_type->ref;
|
||||
func_call = FUNC_CALL(sym->r);
|
||||
func_call = sym->a.func_call;
|
||||
addr = 8;
|
||||
loc = 0;
|
||||
func_vc = 0;
|
||||
@ -491,7 +544,14 @@ ST_FUNC void gfunc_prolog(CType *func_type)
|
||||
/* if the function returns a structure, then add an
|
||||
implicit pointer parameter */
|
||||
func_vt = sym->type;
|
||||
func_var = (sym->c == FUNC_ELLIPSIS);
|
||||
#ifdef TCC_TARGET_PE
|
||||
size = type_size(&func_vt,&align);
|
||||
if (((func_vt.t & VT_BTYPE) == VT_STRUCT)
|
||||
&& (size > 8 || (size & (size - 1)))) {
|
||||
#else
|
||||
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
|
||||
#endif
|
||||
/* XXX: fastcall case ? */
|
||||
func_vc = addr;
|
||||
addr += 4;
|
||||
@ -526,7 +586,7 @@ ST_FUNC void gfunc_prolog(CType *func_type)
|
||||
/* pascal type call ? */
|
||||
if (func_call == FUNC_STDCALL)
|
||||
func_ret_sub = addr - 8;
|
||||
#ifdef TCC_TARGET_PE
|
||||
#ifndef TCC_TARGET_PE
|
||||
else if (func_vc)
|
||||
func_ret_sub = 4;
|
||||
#endif
|
||||
@ -534,9 +594,10 @@ ST_FUNC void gfunc_prolog(CType *func_type)
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
/* leave some room for bound checking code */
|
||||
if (tcc_state->do_bounds_check) {
|
||||
func_bound_offset = lbounds_section->data_offset;
|
||||
func_bound_ind = ind;
|
||||
oad(0xb8, 0); /* lbound section pointer */
|
||||
oad(0xb8, 0); /* call to function */
|
||||
func_bound_offset = lbounds_section->data_offset;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -544,42 +605,47 @@ ST_FUNC void gfunc_prolog(CType *func_type)
|
||||
/* generate function epilog */
|
||||
ST_FUNC void gfunc_epilog(void)
|
||||
{
|
||||
int v, saved_ind;
|
||||
addr_t v, saved_ind;
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check
|
||||
&& func_bound_offset != lbounds_section->data_offset) {
|
||||
int saved_ind;
|
||||
int *bounds_ptr;
|
||||
Sym *sym, *sym_data;
|
||||
addr_t saved_ind;
|
||||
addr_t *bounds_ptr;
|
||||
Sym *sym_data;
|
||||
|
||||
/* add end of table info */
|
||||
bounds_ptr = section_ptr_add(lbounds_section, sizeof(int));
|
||||
bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
|
||||
*bounds_ptr = 0;
|
||||
|
||||
/* generate bound local allocation */
|
||||
saved_ind = ind;
|
||||
ind = func_sub_sp_offset;
|
||||
ind = func_bound_ind;
|
||||
sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
|
||||
func_bound_offset, lbounds_section->data_offset);
|
||||
greloc(cur_text_section, sym_data,
|
||||
ind + 1, R_386_32);
|
||||
oad(0xb8, 0); /* mov %eax, xxx */
|
||||
sym = external_global_sym(TOK___bound_local_new, &func_old_type, 0);
|
||||
greloc(cur_text_section, sym,
|
||||
ind + 1, R_386_PC32);
|
||||
oad(0xe8, -4);
|
||||
gen_static_call(TOK___bound_local_new);
|
||||
ind = saved_ind;
|
||||
|
||||
/* generate bound check local freeing */
|
||||
o(0x5250); /* save returned value, if any */
|
||||
greloc(cur_text_section, sym_data,
|
||||
ind + 1, R_386_32);
|
||||
greloc(cur_text_section, sym_data, ind + 1, R_386_32);
|
||||
oad(0xb8, 0); /* mov %eax, xxx */
|
||||
sym = external_global_sym(TOK___bound_local_delete, &func_old_type, 0);
|
||||
greloc(cur_text_section, sym,
|
||||
ind + 1, R_386_PC32);
|
||||
oad(0xe8, -4);
|
||||
gen_static_call(TOK___bound_local_delete);
|
||||
o(0x585a); /* restore returned value, if any */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* align local size to word & save local variables */
|
||||
v = (-loc + 3) & -4;
|
||||
|
||||
#if USE_EBX
|
||||
o(0x8b);
|
||||
gen_modrm(TREG_EBX, VT_LOCAL, NULL, -(v+4));
|
||||
#endif
|
||||
|
||||
o(0xc9); /* leave */
|
||||
if (func_ret_sub == 0) {
|
||||
o(0xc3); /* ret */
|
||||
@ -588,34 +654,30 @@ ST_FUNC void gfunc_epilog(void)
|
||||
g(func_ret_sub);
|
||||
g(func_ret_sub >> 8);
|
||||
}
|
||||
/* align local size to word & save local variables */
|
||||
|
||||
v = (-loc + 3) & -4;
|
||||
saved_ind = ind;
|
||||
ind = func_sub_sp_offset - FUNC_PROLOG_SIZE;
|
||||
#ifdef TCC_TARGET_PE
|
||||
if (v >= 4096) {
|
||||
Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0);
|
||||
oad(0xb8, v); /* mov stacksize, %eax */
|
||||
oad(0xe8, -4); /* call __chkstk, (does the stackframe too) */
|
||||
greloc(cur_text_section, sym, ind-4, R_386_PC32);
|
||||
gen_static_call(TOK___chkstk); /* call __chkstk, (does the stackframe too) */
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
o(0xe58955); /* push %ebp, mov %esp, %ebp */
|
||||
o(0xec81); /* sub esp, stacksize */
|
||||
gen_le32(v);
|
||||
#if FUNC_PROLOG_SIZE == 10
|
||||
#ifdef TCC_TARGET_PE
|
||||
o(0x90); /* adjust to FUNC_PROLOG_SIZE */
|
||||
#endif
|
||||
}
|
||||
o(0x53 * USE_EBX); /* push ebx */
|
||||
ind = saved_ind;
|
||||
}
|
||||
|
||||
/* generate a jump to a label */
|
||||
ST_FUNC int gjmp(int t)
|
||||
{
|
||||
return psym(0xe9, t);
|
||||
return gjmp2(0xe9, t);
|
||||
}
|
||||
|
||||
/* generate a jump to a fixed address */
|
||||
@ -631,46 +693,57 @@ ST_FUNC void gjmp_addr(int a)
|
||||
}
|
||||
}
|
||||
|
||||
ST_FUNC void gtst_addr(int inv, int a)
|
||||
{
|
||||
int v = vtop->r & VT_VALMASK;
|
||||
if (v == VT_CMP) {
|
||||
inv ^= (vtop--)->c.i;
|
||||
a -= ind + 2;
|
||||
if (a == (char)a) {
|
||||
g(inv - 32);
|
||||
g(a);
|
||||
} else {
|
||||
g(0x0f);
|
||||
oad(inv - 16, a - 4);
|
||||
}
|
||||
} else if ((v & ~1) == VT_JMP) {
|
||||
if ((v & 1) != inv) {
|
||||
gjmp_addr(a);
|
||||
gsym(vtop->c.i);
|
||||
} else {
|
||||
gsym(vtop->c.i);
|
||||
o(0x05eb);
|
||||
gjmp_addr(a);
|
||||
}
|
||||
vtop--;
|
||||
}
|
||||
}
|
||||
|
||||
/* generate a test. set 'inv' to invert test. Stack entry is popped */
|
||||
ST_FUNC int gtst(int inv, int t)
|
||||
{
|
||||
int v, *p;
|
||||
|
||||
v = vtop->r & VT_VALMASK;
|
||||
if (v == VT_CMP) {
|
||||
int v = vtop->r & VT_VALMASK;
|
||||
if (nocode_wanted) {
|
||||
;
|
||||
} else if (v == VT_CMP) {
|
||||
/* fast case : can jump directly since flags are set */
|
||||
g(0x0f);
|
||||
t = psym((vtop->c.i - 16) ^ inv, t);
|
||||
t = gjmp2((vtop->c.i - 16) ^ inv, t);
|
||||
} else if (v == VT_JMP || v == VT_JMPI) {
|
||||
/* && or || optimization */
|
||||
if ((v & 1) == inv) {
|
||||
/* insert vtop->c jump list in t */
|
||||
p = &vtop->c.i;
|
||||
while (*p != 0)
|
||||
p = (int *)(cur_text_section->data + *p);
|
||||
*p = t;
|
||||
t = vtop->c.i;
|
||||
uint32_t n1, n = vtop->c.i;
|
||||
if (n) {
|
||||
while ((n1 = read32le(cur_text_section->data + n)))
|
||||
n = n1;
|
||||
write32le(cur_text_section->data + n, t);
|
||||
t = vtop->c.i;
|
||||
}
|
||||
} else {
|
||||
t = gjmp(t);
|
||||
gsym(vtop->c.i);
|
||||
}
|
||||
} else {
|
||||
if (is_float(vtop->type.t) ||
|
||||
(vtop->type.t & VT_BTYPE) == VT_LLONG) {
|
||||
vpushi(0);
|
||||
gen_op(TOK_NE);
|
||||
}
|
||||
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
|
||||
/* constant jmp optimization */
|
||||
if ((vtop->c.i != 0) != inv)
|
||||
t = gjmp(t);
|
||||
} else {
|
||||
v = gv(RC_INT);
|
||||
o(0x85);
|
||||
o(0xc0 + v * 9);
|
||||
g(0x0f);
|
||||
t = psym(0x85 ^ inv, t);
|
||||
}
|
||||
}
|
||||
vtop--;
|
||||
return t;
|
||||
@ -694,9 +767,9 @@ ST_FUNC void gen_opi(int op)
|
||||
c = vtop->c.i;
|
||||
if (c == (char)c) {
|
||||
/* generate inc and dec for smaller code */
|
||||
if (c==1 && opc==0) {
|
||||
if (c==1 && opc==0 && op != TOK_ADDC1) {
|
||||
o (0x40 | r); // inc
|
||||
} else if (c==1 && opc==5) {
|
||||
} else if (c==1 && opc==5 && op != TOK_SUBC1) {
|
||||
o (0x48 | r); // dec
|
||||
} else {
|
||||
o(0x83);
|
||||
@ -788,6 +861,8 @@ ST_FUNC void gen_opi(int op)
|
||||
fr = vtop[0].r;
|
||||
vtop--;
|
||||
save_reg(TREG_EDX);
|
||||
/* save EAX too if used otherwise */
|
||||
save_reg_upstack(TREG_EAX, 1);
|
||||
if (op == TOK_UMULL) {
|
||||
o(0xf7); /* mul fr */
|
||||
o(0xe0 + fr);
|
||||
@ -854,7 +929,10 @@ ST_FUNC void gen_opf(int op)
|
||||
swapped = 0;
|
||||
if (swapped)
|
||||
o(0xc9d9); /* fxch %st(1) */
|
||||
o(0xe9da); /* fucompp */
|
||||
if (op == TOK_EQ || op == TOK_NE)
|
||||
o(0xe9da); /* fucompp */
|
||||
else
|
||||
o(0xd9de); /* fcompp */
|
||||
o(0xe0df); /* fnstsw %ax */
|
||||
if (op == TOK_EQ) {
|
||||
o(0x45e480); /* and $0x45, %ah */
|
||||
@ -900,7 +978,7 @@ ST_FUNC void gen_opf(int op)
|
||||
break;
|
||||
}
|
||||
ft = vtop->type.t;
|
||||
fc = vtop->c.ul;
|
||||
fc = vtop->c.i;
|
||||
if ((ft & VT_BTYPE) == VT_LDOUBLE) {
|
||||
o(0xde); /* fxxxp %st, %st(1) */
|
||||
o(0xc1 + (a << 3));
|
||||
@ -912,7 +990,7 @@ ST_FUNC void gen_opf(int op)
|
||||
r = get_reg(RC_INT);
|
||||
v1.type.t = VT_INT;
|
||||
v1.r = VT_LOCAL | VT_LVAL;
|
||||
v1.c.ul = fc;
|
||||
v1.c.i = fc;
|
||||
load(r, &v1);
|
||||
fc = 0;
|
||||
}
|
||||
@ -958,55 +1036,20 @@ ST_FUNC void gen_cvt_itof(int t)
|
||||
}
|
||||
|
||||
/* convert fp to int 't' type */
|
||||
/* XXX: handle long long case */
|
||||
ST_FUNC void gen_cvt_ftoi(int t)
|
||||
{
|
||||
int r, r2, size;
|
||||
Sym *sym;
|
||||
CType ushort_type;
|
||||
|
||||
ushort_type.t = VT_SHORT | VT_UNSIGNED;
|
||||
ushort_type.ref = 0;
|
||||
|
||||
gv(RC_FLOAT);
|
||||
if (t != VT_INT)
|
||||
size = 8;
|
||||
else
|
||||
size = 4;
|
||||
|
||||
o(0x2dd9); /* ldcw xxx */
|
||||
sym = external_global_sym(TOK___tcc_int_fpu_control,
|
||||
&ushort_type, VT_LVAL);
|
||||
greloc(cur_text_section, sym,
|
||||
ind, R_386_32);
|
||||
gen_le32(0);
|
||||
|
||||
oad(0xec81, size); /* sub $xxx, %esp */
|
||||
if (size == 4)
|
||||
o(0x1cdb); /* fistpl */
|
||||
int bt = vtop->type.t & VT_BTYPE;
|
||||
if (bt == VT_FLOAT)
|
||||
vpush_global_sym(&func_old_type, TOK___fixsfdi);
|
||||
else if (bt == VT_LDOUBLE)
|
||||
vpush_global_sym(&func_old_type, TOK___fixxfdi);
|
||||
else
|
||||
o(0x3cdf); /* fistpll */
|
||||
o(0x24);
|
||||
o(0x2dd9); /* ldcw xxx */
|
||||
sym = external_global_sym(TOK___tcc_fpu_control,
|
||||
&ushort_type, VT_LVAL);
|
||||
greloc(cur_text_section, sym,
|
||||
ind, R_386_32);
|
||||
gen_le32(0);
|
||||
|
||||
r = get_reg(RC_INT);
|
||||
o(0x58 + r); /* pop r */
|
||||
if (size == 8) {
|
||||
if (t == VT_LLONG) {
|
||||
vtop->r = r; /* mark reg as used */
|
||||
r2 = get_reg(RC_INT);
|
||||
o(0x58 + r2); /* pop r2 */
|
||||
vtop->r2 = r2;
|
||||
} else {
|
||||
o(0x04c483); /* add $4, %esp */
|
||||
}
|
||||
}
|
||||
vtop->r = r;
|
||||
vpush_global_sym(&func_old_type, TOK___fixdfdi);
|
||||
vswap();
|
||||
gfunc_call(1);
|
||||
vpushi(0);
|
||||
vtop->r = REG_IRET;
|
||||
vtop->r2 = REG_LRET;
|
||||
}
|
||||
|
||||
/* convert from one floating point type to another */
|
||||
@ -1029,31 +1072,26 @@ ST_FUNC void ggoto(void)
|
||||
/* generate a bounded pointer addition */
|
||||
ST_FUNC void gen_bounded_ptr_add(void)
|
||||
{
|
||||
Sym *sym;
|
||||
|
||||
/* prepare fast i386 function call (args in eax and edx) */
|
||||
gv2(RC_EAX, RC_EDX);
|
||||
/* save all temporary registers */
|
||||
vtop -= 2;
|
||||
save_regs(0);
|
||||
/* do a fast function call */
|
||||
sym = external_global_sym(TOK___bound_ptr_add, &func_old_type, 0);
|
||||
greloc(cur_text_section, sym,
|
||||
ind + 1, R_386_PC32);
|
||||
oad(0xe8, -4);
|
||||
gen_static_call(TOK___bound_ptr_add);
|
||||
/* returned pointer is in eax */
|
||||
vtop++;
|
||||
vtop->r = TREG_EAX | VT_BOUNDED;
|
||||
/* address of bounding function call point */
|
||||
vtop->c.ul = (cur_text_section->reloc->data_offset - sizeof(Elf32_Rel));
|
||||
vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(Elf32_Rel));
|
||||
}
|
||||
|
||||
/* patch pointer addition in vtop so that pointer dereferencing is
|
||||
also tested */
|
||||
ST_FUNC void gen_bounded_ptr_deref(void)
|
||||
{
|
||||
int func;
|
||||
int size, align;
|
||||
addr_t func;
|
||||
int size, align;
|
||||
Elf32_Rel *rel;
|
||||
Sym *sym;
|
||||
|
||||
@ -1082,7 +1120,7 @@ ST_FUNC void gen_bounded_ptr_deref(void)
|
||||
|
||||
/* patch relocation */
|
||||
/* XXX: find a better solution ? */
|
||||
rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.ul);
|
||||
rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.i);
|
||||
sym = external_global_sym(func, &func_old_type, 0);
|
||||
if (!sym->c)
|
||||
put_extern_sym(sym, NULL, 0, 0);
|
||||
@ -1090,6 +1128,39 @@ ST_FUNC void gen_bounded_ptr_deref(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Save the stack pointer onto the stack */
|
||||
ST_FUNC void gen_vla_sp_save(int addr) {
|
||||
/* mov %esp,addr(%ebp)*/
|
||||
o(0x89);
|
||||
gen_modrm(TREG_ESP, VT_LOCAL, NULL, addr);
|
||||
}
|
||||
|
||||
/* Restore the SP from a location on the stack */
|
||||
ST_FUNC void gen_vla_sp_restore(int addr) {
|
||||
o(0x8b);
|
||||
gen_modrm(TREG_ESP, VT_LOCAL, NULL, addr);
|
||||
}
|
||||
|
||||
/* Subtract from the stack pointer, and push the resulting value onto the stack */
|
||||
ST_FUNC void gen_vla_alloc(CType *type, int align) {
|
||||
#ifdef TCC_TARGET_PE
|
||||
/* alloca does more than just adjust %rsp on Windows */
|
||||
vpush_global_sym(&func_old_type, TOK_alloca);
|
||||
vswap(); /* Move alloca ref past allocation size */
|
||||
gfunc_call(1);
|
||||
#else
|
||||
int r;
|
||||
r = gv(RC_INT); /* allocation size */
|
||||
/* sub r,%rsp */
|
||||
o(0x2b);
|
||||
o(0xe0 | r);
|
||||
/* We align to 16 bytes rather than align */
|
||||
/* and ~15, %esp */
|
||||
o(0xf0e483);
|
||||
vpop();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* end of X86 code generator */
|
||||
/*************************************************************/
|
||||
#endif
|
||||
|
||||
243
i386-link.c
Normal file
243
i386-link.c
Normal file
@ -0,0 +1,243 @@
|
||||
#ifdef TARGET_DEFS_ONLY
|
||||
|
||||
#define EM_TCC_TARGET EM_386
|
||||
|
||||
/* relocation type for 32 bit data relocation */
|
||||
#define R_DATA_32 R_386_32
|
||||
#define R_DATA_PTR R_386_32
|
||||
#define R_JMP_SLOT R_386_JMP_SLOT
|
||||
#define R_GLOB_DAT R_386_GLOB_DAT
|
||||
#define R_COPY R_386_COPY
|
||||
|
||||
#define R_NUM R_386_NUM
|
||||
|
||||
#define ELF_START_ADDR 0x08048000
|
||||
#define ELF_PAGE_SIZE 0x1000
|
||||
|
||||
#define PCRELATIVE_DLLPLT 0
|
||||
#define RELOCATE_DLLPLT 0
|
||||
|
||||
#else /* !TARGET_DEFS_ONLY */
|
||||
|
||||
#include "tcc.h"
|
||||
|
||||
/* Returns 1 for a code relocation, 0 for a data relocation. For unknown
|
||||
relocations, returns -1. */
|
||||
int code_reloc (int reloc_type)
|
||||
{
|
||||
switch (reloc_type) {
|
||||
case R_386_RELATIVE:
|
||||
case R_386_16:
|
||||
case R_386_32:
|
||||
case R_386_GOTPC:
|
||||
case R_386_GOTOFF:
|
||||
case R_386_GOT32:
|
||||
case R_386_GOT32X:
|
||||
case R_386_GLOB_DAT:
|
||||
case R_386_COPY:
|
||||
return 0;
|
||||
|
||||
case R_386_PC16:
|
||||
case R_386_PC32:
|
||||
case R_386_PLT32:
|
||||
case R_386_JMP_SLOT:
|
||||
return 1;
|
||||
}
|
||||
|
||||
tcc_error ("Unknown relocation type: %d", reloc_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Returns an enumerator to describe wether and when the relocation needs a
|
||||
GOT and/or PLT entry to be created. See tcc.h for a description of the
|
||||
different values. */
|
||||
int gotplt_entry_type (int reloc_type)
|
||||
{
|
||||
switch (reloc_type) {
|
||||
case R_386_RELATIVE:
|
||||
case R_386_16:
|
||||
case R_386_GLOB_DAT:
|
||||
case R_386_JMP_SLOT:
|
||||
case R_386_COPY:
|
||||
return NO_GOTPLT_ENTRY;
|
||||
|
||||
case R_386_32:
|
||||
/* This relocations shouldn't normally need GOT or PLT
|
||||
slots if it weren't for simplicity in the code generator.
|
||||
See our caller for comments. */
|
||||
return AUTO_GOTPLT_ENTRY;
|
||||
|
||||
case R_386_PC16:
|
||||
case R_386_PC32:
|
||||
return AUTO_GOTPLT_ENTRY;
|
||||
|
||||
case R_386_GOTPC:
|
||||
case R_386_GOTOFF:
|
||||
return BUILD_GOT_ONLY;
|
||||
|
||||
case R_386_GOT32:
|
||||
case R_386_GOT32X:
|
||||
case R_386_PLT32:
|
||||
return ALWAYS_GOTPLT_ENTRY;
|
||||
}
|
||||
|
||||
tcc_error ("Unknown relocation type: %d", reloc_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr)
|
||||
{
|
||||
Section *plt = s1->plt;
|
||||
uint8_t *p;
|
||||
int modrm;
|
||||
unsigned plt_offset, relofs;
|
||||
|
||||
/* on i386 if we build a DLL, we add a %ebx offset */
|
||||
if (s1->output_type == TCC_OUTPUT_DLL)
|
||||
modrm = 0xa3;
|
||||
else
|
||||
modrm = 0x25;
|
||||
|
||||
/* empty PLT: create PLT0 entry that pushes the library indentifier
|
||||
(GOT + PTR_SIZE) and jumps to ld.so resolution routine
|
||||
(GOT + 2 * PTR_SIZE) */
|
||||
if (plt->data_offset == 0) {
|
||||
p = section_ptr_add(plt, 16);
|
||||
p[0] = 0xff; /* pushl got + PTR_SIZE */
|
||||
p[1] = modrm + 0x10;
|
||||
write32le(p + 2, PTR_SIZE);
|
||||
p[6] = 0xff; /* jmp *(got + PTR_SIZE * 2) */
|
||||
p[7] = modrm;
|
||||
write32le(p + 8, PTR_SIZE * 2);
|
||||
}
|
||||
plt_offset = plt->data_offset;
|
||||
|
||||
/* The PLT slot refers to the relocation entry it needs via offset.
|
||||
The reloc entry is created below, so its offset is the current
|
||||
data_offset */
|
||||
relofs = s1->got->reloc ? s1->got->reloc->data_offset : 0;
|
||||
|
||||
/* Jump to GOT entry where ld.so initially put the address of ip + 4 */
|
||||
p = section_ptr_add(plt, 16);
|
||||
p[0] = 0xff; /* jmp *(got + x) */
|
||||
p[1] = modrm;
|
||||
write32le(p + 2, got_offset);
|
||||
p[6] = 0x68; /* push $xxx */
|
||||
write32le(p + 7, relofs);
|
||||
p[11] = 0xe9; /* jmp plt_start */
|
||||
write32le(p + 12, -(plt->data_offset));
|
||||
return plt_offset;
|
||||
}
|
||||
|
||||
/* relocate the PLT: compute addresses and offsets in the PLT now that final
|
||||
address for PLT and GOT are known (see fill_program_header) */
|
||||
ST_FUNC void relocate_plt(TCCState *s1)
|
||||
{
|
||||
uint8_t *p, *p_end;
|
||||
|
||||
if (!s1->plt)
|
||||
return;
|
||||
|
||||
p = s1->plt->data;
|
||||
p_end = p + s1->plt->data_offset;
|
||||
|
||||
if (p < p_end) {
|
||||
add32le(p + 2, s1->got->sh_addr);
|
||||
add32le(p + 8, s1->got->sh_addr);
|
||||
p += 16;
|
||||
while (p < p_end) {
|
||||
add32le(p + 2, s1->got->sh_addr);
|
||||
p += 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ElfW_Rel *qrel; /* ptr to next reloc entry reused */
|
||||
|
||||
void relocate_init(Section *sr)
|
||||
{
|
||||
qrel = (ElfW_Rel *) sr->data;
|
||||
}
|
||||
|
||||
void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, addr_t val)
|
||||
{
|
||||
int sym_index, esym_index;
|
||||
|
||||
sym_index = ELFW(R_SYM)(rel->r_info);
|
||||
|
||||
switch (type) {
|
||||
case R_386_32:
|
||||
if (s1->output_type == TCC_OUTPUT_DLL) {
|
||||
esym_index = s1->sym_attrs[sym_index].dyn_index;
|
||||
qrel->r_offset = rel->r_offset;
|
||||
if (esym_index) {
|
||||
qrel->r_info = ELFW(R_INFO)(esym_index, R_386_32);
|
||||
qrel++;
|
||||
return;
|
||||
} else {
|
||||
qrel->r_info = ELFW(R_INFO)(0, R_386_RELATIVE);
|
||||
qrel++;
|
||||
}
|
||||
}
|
||||
add32le(ptr, val);
|
||||
return;
|
||||
case R_386_PC32:
|
||||
if (s1->output_type == TCC_OUTPUT_DLL) {
|
||||
/* DLL relocation */
|
||||
esym_index = s1->sym_attrs[sym_index].dyn_index;
|
||||
if (esym_index) {
|
||||
qrel->r_offset = rel->r_offset;
|
||||
qrel->r_info = ELFW(R_INFO)(esym_index, R_386_PC32);
|
||||
qrel++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
add32le(ptr, val - addr);
|
||||
return;
|
||||
case R_386_PLT32:
|
||||
add32le(ptr, val - addr);
|
||||
return;
|
||||
case R_386_GLOB_DAT:
|
||||
case R_386_JMP_SLOT:
|
||||
write32le(ptr, val);
|
||||
return;
|
||||
case R_386_GOTPC:
|
||||
add32le(ptr, s1->got->sh_addr - addr);
|
||||
return;
|
||||
case R_386_GOTOFF:
|
||||
add32le(ptr, val - s1->got->sh_addr);
|
||||
return;
|
||||
case R_386_GOT32:
|
||||
case R_386_GOT32X:
|
||||
/* we load the got offset */
|
||||
add32le(ptr, s1->sym_attrs[sym_index].got_offset);
|
||||
return;
|
||||
case R_386_16:
|
||||
if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) {
|
||||
output_file:
|
||||
tcc_error("can only produce 16-bit binary files");
|
||||
}
|
||||
write16le(ptr, read16le(ptr) + val);
|
||||
return;
|
||||
case R_386_PC16:
|
||||
if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY)
|
||||
goto output_file;
|
||||
write16le(ptr, read16le(ptr) + val - addr);
|
||||
return;
|
||||
case R_386_RELATIVE:
|
||||
/* do nothing */
|
||||
return;
|
||||
case R_386_COPY:
|
||||
/* This reloction must copy initialized data from the library
|
||||
to the program .bss segment. Currently made like for ARM
|
||||
(to remove noise of defaukt case). Is this true?
|
||||
*/
|
||||
return;
|
||||
default:
|
||||
fprintf(stderr,"FIXME: handle reloc type %d at %x [%p] to %x\n",
|
||||
type, (unsigned)addr, ptr, (unsigned)val);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !TARGET_DEFS_ONLY */
|
||||
32
i386-tok.h
32
i386-tok.h
@ -91,7 +91,16 @@
|
||||
DEF_ASM(fs)
|
||||
DEF_ASM(gs)
|
||||
DEF_ASM(st)
|
||||
DEF_ASM(rip)
|
||||
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
/* The four low parts of sp/bp/si/di that exist only on
|
||||
x86-64 (encoding aliased to ah,ch,dh,dh when not using REX). */
|
||||
DEF_ASM(spl)
|
||||
DEF_ASM(bpl)
|
||||
DEF_ASM(sil)
|
||||
DEF_ASM(dil)
|
||||
#endif
|
||||
/* generic two operands */
|
||||
DEF_BWLX(mov)
|
||||
|
||||
@ -126,12 +135,8 @@
|
||||
DEF_BWLX(shr)
|
||||
DEF_BWLX(sar)
|
||||
|
||||
DEF_ASM(shldw)
|
||||
DEF_ASM(shldl)
|
||||
DEF_ASM(shld)
|
||||
DEF_ASM(shrdw)
|
||||
DEF_ASM(shrdl)
|
||||
DEF_ASM(shrd)
|
||||
DEF_WLX(shld)
|
||||
DEF_WLX(shrd)
|
||||
|
||||
DEF_ASM(pushw)
|
||||
DEF_ASM(pushl)
|
||||
@ -150,12 +155,15 @@
|
||||
DEF_BWL(in)
|
||||
DEF_BWL(out)
|
||||
|
||||
DEF_WL(movzb)
|
||||
DEF_WLX(movzb)
|
||||
DEF_ASM(movzwl)
|
||||
DEF_ASM(movsbw)
|
||||
DEF_ASM(movsbl)
|
||||
DEF_ASM(movswl)
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
DEF_ASM(movsbq)
|
||||
DEF_ASM(movswq)
|
||||
DEF_ASM(movzwq)
|
||||
DEF_ASM(movslq)
|
||||
#endif
|
||||
|
||||
@ -172,10 +180,11 @@
|
||||
DEF_ASM(lcall)
|
||||
DEF_ASM(ljmp)
|
||||
|
||||
DEF_ASMTEST(j)
|
||||
DEF_ASMTEST(j,)
|
||||
|
||||
DEF_ASMTEST(set)
|
||||
DEF_ASMTEST(cmov)
|
||||
DEF_ASMTEST(set,)
|
||||
DEF_ASMTEST(set,b)
|
||||
DEF_ASMTEST(cmov,)
|
||||
|
||||
DEF_WLX(bsf)
|
||||
DEF_WLX(bsr)
|
||||
@ -184,6 +193,7 @@
|
||||
DEF_WLX(btr)
|
||||
DEF_WLX(btc)
|
||||
|
||||
DEF_WLX(lar)
|
||||
DEF_WLX(lsl)
|
||||
|
||||
/* generic FP ops */
|
||||
@ -191,7 +201,7 @@
|
||||
DEF_FP(mul)
|
||||
|
||||
DEF_ASM(fcom)
|
||||
DEF_ASM(fcom_1) /* non existant op, just to have a regular table */
|
||||
DEF_ASM(fcom_1) /* non existent op, just to have a regular table */
|
||||
DEF_FP1(com)
|
||||
|
||||
DEF_FP(comp)
|
||||
|
||||
18
il-gen.c
18
il-gen.c
@ -53,11 +53,11 @@ const int reg_classes[NB_REGS] = {
|
||||
#define REG_FRET REG_ST0 /* float return register */
|
||||
|
||||
/* defined if function parameters must be evaluated in reverse order */
|
||||
//#define INVERT_FUNC_PARAMS
|
||||
/* #define INVERT_FUNC_PARAMS */
|
||||
|
||||
/* defined if structures are passed as pointers. Otherwise structures
|
||||
are directly pushed on stack. */
|
||||
//#define FUNC_STRUCT_PARAM_AS_PTR
|
||||
/* #define FUNC_STRUCT_PARAM_AS_PTR */
|
||||
|
||||
/* pointer size, in bytes */
|
||||
#define PTR_SIZE 4
|
||||
@ -441,6 +441,7 @@ void gfunc_prolog(int t)
|
||||
/* if the function returns a structure, then add an
|
||||
implicit pointer parameter */
|
||||
func_vt = sym->t;
|
||||
func_var = (sym->c == FUNC_ELLIPSIS);
|
||||
if ((func_vt & VT_BTYPE) == VT_STRUCT) {
|
||||
func_vc = addr;
|
||||
addr++;
|
||||
@ -528,19 +529,6 @@ int gtst(int inv, int t)
|
||||
t = gjmp(t);
|
||||
gsym(vtop->c.i);
|
||||
}
|
||||
} else {
|
||||
if (is_float(vtop->t)) {
|
||||
vpushi(0);
|
||||
gen_op(TOK_NE);
|
||||
}
|
||||
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_FORWARD)) == VT_CONST) {
|
||||
/* constant jmp optimization */
|
||||
if ((vtop->c.i != 0) != inv)
|
||||
t = gjmp(t);
|
||||
} else {
|
||||
v = gv(RC_INT);
|
||||
t = out_opj(IL_OP_BRTRUE - inv, t);
|
||||
}
|
||||
}
|
||||
vtop--;
|
||||
return t;
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
#define DBL_MAX_10_EXP 308
|
||||
|
||||
/* horrible intel long double */
|
||||
#ifdef __i386__
|
||||
#if defined __i386__ || defined __x86_64__
|
||||
|
||||
#define LDBL_MANT_DIG 64
|
||||
#define LDBL_DIG 18
|
||||
|
||||
@ -4,27 +4,65 @@
|
||||
#ifdef __x86_64__
|
||||
#ifndef _WIN64
|
||||
|
||||
typedef void *va_list;
|
||||
//This should be in sync with the declaration on our lib/libtcc1.c
|
||||
/* GCC compatible definition of va_list. */
|
||||
typedef struct {
|
||||
unsigned int gp_offset;
|
||||
unsigned int fp_offset;
|
||||
union {
|
||||
unsigned int overflow_offset;
|
||||
char *overflow_arg_area;
|
||||
};
|
||||
char *reg_save_area;
|
||||
} __va_list_struct;
|
||||
|
||||
va_list __va_start(void *fp);
|
||||
void *__va_arg(va_list ap, int arg_type, int size);
|
||||
va_list __va_copy(va_list src);
|
||||
void __va_end(va_list ap);
|
||||
typedef __va_list_struct va_list[1];
|
||||
|
||||
#define va_start(ap, last) ((ap) = __va_start(__builtin_frame_address(0)))
|
||||
void __va_start(__va_list_struct *ap, void *fp);
|
||||
void *__va_arg(__va_list_struct *ap, int arg_type, int size, int align);
|
||||
|
||||
#define va_start(ap, last) __va_start(ap, __builtin_frame_address(0))
|
||||
#define va_arg(ap, type) \
|
||||
(*(type *)(__va_arg(ap, __builtin_va_arg_types(type), sizeof(type))))
|
||||
#define va_copy(dest, src) ((dest) = __va_copy(src))
|
||||
#define va_end(ap) __va_end(ap)
|
||||
(*(type *)(__va_arg(ap, __builtin_va_arg_types(type), sizeof(type), __alignof__(type))))
|
||||
#define va_copy(dest, src) (*(dest) = *(src))
|
||||
#define va_end(ap)
|
||||
|
||||
/* avoid conflicting definition for va_list on Macs. */
|
||||
#define _VA_LIST_T
|
||||
|
||||
#else /* _WIN64 */
|
||||
typedef char *va_list;
|
||||
#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+7)&~7)
|
||||
#define va_arg(ap,type) (ap += (sizeof(type)+7)&~7, *(type *)(ap - ((sizeof(type)+7)&~7)))
|
||||
#define va_copy(dest, src) (dest) = (src)
|
||||
#define va_start(ap,last) __builtin_va_start(ap,last)
|
||||
#define va_arg(ap, t) ((sizeof(t) > 8 || (sizeof(t) & (sizeof(t) - 1))) \
|
||||
? **(t **)((ap += 8) - 8) : *(t *)((ap += 8) - 8))
|
||||
#define va_copy(dest, src) ((dest) = (src))
|
||||
#define va_end(ap)
|
||||
#endif
|
||||
|
||||
#elif __arm__
|
||||
typedef char *va_list;
|
||||
#define _tcc_alignof(type) ((int)&((struct {char c;type x;} *)0)->x)
|
||||
#define _tcc_align(addr,type) (((unsigned)addr + _tcc_alignof(type) - 1) \
|
||||
& ~(_tcc_alignof(type) - 1))
|
||||
#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)
|
||||
#define va_arg(ap,type) (ap = (void *) ((_tcc_align(ap,type)+sizeof(type)+3) \
|
||||
&~3), *(type *)(ap - ((sizeof(type)+3)&~3)))
|
||||
#define va_copy(dest, src) (dest) = (src)
|
||||
#define va_end(ap)
|
||||
|
||||
#elif defined(__aarch64__)
|
||||
typedef struct {
|
||||
void *__stack;
|
||||
void *__gr_top;
|
||||
void *__vr_top;
|
||||
int __gr_offs;
|
||||
int __vr_offs;
|
||||
} va_list;
|
||||
#define va_start(ap, last) __va_start(ap, last)
|
||||
#define va_arg(ap, type) __va_arg(ap, type)
|
||||
#define va_end(ap)
|
||||
#define va_copy(dest, src) ((dest) = (src))
|
||||
|
||||
#else /* __i386__ */
|
||||
typedef char *va_list;
|
||||
/* only correct for i386 */
|
||||
|
||||
@ -6,5 +6,6 @@
|
||||
#define bool _Bool
|
||||
#define true 1
|
||||
#define false 0
|
||||
#define __bool_true_false_are_defined 1
|
||||
|
||||
#endif /* _STDBOOL_H */
|
||||
|
||||
@ -20,9 +20,27 @@ typedef unsigned int uint32_t;
|
||||
typedef unsigned long long int uint64_t;
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL ((void*)0)
|
||||
#endif
|
||||
|
||||
#define offsetof(type, field) ((size_t)&((type *)0)->field)
|
||||
|
||||
void *alloca(size_t size);
|
||||
|
||||
#endif
|
||||
|
||||
/* Older glibc require a wint_t from <stddef.h> (when requested
|
||||
by __need_wint_t, as otherwise stddef.h isn't allowed to
|
||||
define this type). Note that this must be outside the normal
|
||||
_STDDEF_H guard, so that it works even when we've included the file
|
||||
already (without requiring wint_t). Some other libs define _WINT_T
|
||||
if they've already provided that type, so we can use that as guard.
|
||||
TCC defines __WINT_TYPE__ for us. */
|
||||
#if defined (__need_wint_t)
|
||||
#ifndef _WINT_T
|
||||
#define _WINT_T
|
||||
typedef __WINT_TYPE__ wint_t;
|
||||
#endif
|
||||
#undef __need_wint_t
|
||||
#endif
|
||||
|
||||
139
lib/Makefile
139
lib/Makefile
@ -4,99 +4,72 @@
|
||||
|
||||
TOP = ..
|
||||
include $(TOP)/Makefile
|
||||
VPATH = $(top_srcdir)/lib $(top_srcdir)/win32/lib
|
||||
VPATH = $(TOPSRC)/lib $(TOPSRC)/win32/lib
|
||||
T = $(or $(CROSS_TARGET),$(NATIVE_TARGET),unknown)
|
||||
X = $(if $(CROSS_TARGET),$(CROSS_TARGET)-)
|
||||
|
||||
ifndef TARGET
|
||||
ifdef CONFIG_WIN64
|
||||
TARGET = x86_64-win32
|
||||
else
|
||||
ifdef CONFIG_WIN32
|
||||
TARGET = i386-win32
|
||||
else
|
||||
ifeq ($(ARCH),i386)
|
||||
TARGET = i386
|
||||
ifneq ($(TARGETOS),Darwin)
|
||||
XCC = $(CC)
|
||||
endif
|
||||
else
|
||||
ifeq ($(ARCH),x86-64)
|
||||
TARGET = x86_64
|
||||
ifneq ($(TARGETOS),Darwin)
|
||||
XCC = $(CC)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
TCC = $(TOP)/$(X)tcc$(EXESUF)
|
||||
XCC = $(TCC)
|
||||
XAR = $(TCC) -ar
|
||||
XFLAGS-unx = -B$(TOPSRC)
|
||||
XFLAGS-win = -B$(TOPSRC)/win32 -I$(TOPSRC)/include
|
||||
XFLAGS = $(XFLAGS$(XCFG))
|
||||
XCFG = $(or $(findstring -win,$T),-unx)
|
||||
|
||||
ifeq ($(X),)
|
||||
BCHECK_O = bcheck.o
|
||||
ifeq "$T" "arm"
|
||||
XCC = $(CC)
|
||||
XAR = $(AR)
|
||||
XFLAGS = $(CFLAGS) -fPIC
|
||||
endif
|
||||
endif
|
||||
|
||||
DIR = $(TARGET)
|
||||
|
||||
native : ../libtcc1.a
|
||||
cross : $(DIR)/libtcc1.a
|
||||
|
||||
native : TCC = $(TOP)/tcc$(EXESUF)
|
||||
cross : TCC = $(TOP)/$(TARGET)-tcc$(EXESUF)
|
||||
|
||||
I386_O = libtcc1.o alloca86.o alloca86-bt.o $(BCHECK_O)
|
||||
X86_64_O = libtcc1.o alloca86_64.o
|
||||
WIN32_O = $(I386_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o
|
||||
WIN64_O = $(X86_64_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o
|
||||
|
||||
ifeq "$(TARGET)" "i386-win32"
|
||||
OBJ = $(addprefix $(DIR)/,$(WIN32_O))
|
||||
TGT = -DTCC_TARGET_I386 -DTCC_TARGET_PE
|
||||
XCC = $(TCC) -B$(top_srcdir)/win32 -I$(top_srcdir)/include
|
||||
XAR = $(DIR)/tiny_libmaker$(EXESUF)
|
||||
else
|
||||
ifeq "$(TARGET)" "x86_64-win32"
|
||||
OBJ = $(addprefix $(DIR)/,$(WIN64_O))
|
||||
TGT = -DTCC_TARGET_X86_64 -DTCC_TARGET_PE
|
||||
XCC = $(TCC) -B$(top_srcdir)/win32 -I$(top_srcdir)/include
|
||||
XAR = $(DIR)/tiny_libmaker$(EXESUF)
|
||||
else
|
||||
ifeq "$(TARGET)" "i386"
|
||||
OBJ = $(addprefix $(DIR)/,$(I386_O))
|
||||
TGT = -DTCC_TARGET_I386
|
||||
XCC ?= $(TCC) -B$(TOP)
|
||||
else
|
||||
ifeq "$(TARGET)" "x86_64"
|
||||
OBJ = $(addprefix $(DIR)/,$(X86_64_O))
|
||||
TGT = -DTCC_TARGET_X86_64
|
||||
XCC ?= $(TCC) -B$(TOP)
|
||||
else
|
||||
$(error libtcc1.a not supported on target '$(TARGET)')
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
XFLAGS = $(CPPFLAGS) $(CFLAGS) $(TGT)
|
||||
|
||||
ifeq ($(TARGETOS),Darwin)
|
||||
XAR = $(DIR)/tiny_libmaker$(EXESUF)
|
||||
XFLAGS += -D_ANSI_SOURCE
|
||||
BCHECK_O =
|
||||
endif
|
||||
|
||||
ifdef XAR
|
||||
AR = $(XAR)
|
||||
endif
|
||||
I386_O = libtcc1.o alloca86.o alloca86-bt.o $(BCHECK_O)
|
||||
X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o $(BCHECK_O)
|
||||
ARM_O = libtcc1.o armeabi.o alloca-arm.o
|
||||
ARM64_O = lib-arm64.o
|
||||
WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o
|
||||
|
||||
$(DIR)/libtcc1.a ../libtcc1.a : $(OBJ) $(XAR)
|
||||
$(AR) rcs $@ $(OBJ)
|
||||
$(DIR)/%.o : %.c
|
||||
$(XCC) -c $< -o $@ $(XFLAGS)
|
||||
$(DIR)/%.o : %.S
|
||||
$(XCC) -c $< -o $@ $(XFLAGS)
|
||||
$(DIR)/%$(EXESUF) : $(TOP)/win32/tools/%.c
|
||||
$(CC) -o $@ $< $(XFLAGS) $(LDFLAGS)
|
||||
OBJ-i386 = $(I386_O)
|
||||
TGT-i386 = -DTCC_TARGET_I386
|
||||
|
||||
$(OBJ) $(XAR) : $(DIR)/exists
|
||||
$(DIR)/exists :
|
||||
mkdir -p $(DIR)
|
||||
@echo $@ > $@
|
||||
OBJ-x86_64 = $(X86_64_O)
|
||||
TGT-x86_64 = -DTCC_TARGET_X86_64
|
||||
|
||||
OBJ-arm = $(ARM_O)
|
||||
TGT-arm = -DTCC_TARGET_ARM
|
||||
|
||||
OBJ-arm64 = $(ARM64_O)
|
||||
TGT-arm64 = -DTCC_TARGET_ARM64
|
||||
|
||||
OBJ-i386-win32 = $(I386_O) chkstk.o $(WIN_O)
|
||||
TGT-i386-win32 = -DTCC_TARGET_I386 -DTCC_TARGET_PE
|
||||
|
||||
OBJ-x86_64-win32 = $(X86_64_O) chkstk.o $(WIN_O)
|
||||
TGT-x86_64-win32 = -DTCC_TARGET_X86_64 -DTCC_TARGET_PE
|
||||
|
||||
OBJ-arm-wince = $(ARM_O) $(WIN_O)
|
||||
TGT-arm-wince = -DTCC_TARGET_ARM -DTCC_TARGET_PE
|
||||
|
||||
all : $(BIN)
|
||||
|
||||
$(BIN) : $(patsubst %.o,$(X)%.o,$(OBJ-$T))
|
||||
$(XAR) rcs $@ $^
|
||||
|
||||
$(X)%.o : %.c
|
||||
$(XCC) -c $< -o $@ $(TGT-$T) $(XFLAGS)
|
||||
|
||||
$(X)%.o : %.S
|
||||
$(XCC) -c $< -o $@ $(TGT-$T) $(XFLAGS)
|
||||
|
||||
$(X)crt1w.o : crt1.c
|
||||
$(X)wincrt1w.o : wincrt1.c
|
||||
|
||||
clean :
|
||||
rm -rfv i386-win32 x86_64-win32 i386 x86_64
|
||||
rm -f *.a *.o $(BIN)
|
||||
|
||||
17
lib/alloca-arm.S
Normal file
17
lib/alloca-arm.S
Normal file
@ -0,0 +1,17 @@
|
||||
.text
|
||||
.align 2
|
||||
.global alloca
|
||||
.type alloca, %function
|
||||
alloca:
|
||||
#ifdef __TINYC__
|
||||
.int 0xe060d00d
|
||||
.int 0xe3cdd007
|
||||
.int 0xe1a0000d
|
||||
.int 0xe1a0f00e
|
||||
#else
|
||||
rsb sp, r0, sp
|
||||
bic sp, sp, #7
|
||||
mov r0, sp
|
||||
mov pc, lr
|
||||
#endif
|
||||
.size alloca, .-alloca
|
||||
@ -14,10 +14,10 @@ __bound_alloca:
|
||||
#ifdef TCC_TARGET_PE
|
||||
p4:
|
||||
cmp $4096,%eax
|
||||
jle p5
|
||||
jbe p5
|
||||
test %eax,-4096(%esp)
|
||||
sub $4096,%esp
|
||||
sub $4096,%eax
|
||||
test %eax,(%esp)
|
||||
jmp p4
|
||||
|
||||
p5:
|
||||
|
||||
@ -13,10 +13,10 @@ alloca:
|
||||
#ifdef TCC_TARGET_PE
|
||||
p1:
|
||||
cmp $4096,%eax
|
||||
jle p2
|
||||
jbe p2
|
||||
test %eax,-4096(%esp)
|
||||
sub $4096,%esp
|
||||
sub $4096,%eax
|
||||
test %eax,(%esp)
|
||||
jmp p1
|
||||
p2:
|
||||
#endif
|
||||
@ -28,8 +28,4 @@ p3:
|
||||
push %edx
|
||||
ret
|
||||
|
||||
/* mark stack as nonexecutable */
|
||||
#if defined __ELF__ && defined __linux__
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
#endif
|
||||
/* ---------------------------------------------- */
|
||||
|
||||
56
lib/alloca86_64-bt.S
Normal file
56
lib/alloca86_64-bt.S
Normal file
@ -0,0 +1,56 @@
|
||||
/* ---------------------------------------------- */
|
||||
/* alloca86_64.S */
|
||||
|
||||
.globl __bound_alloca
|
||||
__bound_alloca:
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
# bound checking is not implemented
|
||||
pop %rdx
|
||||
mov %rcx,%rax
|
||||
add $15,%rax
|
||||
and $-16,%rax
|
||||
jz p3
|
||||
|
||||
p1:
|
||||
cmp $4096,%rax
|
||||
jbe p2
|
||||
test %rax,-4096(%rsp)
|
||||
sub $4096,%rsp
|
||||
sub $4096,%rax
|
||||
jmp p1
|
||||
p2:
|
||||
|
||||
sub %rax,%rsp
|
||||
mov %rsp,%rax
|
||||
add $32,%rax
|
||||
|
||||
p3:
|
||||
push %rdx
|
||||
ret
|
||||
#else
|
||||
pop %rdx
|
||||
mov %rdi,%rax
|
||||
mov %rax,%rsi # size, a second parm to the __bound_new_region
|
||||
|
||||
add $15,%rax
|
||||
and $-16,%rax
|
||||
jz p3
|
||||
|
||||
|
||||
sub %rax,%rsp
|
||||
mov %rsp,%rdi # pointer, a first parm to the __bound_new_region
|
||||
mov %rsp,%rax
|
||||
|
||||
push %rdx
|
||||
push %rax
|
||||
call __bound_new_region
|
||||
pop %rax
|
||||
pop %rdx
|
||||
|
||||
p3:
|
||||
push %rdx
|
||||
ret
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------- */
|
||||
@ -17,10 +17,10 @@ alloca:
|
||||
#ifdef TCC_TARGET_PE
|
||||
p1:
|
||||
cmp $4096,%rax
|
||||
jle p2
|
||||
jbe p2
|
||||
test %rax,-4096(%rsp)
|
||||
sub $4096,%rsp
|
||||
sub $4096,%rax
|
||||
test %rax,(%rsp)
|
||||
jmp p1
|
||||
p2:
|
||||
#endif
|
||||
@ -35,8 +35,4 @@ p3:
|
||||
push %rdx
|
||||
ret
|
||||
|
||||
/* mark stack as nonexecutable */
|
||||
#if defined __ELF__ && defined __linux__
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
#endif
|
||||
/* ---------------------------------------------- */
|
||||
|
||||
501
lib/armeabi.c
Normal file
501
lib/armeabi.c
Normal file
@ -0,0 +1,501 @@
|
||||
/* TCC ARM runtime EABI
|
||||
Copyright (C) 2013 Thomas Preud'homme
|
||||
|
||||
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.*/
|
||||
|
||||
#ifdef __TINYC__
|
||||
#define INT_MIN (-2147483647 - 1)
|
||||
#define INT_MAX 2147483647
|
||||
#define UINT_MAX 0xffffffff
|
||||
#define LONG_MIN (-2147483647L - 1)
|
||||
#define LONG_MAX 2147483647L
|
||||
#define ULONG_MAX 0xffffffffUL
|
||||
#define LLONG_MAX 9223372036854775807LL
|
||||
#define LLONG_MIN (-9223372036854775807LL - 1)
|
||||
#define ULLONG_MAX 0xffffffffffffffffULL
|
||||
#else
|
||||
#include <limits.h>
|
||||
#endif
|
||||
|
||||
/* We rely on the little endianness and EABI calling convention for this to
|
||||
work */
|
||||
|
||||
typedef struct double_unsigned_struct {
|
||||
unsigned low;
|
||||
unsigned high;
|
||||
} double_unsigned_struct;
|
||||
|
||||
typedef struct unsigned_int_struct {
|
||||
unsigned low;
|
||||
int high;
|
||||
} unsigned_int_struct;
|
||||
|
||||
#define REGS_RETURN(name, type) \
|
||||
void name ## _return(type ret) {}
|
||||
|
||||
|
||||
/* Float helper functions */
|
||||
|
||||
#define FLOAT_EXP_BITS 8
|
||||
#define FLOAT_FRAC_BITS 23
|
||||
|
||||
#define DOUBLE_EXP_BITS 11
|
||||
#define DOUBLE_FRAC_BITS 52
|
||||
|
||||
#define ONE_EXP(type) ((1 << (type ## _EXP_BITS - 1)) - 1)
|
||||
|
||||
REGS_RETURN(unsigned_int_struct, unsigned_int_struct)
|
||||
REGS_RETURN(double_unsigned_struct, double_unsigned_struct)
|
||||
|
||||
/* float -> integer: (sign) 1.fraction x 2^(exponent - exp_for_one) */
|
||||
|
||||
|
||||
/* float to [unsigned] long long conversion */
|
||||
#define DEFINE__AEABI_F2XLZ(name, with_sign) \
|
||||
void __aeabi_ ## name(unsigned val) \
|
||||
{ \
|
||||
int exp, high_shift, sign; \
|
||||
double_unsigned_struct ret; \
|
||||
\
|
||||
/* compute sign */ \
|
||||
sign = val >> 31; \
|
||||
\
|
||||
/* compute real exponent */ \
|
||||
exp = val >> FLOAT_FRAC_BITS; \
|
||||
exp &= (1 << FLOAT_EXP_BITS) - 1; \
|
||||
exp -= ONE_EXP(FLOAT); \
|
||||
\
|
||||
/* undefined behavior if truncated value cannot be represented */ \
|
||||
if (with_sign) { \
|
||||
if (exp > 62) /* |val| too big, double cannot represent LLONG_MAX */ \
|
||||
return; \
|
||||
} else { \
|
||||
if ((sign && exp >= 0) || exp > 63) /* if val < 0 || val too big */ \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
val &= (1 << FLOAT_FRAC_BITS) - 1; \
|
||||
if (exp >= 32) { \
|
||||
ret.high = 1 << (exp - 32); \
|
||||
if (exp - 32 >= FLOAT_FRAC_BITS) { \
|
||||
ret.high |= val << (exp - 32 - FLOAT_FRAC_BITS); \
|
||||
ret.low = 0; \
|
||||
} else { \
|
||||
high_shift = FLOAT_FRAC_BITS - (exp - 32); \
|
||||
ret.high |= val >> high_shift; \
|
||||
ret.low = val << (32 - high_shift); \
|
||||
} \
|
||||
} else { \
|
||||
ret.high = 0; \
|
||||
ret.low = 1 << exp; \
|
||||
if (exp > FLOAT_FRAC_BITS) \
|
||||
ret.low |= val << (exp - FLOAT_FRAC_BITS); \
|
||||
else \
|
||||
ret.low |= val >> (FLOAT_FRAC_BITS - exp); \
|
||||
} \
|
||||
\
|
||||
/* encode negative integer using 2's complement */ \
|
||||
if (with_sign && sign) { \
|
||||
ret.low = ~ret.low; \
|
||||
ret.high = ~ret.high; \
|
||||
if (ret.low == UINT_MAX) { \
|
||||
ret.low = 0; \
|
||||
ret.high++; \
|
||||
} else \
|
||||
ret.low++; \
|
||||
} \
|
||||
\
|
||||
double_unsigned_struct_return(ret); \
|
||||
}
|
||||
|
||||
/* float to unsigned long long conversion */
|
||||
DEFINE__AEABI_F2XLZ(f2ulz, 0)
|
||||
|
||||
/* float to long long conversion */
|
||||
DEFINE__AEABI_F2XLZ(f2lz, 1)
|
||||
|
||||
/* double to [unsigned] long long conversion */
|
||||
#define DEFINE__AEABI_D2XLZ(name, with_sign) \
|
||||
void __aeabi_ ## name(double_unsigned_struct val) \
|
||||
{ \
|
||||
int exp, high_shift, sign; \
|
||||
double_unsigned_struct ret; \
|
||||
\
|
||||
/* compute sign */ \
|
||||
sign = val.high >> 31; \
|
||||
\
|
||||
/* compute real exponent */ \
|
||||
exp = (val.high >> (DOUBLE_FRAC_BITS - 32)); \
|
||||
exp &= (1 << DOUBLE_EXP_BITS) - 1; \
|
||||
exp -= ONE_EXP(DOUBLE); \
|
||||
\
|
||||
/* undefined behavior if truncated value cannot be represented */ \
|
||||
if (with_sign) { \
|
||||
if (exp > 62) /* |val| too big, double cannot represent LLONG_MAX */ \
|
||||
return; \
|
||||
} else { \
|
||||
if ((sign && exp >= 0) || exp > 63) /* if val < 0 || val too big */ \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
val.high &= (1 << (DOUBLE_FRAC_BITS - 32)) - 1; \
|
||||
if (exp >= 32) { \
|
||||
ret.high = 1 << (exp - 32); \
|
||||
if (exp >= DOUBLE_FRAC_BITS) { \
|
||||
high_shift = exp - DOUBLE_FRAC_BITS; \
|
||||
ret.high |= val.high << high_shift; \
|
||||
ret.high |= val.low >> (32 - high_shift); \
|
||||
ret.low = val.low << high_shift; \
|
||||
} else { \
|
||||
high_shift = DOUBLE_FRAC_BITS - exp; \
|
||||
ret.high |= val.high >> high_shift; \
|
||||
ret.low = val.high << (32 - high_shift); \
|
||||
ret.low |= val.low >> high_shift; \
|
||||
} \
|
||||
} else { \
|
||||
ret.high = 0; \
|
||||
ret.low = 1 << exp; \
|
||||
if (exp > DOUBLE_FRAC_BITS - 32) { \
|
||||
high_shift = exp - DOUBLE_FRAC_BITS - 32; \
|
||||
ret.low |= val.high << high_shift; \
|
||||
ret.low |= val.low >> (32 - high_shift); \
|
||||
} else \
|
||||
ret.low |= val.high >> (DOUBLE_FRAC_BITS - 32 - exp); \
|
||||
} \
|
||||
\
|
||||
/* encode negative integer using 2's complement */ \
|
||||
if (with_sign && sign) { \
|
||||
ret.low = ~ret.low; \
|
||||
ret.high = ~ret.high; \
|
||||
if (ret.low == UINT_MAX) { \
|
||||
ret.low = 0; \
|
||||
ret.high++; \
|
||||
} else \
|
||||
ret.low++; \
|
||||
} \
|
||||
\
|
||||
double_unsigned_struct_return(ret); \
|
||||
}
|
||||
|
||||
/* double to unsigned long long conversion */
|
||||
DEFINE__AEABI_D2XLZ(d2ulz, 0)
|
||||
|
||||
/* double to long long conversion */
|
||||
DEFINE__AEABI_D2XLZ(d2lz, 1)
|
||||
|
||||
/* long long to float conversion */
|
||||
#define DEFINE__AEABI_XL2F(name, with_sign) \
|
||||
unsigned __aeabi_ ## name(unsigned long long v) \
|
||||
{ \
|
||||
int s /* shift */, flb /* first lost bit */, sign = 0; \
|
||||
unsigned p = 0 /* power */, ret; \
|
||||
double_unsigned_struct val; \
|
||||
\
|
||||
/* fraction in negative float is encoded in 1's complement */ \
|
||||
if (with_sign && (v & (1ULL << 63))) { \
|
||||
sign = 1; \
|
||||
v = ~v + 1; \
|
||||
} \
|
||||
val.low = v; \
|
||||
val.high = v >> 32; \
|
||||
/* fill fraction bits */ \
|
||||
for (s = 31, p = 1 << 31; p && !(val.high & p); s--, p >>= 1); \
|
||||
if (p) { \
|
||||
ret = val.high & (p - 1); \
|
||||
if (s < FLOAT_FRAC_BITS) { \
|
||||
ret <<= FLOAT_FRAC_BITS - s; \
|
||||
ret |= val.low >> (32 - (FLOAT_FRAC_BITS - s)); \
|
||||
flb = (val.low >> (32 - (FLOAT_FRAC_BITS - s - 1))) & 1; \
|
||||
} else { \
|
||||
flb = (ret >> (s - FLOAT_FRAC_BITS - 1)) & 1; \
|
||||
ret >>= s - FLOAT_FRAC_BITS; \
|
||||
} \
|
||||
s += 32; \
|
||||
} else { \
|
||||
for (s = 31, p = 1 << 31; p && !(val.low & p); s--, p >>= 1); \
|
||||
if (p) { \
|
||||
ret = val.low & (p - 1); \
|
||||
if (s <= FLOAT_FRAC_BITS) { \
|
||||
ret <<= FLOAT_FRAC_BITS - s; \
|
||||
flb = 0; \
|
||||
} else { \
|
||||
flb = (ret >> (s - FLOAT_FRAC_BITS - 1)) & 1; \
|
||||
ret >>= s - FLOAT_FRAC_BITS; \
|
||||
} \
|
||||
} else \
|
||||
return 0; \
|
||||
} \
|
||||
if (flb) \
|
||||
ret++; \
|
||||
\
|
||||
/* fill exponent bits */ \
|
||||
ret |= (s + ONE_EXP(FLOAT)) << FLOAT_FRAC_BITS; \
|
||||
\
|
||||
/* fill sign bit */ \
|
||||
ret |= sign << 31; \
|
||||
\
|
||||
return ret; \
|
||||
}
|
||||
|
||||
/* unsigned long long to float conversion */
|
||||
DEFINE__AEABI_XL2F(ul2f, 0)
|
||||
|
||||
/* long long to float conversion */
|
||||
DEFINE__AEABI_XL2F(l2f, 1)
|
||||
|
||||
/* long long to double conversion */
|
||||
#define __AEABI_XL2D(name, with_sign) \
|
||||
void __aeabi_ ## name(unsigned long long v) \
|
||||
{ \
|
||||
int s /* shift */, high_shift, sign = 0; \
|
||||
unsigned tmp, p = 0; \
|
||||
double_unsigned_struct val, ret; \
|
||||
\
|
||||
/* fraction in negative float is encoded in 1's complement */ \
|
||||
if (with_sign && (v & (1ULL << 63))) { \
|
||||
sign = 1; \
|
||||
v = ~v + 1; \
|
||||
} \
|
||||
val.low = v; \
|
||||
val.high = v >> 32; \
|
||||
\
|
||||
/* fill fraction bits */ \
|
||||
for (s = 31, p = 1 << 31; p && !(val.high & p); s--, p >>= 1); \
|
||||
if (p) { \
|
||||
tmp = val.high & (p - 1); \
|
||||
if (s < DOUBLE_FRAC_BITS - 32) { \
|
||||
high_shift = DOUBLE_FRAC_BITS - 32 - s; \
|
||||
ret.high = tmp << high_shift; \
|
||||
ret.high |= val.low >> (32 - high_shift); \
|
||||
ret.low = val.low << high_shift; \
|
||||
} else { \
|
||||
high_shift = s - (DOUBLE_FRAC_BITS - 32); \
|
||||
ret.high = tmp >> high_shift; \
|
||||
ret.low = tmp << (32 - high_shift); \
|
||||
ret.low |= val.low >> high_shift; \
|
||||
if ((val.low >> (high_shift - 1)) & 1) { \
|
||||
if (ret.low == UINT_MAX) { \
|
||||
ret.high++; \
|
||||
ret.low = 0; \
|
||||
} else \
|
||||
ret.low++; \
|
||||
} \
|
||||
} \
|
||||
s += 32; \
|
||||
} else { \
|
||||
for (s = 31, p = 1 << 31; p && !(val.low & p); s--, p >>= 1); \
|
||||
if (p) { \
|
||||
tmp = val.low & (p - 1); \
|
||||
if (s <= DOUBLE_FRAC_BITS - 32) { \
|
||||
high_shift = DOUBLE_FRAC_BITS - 32 - s; \
|
||||
ret.high = tmp << high_shift; \
|
||||
ret.low = 0; \
|
||||
} else { \
|
||||
high_shift = s - (DOUBLE_FRAC_BITS - 32); \
|
||||
ret.high = tmp >> high_shift; \
|
||||
ret.low = tmp << (32 - high_shift); \
|
||||
} \
|
||||
} else { \
|
||||
ret.high = ret.low = 0; \
|
||||
double_unsigned_struct_return(ret); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* fill exponent bits */ \
|
||||
ret.high |= (s + ONE_EXP(DOUBLE)) << (DOUBLE_FRAC_BITS - 32); \
|
||||
\
|
||||
/* fill sign bit */ \
|
||||
ret.high |= sign << 31; \
|
||||
\
|
||||
double_unsigned_struct_return(ret); \
|
||||
}
|
||||
|
||||
/* unsigned long long to double conversion */
|
||||
__AEABI_XL2D(ul2d, 0)
|
||||
|
||||
/* long long to double conversion */
|
||||
__AEABI_XL2D(l2d, 1)
|
||||
|
||||
|
||||
/* Long long helper functions */
|
||||
|
||||
/* TODO: add error in case of den == 0 (see §4.3.1 and §4.3.2) */
|
||||
|
||||
#define define_aeabi_xdivmod_signed_type(basetype, type) \
|
||||
typedef struct type { \
|
||||
basetype quot; \
|
||||
unsigned basetype rem; \
|
||||
} type
|
||||
|
||||
#define define_aeabi_xdivmod_unsigned_type(basetype, type) \
|
||||
typedef struct type { \
|
||||
basetype quot; \
|
||||
basetype rem; \
|
||||
} type
|
||||
|
||||
#define AEABI_UXDIVMOD(name,type, rettype, typemacro) \
|
||||
static inline rettype aeabi_ ## name (type num, type den) \
|
||||
{ \
|
||||
rettype ret; \
|
||||
type quot = 0; \
|
||||
\
|
||||
/* Increase quotient while it is less than numerator */ \
|
||||
while (num >= den) { \
|
||||
type q = 1; \
|
||||
\
|
||||
/* Find closest power of two */ \
|
||||
while ((q << 1) * den <= num && q * den <= typemacro ## _MAX / 2) \
|
||||
q <<= 1; \
|
||||
\
|
||||
/* Compute difference between current quotient and numerator */ \
|
||||
num -= q * den; \
|
||||
quot += q; \
|
||||
} \
|
||||
ret.quot = quot; \
|
||||
ret.rem = num; \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#define __AEABI_XDIVMOD(name, type, uiname, rettype, urettype, typemacro) \
|
||||
void __aeabi_ ## name(type numerator, type denominator) \
|
||||
{ \
|
||||
unsigned type num, den; \
|
||||
urettype uxdiv_ret; \
|
||||
rettype ret; \
|
||||
\
|
||||
if (numerator >= 0) \
|
||||
num = numerator; \
|
||||
else \
|
||||
num = 0 - numerator; \
|
||||
if (denominator >= 0) \
|
||||
den = denominator; \
|
||||
else \
|
||||
den = 0 - denominator; \
|
||||
uxdiv_ret = aeabi_ ## uiname(num, den); \
|
||||
/* signs differ */ \
|
||||
if ((numerator & typemacro ## _MIN) != (denominator & typemacro ## _MIN)) \
|
||||
ret.quot = 0 - uxdiv_ret.quot; \
|
||||
else \
|
||||
ret.quot = uxdiv_ret.quot; \
|
||||
if (numerator < 0) \
|
||||
ret.rem = 0 - uxdiv_ret.rem; \
|
||||
else \
|
||||
ret.rem = uxdiv_ret.rem; \
|
||||
\
|
||||
rettype ## _return(ret); \
|
||||
}
|
||||
|
||||
define_aeabi_xdivmod_signed_type(long long, lldiv_t);
|
||||
define_aeabi_xdivmod_unsigned_type(unsigned long long, ulldiv_t);
|
||||
define_aeabi_xdivmod_signed_type(int, idiv_t);
|
||||
define_aeabi_xdivmod_unsigned_type(unsigned, uidiv_t);
|
||||
|
||||
REGS_RETURN(lldiv_t, lldiv_t)
|
||||
REGS_RETURN(ulldiv_t, ulldiv_t)
|
||||
REGS_RETURN(idiv_t, idiv_t)
|
||||
REGS_RETURN(uidiv_t, uidiv_t)
|
||||
|
||||
AEABI_UXDIVMOD(uldivmod, unsigned long long, ulldiv_t, ULLONG)
|
||||
|
||||
__AEABI_XDIVMOD(ldivmod, long long, uldivmod, lldiv_t, ulldiv_t, LLONG)
|
||||
|
||||
void __aeabi_uldivmod(unsigned long long num, unsigned long long den)
|
||||
{
|
||||
ulldiv_t_return(aeabi_uldivmod(num, den));
|
||||
}
|
||||
|
||||
void __aeabi_llsl(double_unsigned_struct val, int shift)
|
||||
{
|
||||
double_unsigned_struct ret;
|
||||
|
||||
if (shift >= 32) {
|
||||
val.high = val.low;
|
||||
val.low = 0;
|
||||
shift -= 32;
|
||||
}
|
||||
if (shift > 0) {
|
||||
ret.low = val.low << shift;
|
||||
ret.high = (val.high << shift) | (val.low >> (32 - shift));
|
||||
double_unsigned_struct_return(ret);
|
||||
return;
|
||||
}
|
||||
double_unsigned_struct_return(val);
|
||||
}
|
||||
|
||||
#define aeabi_lsr(val, shift, fill, type) \
|
||||
type ## _struct ret; \
|
||||
\
|
||||
if (shift >= 32) { \
|
||||
val.low = val.high; \
|
||||
val.high = fill; \
|
||||
shift -= 32; \
|
||||
} \
|
||||
if (shift > 0) { \
|
||||
ret.high = val.high >> shift; \
|
||||
ret.low = (val.high << (32 - shift)) | (val.low >> shift); \
|
||||
type ## _struct_return(ret); \
|
||||
return; \
|
||||
} \
|
||||
type ## _struct_return(val);
|
||||
|
||||
void __aeabi_llsr(double_unsigned_struct val, int shift)
|
||||
{
|
||||
aeabi_lsr(val, shift, 0, double_unsigned);
|
||||
}
|
||||
|
||||
void __aeabi_lasr(unsigned_int_struct val, int shift)
|
||||
{
|
||||
aeabi_lsr(val, shift, val.high >> 31, unsigned_int);
|
||||
}
|
||||
|
||||
|
||||
/* Integer division functions */
|
||||
|
||||
AEABI_UXDIVMOD(uidivmod, unsigned, uidiv_t, UINT)
|
||||
|
||||
int __aeabi_idiv(int numerator, int denominator)
|
||||
{
|
||||
unsigned num, den;
|
||||
uidiv_t ret;
|
||||
|
||||
if (numerator >= 0)
|
||||
num = numerator;
|
||||
else
|
||||
num = 0 - numerator;
|
||||
if (denominator >= 0)
|
||||
den = denominator;
|
||||
else
|
||||
den = 0 - denominator;
|
||||
ret = aeabi_uidivmod(num, den);
|
||||
if ((numerator & INT_MIN) != (denominator & INT_MIN)) /* signs differ */
|
||||
ret.quot *= -1;
|
||||
return ret.quot;
|
||||
}
|
||||
|
||||
unsigned __aeabi_uidiv(unsigned num, unsigned den)
|
||||
{
|
||||
return aeabi_uidivmod(num, den).quot;
|
||||
}
|
||||
|
||||
__AEABI_XDIVMOD(idivmod, int, uidivmod, idiv_t, uidiv_t, INT)
|
||||
|
||||
void __aeabi_uidivmod(unsigned num, unsigned den)
|
||||
{
|
||||
uidiv_t_return(aeabi_uidivmod(num, den));
|
||||
}
|
||||
260
lib/bcheck.c
260
lib/bcheck.c
@ -22,18 +22,24 @@
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) \
|
||||
&& !defined(__DragonFly__) && !defined(__OpenBSD__)
|
||||
&& !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#if !defined(_WIN32)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
//#define BOUND_DEBUG
|
||||
/* #define BOUND_DEBUG */
|
||||
|
||||
#ifdef BOUND_DEBUG
|
||||
#define dprintf(a...) fprintf(a)
|
||||
#else
|
||||
#define dprintf(a...)
|
||||
#endif
|
||||
|
||||
/* define so that bound array is static (faster, but use memory if
|
||||
bound checking not used) */
|
||||
//#define BOUND_STATIC
|
||||
/* #define BOUND_STATIC */
|
||||
|
||||
/* use malloc hooks. Currently the code cannot be reliable if no hooks */
|
||||
#define CONFIG_TCC_MALLOC_HOOKS
|
||||
@ -41,45 +47,49 @@
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
|
||||
|| defined(__DragonFly__) || defined(__dietlibc__) \
|
||||
|| defined(__UCLIBC__) || defined(__OpenBSD__) \
|
||||
|| defined(__UCLIBC__) || defined(__OpenBSD__) || defined(__NetBSD__) \
|
||||
|| defined(_WIN32) || defined(TCC_UCLIBC)
|
||||
#warning Bound checking does not support malloc (etc.) in this environment.
|
||||
//#warning Bound checking does not support malloc (etc.) in this environment.
|
||||
#undef CONFIG_TCC_MALLOC_HOOKS
|
||||
#undef HAVE_MEMALIGN
|
||||
#endif
|
||||
|
||||
#define BOUND_T1_BITS 13
|
||||
#define BOUND_T2_BITS 11
|
||||
#define BOUND_T3_BITS (32 - BOUND_T1_BITS - BOUND_T2_BITS)
|
||||
#define BOUND_T3_BITS (sizeof(size_t)*8 - BOUND_T1_BITS - BOUND_T2_BITS)
|
||||
#define BOUND_E_BITS (sizeof(size_t))
|
||||
|
||||
#define BOUND_T1_SIZE (1 << BOUND_T1_BITS)
|
||||
#define BOUND_T2_SIZE (1 << BOUND_T2_BITS)
|
||||
#define BOUND_T3_SIZE (1 << BOUND_T3_BITS)
|
||||
#define BOUND_E_BITS 4
|
||||
#define BOUND_T1_SIZE ((size_t)1 << BOUND_T1_BITS)
|
||||
#define BOUND_T2_SIZE ((size_t)1 << BOUND_T2_BITS)
|
||||
#define BOUND_T3_SIZE ((size_t)1 << BOUND_T3_BITS)
|
||||
|
||||
#define BOUND_T23_BITS (BOUND_T2_BITS + BOUND_T3_BITS)
|
||||
#define BOUND_T23_SIZE (1 << BOUND_T23_BITS)
|
||||
#define BOUND_T23_SIZE ((size_t)1 << BOUND_T23_BITS)
|
||||
|
||||
|
||||
/* this pointer is generated when bound check is incorrect */
|
||||
#define INVALID_POINTER ((void *)(-2))
|
||||
/* size of an empty region */
|
||||
#define EMPTY_SIZE 0xffffffff
|
||||
#define EMPTY_SIZE ((size_t)(-1))
|
||||
/* size of an invalid region */
|
||||
#define INVALID_SIZE 0
|
||||
|
||||
typedef struct BoundEntry {
|
||||
unsigned long start;
|
||||
unsigned long size;
|
||||
size_t start;
|
||||
size_t size;
|
||||
struct BoundEntry *next;
|
||||
unsigned long is_invalid; /* true if pointers outside region are invalid */
|
||||
size_t is_invalid; /* true if pointers outside region are invalid */
|
||||
} BoundEntry;
|
||||
|
||||
/* external interface */
|
||||
void __bound_init(void);
|
||||
void __bound_new_region(void *p, unsigned long size);
|
||||
void __bound_new_region(void *p, size_t size);
|
||||
int __bound_delete_region(void *p);
|
||||
|
||||
#ifdef __attribute__
|
||||
/* an __attribute__ macro is defined in the system headers */
|
||||
#undef __attribute__
|
||||
#endif
|
||||
#define FASTCALL __attribute__((regparm(3)))
|
||||
|
||||
void *__bound_malloc(size_t size, const void *caller);
|
||||
@ -104,7 +114,7 @@ extern char __bounds_start; /* start of static bounds table */
|
||||
const char *__bound_error_msg;
|
||||
|
||||
/* runtime error output */
|
||||
extern void rt_error(unsigned long pc, const char *fmt, ...);
|
||||
extern void rt_error(size_t pc, const char *fmt, ...);
|
||||
|
||||
#ifdef BOUND_STATIC
|
||||
static BoundEntry *__bound_t1[BOUND_T1_SIZE]; /* page table */
|
||||
@ -116,12 +126,12 @@ static BoundEntry *__bound_invalid_t2; /* invalid page, for invalid pointers */
|
||||
|
||||
static BoundEntry *__bound_find_region(BoundEntry *e1, void *p)
|
||||
{
|
||||
unsigned long addr, tmp;
|
||||
size_t addr, tmp;
|
||||
BoundEntry *e;
|
||||
|
||||
e = e1;
|
||||
while (e != NULL) {
|
||||
addr = (unsigned long)p;
|
||||
addr = (size_t)p;
|
||||
addr -= e->start;
|
||||
if (addr <= e->size) {
|
||||
/* put region at the head */
|
||||
@ -146,7 +156,8 @@ static BoundEntry *__bound_find_region(BoundEntry *e1, void *p)
|
||||
static void bound_error(const char *fmt, ...)
|
||||
{
|
||||
__bound_error_msg = fmt;
|
||||
*(int *)0 = 0; /* force a runtime error */
|
||||
fprintf(stderr,"%s %s: %s\n", __FILE__, __FUNCTION__, fmt);
|
||||
*(void **)0 = 0; /* force a runtime error */
|
||||
}
|
||||
|
||||
static void bound_alloc_error(void)
|
||||
@ -156,13 +167,15 @@ static void bound_alloc_error(void)
|
||||
|
||||
/* return '(p + offset)' for pointer arithmetic (a pointer can reach
|
||||
the end of a region in this case */
|
||||
void * FASTCALL __bound_ptr_add(void *p, int offset)
|
||||
void * FASTCALL __bound_ptr_add(void *p, size_t offset)
|
||||
{
|
||||
unsigned long addr = (unsigned long)p;
|
||||
size_t addr = (size_t)p;
|
||||
BoundEntry *e;
|
||||
#if defined(BOUND_DEBUG)
|
||||
printf("add: 0x%x %d\n", (int)p, offset);
|
||||
#endif
|
||||
|
||||
dprintf(stderr, "%s %s: %p %x\n",
|
||||
__FILE__, __FUNCTION__, p, (unsigned)offset);
|
||||
|
||||
__bound_init();
|
||||
|
||||
e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)];
|
||||
e = (BoundEntry *)((char *)e +
|
||||
@ -171,22 +184,29 @@ void * FASTCALL __bound_ptr_add(void *p, int offset)
|
||||
addr -= e->start;
|
||||
if (addr > e->size) {
|
||||
e = __bound_find_region(e, p);
|
||||
addr = (unsigned long)p - e->start;
|
||||
addr = (size_t)p - e->start;
|
||||
}
|
||||
addr += offset;
|
||||
if (addr > e->size)
|
||||
if (addr >= e->size) {
|
||||
fprintf(stderr,"%s %s: %p is outside of the region\n",
|
||||
__FILE__, __FUNCTION__, p + offset);
|
||||
return INVALID_POINTER; /* return an invalid pointer */
|
||||
}
|
||||
return p + offset;
|
||||
}
|
||||
|
||||
/* return '(p + offset)' for pointer indirection (the resulting must
|
||||
be strictly inside the region */
|
||||
#define BOUND_PTR_INDIR(dsize) \
|
||||
void * FASTCALL __bound_ptr_indir ## dsize (void *p, int offset) \
|
||||
void * FASTCALL __bound_ptr_indir ## dsize (void *p, size_t offset) \
|
||||
{ \
|
||||
unsigned long addr = (unsigned long)p; \
|
||||
size_t addr = (size_t)p; \
|
||||
BoundEntry *e; \
|
||||
\
|
||||
dprintf(stderr, "%s %s: %p %x start\n", \
|
||||
__FILE__, __FUNCTION__, p, (unsigned)offset); \
|
||||
\
|
||||
__bound_init(); \
|
||||
e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)]; \
|
||||
e = (BoundEntry *)((char *)e + \
|
||||
((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) & \
|
||||
@ -194,11 +214,16 @@ void * FASTCALL __bound_ptr_indir ## dsize (void *p, int offset) \
|
||||
addr -= e->start; \
|
||||
if (addr > e->size) { \
|
||||
e = __bound_find_region(e, p); \
|
||||
addr = (unsigned long)p - e->start; \
|
||||
addr = (size_t)p - e->start; \
|
||||
} \
|
||||
addr += offset + dsize; \
|
||||
if (addr > e->size) \
|
||||
if (addr > e->size) { \
|
||||
fprintf(stderr,"%s %s: %p is outside of the region\n", \
|
||||
__FILE__, __FUNCTION__, p + offset); \
|
||||
return INVALID_POINTER; /* return an invalid pointer */ \
|
||||
} \
|
||||
dprintf(stderr, "%s %s: return p+offset = %p\n", \
|
||||
__FILE__, __FUNCTION__, p + offset); \
|
||||
return p + offset; \
|
||||
}
|
||||
|
||||
@ -209,16 +234,27 @@ BOUND_PTR_INDIR(8)
|
||||
BOUND_PTR_INDIR(12)
|
||||
BOUND_PTR_INDIR(16)
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ >= 6)
|
||||
/*
|
||||
* At least gcc 6.2 complains when __builtin_frame_address is used whith
|
||||
* nonzero argument.
|
||||
*/
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wframe-address"
|
||||
#endif
|
||||
|
||||
/* return the frame pointer of the caller */
|
||||
#define GET_CALLER_FP(fp)\
|
||||
{\
|
||||
fp = (unsigned long)__builtin_frame_address(1);\
|
||||
fp = (size_t)__builtin_frame_address(1);\
|
||||
}
|
||||
|
||||
/* called when entering a function to add all the local regions */
|
||||
void FASTCALL __bound_local_new(void *p1)
|
||||
{
|
||||
unsigned long addr, size, fp, *p = p1;
|
||||
size_t addr, size, fp, *p = p1;
|
||||
|
||||
dprintf(stderr, "%s, %s start p1=%p\n", __FILE__, __FUNCTION__, p);
|
||||
GET_CALLER_FP(fp);
|
||||
for(;;) {
|
||||
addr = p[0];
|
||||
@ -229,12 +265,13 @@ void FASTCALL __bound_local_new(void *p1)
|
||||
p += 2;
|
||||
__bound_new_region((void *)addr, size);
|
||||
}
|
||||
dprintf(stderr, "%s, %s end\n", __FILE__, __FUNCTION__);
|
||||
}
|
||||
|
||||
/* called when leaving a function to delete all the local regions */
|
||||
void FASTCALL __bound_local_delete(void *p1)
|
||||
{
|
||||
unsigned long addr, fp, *p = p1;
|
||||
size_t addr, fp, *p = p1;
|
||||
GET_CALLER_FP(fp);
|
||||
for(;;) {
|
||||
addr = p[0];
|
||||
@ -246,10 +283,14 @@ void FASTCALL __bound_local_delete(void *p1)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ >= 6)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
static BoundEntry *__bound_new_page(void)
|
||||
{
|
||||
BoundEntry *page;
|
||||
int i;
|
||||
size_t i;
|
||||
|
||||
page = libc_malloc(sizeof(BoundEntry) * BOUND_T2_SIZE);
|
||||
if (!page)
|
||||
@ -277,11 +318,11 @@ static void bound_free_entry(BoundEntry *e)
|
||||
libc_free(e);
|
||||
}
|
||||
|
||||
static inline BoundEntry *get_page(int index)
|
||||
static BoundEntry *get_page(size_t index)
|
||||
{
|
||||
BoundEntry *page;
|
||||
page = __bound_t1[index];
|
||||
if (page == __bound_empty_t2 || page == __bound_invalid_t2) {
|
||||
if (!page || page == __bound_empty_t2 || page == __bound_invalid_t2) {
|
||||
/* create a new page if necessary */
|
||||
page = __bound_new_page();
|
||||
__bound_t1[index] = page;
|
||||
@ -290,11 +331,11 @@ static inline BoundEntry *get_page(int index)
|
||||
}
|
||||
|
||||
/* mark a region as being invalid (can only be used during init) */
|
||||
static void mark_invalid(unsigned long addr, unsigned long size)
|
||||
static void mark_invalid(size_t addr, size_t size)
|
||||
{
|
||||
unsigned long start, end;
|
||||
size_t start, end;
|
||||
BoundEntry *page;
|
||||
int t1_start, t1_end, i, j, t2_start, t2_end;
|
||||
size_t t1_start, t1_end, i, j, t2_start, t2_end;
|
||||
|
||||
start = addr;
|
||||
end = addr + size;
|
||||
@ -306,7 +347,7 @@ static void mark_invalid(unsigned long addr, unsigned long size)
|
||||
t2_end = 1 << (BOUND_T1_BITS + BOUND_T2_BITS);
|
||||
|
||||
#if 0
|
||||
printf("mark_invalid: start = %x %x\n", t2_start, t2_end);
|
||||
dprintf(stderr, "mark_invalid: start = %x %x\n", t2_start, t2_end);
|
||||
#endif
|
||||
|
||||
/* first we handle full pages */
|
||||
@ -345,10 +386,18 @@ static void mark_invalid(unsigned long addr, unsigned long size)
|
||||
|
||||
void __bound_init(void)
|
||||
{
|
||||
int i;
|
||||
size_t i;
|
||||
BoundEntry *page;
|
||||
unsigned long start, size;
|
||||
int *p;
|
||||
size_t start, size;
|
||||
size_t *p;
|
||||
|
||||
static int inited;
|
||||
if (inited)
|
||||
return;
|
||||
|
||||
inited = 1;
|
||||
|
||||
dprintf(stderr, "%s, %s() start\n", __FILE__, __FUNCTION__);
|
||||
|
||||
/* save malloc hooks and install bound check hooks */
|
||||
install_malloc_hooks();
|
||||
@ -374,7 +423,7 @@ void __bound_init(void)
|
||||
__bound_invalid_t2 = page;
|
||||
|
||||
/* invalid pointer zone */
|
||||
start = (unsigned long)INVALID_POINTER & ~(BOUND_T23_SIZE - 1);
|
||||
start = (size_t)INVALID_POINTER & ~(BOUND_T23_SIZE - 1);
|
||||
size = BOUND_T23_SIZE;
|
||||
mark_invalid(start, size);
|
||||
|
||||
@ -405,26 +454,40 @@ void __bound_init(void)
|
||||
* (b) on Linux >= v3.3, the alternative is to read
|
||||
* start_brk from /proc/self/stat
|
||||
*/
|
||||
start = (unsigned long)sbrk(0);
|
||||
start = (size_t)sbrk(0);
|
||||
size = 128 * 0x100000;
|
||||
mark_invalid(start, size);
|
||||
#endif
|
||||
|
||||
/* add all static bound check values */
|
||||
p = (int *)&__bounds_start;
|
||||
p = (size_t *)&__bounds_start;
|
||||
while (p[0] != 0) {
|
||||
__bound_new_region((void *)p[0], p[1]);
|
||||
p += 2;
|
||||
}
|
||||
|
||||
dprintf(stderr, "%s, %s() end\n\n", __FILE__, __FUNCTION__);
|
||||
}
|
||||
|
||||
void __bound_main_arg(void **p)
|
||||
{
|
||||
void *start = p;
|
||||
while (*p++);
|
||||
|
||||
dprintf(stderr, "%s, %s calling __bound_new_region(%p %x)\n",
|
||||
__FILE__, __FUNCTION__, start, (unsigned)((void *)p - start));
|
||||
|
||||
__bound_new_region(start, (void *) p - start);
|
||||
}
|
||||
|
||||
void __bound_exit(void)
|
||||
{
|
||||
dprintf(stderr, "%s, %s()\n", __FILE__, __FUNCTION__);
|
||||
restore_malloc_hooks();
|
||||
}
|
||||
|
||||
static inline void add_region(BoundEntry *e,
|
||||
unsigned long start, unsigned long size)
|
||||
size_t start, size_t size)
|
||||
{
|
||||
BoundEntry *e1;
|
||||
if (e->start == 0) {
|
||||
@ -444,13 +507,18 @@ static inline void add_region(BoundEntry *e,
|
||||
}
|
||||
|
||||
/* create a new region. It should not already exist in the region list */
|
||||
void __bound_new_region(void *p, unsigned long size)
|
||||
void __bound_new_region(void *p, size_t size)
|
||||
{
|
||||
unsigned long start, end;
|
||||
size_t start, end;
|
||||
BoundEntry *page, *e, *e2;
|
||||
int t1_start, t1_end, i, t2_start, t2_end;
|
||||
size_t t1_start, t1_end, i, t2_start, t2_end;
|
||||
|
||||
start = (unsigned long)p;
|
||||
dprintf(stderr, "%s, %s(%p, %x) start\n",
|
||||
__FILE__, __FUNCTION__, p, (unsigned)size);
|
||||
|
||||
__bound_init();
|
||||
|
||||
start = (size_t)p;
|
||||
end = start + size;
|
||||
t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS);
|
||||
t1_end = end >> (BOUND_T2_BITS + BOUND_T3_BITS);
|
||||
@ -461,10 +529,7 @@ void __bound_new_region(void *p, unsigned long size)
|
||||
((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
|
||||
t2_end = (end >> (BOUND_T3_BITS - BOUND_E_BITS)) &
|
||||
((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
|
||||
#ifdef BOUND_DEBUG
|
||||
printf("new %lx %lx %x %x %x %x\n",
|
||||
start, end, t1_start, t1_end, t2_start, t2_end);
|
||||
#endif
|
||||
|
||||
|
||||
e = (BoundEntry *)((char *)page + t2_start);
|
||||
add_region(e, start, size);
|
||||
@ -506,16 +571,17 @@ void __bound_new_region(void *p, unsigned long size)
|
||||
}
|
||||
add_region(e, start, size);
|
||||
}
|
||||
|
||||
dprintf(stderr, "%s, %s end\n", __FILE__, __FUNCTION__);
|
||||
}
|
||||
|
||||
/* delete a region */
|
||||
static inline void delete_region(BoundEntry *e,
|
||||
void *p, unsigned long empty_size)
|
||||
static inline void delete_region(BoundEntry *e, void *p, size_t empty_size)
|
||||
{
|
||||
unsigned long addr;
|
||||
size_t addr;
|
||||
BoundEntry *e1;
|
||||
|
||||
addr = (unsigned long)p;
|
||||
addr = (size_t)p;
|
||||
addr -= e->start;
|
||||
if (addr <= e->size) {
|
||||
/* region found is first one */
|
||||
@ -539,7 +605,7 @@ static inline void delete_region(BoundEntry *e,
|
||||
/* region not found: do nothing */
|
||||
if (e == NULL)
|
||||
break;
|
||||
addr = (unsigned long)p - e->start;
|
||||
addr = (size_t)p - e->start;
|
||||
if (addr <= e->size) {
|
||||
/* found: remove entry */
|
||||
e1->next = e->next;
|
||||
@ -554,11 +620,15 @@ static inline void delete_region(BoundEntry *e,
|
||||
/* return non zero if error */
|
||||
int __bound_delete_region(void *p)
|
||||
{
|
||||
unsigned long start, end, addr, size, empty_size;
|
||||
size_t start, end, addr, size, empty_size;
|
||||
BoundEntry *page, *e, *e2;
|
||||
int t1_start, t1_end, t2_start, t2_end, i;
|
||||
size_t t1_start, t1_end, t2_start, t2_end, i;
|
||||
|
||||
start = (unsigned long)p;
|
||||
dprintf(stderr, "%s %s() start\n", __FILE__, __FUNCTION__);
|
||||
|
||||
__bound_init();
|
||||
|
||||
start = (size_t)p;
|
||||
t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS);
|
||||
t2_start = (start >> (BOUND_T3_BITS - BOUND_E_BITS)) &
|
||||
((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
|
||||
@ -570,7 +640,7 @@ int __bound_delete_region(void *p)
|
||||
if (addr > e->size)
|
||||
e = __bound_find_region(e, p);
|
||||
/* test if invalid region */
|
||||
if (e->size == EMPTY_SIZE || (unsigned long)p != e->start)
|
||||
if (e->size == EMPTY_SIZE || (size_t)p != e->start)
|
||||
return -1;
|
||||
/* compute the size we put in invalid regions */
|
||||
if (e->is_invalid)
|
||||
@ -624,14 +694,17 @@ int __bound_delete_region(void *p)
|
||||
}
|
||||
delete_region(e, p, empty_size);
|
||||
}
|
||||
|
||||
dprintf(stderr, "%s %s() end\n", __FILE__, __FUNCTION__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return the size of the region starting at p, or EMPTY_SIZE if non
|
||||
existant region. */
|
||||
static unsigned long get_region_size(void *p)
|
||||
existent region. */
|
||||
static size_t get_region_size(void *p)
|
||||
{
|
||||
unsigned long addr = (unsigned long)p;
|
||||
size_t addr = (size_t)p;
|
||||
BoundEntry *e;
|
||||
|
||||
e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)];
|
||||
@ -641,7 +714,7 @@ static unsigned long get_region_size(void *p)
|
||||
addr -= e->start;
|
||||
if (addr > e->size)
|
||||
e = __bound_find_region(e, p);
|
||||
if (e->start != (unsigned long)p)
|
||||
if (e->start != (size_t)p)
|
||||
return EMPTY_SIZE;
|
||||
return e->size;
|
||||
}
|
||||
@ -709,6 +782,10 @@ void *__bound_malloc(size_t size, const void *caller)
|
||||
|
||||
if (!ptr)
|
||||
return NULL;
|
||||
|
||||
dprintf(stderr, "%s, %s calling __bound_new_region(%p, %x)\n",
|
||||
__FILE__, __FUNCTION__, ptr, (unsigned)size);
|
||||
|
||||
__bound_new_region(ptr, size);
|
||||
return ptr;
|
||||
}
|
||||
@ -738,6 +815,10 @@ void *__bound_memalign(size_t size, size_t align, const void *caller)
|
||||
|
||||
if (!ptr)
|
||||
return NULL;
|
||||
|
||||
dprintf(stderr, "%s, %s calling __bound_new_region(%p, %x)\n",
|
||||
__FILE__, __FUNCTION__, ptr, (unsigned)size);
|
||||
|
||||
__bound_new_region(ptr, size);
|
||||
return ptr;
|
||||
}
|
||||
@ -755,7 +836,7 @@ void __bound_free(void *ptr, const void *caller)
|
||||
void *__bound_realloc(void *ptr, size_t size, const void *caller)
|
||||
{
|
||||
void *ptr1;
|
||||
int old_size;
|
||||
size_t old_size;
|
||||
|
||||
if (size == 0) {
|
||||
__bound_free(ptr, caller);
|
||||
@ -790,23 +871,23 @@ void *__bound_calloc(size_t nmemb, size_t size)
|
||||
static void bound_dump(void)
|
||||
{
|
||||
BoundEntry *page, *e;
|
||||
int i, j;
|
||||
size_t i, j;
|
||||
|
||||
printf("region dump:\n");
|
||||
fprintf(stderr, "region dump:\n");
|
||||
for(i=0;i<BOUND_T1_SIZE;i++) {
|
||||
page = __bound_t1[i];
|
||||
for(j=0;j<BOUND_T2_SIZE;j++) {
|
||||
e = page + j;
|
||||
/* do not print invalid or empty entries */
|
||||
if (e->size != EMPTY_SIZE && e->start != 0) {
|
||||
printf("%08x:",
|
||||
fprintf(stderr, "%08x:",
|
||||
(i << (BOUND_T2_BITS + BOUND_T3_BITS)) +
|
||||
(j << BOUND_T3_BITS));
|
||||
do {
|
||||
printf(" %08lx:%08lx", e->start, e->start + e->size);
|
||||
fprintf(stderr, " %08lx:%08lx", e->start, e->start + e->size);
|
||||
e = e->next;
|
||||
} while (e != NULL);
|
||||
printf("\n");
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -820,19 +901,28 @@ static void __bound_check(const void *p, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return;
|
||||
p = __bound_ptr_add((void *)p, size);
|
||||
p = __bound_ptr_add((void *)p, size - 1);
|
||||
if (p == INVALID_POINTER)
|
||||
bound_error("invalid pointer");
|
||||
}
|
||||
|
||||
void *__bound_memcpy(void *dst, const void *src, size_t size)
|
||||
{
|
||||
void* p;
|
||||
|
||||
dprintf(stderr, "%s %s: start, dst=%p src=%p size=%x\n",
|
||||
__FILE__, __FUNCTION__, dst, src, (unsigned)size);
|
||||
|
||||
__bound_check(dst, size);
|
||||
__bound_check(src, size);
|
||||
/* check also region overlap */
|
||||
if (src >= dst && src < dst + size)
|
||||
bound_error("overlapping regions in memcpy()");
|
||||
return memcpy(dst, src, size);
|
||||
|
||||
p = memcpy(dst, src, size);
|
||||
|
||||
dprintf(stderr, "%s %s: end, p=%p\n", __FILE__, __FUNCTION__, p);
|
||||
return p;
|
||||
}
|
||||
|
||||
void *__bound_memmove(void *dst, const void *src, size_t size)
|
||||
@ -852,7 +942,7 @@ void *__bound_memset(void *dst, int c, size_t size)
|
||||
int __bound_strlen(const char *s)
|
||||
{
|
||||
const char *p;
|
||||
int len;
|
||||
size_t len;
|
||||
|
||||
len = 0;
|
||||
for(;;) {
|
||||
@ -868,8 +958,14 @@ int __bound_strlen(const char *s)
|
||||
|
||||
char *__bound_strcpy(char *dst, const char *src)
|
||||
{
|
||||
int len;
|
||||
len = __bound_strlen(src);
|
||||
return __bound_memcpy(dst, src, len + 1);
|
||||
}
|
||||
size_t len;
|
||||
void *p;
|
||||
|
||||
dprintf(stderr, "%s %s: strcpy start, dst=%p src=%p\n",
|
||||
__FILE__, __FUNCTION__, dst, src);
|
||||
len = __bound_strlen(src);
|
||||
p = __bound_memcpy(dst, src, len + 1);
|
||||
dprintf(stderr, "%s %s: strcpy end, p = %p\n",
|
||||
__FILE__, __FUNCTION__, p);
|
||||
return p;
|
||||
}
|
||||
|
||||
664
lib/lib-arm64.c
Normal file
664
lib/lib-arm64.c
Normal file
@ -0,0 +1,664 @@
|
||||
/*
|
||||
* TCC runtime library for arm64.
|
||||
*
|
||||
* Copyright (c) 2015 Edmund Grimley Evans
|
||||
*
|
||||
* Copying and distribution of this file, with or without modification,
|
||||
* are permitted in any medium without royalty provided the copyright
|
||||
* notice and this notice are preserved. This file is offered as-is,
|
||||
* without any warranty.
|
||||
*/
|
||||
|
||||
#ifdef __TINYC__
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef short int16_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef int int32_t;
|
||||
typedef unsigned uint32_t;
|
||||
typedef long long int64_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
void *memcpy(void*,void*,__SIZE_TYPE__);
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
void __clear_cache(void *beg, void *end)
|
||||
{
|
||||
__arm64_clear_cache(beg, end);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint64_t x0, x1;
|
||||
} u128_t;
|
||||
|
||||
static long double f3_zero(int sgn)
|
||||
{
|
||||
long double f;
|
||||
u128_t x = { 0, (uint64_t)sgn << 63 };
|
||||
memcpy(&f, &x, 16);
|
||||
return f;
|
||||
}
|
||||
|
||||
static long double f3_infinity(int sgn)
|
||||
{
|
||||
long double f;
|
||||
u128_t x = { 0, (uint64_t)sgn << 63 | 0x7fff000000000000 };
|
||||
memcpy(&f, &x, 16);
|
||||
return f;
|
||||
}
|
||||
|
||||
static long double f3_NaN(void)
|
||||
{
|
||||
long double f;
|
||||
#if 0
|
||||
// ARM's default NaN usually has just the top fraction bit set:
|
||||
u128_t x = { 0, 0x7fff800000000000 };
|
||||
#else
|
||||
// GCC's library sets all fraction bits:
|
||||
u128_t x = { -1, 0x7fffffffffffffff };
|
||||
#endif
|
||||
memcpy(&f, &x, 16);
|
||||
return f;
|
||||
}
|
||||
|
||||
static int fp3_convert_NaN(long double *f, int sgn, u128_t mnt)
|
||||
{
|
||||
u128_t x = { mnt.x0,
|
||||
mnt.x1 | 0x7fff800000000000 | (uint64_t)sgn << 63 };
|
||||
memcpy(f, &x, 16);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int fp3_detect_NaNs(long double *f,
|
||||
int a_sgn, int a_exp, u128_t a,
|
||||
int b_sgn, int b_exp, u128_t b)
|
||||
{
|
||||
// Detect signalling NaNs:
|
||||
if (a_exp == 32767 && (a.x0 | a.x1 << 16) && !(a.x1 >> 47 & 1))
|
||||
return fp3_convert_NaN(f, a_sgn, a);
|
||||
if (b_exp == 32767 && (b.x0 | b.x1 << 16) && !(b.x1 >> 47 & 1))
|
||||
return fp3_convert_NaN(f, b_sgn, b);
|
||||
|
||||
// Detect quiet NaNs:
|
||||
if (a_exp == 32767 && (a.x0 | a.x1 << 16))
|
||||
return fp3_convert_NaN(f, a_sgn, a);
|
||||
if (b_exp == 32767 && (b.x0 | b.x1 << 16))
|
||||
return fp3_convert_NaN(f, b_sgn, b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void f3_unpack(int *sgn, int32_t *exp, u128_t *mnt, long double f)
|
||||
{
|
||||
u128_t x;
|
||||
memcpy(&x, &f, 16);
|
||||
*sgn = x.x1 >> 63;
|
||||
*exp = x.x1 >> 48 & 32767;
|
||||
x.x1 = x.x1 << 16 >> 16;
|
||||
if (*exp)
|
||||
x.x1 |= (uint64_t)1 << 48;
|
||||
else
|
||||
*exp = 1;
|
||||
*mnt = x;
|
||||
}
|
||||
|
||||
static u128_t f3_normalise(int32_t *exp, u128_t mnt)
|
||||
{
|
||||
int sh;
|
||||
if (!(mnt.x0 | mnt.x1))
|
||||
return mnt;
|
||||
if (!mnt.x1) {
|
||||
mnt.x1 = mnt.x0;
|
||||
mnt.x0 = 0;
|
||||
*exp -= 64;
|
||||
}
|
||||
for (sh = 32; sh; sh >>= 1) {
|
||||
if (!(mnt.x1 >> (64 - sh))) {
|
||||
mnt.x1 = mnt.x1 << sh | mnt.x0 >> (64 - sh);
|
||||
mnt.x0 = mnt.x0 << sh;
|
||||
*exp -= sh;
|
||||
}
|
||||
}
|
||||
return mnt;
|
||||
}
|
||||
|
||||
static u128_t f3_sticky_shift(int32_t sh, u128_t x)
|
||||
{
|
||||
if (sh >= 128) {
|
||||
x.x0 = !!(x.x0 | x.x1);
|
||||
x.x1 = 0;
|
||||
return x;
|
||||
}
|
||||
if (sh >= 64) {
|
||||
x.x0 = x.x1 | !!x.x0;
|
||||
x.x1 = 0;
|
||||
sh -= 64;
|
||||
}
|
||||
if (sh > 0) {
|
||||
x.x0 = x.x0 >> sh | x.x1 << (64 - sh) | !!(x.x0 << (64 - sh));
|
||||
x.x1 = x.x1 >> sh;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
static long double f3_round(int sgn, int32_t exp, u128_t x)
|
||||
{
|
||||
long double f;
|
||||
int error;
|
||||
|
||||
if (exp > 0) {
|
||||
x = f3_sticky_shift(13, x);
|
||||
}
|
||||
else {
|
||||
x = f3_sticky_shift(14 - exp, x);
|
||||
exp = 0;
|
||||
}
|
||||
|
||||
error = x.x0 & 3;
|
||||
x.x0 = x.x0 >> 2 | x.x1 << 62;
|
||||
x.x1 = x.x1 >> 2;
|
||||
|
||||
if (error == 3 || ((error == 2) & (x.x0 & 1))) {
|
||||
if (!++x.x0) {
|
||||
++x.x1;
|
||||
if (x.x1 == (uint64_t)1 << 48)
|
||||
exp = 1;
|
||||
else if (x.x1 == (uint64_t)1 << 49) {
|
||||
++exp;
|
||||
x.x0 = x.x0 >> 1 | x.x1 << 63;
|
||||
x.x1 = x.x1 >> 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (exp >= 32767)
|
||||
return f3_infinity(sgn);
|
||||
|
||||
x.x1 = x.x1 << 16 >> 16 | (uint64_t)exp << 48 | (uint64_t)sgn << 63;
|
||||
memcpy(&f, &x, 16);
|
||||
return f;
|
||||
}
|
||||
|
||||
static long double f3_add(long double fa, long double fb, int neg)
|
||||
{
|
||||
u128_t a, b, x;
|
||||
int32_t a_exp, b_exp, x_exp;
|
||||
int a_sgn, b_sgn, x_sgn;
|
||||
long double fx;
|
||||
|
||||
f3_unpack(&a_sgn, &a_exp, &a, fa);
|
||||
f3_unpack(&b_sgn, &b_exp, &b, fb);
|
||||
|
||||
if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b))
|
||||
return fx;
|
||||
|
||||
b_sgn ^= neg;
|
||||
|
||||
// Handle infinities and zeroes:
|
||||
if (a_exp == 32767 && b_exp == 32767 && a_sgn != b_sgn)
|
||||
return f3_NaN();
|
||||
if (a_exp == 32767)
|
||||
return f3_infinity(a_sgn);
|
||||
if (b_exp == 32767)
|
||||
return f3_infinity(b_sgn);
|
||||
if (!(a.x0 | a.x1 | b.x0 | b.x1))
|
||||
return f3_zero(a_sgn & b_sgn);
|
||||
|
||||
a.x1 = a.x1 << 3 | a.x0 >> 61;
|
||||
a.x0 = a.x0 << 3;
|
||||
b.x1 = b.x1 << 3 | b.x0 >> 61;
|
||||
b.x0 = b.x0 << 3;
|
||||
|
||||
if (a_exp <= b_exp) {
|
||||
a = f3_sticky_shift(b_exp - a_exp, a);
|
||||
a_exp = b_exp;
|
||||
}
|
||||
else {
|
||||
b = f3_sticky_shift(a_exp - b_exp, b);
|
||||
b_exp = a_exp;
|
||||
}
|
||||
|
||||
x_sgn = a_sgn;
|
||||
x_exp = a_exp;
|
||||
if (a_sgn == b_sgn) {
|
||||
x.x0 = a.x0 + b.x0;
|
||||
x.x1 = a.x1 + b.x1 + (x.x0 < a.x0);
|
||||
}
|
||||
else {
|
||||
x.x0 = a.x0 - b.x0;
|
||||
x.x1 = a.x1 - b.x1 - (x.x0 > a.x0);
|
||||
if (x.x1 >> 63) {
|
||||
x_sgn ^= 1;
|
||||
x.x0 = -x.x0;
|
||||
x.x1 = -x.x1 - !!x.x0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(x.x0 | x.x1))
|
||||
return f3_zero(0);
|
||||
|
||||
x = f3_normalise(&x_exp, x);
|
||||
|
||||
return f3_round(x_sgn, x_exp + 12, x);
|
||||
}
|
||||
|
||||
long double __addtf3(long double a, long double b)
|
||||
{
|
||||
return f3_add(a, b, 0);
|
||||
}
|
||||
|
||||
long double __subtf3(long double a, long double b)
|
||||
{
|
||||
return f3_add(a, b, 1);
|
||||
}
|
||||
|
||||
long double __multf3(long double fa, long double fb)
|
||||
{
|
||||
u128_t a, b, x;
|
||||
int32_t a_exp, b_exp, x_exp;
|
||||
int a_sgn, b_sgn, x_sgn;
|
||||
long double fx;
|
||||
|
||||
f3_unpack(&a_sgn, &a_exp, &a, fa);
|
||||
f3_unpack(&b_sgn, &b_exp, &b, fb);
|
||||
|
||||
if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b))
|
||||
return fx;
|
||||
|
||||
// Handle infinities and zeroes:
|
||||
if ((a_exp == 32767 && !(b.x0 | b.x1)) ||
|
||||
(b_exp == 32767 && !(a.x0 | a.x1)))
|
||||
return f3_NaN();
|
||||
if (a_exp == 32767 || b_exp == 32767)
|
||||
return f3_infinity(a_sgn ^ b_sgn);
|
||||
if (!(a.x0 | a.x1) || !(b.x0 | b.x1))
|
||||
return f3_zero(a_sgn ^ b_sgn);
|
||||
|
||||
a = f3_normalise(&a_exp, a);
|
||||
b = f3_normalise(&b_exp, b);
|
||||
|
||||
x_sgn = a_sgn ^ b_sgn;
|
||||
x_exp = a_exp + b_exp - 16352;
|
||||
|
||||
{
|
||||
// Convert to base (1 << 30), discarding bottom 6 bits, which are zero,
|
||||
// so there are (32, 30, 30, 30) bits in (a3, a2, a1, a0):
|
||||
uint64_t a0 = a.x0 << 28 >> 34;
|
||||
uint64_t b0 = b.x0 << 28 >> 34;
|
||||
uint64_t a1 = a.x0 >> 36 | a.x1 << 62 >> 34;
|
||||
uint64_t b1 = b.x0 >> 36 | b.x1 << 62 >> 34;
|
||||
uint64_t a2 = a.x1 << 32 >> 34;
|
||||
uint64_t b2 = b.x1 << 32 >> 34;
|
||||
uint64_t a3 = a.x1 >> 32;
|
||||
uint64_t b3 = b.x1 >> 32;
|
||||
// Use 16 small multiplications and additions that do not overflow:
|
||||
uint64_t x0 = a0 * b0;
|
||||
uint64_t x1 = (x0 >> 30) + a0 * b1 + a1 * b0;
|
||||
uint64_t x2 = (x1 >> 30) + a0 * b2 + a1 * b1 + a2 * b0;
|
||||
uint64_t x3 = (x2 >> 30) + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0;
|
||||
uint64_t x4 = (x3 >> 30) + a1 * b3 + a2 * b2 + a3 * b1;
|
||||
uint64_t x5 = (x4 >> 30) + a2 * b3 + a3 * b2;
|
||||
uint64_t x6 = (x5 >> 30) + a3 * b3;
|
||||
// We now have (64, 30, 30, ...) bits in (x6, x5, x4, ...).
|
||||
// Take the top 128 bits, setting bottom bit if any lower bits were set:
|
||||
uint64_t y0 = (x5 << 34 | x4 << 34 >> 30 | x3 << 34 >> 60 |
|
||||
!!(x3 << 38 | (x2 | x1 | x0) << 34));
|
||||
uint64_t y1 = x6;
|
||||
// Top bit may be zero. Renormalise:
|
||||
if (!(y1 >> 63)) {
|
||||
y1 = y1 << 1 | y0 >> 63;
|
||||
y0 = y0 << 1;
|
||||
--x_exp;
|
||||
}
|
||||
x.x0 = y0;
|
||||
x.x1 = y1;
|
||||
}
|
||||
|
||||
return f3_round(x_sgn, x_exp, x);
|
||||
}
|
||||
|
||||
long double __divtf3(long double fa, long double fb)
|
||||
{
|
||||
u128_t a, b, x;
|
||||
int32_t a_exp, b_exp, x_exp;
|
||||
int a_sgn, b_sgn, x_sgn, i;
|
||||
long double fx;
|
||||
|
||||
f3_unpack(&a_sgn, &a_exp, &a, fa);
|
||||
f3_unpack(&b_sgn, &b_exp, &b, fb);
|
||||
|
||||
if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b))
|
||||
return fx;
|
||||
|
||||
// Handle infinities and zeroes:
|
||||
if ((a_exp == 32767 && b_exp == 32767) ||
|
||||
(!(a.x0 | a.x1) && !(b.x0 | b.x1)))
|
||||
return f3_NaN();
|
||||
if (a_exp == 32767 || !(b.x0 | b.x1))
|
||||
return f3_infinity(a_sgn ^ b_sgn);
|
||||
if (!(a.x0 | a.x1) || b_exp == 32767)
|
||||
return f3_zero(a_sgn ^ b_sgn);
|
||||
|
||||
a = f3_normalise(&a_exp, a);
|
||||
b = f3_normalise(&b_exp, b);
|
||||
|
||||
x_sgn = a_sgn ^ b_sgn;
|
||||
x_exp = a_exp - b_exp + 16395;
|
||||
|
||||
a.x0 = a.x0 >> 1 | a.x1 << 63;
|
||||
a.x1 = a.x1 >> 1;
|
||||
b.x0 = b.x0 >> 1 | b.x1 << 63;
|
||||
b.x1 = b.x1 >> 1;
|
||||
x.x0 = 0;
|
||||
x.x1 = 0;
|
||||
for (i = 0; i < 116; i++) {
|
||||
x.x1 = x.x1 << 1 | x.x0 >> 63;
|
||||
x.x0 = x.x0 << 1;
|
||||
if (a.x1 > b.x1 || (a.x1 == b.x1 && a.x0 >= b.x0)) {
|
||||
a.x1 = a.x1 - b.x1 - (a.x0 < b.x0);
|
||||
a.x0 = a.x0 - b.x0;
|
||||
x.x0 |= 1;
|
||||
}
|
||||
a.x1 = a.x1 << 1 | a.x0 >> 63;
|
||||
a.x0 = a.x0 << 1;
|
||||
}
|
||||
x.x0 |= !!(a.x0 | a.x1);
|
||||
|
||||
x = f3_normalise(&x_exp, x);
|
||||
|
||||
return f3_round(x_sgn, x_exp, x);
|
||||
}
|
||||
|
||||
long double __extendsftf2(float f)
|
||||
{
|
||||
long double fx;
|
||||
u128_t x;
|
||||
uint32_t a;
|
||||
uint64_t aa;
|
||||
memcpy(&a, &f, 4);
|
||||
aa = a;
|
||||
x.x0 = 0;
|
||||
if (!(a << 1))
|
||||
x.x1 = aa << 32;
|
||||
else if (a << 1 >> 24 == 255)
|
||||
x.x1 = (0x7fff000000000000 | aa >> 31 << 63 | aa << 41 >> 16 |
|
||||
(uint64_t)!!(a << 9) << 47);
|
||||
else
|
||||
x.x1 = (aa >> 31 << 63 | ((aa >> 23 & 255) + 16256) << 48 |
|
||||
aa << 41 >> 16);
|
||||
memcpy(&fx, &x, 16);
|
||||
return fx;
|
||||
}
|
||||
|
||||
long double __extenddftf2(double f)
|
||||
{
|
||||
long double fx;
|
||||
u128_t x;
|
||||
uint64_t a;
|
||||
memcpy(&a, &f, 8);
|
||||
x.x0 = a << 60;
|
||||
if (!(a << 1))
|
||||
x.x1 = a;
|
||||
else if (a << 1 >> 53 == 2047)
|
||||
x.x1 = (0x7fff000000000000 | a >> 63 << 63 | a << 12 >> 16 |
|
||||
(uint64_t)!!(a << 12) << 47);
|
||||
else
|
||||
x.x1 = a >> 63 << 63 | ((a >> 52 & 2047) + 15360) << 48 | a << 12 >> 16;
|
||||
memcpy(&fx, &x, 16);
|
||||
return fx;
|
||||
}
|
||||
|
||||
float __trunctfsf2(long double f)
|
||||
{
|
||||
u128_t mnt;
|
||||
int32_t exp;
|
||||
int sgn;
|
||||
uint32_t x;
|
||||
float fx;
|
||||
|
||||
f3_unpack(&sgn, &exp, &mnt, f);
|
||||
|
||||
if (exp == 32767 && (mnt.x0 | mnt.x1 << 16))
|
||||
x = 0x7fc00000 | (uint32_t)sgn << 31 | (mnt.x1 >> 25 & 0x007fffff);
|
||||
else if (exp > 16510)
|
||||
x = 0x7f800000 | (uint32_t)sgn << 31;
|
||||
else if (exp < 16233)
|
||||
x = (uint32_t)sgn << 31;
|
||||
else {
|
||||
exp -= 16257;
|
||||
x = mnt.x1 >> 23 | !!(mnt.x0 | mnt.x1 << 41);
|
||||
if (exp < 0) {
|
||||
x = x >> -exp | !!(x << (32 + exp));
|
||||
exp = 0;
|
||||
}
|
||||
if ((x & 3) == 3 || (x & 7) == 6)
|
||||
x += 4;
|
||||
x = ((x >> 2) + (exp << 23)) | (uint32_t)sgn << 31;
|
||||
}
|
||||
memcpy(&fx, &x, 4);
|
||||
return fx;
|
||||
}
|
||||
|
||||
double __trunctfdf2(long double f)
|
||||
{
|
||||
u128_t mnt;
|
||||
int32_t exp;
|
||||
int sgn;
|
||||
uint64_t x;
|
||||
double fx;
|
||||
|
||||
f3_unpack(&sgn, &exp, &mnt, f);
|
||||
|
||||
if (exp == 32767 && (mnt.x0 | mnt.x1 << 16))
|
||||
x = (0x7ff8000000000000 | (uint64_t)sgn << 63 |
|
||||
mnt.x1 << 16 >> 12 | mnt.x0 >> 60);
|
||||
else if (exp > 17406)
|
||||
x = 0x7ff0000000000000 | (uint64_t)sgn << 63;
|
||||
else if (exp < 15308)
|
||||
x = (uint64_t)sgn << 63;
|
||||
else {
|
||||
exp -= 15361;
|
||||
x = mnt.x1 << 6 | mnt.x0 >> 58 | !!(mnt.x0 << 6);
|
||||
if (exp < 0) {
|
||||
x = x >> -exp | !!(x << (64 + exp));
|
||||
exp = 0;
|
||||
}
|
||||
if ((x & 3) == 3 || (x & 7) == 6)
|
||||
x += 4;
|
||||
x = ((x >> 2) + ((uint64_t)exp << 52)) | (uint64_t)sgn << 63;
|
||||
}
|
||||
memcpy(&fx, &x, 8);
|
||||
return fx;
|
||||
}
|
||||
|
||||
int32_t __fixtfsi(long double fa)
|
||||
{
|
||||
u128_t a;
|
||||
int32_t a_exp;
|
||||
int a_sgn;
|
||||
int32_t x;
|
||||
f3_unpack(&a_sgn, &a_exp, &a, fa);
|
||||
if (a_exp < 16369)
|
||||
return 0;
|
||||
if (a_exp > 16413)
|
||||
return a_sgn ? -0x80000000 : 0x7fffffff;
|
||||
x = a.x1 >> (16431 - a_exp);
|
||||
return a_sgn ? -x : x;
|
||||
}
|
||||
|
||||
int64_t __fixtfdi(long double fa)
|
||||
{
|
||||
u128_t a;
|
||||
int32_t a_exp;
|
||||
int a_sgn;
|
||||
int64_t x;
|
||||
f3_unpack(&a_sgn, &a_exp, &a, fa);
|
||||
if (a_exp < 16383)
|
||||
return 0;
|
||||
if (a_exp > 16445)
|
||||
return a_sgn ? -0x8000000000000000 : 0x7fffffffffffffff;
|
||||
x = (a.x1 << 15 | a.x0 >> 49) >> (16446 - a_exp);
|
||||
return a_sgn ? -x : x;
|
||||
}
|
||||
|
||||
uint32_t __fixunstfsi(long double fa)
|
||||
{
|
||||
u128_t a;
|
||||
int32_t a_exp;
|
||||
int a_sgn;
|
||||
f3_unpack(&a_sgn, &a_exp, &a, fa);
|
||||
if (a_sgn || a_exp < 16369)
|
||||
return 0;
|
||||
if (a_exp > 16414)
|
||||
return -1;
|
||||
return a.x1 >> (16431 - a_exp);
|
||||
}
|
||||
|
||||
uint64_t __fixunstfdi(long double fa)
|
||||
{
|
||||
u128_t a;
|
||||
int32_t a_exp;
|
||||
int a_sgn;
|
||||
f3_unpack(&a_sgn, &a_exp, &a, fa);
|
||||
if (a_sgn || a_exp < 16383)
|
||||
return 0;
|
||||
if (a_exp > 16446)
|
||||
return -1;
|
||||
return (a.x1 << 15 | a.x0 >> 49) >> (16446 - a_exp);
|
||||
}
|
||||
|
||||
long double __floatsitf(int32_t a)
|
||||
{
|
||||
int sgn = 0;
|
||||
int exp = 16414;
|
||||
uint32_t mnt = a;
|
||||
u128_t x = { 0, 0 };
|
||||
long double f;
|
||||
int i;
|
||||
if (a) {
|
||||
if (a < 0) {
|
||||
sgn = 1;
|
||||
mnt = -mnt;
|
||||
}
|
||||
for (i = 16; i; i >>= 1)
|
||||
if (!(mnt >> (32 - i))) {
|
||||
mnt <<= i;
|
||||
exp -= i;
|
||||
}
|
||||
x.x1 = ((uint64_t)sgn << 63 | (uint64_t)exp << 48 |
|
||||
(uint64_t)(mnt << 1) << 16);
|
||||
}
|
||||
memcpy(&f, &x, 16);
|
||||
return f;
|
||||
}
|
||||
|
||||
long double __floatditf(int64_t a)
|
||||
{
|
||||
int sgn = 0;
|
||||
int exp = 16446;
|
||||
uint64_t mnt = a;
|
||||
u128_t x = { 0, 0 };
|
||||
long double f;
|
||||
int i;
|
||||
if (a) {
|
||||
if (a < 0) {
|
||||
sgn = 1;
|
||||
mnt = -mnt;
|
||||
}
|
||||
for (i = 32; i; i >>= 1)
|
||||
if (!(mnt >> (64 - i))) {
|
||||
mnt <<= i;
|
||||
exp -= i;
|
||||
}
|
||||
x.x0 = mnt << 49;
|
||||
x.x1 = (uint64_t)sgn << 63 | (uint64_t)exp << 48 | mnt << 1 >> 16;
|
||||
}
|
||||
memcpy(&f, &x, 16);
|
||||
return f;
|
||||
}
|
||||
|
||||
long double __floatunsitf(uint32_t a)
|
||||
{
|
||||
int exp = 16414;
|
||||
uint32_t mnt = a;
|
||||
u128_t x = { 0, 0 };
|
||||
long double f;
|
||||
int i;
|
||||
if (a) {
|
||||
for (i = 16; i; i >>= 1)
|
||||
if (!(mnt >> (32 - i))) {
|
||||
mnt <<= i;
|
||||
exp -= i;
|
||||
}
|
||||
x.x1 = (uint64_t)exp << 48 | (uint64_t)(mnt << 1) << 16;
|
||||
}
|
||||
memcpy(&f, &x, 16);
|
||||
return f;
|
||||
}
|
||||
|
||||
long double __floatunditf(uint64_t a)
|
||||
{
|
||||
int exp = 16446;
|
||||
uint64_t mnt = a;
|
||||
u128_t x = { 0, 0 };
|
||||
long double f;
|
||||
int i;
|
||||
if (a) {
|
||||
for (i = 32; i; i >>= 1)
|
||||
if (!(mnt >> (64 - i))) {
|
||||
mnt <<= i;
|
||||
exp -= i;
|
||||
}
|
||||
x.x0 = mnt << 49;
|
||||
x.x1 = (uint64_t)exp << 48 | mnt << 1 >> 16;
|
||||
}
|
||||
memcpy(&f, &x, 16);
|
||||
return f;
|
||||
}
|
||||
|
||||
static int f3_cmp(long double fa, long double fb)
|
||||
{
|
||||
u128_t a, b;
|
||||
memcpy(&a, &fa, 16);
|
||||
memcpy(&b, &fb, 16);
|
||||
return (!(a.x0 | a.x1 << 1 | b.x0 | b.x1 << 1) ? 0 :
|
||||
((a.x1 << 1 >> 49 == 0x7fff && (a.x0 | a.x1 << 16)) ||
|
||||
(b.x1 << 1 >> 49 == 0x7fff && (b.x0 | b.x1 << 16))) ? 2 :
|
||||
a.x1 >> 63 != b.x1 >> 63 ? (int)(b.x1 >> 63) - (int)(a.x1 >> 63) :
|
||||
a.x1 < b.x1 ? (int)(a.x1 >> 63 << 1) - 1 :
|
||||
a.x1 > b.x1 ? 1 - (int)(a.x1 >> 63 << 1) :
|
||||
a.x0 < b.x0 ? (int)(a.x1 >> 63 << 1) - 1 :
|
||||
b.x0 < a.x0 ? 1 - (int)(a.x1 >> 63 << 1) : 0);
|
||||
}
|
||||
|
||||
int __eqtf2(long double a, long double b)
|
||||
{
|
||||
return !!f3_cmp(a, b);
|
||||
}
|
||||
|
||||
int __netf2(long double a, long double b)
|
||||
{
|
||||
return !!f3_cmp(a, b);
|
||||
}
|
||||
|
||||
int __lttf2(long double a, long double b)
|
||||
{
|
||||
return f3_cmp(a, b);
|
||||
}
|
||||
|
||||
int __letf2(long double a, long double b)
|
||||
{
|
||||
return f3_cmp(a, b);
|
||||
}
|
||||
|
||||
int __gttf2(long double a, long double b)
|
||||
{
|
||||
return -f3_cmp(b, a);
|
||||
}
|
||||
|
||||
int __getf2(long double a, long double b)
|
||||
{
|
||||
return -f3_cmp(b, a);
|
||||
}
|
||||
119
lib/libtcc1.c
119
lib/libtcc1.c
@ -103,14 +103,14 @@ union double_long {
|
||||
|
||||
union float_long {
|
||||
float f;
|
||||
long l;
|
||||
unsigned int l;
|
||||
};
|
||||
|
||||
/* XXX: we don't support several builtin supports for now */
|
||||
#ifndef __x86_64__
|
||||
#if !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_ARM)
|
||||
|
||||
/* XXX: use gcc/tcc intrinsic ? */
|
||||
#if defined(__i386__)
|
||||
#if defined(TCC_TARGET_I386)
|
||||
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
|
||||
__asm__ ("subl %5,%1\n\tsbbl %3,%0" \
|
||||
: "=r" ((USItype) (sh)), \
|
||||
@ -478,13 +478,6 @@ long long __ashldi3(long long a, int b)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__i386__)
|
||||
/* FPU control word for rounding to nearest mode */
|
||||
unsigned short __tcc_fpu_control = 0x137f;
|
||||
/* FPU control word for round to zero mode for int conversion */
|
||||
unsigned short __tcc_int_fpu_control = 0x137f | 0x0c00;
|
||||
#endif
|
||||
|
||||
#endif /* !__x86_64__ */
|
||||
|
||||
/* XXX: fix tcc's code generator to do this instead */
|
||||
@ -605,22 +598,50 @@ unsigned long long __fixunsxfdi (long double a1)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(__x86_64__) && !defined(_WIN64)
|
||||
long long __fixsfdi (float a1)
|
||||
{
|
||||
long long ret; int s;
|
||||
ret = __fixunssfdi((s = a1 >= 0) ? a1 : -a1);
|
||||
return s ? ret : -ret;
|
||||
}
|
||||
|
||||
/* helper functions for stdarg.h */
|
||||
long long __fixdfdi (double a1)
|
||||
{
|
||||
long long ret; int s;
|
||||
ret = __fixunsdfdi((s = a1 >= 0) ? a1 : -a1);
|
||||
return s ? ret : -ret;
|
||||
}
|
||||
|
||||
long long __fixxfdi (long double a1)
|
||||
{
|
||||
long long ret; int s;
|
||||
ret = __fixunsxfdi((s = a1 >= 0) ? a1 : -a1);
|
||||
return s ? ret : -ret;
|
||||
}
|
||||
|
||||
#if defined(TCC_TARGET_X86_64) && !defined(_WIN64)
|
||||
|
||||
#include <stdlib.h>
|
||||
#ifndef __TINYC__
|
||||
/* gives "incompatible types for redefinition of __va_arg" below */
|
||||
#include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
# include <stdio.h>
|
||||
# include <string.h>
|
||||
# undef __va_start
|
||||
# undef __va_arg
|
||||
# undef __va_copy
|
||||
# undef __va_end
|
||||
#else
|
||||
/* Avoid include files, they may not be available when cross compiling */
|
||||
extern void *memset(void *s, int c, __SIZE_TYPE__ n);
|
||||
extern void abort(void);
|
||||
#endif
|
||||
|
||||
/* This should be in sync with our include/stdarg.h */
|
||||
enum __va_arg_type {
|
||||
__va_gen_reg, __va_float_reg, __va_stack
|
||||
};
|
||||
|
||||
/* GCC compatible definition of va_list. */
|
||||
struct __va_list_struct {
|
||||
typedef struct {
|
||||
unsigned int gp_offset;
|
||||
unsigned int fp_offset;
|
||||
union {
|
||||
@ -628,30 +649,28 @@ struct __va_list_struct {
|
||||
char *overflow_arg_area;
|
||||
};
|
||||
char *reg_save_area;
|
||||
};
|
||||
} __va_list_struct;
|
||||
|
||||
void *__va_start(void *fp)
|
||||
void __va_start(__va_list_struct *ap, void *fp)
|
||||
{
|
||||
struct __va_list_struct *ap =
|
||||
(struct __va_list_struct *)malloc(sizeof(struct __va_list_struct));
|
||||
*ap = *(struct __va_list_struct *)((char *)fp - 16);
|
||||
memset(ap, 0, sizeof(__va_list_struct));
|
||||
*ap = *(__va_list_struct *)((char *)fp - 16);
|
||||
ap->overflow_arg_area = (char *)fp + ap->overflow_offset;
|
||||
ap->reg_save_area = (char *)fp - 176 - 16;
|
||||
return ap;
|
||||
}
|
||||
|
||||
void *__va_arg(struct __va_list_struct *ap,
|
||||
void *__va_arg(__va_list_struct *ap,
|
||||
enum __va_arg_type arg_type,
|
||||
int size)
|
||||
int size, int align)
|
||||
{
|
||||
size = (size + 7) & ~7;
|
||||
align = (align + 7) & ~7;
|
||||
switch (arg_type) {
|
||||
case __va_gen_reg:
|
||||
if (ap->gp_offset < 48) {
|
||||
ap->gp_offset += 8;
|
||||
return ap->reg_save_area + ap->gp_offset - 8;
|
||||
if (ap->gp_offset + size <= 48) {
|
||||
ap->gp_offset += size;
|
||||
return ap->reg_save_area + ap->gp_offset - size;
|
||||
}
|
||||
size = 8;
|
||||
goto use_overflow_area;
|
||||
|
||||
case __va_float_reg:
|
||||
@ -665,27 +684,35 @@ void *__va_arg(struct __va_list_struct *ap,
|
||||
case __va_stack:
|
||||
use_overflow_area:
|
||||
ap->overflow_arg_area += size;
|
||||
ap->overflow_arg_area = (char*)((long long)(ap->overflow_arg_area + align - 1) & -align);
|
||||
return ap->overflow_arg_area - size;
|
||||
|
||||
default:
|
||||
#ifndef __TINYC__
|
||||
fprintf(stderr, "unknown ABI type for __va_arg\n");
|
||||
#endif
|
||||
default: /* should never happen */
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void *__va_copy(struct __va_list_struct *src)
|
||||
{
|
||||
struct __va_list_struct *dest =
|
||||
(struct __va_list_struct *)malloc(sizeof(struct __va_list_struct));
|
||||
*dest = *src;
|
||||
return dest;
|
||||
}
|
||||
|
||||
void __va_end(struct __va_list_struct *ap)
|
||||
{
|
||||
free(ap);
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
||||
|
||||
#if defined TCC_TARGET_ARM && !defined __TINYC__
|
||||
#define _GNU_SOURCE
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Flushing for tccrun */
|
||||
void __clear_cache(void *beginning, void *end)
|
||||
{
|
||||
/* __ARM_NR_cacheflush is kernel private and should not be used in user space.
|
||||
* However, there is no ARM asm parser in tcc so we use it for now */
|
||||
#if 1
|
||||
syscall(__ARM_NR_cacheflush, beginning, end, 0);
|
||||
#else
|
||||
__asm__ ("push {r7}\n\t"
|
||||
"mov r7, #0xf0002\n\t"
|
||||
"mov r2, #0\n\t"
|
||||
"swi 0\n\t"
|
||||
"pop {r7}\n\t"
|
||||
"ret");
|
||||
#endif
|
||||
}
|
||||
#endif /* arm */
|
||||
|
||||
12
libtcc.h
12
libtcc.h
@ -27,7 +27,7 @@ LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque,
|
||||
void (*error_func)(void *opaque, const char *msg));
|
||||
|
||||
/* set options as from command line (multiple supported) */
|
||||
LIBTCCAPI int tcc_set_options(TCCState *s, const char *str);
|
||||
LIBTCCAPI void tcc_set_options(TCCState *s, const char *str);
|
||||
|
||||
/*****************************/
|
||||
/* preprocessor */
|
||||
@ -58,11 +58,11 @@ LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf);
|
||||
|
||||
/* set output type. MUST BE CALLED before any compilation */
|
||||
LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type);
|
||||
#define TCC_OUTPUT_MEMORY 0 /* output will be run in memory (default) */
|
||||
#define TCC_OUTPUT_EXE 1 /* executable file */
|
||||
#define TCC_OUTPUT_DLL 2 /* dynamic library */
|
||||
#define TCC_OUTPUT_OBJ 3 /* object file */
|
||||
#define TCC_OUTPUT_PREPROCESS 4 /* only preprocess (used internally) */
|
||||
#define TCC_OUTPUT_MEMORY 1 /* output will be run in memory (default) */
|
||||
#define TCC_OUTPUT_EXE 2 /* executable file */
|
||||
#define TCC_OUTPUT_DLL 3 /* dynamic library */
|
||||
#define TCC_OUTPUT_OBJ 4 /* object file */
|
||||
#define TCC_OUTPUT_PREPROCESS 5 /* only preprocess (used internally) */
|
||||
|
||||
/* equivalent to -Lpath option */
|
||||
LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname);
|
||||
|
||||
102
tcc-doc.texi
102
tcc-doc.texi
@ -176,22 +176,15 @@ In a script, it gives the following header:
|
||||
#!/usr/local/bin/tcc -run -L/usr/X11R6/lib -lX11
|
||||
@end example
|
||||
|
||||
@item -dumpversion
|
||||
Print only the compiler version and nothing else.
|
||||
|
||||
@item -v
|
||||
Display TCC version.
|
||||
|
||||
@item -vv
|
||||
Show included files. As sole argument, print search dirs (as below).
|
||||
Show included files. As sole argument, print search dirs. -vvv shows tries too.
|
||||
|
||||
@item -bench
|
||||
Display compilation statistics.
|
||||
|
||||
@item -print-search-dirs
|
||||
Print the configured installation directory and a list of library
|
||||
and include directories tcc will search.
|
||||
|
||||
@end table
|
||||
|
||||
Preprocessor options:
|
||||
@ -213,11 +206,15 @@ also be defined: @option{-DF(a)=a+1}
|
||||
|
||||
@item -Usym
|
||||
Undefine preprocessor symbol @samp{sym}.
|
||||
|
||||
@item -E
|
||||
Preprocess only, to stdout or file (with -o).
|
||||
|
||||
@end table
|
||||
|
||||
Compilation flags:
|
||||
|
||||
Note: each of the following warning options has a negative form beginning with
|
||||
Note: each of the following options has a negative form beginning with
|
||||
@option{-fno-}.
|
||||
|
||||
@table @option
|
||||
@ -233,6 +230,14 @@ Do not generate common symbols for uninitialized data.
|
||||
@item -fleading-underscore
|
||||
Add a leading underscore at the beginning of each C symbol.
|
||||
|
||||
@item -fms-extensions
|
||||
Allow a MS C compiler extensions to the language. Currently this
|
||||
assumes a nested named structure declaration without an identifier
|
||||
behaves like an unnamed one.
|
||||
|
||||
@item -fdollars-in-identifiers
|
||||
Allow dollar signs in identifiers
|
||||
|
||||
@end table
|
||||
|
||||
Warning options:
|
||||
@ -276,7 +281,7 @@ default library paths are @file{/usr/local/lib}, @file{/usr/lib} and @file{/lib}
|
||||
@item -lxxx
|
||||
Link your program with dynamic library libxxx.so or static library
|
||||
libxxx.a. The library is searched in the paths specified by the
|
||||
@option{-L} option.
|
||||
@option{-L} option and @env{LIBRARY_PATH} variable.
|
||||
|
||||
@item -Bdir
|
||||
Set the path where the tcc internal libraries (and include files) can be
|
||||
@ -300,7 +305,11 @@ opened with @code{dlopen()} needs to access executable symbols.
|
||||
Generate an object file combining all input files.
|
||||
|
||||
@item -Wl,-rpath=path
|
||||
Put custom seatch path for dynamic libraries into executable.
|
||||
Put custom search path for dynamic libraries into executable.
|
||||
|
||||
@item -Wl,--enable-new-dtags
|
||||
When putting a custom search path for dynamic libraries into the executable,
|
||||
create the new ELF dynamic tag DT_RUNPATH instead of the old legacy DT_RPATH.
|
||||
|
||||
@item -Wl,--oformat=fmt
|
||||
Use @var{fmt} as output format. The supported output formats are:
|
||||
@ -322,6 +331,9 @@ Modify executable layout.
|
||||
@item -Wl,-Bsymbolic
|
||||
Set DT_SYMBOLIC tag.
|
||||
|
||||
@item -Wl,-(no-)whole-archive
|
||||
Turn on/off linking of all objects in archives.
|
||||
|
||||
@end table
|
||||
|
||||
Debugger options:
|
||||
@ -338,7 +350,7 @@ Generate additional support code to check
|
||||
memory allocations and array/pointer bounds. @option{-g} is implied. Note
|
||||
that the generated code is slower and bigger in this case.
|
||||
|
||||
Note: @option{-b} is only available on i386 for the moment.
|
||||
Note: @option{-b} is only available on i386 when using libtcc for the moment.
|
||||
|
||||
@item -bt N
|
||||
Display N callers in stack traces. This is useful with @option{-g} or
|
||||
@ -355,18 +367,62 @@ Generate makefile fragment with dependencies.
|
||||
@item -MF depfile
|
||||
Use @file{depfile} as output for -MD.
|
||||
|
||||
@item -print-search-dirs
|
||||
Print the configured installation directory and a list of library
|
||||
and include directories tcc will search.
|
||||
|
||||
@item -dumpversion
|
||||
Print version.
|
||||
|
||||
@end table
|
||||
|
||||
Target specific options:
|
||||
|
||||
@table @option
|
||||
@item -mms-bitfields
|
||||
Use an algorithm for bitfield alignment consistent with MSVC. Default is
|
||||
gcc's algorithm.
|
||||
|
||||
@item -mfloat-abi (ARM only)
|
||||
Select the float ABI. Possible values: @code{softfp} and @code{hard}
|
||||
|
||||
@item -mno-sse
|
||||
Do not use sse registers on x86_64
|
||||
|
||||
@item -m32, -m64
|
||||
Pass command line to the i386/x86_64 cross compiler.
|
||||
|
||||
@end table
|
||||
|
||||
Note: GCC options @option{-Ox}, @option{-fx} and @option{-mx} are
|
||||
ignored.
|
||||
@c man end
|
||||
|
||||
@c man begin ENVIRONMENT
|
||||
Environment variables that affect how tcc operates.
|
||||
|
||||
@table @option
|
||||
|
||||
@item CPATH
|
||||
@item C_INCLUDE_PATH
|
||||
A colon-separated list of directories searched for include files,
|
||||
directories given with @option{-I} are searched first.
|
||||
|
||||
@item LIBRARY_PATH
|
||||
A colon-separated list of directories searched for libraries for the
|
||||
@option{-l} option, directories given with @option{-L} are searched first.
|
||||
|
||||
@end table
|
||||
|
||||
@c man end
|
||||
|
||||
@ignore
|
||||
|
||||
@setfilename tcc
|
||||
@settitle Tiny C Compiler
|
||||
|
||||
@c man begin SEEALSO
|
||||
cpp(1),
|
||||
gcc(1)
|
||||
@c man end
|
||||
|
||||
@ -388,13 +444,14 @@ and floating point numbers (@code{long double}, @code{double}, and
|
||||
@section ISOC99 extensions
|
||||
|
||||
TCC implements many features of the new C standard: ISO C99. Currently
|
||||
missing items are: complex and imaginary numbers and variable length
|
||||
arrays.
|
||||
missing items are: complex and imaginary numbers.
|
||||
|
||||
Currently implemented ISOC99 features:
|
||||
|
||||
@itemize
|
||||
|
||||
@item variable length arrays.
|
||||
|
||||
@item 64 bit @code{long long} types are fully supported.
|
||||
|
||||
@item The boolean type @code{_Bool} is supported.
|
||||
@ -596,8 +653,7 @@ are supported.
|
||||
|
||||
@itemize
|
||||
|
||||
@item @code{__TINYC__} is a predefined macro to @code{1} to
|
||||
indicate that you use TCC.
|
||||
@item @code{__TINYC__} is a predefined macro to indicate that you use TCC.
|
||||
|
||||
@item @code{#!} at the start of a line is ignored to allow scripting.
|
||||
|
||||
@ -702,7 +758,7 @@ They can be defined several times in the same source. Use 'b'
|
||||
@cindex asciz directive
|
||||
@cindex ascii directive
|
||||
|
||||
All directives are preceeded by a '.'. The following directives are
|
||||
All directives are preceded by a '.'. The following directives are
|
||||
supported:
|
||||
|
||||
@itemize
|
||||
@ -921,7 +977,7 @@ reverse order, a first pass is done to reverse the argument order.
|
||||
|
||||
@section Types
|
||||
|
||||
The types are stored in a single 'int' variable. It was choosen in the
|
||||
The types are stored in a single 'int' variable. It was chosen in the
|
||||
first stages of development when tcc was much simpler. Now, it may not
|
||||
be the best solution.
|
||||
|
||||
@ -948,7 +1004,7 @@ be the best solution.
|
||||
#define VT_BITFIELD 0x0040 /* bitfield modifier */
|
||||
#define VT_CONSTANT 0x0800 /* const modifier */
|
||||
#define VT_VOLATILE 0x1000 /* volatile modifier */
|
||||
#define VT_SIGNED 0x2000 /* signed type */
|
||||
#define VT_DEFSIGN 0x2000 /* signed type */
|
||||
|
||||
#define VT_STRUCT_SHIFT 18 /* structure/enum name shift (14 bits left) */
|
||||
@end example
|
||||
@ -1058,7 +1114,7 @@ are used when bound checking is activated
|
||||
|
||||
@item stab_section
|
||||
@itemx stabstr_section
|
||||
are used when debugging is actived to store debug information
|
||||
are used when debugging is active to store debug information
|
||||
|
||||
@item symtab_section
|
||||
@itemx strtab_section
|
||||
@ -1158,8 +1214,10 @@ if the lvalue has an integer type, then these flags give its real
|
||||
type. The type alone is not enough in case of cast optimisations.
|
||||
|
||||
@item VT_LLOCAL
|
||||
is a saved lvalue on the stack. @code{VT_LLOCAL} should be eliminated
|
||||
ASAP because its semantics are rather complicated.
|
||||
is a saved lvalue on the stack. @code{VT_LVAL} must also be set with
|
||||
@code{VT_LLOCAL}. @code{VT_LLOCAL} can arise when a @code{VT_LVAL} in
|
||||
a register has to be saved to the stack, or it can come from an
|
||||
architecture-specific calling convention.
|
||||
|
||||
@item VT_MUSTCAST
|
||||
indicates that a cast to the value type must be performed if the value
|
||||
|
||||
502
tcc.c
502
tcc.c
@ -23,131 +23,187 @@
|
||||
#else
|
||||
#include "tcc.h"
|
||||
#endif
|
||||
#include "tcctools.c"
|
||||
|
||||
static void help(void)
|
||||
{
|
||||
printf("tcc version " TCC_VERSION " - Tiny C Compiler - Copyright (C) 2001-2006 Fabrice Bellard\n"
|
||||
"Usage: tcc [options...] [-o outfile] [-c] infile(s)...\n"
|
||||
" tcc [options...] -run infile [arguments...]\n"
|
||||
"General options:\n"
|
||||
" -c compile only - generate an object file\n"
|
||||
" -o outfile set output filename\n"
|
||||
" -run run compiled source\n"
|
||||
" -fflag set or reset (with 'no-' prefix) 'flag' (see man page)\n"
|
||||
" -Wwarning set or reset (with 'no-' prefix) 'warning' (see man page)\n"
|
||||
" -w disable all warnings\n"
|
||||
" -v show version\n"
|
||||
" -vv show included files (as sole argument: show search paths)\n"
|
||||
" -dumpversion\n"
|
||||
" -bench show compilation statistics\n"
|
||||
"Preprocessor options:\n"
|
||||
" -E preprocess only\n"
|
||||
" -Idir add include path 'dir'\n"
|
||||
" -Dsym[=val] define 'sym' with value 'val'\n"
|
||||
" -Usym undefine 'sym'\n"
|
||||
"Linker options:\n"
|
||||
" -Ldir add library path 'dir'\n"
|
||||
" -llib link with dynamic or static library 'lib'\n"
|
||||
" -pthread link with -lpthread and -D_REENTRANT (POSIX Linux)\n"
|
||||
" -r generate (relocatable) object file\n"
|
||||
" -rdynamic export all global symbols to dynamic linker\n"
|
||||
" -shared generate a shared library\n"
|
||||
" -soname set name for shared library to be used at runtime\n"
|
||||
" -static static linking\n"
|
||||
" -Wl,-opt[=val] set linker option (see manual)\n"
|
||||
"Debugger options:\n"
|
||||
" -g generate runtime debug info\n"
|
||||
static const char help[] =
|
||||
"Tiny C Compiler "TCC_VERSION" - Copyright (C) 2001-2006 Fabrice Bellard\n"
|
||||
"Usage: tcc [options...] [-o outfile] [-c] infile(s)...\n"
|
||||
" tcc [options...] -run infile [arguments...]\n"
|
||||
"General options:\n"
|
||||
" -c compile only - generate an object file\n"
|
||||
" -o outfile set output filename\n"
|
||||
" -run run compiled source\n"
|
||||
" -fflag set or reset (with 'no-' prefix) 'flag' (see tcc -hh)\n"
|
||||
" -Wwarning set or reset (with 'no-' prefix) 'warning' (see tcc -hh)\n"
|
||||
" -w disable all warnings\n"
|
||||
" -v -vv show version, show search paths or loaded files\n"
|
||||
" -h -hh show this, show more help\n"
|
||||
" -bench show compilation statistics\n"
|
||||
" - use stdin pipe as infile\n"
|
||||
" @listfile read arguments from listfile\n"
|
||||
"Preprocessor options:\n"
|
||||
" -Idir add include path 'dir'\n"
|
||||
" -Dsym[=val] define 'sym' with value 'val'\n"
|
||||
" -Usym undefine 'sym'\n"
|
||||
" -E preprocess only\n"
|
||||
"Linker options:\n"
|
||||
" -Ldir add library path 'dir'\n"
|
||||
" -llib link with dynamic or static library 'lib'\n"
|
||||
" -r generate (relocatable) object file\n"
|
||||
" -shared generate a shared library/dll\n"
|
||||
" -rdynamic export all global symbols to dynamic linker\n"
|
||||
" -soname set name for shared library to be used at runtime\n"
|
||||
" -Wl,-opt[=val] set linker option (see tcc -hh)\n"
|
||||
"Debugger options:\n"
|
||||
" -g generate runtime debug info\n"
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
" -b compile with built-in memory and bounds checker (implies -g)\n"
|
||||
" -b compile with built-in memory and bounds checker (implies -g)\n"
|
||||
#endif
|
||||
#ifdef CONFIG_TCC_BACKTRACE
|
||||
" -bt N show N callers in stack traces\n"
|
||||
" -bt N show N callers in stack traces\n"
|
||||
#endif
|
||||
"Misc options:\n"
|
||||
" -nostdinc do not use standard system include paths\n"
|
||||
" -nostdlib do not link with standard crt and libraries\n"
|
||||
" -Bdir use 'dir' as tcc internal library and include path\n"
|
||||
" -MD generate target dependencies for make\n"
|
||||
" -MF depfile put generated dependencies here\n"
|
||||
);
|
||||
}
|
||||
|
||||
/* re-execute the i386/x86_64 cross-compilers with tcc -m32/-m64: */
|
||||
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
|
||||
#ifdef _WIN32
|
||||
#include <process.h>
|
||||
static int execvp_win32(const char *prog, char **argv)
|
||||
{
|
||||
int ret = spawnvp(P_NOWAIT, prog, (char const*const*)argv);
|
||||
if (-1 == ret)
|
||||
return ret;
|
||||
cwait(&ret, ret, WAIT_CHILD);
|
||||
exit(ret);
|
||||
}
|
||||
#define execvp execvp_win32
|
||||
#endif
|
||||
static void exec_other_tcc(TCCState *s, char **argv, const char *optarg)
|
||||
{
|
||||
char child_path[4096], *child_name; const char *target;
|
||||
switch (atoi(optarg)) {
|
||||
#ifdef TCC_TARGET_I386
|
||||
case 32: break;
|
||||
case 64: target = "x86_64";
|
||||
#else
|
||||
case 64: break;
|
||||
case 32: target = "i386";
|
||||
#endif
|
||||
pstrcpy(child_path, sizeof child_path - 40, argv[0]);
|
||||
child_name = tcc_basename(child_path);
|
||||
strcpy(child_name, target);
|
||||
"Misc. options:\n"
|
||||
" -x[c|a|n] specify type of the next infile\n"
|
||||
" -nostdinc do not use standard system include paths\n"
|
||||
" -nostdlib do not link with standard crt and libraries\n"
|
||||
" -Bdir set tcc's private include/library dir\n"
|
||||
" -MD generate dependency file for make\n"
|
||||
" -MF file specify dependency file name\n"
|
||||
" -m32/64 defer to i386/x86_64 cross compiler\n"
|
||||
"Tools:\n"
|
||||
" create library : tcc -ar [rcsv] lib.a files\n"
|
||||
#ifdef TCC_TARGET_PE
|
||||
strcat(child_name, "-win32");
|
||||
" create def file : tcc -impdef lib.dll [-v] [-o lib.def]\n"
|
||||
#endif
|
||||
strcat(child_name, "-tcc");
|
||||
if (strcmp(argv[0], child_path)) {
|
||||
if (s->verbose > 0)
|
||||
printf("tcc: using '%s'\n", child_name), fflush(stdout);
|
||||
execvp(argv[0] = child_path, argv);
|
||||
}
|
||||
tcc_error("'%s' not found", child_name);
|
||||
case 0: /* ignore -march etc. */
|
||||
break;
|
||||
default:
|
||||
tcc_warning("unsupported option \"-m%s\"", optarg);
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
static const char help2[] =
|
||||
"Tiny C Compiler "TCC_VERSION" - More Options\n"
|
||||
"Special options:\n"
|
||||
" -P -P1 with -E: no/alternative #line output\n"
|
||||
" -dD -dM with -E: output #define directives\n"
|
||||
" -pthread same as -D_REENTRANT and -lpthread\n"
|
||||
" -On same as -D__OPTIMIZE__ for n > 0\n"
|
||||
" -Wp,-opt same as -opt\n"
|
||||
" -include file include 'file' above each input file\n"
|
||||
" -isystem dir add 'dir' to system include path\n"
|
||||
" -iwithprefix dir set tcc's private include/library subdir\n"
|
||||
" -static link to static libraries (not recommended)\n"
|
||||
" -dumpversion print version\n"
|
||||
" -print-search-dirs print search paths\n"
|
||||
"Ignored options:\n"
|
||||
" --param -pedantic -pipe -s -std -traditional\n"
|
||||
"-W... warnings:\n"
|
||||
" all turn on some (*) warnings\n"
|
||||
" error stop after first warning\n"
|
||||
" unsupported warn about ignored options, pragmas, etc.\n"
|
||||
" write-strings strings are const\n"
|
||||
" implicit-function-declaration warn for missing prototype (*)\n"
|
||||
"-f[no-]... flags:\n"
|
||||
" unsigned-char default char is unsigned\n"
|
||||
" signed-char default char is signed\n"
|
||||
" common use common section instead of bss\n"
|
||||
" leading-underscore decorate extern symbols\n"
|
||||
" ms-extensions allow anonymous struct in struct\n"
|
||||
" dollars-in-identifiers allow '$' in C symbols\n"
|
||||
"-m... target specific options:\n"
|
||||
" ms-bitfields use MSVC bitfield layout\n"
|
||||
#ifdef TCC_TARGET_ARM
|
||||
" float-abi hard/softfp on arm\n"
|
||||
#endif
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
" no-sse disable floats on x86_64\n"
|
||||
#endif
|
||||
"-Wl,... linker options:\n"
|
||||
" -nostdlib do not link with standard crt/libs\n"
|
||||
" -[no-]whole-archive load lib(s) fully/only as needed\n"
|
||||
" -export-all-symbols same as -rdynamic\n"
|
||||
" -image-base= -Ttext= set base address of executable\n"
|
||||
" -section-alignment= set section alignment in executable\n"
|
||||
#ifdef TCC_TARGET_PE
|
||||
" -file-alignment= set PE file alignment\n"
|
||||
" -stack= set PE stack reserve\n"
|
||||
" -large-address-aware set related PE option\n"
|
||||
" -subsystem=[console/windows] set PE subsystem\n"
|
||||
" -oformat=[pe-* binary] set executable output format\n"
|
||||
"Predefined macros:\n"
|
||||
" tcc -E -dM - < nul\n"
|
||||
#else
|
||||
#define exec_other_tcc(s, argv, optarg)
|
||||
" -rpath= set dynamic library seach path\n"
|
||||
" -enable-new-dtags set DT_RUNPATH instead of DT_RPATH\n"
|
||||
" -soname= set DT_SONAME elf tag\n"
|
||||
" -Bsymbolic set DT_SYMBOLIC elf tag\n"
|
||||
" -oformat=[elf32/64-* binary] set executable output format\n"
|
||||
" -init= -fini= -as-needed -O (ignored)\n"
|
||||
"Predefined macros:\n"
|
||||
" tcc -E -dM - < /dev/null\n"
|
||||
#endif
|
||||
"See also the manual for more details.\n"
|
||||
;
|
||||
|
||||
static void gen_makedeps(TCCState *s, const char *target, const char *filename)
|
||||
static const char version[] =
|
||||
"tcc version "TCC_VERSION" ("
|
||||
#ifdef TCC_TARGET_I386
|
||||
"i386"
|
||||
#elif defined TCC_TARGET_X86_64
|
||||
"x86_64"
|
||||
#elif defined TCC_TARGET_C67
|
||||
"C67"
|
||||
#elif defined TCC_TARGET_ARM
|
||||
"ARM"
|
||||
#elif defined TCC_TARGET_ARM64
|
||||
"AArch64"
|
||||
#endif
|
||||
#ifdef TCC_ARM_HARDFLOAT
|
||||
" Hard Float"
|
||||
#endif
|
||||
#ifdef TCC_TARGET_PE
|
||||
" Windows"
|
||||
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
" FreeBSD"
|
||||
#else
|
||||
" Linux"
|
||||
#endif
|
||||
")\n"
|
||||
;
|
||||
|
||||
static void print_dirs(const char *msg, char **paths, int nb_paths)
|
||||
{
|
||||
FILE *depout;
|
||||
char buf[1024], *ext;
|
||||
int i;
|
||||
printf("%s:\n%s", msg, nb_paths ? "" : " -\n");
|
||||
for(i = 0; i < nb_paths; i++)
|
||||
printf(" %s\n", paths[i]);
|
||||
}
|
||||
|
||||
if (!filename) {
|
||||
/* compute filename automatically
|
||||
* dir/file.o -> dir/file.d */
|
||||
pstrcpy(buf, sizeof(buf), target);
|
||||
ext = tcc_fileextension(buf);
|
||||
pstrcpy(ext, sizeof(buf) - (ext-buf), ".d");
|
||||
filename = buf;
|
||||
static void print_search_dirs(TCCState *s)
|
||||
{
|
||||
printf("install: %s\n", s->tcc_lib_path);
|
||||
/* print_dirs("programs", NULL, 0); */
|
||||
print_dirs("include", s->sysinclude_paths, s->nb_sysinclude_paths);
|
||||
print_dirs("libraries", s->library_paths, s->nb_library_paths);
|
||||
#ifndef TCC_TARGET_PE
|
||||
print_dirs("crt", s->crt_paths, s->nb_crt_paths);
|
||||
printf("libtcc1:\n %s/"TCC_LIBTCC1"\n", s->tcc_lib_path);
|
||||
printf("elfinterp:\n %s\n", DEFAULT_ELFINTERP(s));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void set_environment(TCCState *s)
|
||||
{
|
||||
char * path;
|
||||
|
||||
path = getenv("C_INCLUDE_PATH");
|
||||
if(path != NULL) {
|
||||
tcc_add_include_path(s, path);
|
||||
}
|
||||
path = getenv("CPATH");
|
||||
if(path != NULL) {
|
||||
tcc_add_include_path(s, path);
|
||||
}
|
||||
path = getenv("LIBRARY_PATH");
|
||||
if(path != NULL) {
|
||||
tcc_add_library_path(s, path);
|
||||
}
|
||||
|
||||
if (s->verbose)
|
||||
printf("<- %s\n", filename);
|
||||
|
||||
/* XXX return err codes instead of error() ? */
|
||||
depout = fopen(filename, "w");
|
||||
if (!depout)
|
||||
tcc_error("could not open '%s'", filename);
|
||||
|
||||
fprintf(depout, "%s : \\\n", target);
|
||||
for (i=0; i<s->nb_target_deps; ++i)
|
||||
fprintf(depout, " %s \\\n", s->target_deps[i]);
|
||||
fprintf(depout, "\n");
|
||||
fclose(depout);
|
||||
}
|
||||
|
||||
static char *default_outputfile(TCCState *s, const char *first_file)
|
||||
@ -158,7 +214,7 @@ static char *default_outputfile(TCCState *s, const char *first_file)
|
||||
|
||||
if (first_file && strcmp(first_file, "-"))
|
||||
name = tcc_basename(first_file);
|
||||
pstrcpy(buf, sizeof(buf), name);
|
||||
snprintf(buf, sizeof(buf), "%s", name);
|
||||
ext = tcc_fileextension(buf);
|
||||
#ifdef TCC_TARGET_PE
|
||||
if (s->output_type == TCC_OUTPUT_DLL)
|
||||
@ -168,185 +224,135 @@ static char *default_outputfile(TCCState *s, const char *first_file)
|
||||
strcpy(ext, ".exe");
|
||||
else
|
||||
#endif
|
||||
if (( (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) ||
|
||||
(s->output_type == TCC_OUTPUT_PREPROCESS) )
|
||||
&& *ext)
|
||||
if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r && *ext)
|
||||
strcpy(ext, ".o");
|
||||
else
|
||||
strcpy(buf, "a.out");
|
||||
|
||||
return tcc_strdup(buf);
|
||||
}
|
||||
|
||||
static void print_paths(const char *msg, char **paths, int nb_paths)
|
||||
{
|
||||
int i;
|
||||
printf("%s:\n%s", msg, nb_paths ? "" : " -\n");
|
||||
for(i = 0; i < nb_paths; i++)
|
||||
printf(" %s\n", paths[i]);
|
||||
}
|
||||
|
||||
static void display_info(TCCState *s, int what)
|
||||
{
|
||||
switch (what) {
|
||||
case 0:
|
||||
printf("tcc version %s ("
|
||||
#ifdef TCC_TARGET_I386
|
||||
"i386"
|
||||
# ifdef TCC_TARGET_PE
|
||||
" Win32"
|
||||
# endif
|
||||
#elif defined TCC_TARGET_X86_64
|
||||
"x86-64"
|
||||
# ifdef TCC_TARGET_PE
|
||||
" Win64"
|
||||
# endif
|
||||
#elif defined TCC_TARGET_ARM
|
||||
"ARM"
|
||||
# ifdef TCC_ARM_HARDFLOAT
|
||||
" Hard Float"
|
||||
# endif
|
||||
# ifdef TCC_TARGET_PE
|
||||
" WinCE"
|
||||
# endif
|
||||
#endif
|
||||
#ifndef TCC_TARGET_PE
|
||||
# ifdef __linux
|
||||
" Linux"
|
||||
# endif
|
||||
#endif
|
||||
")\n", TCC_VERSION);
|
||||
break;
|
||||
case 1:
|
||||
printf("install: %s/\n", s->tcc_lib_path);
|
||||
/* print_paths("programs", NULL, 0); */
|
||||
print_paths("crt", s->crt_paths, s->nb_crt_paths);
|
||||
print_paths("libraries", s->library_paths, s->nb_library_paths);
|
||||
print_paths("include", s->sysinclude_paths, s->nb_sysinclude_paths);
|
||||
printf("elfinterp:\n %s\n", CONFIG_TCC_ELFINTERP);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int64_t getclock_us(void)
|
||||
static unsigned getclock_ms(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
struct _timeb tb;
|
||||
_ftime(&tb);
|
||||
return (tb.time * 1000LL + tb.millitm) * 1000LL;
|
||||
return GetTickCount();
|
||||
#else
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return tv.tv_sec * 1000000LL + tv.tv_usec;
|
||||
return tv.tv_sec*1000 + (tv.tv_usec+500)/1000;
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
TCCState *s;
|
||||
int ret, optind, i, bench;
|
||||
int64_t start_time = 0;
|
||||
const char *first_file = NULL;
|
||||
int ret, opt, n = 0;
|
||||
unsigned start_time = 0;
|
||||
const char *first_file;
|
||||
|
||||
redo:
|
||||
s = tcc_new();
|
||||
s->output_type = TCC_OUTPUT_EXE;
|
||||
opt = tcc_parse_args(s, &argc, &argv, 1);
|
||||
|
||||
optind = tcc_parse_args(s, argc - 1, argv + 1);
|
||||
|
||||
if (optind == 0) {
|
||||
help();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (s->option_m)
|
||||
exec_other_tcc(s, argv, s->option_m);
|
||||
|
||||
if (s->verbose)
|
||||
display_info(s, 0);
|
||||
|
||||
if (s->print_search_dirs || (s->verbose == 2 && optind == 1)) {
|
||||
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
|
||||
display_info(s, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (s->verbose && optind == 1)
|
||||
return 0;
|
||||
|
||||
if (s->nb_files == 0)
|
||||
tcc_error("no input files\n");
|
||||
|
||||
/* check -c consistency : only single file handled. XXX: checks file type */
|
||||
if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) {
|
||||
if (s->nb_libraries != 0)
|
||||
tcc_error("cannot specify libraries with -c");
|
||||
/* accepts only a single input file */
|
||||
if (s->nb_files != 1)
|
||||
tcc_error("cannot specify multiple files with -c");
|
||||
}
|
||||
|
||||
if (s->output_type == TCC_OUTPUT_PREPROCESS) {
|
||||
if (!s->outfile) {
|
||||
s->ppfp = stdout;
|
||||
} else {
|
||||
s->ppfp = fopen(s->outfile, "w");
|
||||
if (!s->ppfp)
|
||||
tcc_error("could not write '%s'", s->outfile);
|
||||
if (n == 0) {
|
||||
if (opt == OPT_HELP)
|
||||
return printf(help), 1;
|
||||
if (opt == OPT_HELP2)
|
||||
return printf(help2), 1;
|
||||
if (opt == OPT_M32 || opt == OPT_M64)
|
||||
tcc_tool_cross(s, argv, opt); /* never returns */
|
||||
if (s->verbose)
|
||||
printf(version);
|
||||
if (opt == OPT_AR)
|
||||
return tcc_tool_ar(s, argc, argv);
|
||||
#ifdef TCC_TARGET_PE
|
||||
if (opt == OPT_IMPDEF)
|
||||
return tcc_tool_impdef(s, argc, argv);
|
||||
#endif
|
||||
if (opt == OPT_V)
|
||||
return 0;
|
||||
if (opt == OPT_PRINT_DIRS) {
|
||||
/* initialize search dirs */
|
||||
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
|
||||
print_search_dirs(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
n = s->nb_files;
|
||||
if (n == 0)
|
||||
tcc_error("no input files\n");
|
||||
|
||||
if (s->output_type == TCC_OUTPUT_PREPROCESS) {
|
||||
if (!s->outfile) {
|
||||
s->ppfp = stdout;
|
||||
} else {
|
||||
s->ppfp = fopen(s->outfile, "w");
|
||||
if (!s->ppfp)
|
||||
tcc_error("could not write '%s'", s->outfile);
|
||||
}
|
||||
} else if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) {
|
||||
if (s->nb_libraries)
|
||||
tcc_error("cannot specify libraries with -c");
|
||||
if (n > 1 && s->outfile)
|
||||
tcc_error("cannot specify output file with -c many files");
|
||||
} else {
|
||||
if (s->option_pthread)
|
||||
tcc_set_options(s, "-lpthread");
|
||||
}
|
||||
|
||||
if (s->do_bench)
|
||||
start_time = getclock_ms();
|
||||
}
|
||||
|
||||
bench = s->do_bench;
|
||||
if (bench)
|
||||
start_time = getclock_us();
|
||||
|
||||
set_environment(s);
|
||||
if (s->output_type == 0)
|
||||
s->output_type = TCC_OUTPUT_EXE;
|
||||
tcc_set_output_type(s, s->output_type);
|
||||
|
||||
/* compile or add each files or library */
|
||||
for(i = ret = 0; i < s->nb_files && ret == 0; i++) {
|
||||
const char *filename;
|
||||
|
||||
filename = s->files[i];
|
||||
if (filename[0] == '-' && filename[1] == 'l') {
|
||||
if (tcc_add_library(s, filename + 2) < 0) {
|
||||
tcc_error_noabort("cannot find '%s'", filename);
|
||||
for (first_file = NULL, ret = 0;;) {
|
||||
struct filespec *f = s->files[s->nb_files - n];
|
||||
s->filetype = f->type;
|
||||
s->alacarte_link = f->alacarte;
|
||||
if (f->type == AFF_TYPE_LIB) {
|
||||
if (tcc_add_library_err(s, f->name) < 0)
|
||||
ret = 1;
|
||||
}
|
||||
} else {
|
||||
if (1 == s->verbose)
|
||||
printf("-> %s\n", filename);
|
||||
if (tcc_add_file(s, filename) < 0)
|
||||
ret = 1;
|
||||
printf("-> %s\n", f->name);
|
||||
if (!first_file)
|
||||
first_file = filename;
|
||||
first_file = f->name;
|
||||
if (tcc_add_file(s, f->name) < 0)
|
||||
ret = 1;
|
||||
}
|
||||
s->filetype = 0;
|
||||
s->alacarte_link = 1;
|
||||
if (ret || --n == 0
|
||||
|| (s->output_type == TCC_OUTPUT_OBJ && !s->option_r))
|
||||
break;
|
||||
}
|
||||
|
||||
if (0 == ret) {
|
||||
if (bench)
|
||||
tcc_print_stats(s, getclock_us() - start_time);
|
||||
|
||||
if (s->output_type == TCC_OUTPUT_PREPROCESS) {
|
||||
if (s->outfile)
|
||||
fclose(s->ppfp);
|
||||
} else if (0 == ret) {
|
||||
if (s->output_type == TCC_OUTPUT_MEMORY) {
|
||||
#ifdef TCC_IS_NATIVE
|
||||
ret = tcc_run(s, argc - 1 - optind, argv + 1 + optind);
|
||||
#else
|
||||
tcc_error_noabort("-run is not available in a cross compiler");
|
||||
ret = 1;
|
||||
ret = tcc_run(s, argc, argv);
|
||||
#endif
|
||||
} else if (s->output_type == TCC_OUTPUT_PREPROCESS) {
|
||||
if (s->outfile)
|
||||
fclose(s->ppfp);
|
||||
} else {
|
||||
if (!s->outfile)
|
||||
s->outfile = default_outputfile(s, first_file);
|
||||
ret = !!tcc_output_file(s, s->outfile);
|
||||
/* dump collected dependencies */
|
||||
if (s->gen_deps && !ret)
|
||||
if (tcc_output_file(s, s->outfile))
|
||||
ret = 1;
|
||||
else if (s->gen_deps)
|
||||
gen_makedeps(s, s->outfile, s->deps_outfile);
|
||||
}
|
||||
}
|
||||
|
||||
if (s->do_bench && ret == 0 && n == 0)
|
||||
tcc_print_stats(s, getclock_ms() - start_time);
|
||||
tcc_delete(s);
|
||||
if (bench)
|
||||
tcc_memstats();
|
||||
if (ret == 0 && n)
|
||||
goto redo; /* compile more files with -c */
|
||||
return ret;
|
||||
}
|
||||
|
||||
538
tccasm.c
538
tccasm.c
@ -32,6 +32,53 @@ ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n)
|
||||
}
|
||||
|
||||
ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe);
|
||||
static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global);
|
||||
static Sym sym_dot;
|
||||
|
||||
/* Return a symbol we can use inside the assembler, having name NAME.
|
||||
The assembler symbol table is different from the C symbol table
|
||||
(and the Sym members are used differently). But we must be able
|
||||
to look up file-global C symbols from inside the assembler, e.g.
|
||||
for global asm blocks to be able to refer to defined C symbols.
|
||||
|
||||
This routine gives back either an existing asm-internal
|
||||
symbol, or a new one. In the latter case the new asm-internal
|
||||
symbol is initialized with info from the C symbol table.
|
||||
|
||||
If CSYM is non-null we take symbol info from it, otherwise
|
||||
we look up NAME in the C symbol table and use that. */
|
||||
ST_FUNC Sym* get_asm_sym(int name, Sym *csym)
|
||||
{
|
||||
Sym *sym = label_find(name);
|
||||
if (!sym) {
|
||||
sym = label_push(&tcc_state->asm_labels, name, 0);
|
||||
sym->type.t = VT_VOID | VT_EXTERN;
|
||||
if (!csym) {
|
||||
csym = sym_find(name);
|
||||
/* We might be called for an asm block from inside a C routine
|
||||
and so might have local decls on the identifier stack. Search
|
||||
for the first global one. */
|
||||
while (csym && csym->scope)
|
||||
csym = csym->prev_tok;
|
||||
}
|
||||
/* Now, if we have a defined global symbol copy over
|
||||
section and offset. */
|
||||
if (csym &&
|
||||
((csym->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST)) &&
|
||||
csym->c) {
|
||||
ElfW(Sym) *esym;
|
||||
esym = &((ElfW(Sym) *)symtab_section->data)[csym->c];
|
||||
sym->c = csym->c;
|
||||
sym->r = esym->st_shndx;
|
||||
sym->jnext = esym->st_value;
|
||||
/* XXX can't yet store st_size anywhere. */
|
||||
sym->type.t &= ~VT_EXTERN;
|
||||
/* Mark that this asm symbol doesn't need to be fed back. */
|
||||
sym->type.t |= VT_IMPORT;
|
||||
}
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
|
||||
/* We do not use the C expression parser to handle symbols. Maybe the
|
||||
C expression parser could be tweaked to do so. */
|
||||
@ -39,12 +86,13 @@ ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe);
|
||||
static void asm_expr_unary(TCCState *s1, ExprValue *pe)
|
||||
{
|
||||
Sym *sym;
|
||||
int op, n, label;
|
||||
int op, label;
|
||||
unsigned long n;
|
||||
const char *p;
|
||||
|
||||
switch(tok) {
|
||||
case TOK_PPNUM:
|
||||
p = tokc.cstr->data;
|
||||
p = tokc.str.data;
|
||||
n = strtoul(p, (char **)&p, 0);
|
||||
if (*p == 'b' || *p == 'f') {
|
||||
/* backward or forward label */
|
||||
@ -61,14 +109,16 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
|
||||
if (!sym || sym->r) {
|
||||
/* if the last label is defined, then define a new one */
|
||||
sym = label_push(&s1->asm_labels, label, 0);
|
||||
sym->type.t = VT_STATIC | VT_VOID;
|
||||
sym->type.t = VT_STATIC | VT_VOID | VT_EXTERN;
|
||||
}
|
||||
}
|
||||
pe->v = 0;
|
||||
pe->sym = sym;
|
||||
pe->v = 0;
|
||||
pe->sym = sym;
|
||||
pe->pcrel = 0;
|
||||
} else if (*p == '\0') {
|
||||
pe->v = n;
|
||||
pe->sym = NULL;
|
||||
pe->pcrel = 0;
|
||||
} else {
|
||||
tcc_error("invalid number syntax");
|
||||
}
|
||||
@ -94,6 +144,7 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
|
||||
case TOK_LCHAR:
|
||||
pe->v = tokc.i;
|
||||
pe->sym = NULL;
|
||||
pe->pcrel = 0;
|
||||
next();
|
||||
break;
|
||||
case '(':
|
||||
@ -101,22 +152,28 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
|
||||
asm_expr(s1, pe);
|
||||
skip(')');
|
||||
break;
|
||||
case '.':
|
||||
pe->v = 0;
|
||||
pe->sym = &sym_dot;
|
||||
pe->pcrel = 0;
|
||||
sym_dot.type.t = VT_VOID | VT_STATIC;
|
||||
sym_dot.r = cur_text_section->sh_num;
|
||||
sym_dot.jnext = ind;
|
||||
next();
|
||||
break;
|
||||
default:
|
||||
if (tok >= TOK_IDENT) {
|
||||
/* label case : if the label was not found, add one */
|
||||
sym = label_find(tok);
|
||||
if (!sym) {
|
||||
sym = label_push(&s1->asm_labels, tok, 0);
|
||||
/* NOTE: by default, the symbol is global */
|
||||
sym->type.t = VT_VOID;
|
||||
}
|
||||
sym = get_asm_sym(tok, NULL);
|
||||
if (sym->r == SHN_ABS) {
|
||||
/* if absolute symbol, no need to put a symbol value */
|
||||
pe->v = sym->jnext;
|
||||
pe->sym = NULL;
|
||||
pe->pcrel = 0;
|
||||
} else {
|
||||
pe->v = 0;
|
||||
pe->sym = sym;
|
||||
pe->pcrel = 0;
|
||||
}
|
||||
next();
|
||||
} else {
|
||||
@ -219,20 +276,21 @@ static inline void asm_expr_sum(TCCState *s1, ExprValue *pe)
|
||||
pe->v -= e2.v;
|
||||
/* NOTE: we are less powerful than gas in that case
|
||||
because we store only one symbol in the expression */
|
||||
if (!pe->sym && !e2.sym) {
|
||||
/* OK */
|
||||
} else if (pe->sym && !e2.sym) {
|
||||
/* OK */
|
||||
} else if (pe->sym && e2.sym) {
|
||||
if (pe->sym == e2.sym) {
|
||||
/* OK */
|
||||
} else if (pe->sym->r == e2.sym->r && pe->sym->r != 0) {
|
||||
/* we also accept defined symbols in the same section */
|
||||
pe->v += pe->sym->jnext - e2.sym->jnext;
|
||||
} else {
|
||||
goto cannot_relocate;
|
||||
}
|
||||
pe->sym = NULL; /* same symbols can be substracted to NULL */
|
||||
if (!e2.sym) {
|
||||
/* OK */
|
||||
} else if (pe->sym == e2.sym) {
|
||||
/* OK */
|
||||
pe->sym = NULL; /* same symbols can be subtracted to NULL */
|
||||
} else if (pe->sym && pe->sym->r == e2.sym->r && pe->sym->r != 0) {
|
||||
/* we also accept defined symbols in the same section */
|
||||
pe->v += pe->sym->jnext - e2.sym->jnext;
|
||||
pe->sym = NULL;
|
||||
} else if (e2.sym->r == cur_text_section->sh_num) {
|
||||
/* When subtracting a defined symbol in current section
|
||||
this actually makes the value PC-relative. */
|
||||
pe->v -= e2.sym->jnext - ind - 4;
|
||||
pe->pcrel = 1;
|
||||
e2.sym = NULL;
|
||||
} else {
|
||||
cannot_relocate:
|
||||
tcc_error("invalid operation with label");
|
||||
@ -241,9 +299,51 @@ static inline void asm_expr_sum(TCCState *s1, ExprValue *pe)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void asm_expr_cmp(TCCState *s1, ExprValue *pe)
|
||||
{
|
||||
int op;
|
||||
ExprValue e2;
|
||||
|
||||
asm_expr_sum(s1, pe);
|
||||
for(;;) {
|
||||
op = tok;
|
||||
if (op != TOK_EQ && op != TOK_NE
|
||||
&& (op > TOK_GT || op < TOK_ULE))
|
||||
break;
|
||||
next();
|
||||
asm_expr_sum(s1, &e2);
|
||||
if (pe->sym || e2.sym)
|
||||
tcc_error("invalid operation with label");
|
||||
switch(op) {
|
||||
case TOK_EQ:
|
||||
pe->v = pe->v == e2.v;
|
||||
break;
|
||||
case TOK_NE:
|
||||
pe->v = pe->v != e2.v;
|
||||
break;
|
||||
case TOK_LT:
|
||||
pe->v = (int64_t)pe->v < (int64_t)e2.v;
|
||||
break;
|
||||
case TOK_GE:
|
||||
pe->v = (int64_t)pe->v >= (int64_t)e2.v;
|
||||
break;
|
||||
case TOK_LE:
|
||||
pe->v = (int64_t)pe->v <= (int64_t)e2.v;
|
||||
break;
|
||||
case TOK_GT:
|
||||
pe->v = (int64_t)pe->v > (int64_t)e2.v;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* GAS compare results are -1/0 not 1/0. */
|
||||
pe->v = -(int64_t)pe->v;
|
||||
}
|
||||
}
|
||||
|
||||
ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe)
|
||||
{
|
||||
asm_expr_sum(s1, pe);
|
||||
asm_expr_cmp(s1, pe);
|
||||
}
|
||||
|
||||
ST_FUNC int asm_int_expr(TCCState *s1)
|
||||
@ -257,14 +357,17 @@ ST_FUNC int asm_int_expr(TCCState *s1)
|
||||
|
||||
/* NOTE: the same name space as C labels is used to avoid using too
|
||||
much memory when storing labels in TokenStrings */
|
||||
static void asm_new_label1(TCCState *s1, int label, int is_local,
|
||||
static Sym* asm_new_label1(TCCState *s1, int label, int is_local,
|
||||
int sh_num, int value)
|
||||
{
|
||||
Sym *sym;
|
||||
|
||||
sym = label_find(label);
|
||||
if (sym) {
|
||||
if (sym->r) {
|
||||
/* A VT_EXTERN symbol, even if it has a section is considered
|
||||
overridable. This is how we "define" .set targets. Real
|
||||
definitions won't have VT_EXTERN set. */
|
||||
if (sym->r && !(sym->type.t & VT_EXTERN)) {
|
||||
/* the label is already defined */
|
||||
if (!is_local) {
|
||||
tcc_error("assembler label '%s' already defined",
|
||||
@ -277,26 +380,45 @@ static void asm_new_label1(TCCState *s1, int label, int is_local,
|
||||
} else {
|
||||
new_label:
|
||||
sym = label_push(&s1->asm_labels, label, 0);
|
||||
sym->type.t = VT_STATIC | VT_VOID;
|
||||
/* If we need a symbol to hold a value, mark it as
|
||||
tentative only (for .set). If this is for a real label
|
||||
we'll remove VT_EXTERN. */
|
||||
sym->type.t = VT_STATIC | VT_VOID | VT_EXTERN;
|
||||
}
|
||||
sym->r = sh_num;
|
||||
sym->jnext = value;
|
||||
return sym;
|
||||
}
|
||||
|
||||
static void asm_new_label(TCCState *s1, int label, int is_local)
|
||||
static Sym* asm_new_label(TCCState *s1, int label, int is_local)
|
||||
{
|
||||
asm_new_label1(s1, label, is_local, cur_text_section->sh_num, ind);
|
||||
return asm_new_label1(s1, label, is_local, cur_text_section->sh_num, ind);
|
||||
}
|
||||
|
||||
/* Set the value of LABEL to that of some expression (possibly
|
||||
involving other symbols). LABEL can be overwritten later still. */
|
||||
static Sym* set_symbol(TCCState *s1, int label)
|
||||
{
|
||||
long n;
|
||||
ExprValue e;
|
||||
next();
|
||||
asm_expr(s1, &e);
|
||||
n = e.v;
|
||||
if (e.sym)
|
||||
n += e.sym->jnext;
|
||||
return asm_new_label1(s1, label, 0, e.sym ? e.sym->r : SHN_ABS, n);
|
||||
}
|
||||
|
||||
static void asm_free_labels(TCCState *st)
|
||||
{
|
||||
Sym *s, *s1;
|
||||
Section *sec;
|
||||
|
||||
|
||||
for(s = st->asm_labels; s != NULL; s = s1) {
|
||||
s1 = s->prev;
|
||||
/* define symbol value in object file */
|
||||
if (s->r) {
|
||||
s->type.t &= ~VT_EXTERN;
|
||||
if (s->r && !(s->type.t & VT_IMPORT)) {
|
||||
if (s->r == SHN_ABS)
|
||||
sec = SECTION_ABS;
|
||||
else
|
||||
@ -324,23 +446,47 @@ static void use_section(TCCState *s1, const char *name)
|
||||
use_section1(s1, sec);
|
||||
}
|
||||
|
||||
static void asm_parse_directive(TCCState *s1)
|
||||
static void push_section(TCCState *s1, const char *name)
|
||||
{
|
||||
Section *sec = find_section(s1, name);
|
||||
sec->prev = cur_text_section;
|
||||
use_section1(s1, sec);
|
||||
}
|
||||
|
||||
static void pop_section(TCCState *s1)
|
||||
{
|
||||
Section *prev = cur_text_section->prev;
|
||||
if (!prev)
|
||||
tcc_error(".popsection without .pushsection");
|
||||
cur_text_section->prev = NULL;
|
||||
use_section1(s1, prev);
|
||||
}
|
||||
|
||||
static void asm_parse_directive(TCCState *s1, int global)
|
||||
{
|
||||
int n, offset, v, size, tok1;
|
||||
Section *sec;
|
||||
uint8_t *ptr;
|
||||
|
||||
/* assembler directive */
|
||||
next();
|
||||
sec = cur_text_section;
|
||||
switch(tok) {
|
||||
case TOK_ASM_align:
|
||||
case TOK_ASM_skip:
|
||||
case TOK_ASM_space:
|
||||
case TOK_ASMDIR_align:
|
||||
case TOK_ASMDIR_balign:
|
||||
case TOK_ASMDIR_p2align:
|
||||
case TOK_ASMDIR_skip:
|
||||
case TOK_ASMDIR_space:
|
||||
tok1 = tok;
|
||||
next();
|
||||
n = asm_int_expr(s1);
|
||||
if (tok1 == TOK_ASM_align) {
|
||||
if (tok1 == TOK_ASMDIR_p2align)
|
||||
{
|
||||
if (n < 0 || n > 30)
|
||||
tcc_error("invalid p2align, must be between 0 and 30");
|
||||
n = 1 << n;
|
||||
tok1 = TOK_ASMDIR_align;
|
||||
}
|
||||
if (tok1 == TOK_ASMDIR_align || tok1 == TOK_ASMDIR_balign) {
|
||||
if (n < 0 || (n & (n-1)) != 0)
|
||||
tcc_error("alignment must be a positive power of two");
|
||||
offset = (ind + n - 1) & -n;
|
||||
@ -349,6 +495,8 @@ static void asm_parse_directive(TCCState *s1)
|
||||
if (sec->sh_addralign < n)
|
||||
sec->sh_addralign = n;
|
||||
} else {
|
||||
if (n < 0)
|
||||
n = 0;
|
||||
size = n;
|
||||
}
|
||||
v = 0;
|
||||
@ -364,13 +512,17 @@ static void asm_parse_directive(TCCState *s1)
|
||||
}
|
||||
ind += size;
|
||||
break;
|
||||
case TOK_ASM_quad:
|
||||
case TOK_ASMDIR_quad:
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
size = 8;
|
||||
goto asm_data;
|
||||
#else
|
||||
next();
|
||||
for(;;) {
|
||||
uint64_t vl;
|
||||
const char *p;
|
||||
|
||||
p = tokc.cstr->data;
|
||||
p = tokc.str.data;
|
||||
if (tok != TOK_PPNUM) {
|
||||
error_constant:
|
||||
tcc_error("64 bit constant");
|
||||
@ -391,15 +543,16 @@ static void asm_parse_directive(TCCState *s1)
|
||||
next();
|
||||
}
|
||||
break;
|
||||
case TOK_ASM_byte:
|
||||
#endif
|
||||
case TOK_ASMDIR_byte:
|
||||
size = 1;
|
||||
goto asm_data;
|
||||
case TOK_ASM_word:
|
||||
case TOK_SHORT:
|
||||
case TOK_ASMDIR_word:
|
||||
case TOK_ASMDIR_short:
|
||||
size = 2;
|
||||
goto asm_data;
|
||||
case TOK_LONG:
|
||||
case TOK_INT:
|
||||
case TOK_ASMDIR_long:
|
||||
case TOK_ASMDIR_int:
|
||||
size = 4;
|
||||
asm_data:
|
||||
next();
|
||||
@ -409,6 +562,10 @@ static void asm_parse_directive(TCCState *s1)
|
||||
if (sec->sh_type != SHT_NOBITS) {
|
||||
if (size == 4) {
|
||||
gen_expr32(&e);
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
} else if (size == 8) {
|
||||
gen_expr64(&e);
|
||||
#endif
|
||||
} else {
|
||||
if (e.sym)
|
||||
expect("constant");
|
||||
@ -425,7 +582,7 @@ static void asm_parse_directive(TCCState *s1)
|
||||
next();
|
||||
}
|
||||
break;
|
||||
case TOK_ASM_fill:
|
||||
case TOK_ASMDIR_fill:
|
||||
{
|
||||
int repeat, size, val, i, j;
|
||||
uint8_t repeat_buf[8];
|
||||
@ -467,12 +624,46 @@ static void asm_parse_directive(TCCState *s1)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TOK_ASM_org:
|
||||
case TOK_ASMDIR_rept:
|
||||
{
|
||||
int repeat;
|
||||
TokenString *init_str;
|
||||
ParseState saved_parse_state = {0};
|
||||
next();
|
||||
repeat = asm_int_expr(s1);
|
||||
init_str = tok_str_alloc();
|
||||
next();
|
||||
while ((tok != TOK_ASMDIR_endr) && (tok != CH_EOF)) {
|
||||
tok_str_add_tok(init_str);
|
||||
next();
|
||||
}
|
||||
if (tok == CH_EOF) tcc_error("we at end of file, .endr not found");
|
||||
next();
|
||||
tok_str_add(init_str, -1);
|
||||
tok_str_add(init_str, 0);
|
||||
save_parse_state(&saved_parse_state);
|
||||
begin_macro(init_str, 1);
|
||||
while (repeat-- > 0) {
|
||||
tcc_assemble_internal(s1, (parse_flags & PARSE_FLAG_PREPROCESS),
|
||||
global);
|
||||
macro_ptr = init_str->str;
|
||||
}
|
||||
end_macro();
|
||||
restore_parse_state(&saved_parse_state);
|
||||
break;
|
||||
}
|
||||
case TOK_ASMDIR_org:
|
||||
{
|
||||
unsigned long n;
|
||||
ExprValue e;
|
||||
next();
|
||||
/* XXX: handle section symbols too */
|
||||
n = asm_int_expr(s1);
|
||||
asm_expr(s1, &e);
|
||||
n = e.v;
|
||||
if (e.sym) {
|
||||
if (e.sym->r != cur_text_section->sh_num)
|
||||
expect("constant or same-section symbol");
|
||||
n += e.sym->jnext;
|
||||
}
|
||||
if (n < ind)
|
||||
tcc_error("attempt to .org backwards");
|
||||
v = 0;
|
||||
@ -480,28 +671,37 @@ static void asm_parse_directive(TCCState *s1)
|
||||
goto zero_pad;
|
||||
}
|
||||
break;
|
||||
case TOK_ASM_globl:
|
||||
case TOK_ASM_global:
|
||||
case TOK_ASM_weak:
|
||||
tok1 = tok;
|
||||
case TOK_ASMDIR_set:
|
||||
next();
|
||||
tok1 = tok;
|
||||
next();
|
||||
/* Also accept '.set stuff', but don't do anything with this.
|
||||
It's used in GAS to set various features like '.set mips16'. */
|
||||
if (tok == ',')
|
||||
set_symbol(s1, tok1);
|
||||
break;
|
||||
case TOK_ASMDIR_globl:
|
||||
case TOK_ASMDIR_global:
|
||||
case TOK_ASMDIR_weak:
|
||||
case TOK_ASMDIR_hidden:
|
||||
tok1 = tok;
|
||||
do {
|
||||
Sym *sym;
|
||||
|
||||
next();
|
||||
sym = label_find(tok);
|
||||
if (!sym) {
|
||||
sym = label_push(&s1->asm_labels, tok, 0);
|
||||
sym->type.t = VT_VOID;
|
||||
}
|
||||
sym->type.t &= ~VT_STATIC;
|
||||
if (tok1 == TOK_ASM_weak)
|
||||
sym = get_asm_sym(tok, NULL);
|
||||
if (tok1 != TOK_ASMDIR_hidden)
|
||||
sym->type.t &= ~VT_STATIC;
|
||||
if (tok1 == TOK_ASMDIR_weak)
|
||||
sym->type.t |= VT_WEAK;
|
||||
else if (tok1 == TOK_ASMDIR_hidden)
|
||||
sym->type.t |= STV_HIDDEN << VT_VIS_SHIFT;
|
||||
next();
|
||||
} while (tok == ',');
|
||||
break;
|
||||
case TOK_ASM_string:
|
||||
case TOK_ASM_ascii:
|
||||
case TOK_ASM_asciz:
|
||||
case TOK_ASMDIR_string:
|
||||
case TOK_ASMDIR_ascii:
|
||||
case TOK_ASMDIR_asciz:
|
||||
{
|
||||
const uint8_t *p;
|
||||
int i, size, t;
|
||||
@ -511,9 +711,9 @@ static void asm_parse_directive(TCCState *s1)
|
||||
for(;;) {
|
||||
if (tok != TOK_STR)
|
||||
expect("string constant");
|
||||
p = tokc.cstr->data;
|
||||
size = tokc.cstr->size;
|
||||
if (t == TOK_ASM_ascii && size > 0)
|
||||
p = tokc.str.data;
|
||||
size = tokc.str.size;
|
||||
if (t == TOK_ASMDIR_ascii && size > 0)
|
||||
size--;
|
||||
for(i = 0; i < size; i++)
|
||||
g(p[i]);
|
||||
@ -526,9 +726,9 @@ static void asm_parse_directive(TCCState *s1)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TOK_ASM_text:
|
||||
case TOK_ASM_data:
|
||||
case TOK_ASM_bss:
|
||||
case TOK_ASMDIR_text:
|
||||
case TOK_ASMDIR_data:
|
||||
case TOK_ASMDIR_bss:
|
||||
{
|
||||
char sname[64];
|
||||
tok1 = tok;
|
||||
@ -538,11 +738,14 @@ static void asm_parse_directive(TCCState *s1)
|
||||
n = asm_int_expr(s1);
|
||||
next();
|
||||
}
|
||||
sprintf(sname, (n?".%s%d":".%s"), get_tok_str(tok1, NULL), n);
|
||||
if (n)
|
||||
sprintf(sname, "%s%d", get_tok_str(tok1, NULL), n);
|
||||
else
|
||||
sprintf(sname, "%s", get_tok_str(tok1, NULL));
|
||||
use_section(s1, sname);
|
||||
}
|
||||
break;
|
||||
case TOK_ASM_file:
|
||||
case TOK_ASMDIR_file:
|
||||
{
|
||||
char filename[512];
|
||||
|
||||
@ -550,7 +753,7 @@ static void asm_parse_directive(TCCState *s1)
|
||||
next();
|
||||
|
||||
if (tok == TOK_STR)
|
||||
pstrcat(filename, sizeof(filename), tokc.cstr->data);
|
||||
pstrcat(filename, sizeof(filename), tokc.str.data);
|
||||
else
|
||||
pstrcat(filename, sizeof(filename), get_tok_str(tok, NULL));
|
||||
|
||||
@ -560,7 +763,7 @@ static void asm_parse_directive(TCCState *s1)
|
||||
next();
|
||||
}
|
||||
break;
|
||||
case TOK_ASM_ident:
|
||||
case TOK_ASMDIR_ident:
|
||||
{
|
||||
char ident[256];
|
||||
|
||||
@ -568,7 +771,7 @@ static void asm_parse_directive(TCCState *s1)
|
||||
next();
|
||||
|
||||
if (tok == TOK_STR)
|
||||
pstrcat(ident, sizeof(ident), tokc.cstr->data);
|
||||
pstrcat(ident, sizeof(ident), tokc.str.data);
|
||||
else
|
||||
pstrcat(ident, sizeof(ident), get_tok_str(tok, NULL));
|
||||
|
||||
@ -578,7 +781,7 @@ static void asm_parse_directive(TCCState *s1)
|
||||
next();
|
||||
}
|
||||
break;
|
||||
case TOK_ASM_size:
|
||||
case TOK_ASMDIR_size:
|
||||
{
|
||||
Sym *sym;
|
||||
|
||||
@ -588,41 +791,36 @@ static void asm_parse_directive(TCCState *s1)
|
||||
tcc_error("label not found: %s", get_tok_str(tok, NULL));
|
||||
}
|
||||
|
||||
next();
|
||||
skip(',');
|
||||
/* XXX .size name,label2-label1 */
|
||||
if (s1->warn_unsupported)
|
||||
tcc_warning("ignoring .size %s,*", get_tok_str(tok, NULL));
|
||||
|
||||
while (tok != '\n' && tok != CH_EOF) {
|
||||
next();
|
||||
skip(',');
|
||||
while (tok != TOK_LINEFEED && tok != ';' && tok != CH_EOF) {
|
||||
next();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TOK_ASM_type:
|
||||
case TOK_ASMDIR_type:
|
||||
{
|
||||
Sym *sym;
|
||||
const char *newtype;
|
||||
|
||||
next();
|
||||
sym = label_find(tok);
|
||||
if (!sym) {
|
||||
sym = label_push(&s1->asm_labels, tok, 0);
|
||||
sym->type.t = VT_VOID;
|
||||
}
|
||||
|
||||
sym = get_asm_sym(tok, NULL);
|
||||
next();
|
||||
skip(',');
|
||||
if (tok == TOK_STR) {
|
||||
newtype = tokc.cstr->data;
|
||||
newtype = tokc.str.data;
|
||||
} else {
|
||||
if (tok == '@' || tok == '%')
|
||||
skip(tok);
|
||||
next();
|
||||
newtype = get_tok_str(tok, NULL);
|
||||
}
|
||||
|
||||
if (!strcmp(newtype, "function") || !strcmp(newtype, "STT_FUNC")) {
|
||||
sym->type.t = VT_FUNC;
|
||||
sym->type.t = (sym->type.t & ~VT_BTYPE) | VT_FUNC;
|
||||
}
|
||||
else if (s1->warn_unsupported)
|
||||
tcc_warning("change type of '%s' from 0x%x to '%s' ignored",
|
||||
@ -631,16 +829,19 @@ static void asm_parse_directive(TCCState *s1)
|
||||
next();
|
||||
}
|
||||
break;
|
||||
case TOK_SECTION1:
|
||||
case TOK_ASMDIR_pushsection:
|
||||
case TOK_ASMDIR_section:
|
||||
{
|
||||
char sname[256];
|
||||
int old_nb_section = s1->nb_sections;
|
||||
|
||||
tok1 = tok;
|
||||
/* XXX: support more options */
|
||||
next();
|
||||
sname[0] = '\0';
|
||||
while (tok != ';' && tok != TOK_LINEFEED && tok != ',') {
|
||||
if (tok == TOK_STR)
|
||||
pstrcat(sname, sizeof(sname), tokc.cstr->data);
|
||||
pstrcat(sname, sizeof(sname), tokc.str.data);
|
||||
else
|
||||
pstrcat(sname, sizeof(sname), get_tok_str(tok, NULL));
|
||||
next();
|
||||
@ -651,12 +852,26 @@ static void asm_parse_directive(TCCState *s1)
|
||||
if (tok != TOK_STR)
|
||||
expect("string constant");
|
||||
next();
|
||||
if (tok == ',') {
|
||||
next();
|
||||
if (tok == '@' || tok == '%')
|
||||
next();
|
||||
next();
|
||||
}
|
||||
}
|
||||
last_text_section = cur_text_section;
|
||||
use_section(s1, sname);
|
||||
if (tok1 == TOK_ASMDIR_section)
|
||||
use_section(s1, sname);
|
||||
else
|
||||
push_section(s1, sname);
|
||||
/* If we just allocated a new section reset its alignment to
|
||||
1. new_section normally acts for GCC compatibility and
|
||||
sets alignment to PTR_SIZE. The assembler behaves different. */
|
||||
if (old_nb_section != s1->nb_sections)
|
||||
cur_text_section->sh_addralign = 1;
|
||||
}
|
||||
break;
|
||||
case TOK_ASM_previous:
|
||||
case TOK_ASMDIR_previous:
|
||||
{
|
||||
Section *sec;
|
||||
next();
|
||||
@ -667,14 +882,18 @@ static void asm_parse_directive(TCCState *s1)
|
||||
last_text_section = sec;
|
||||
}
|
||||
break;
|
||||
case TOK_ASMDIR_popsection:
|
||||
next();
|
||||
pop_section(s1);
|
||||
break;
|
||||
#ifdef TCC_TARGET_I386
|
||||
case TOK_ASM_code16:
|
||||
case TOK_ASMDIR_code16:
|
||||
{
|
||||
next();
|
||||
s1->seg_size = 16;
|
||||
}
|
||||
break;
|
||||
case TOK_ASM_code32:
|
||||
case TOK_ASMDIR_code32:
|
||||
{
|
||||
next();
|
||||
s1->seg_size = 32;
|
||||
@ -683,7 +902,7 @@ static void asm_parse_directive(TCCState *s1)
|
||||
#endif
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
/* added for compatibility with GAS */
|
||||
case TOK_ASM_code64:
|
||||
case TOK_ASMDIR_code64:
|
||||
next();
|
||||
break;
|
||||
#endif
|
||||
@ -695,70 +914,45 @@ static void asm_parse_directive(TCCState *s1)
|
||||
|
||||
|
||||
/* assemble a file */
|
||||
static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
|
||||
static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
|
||||
{
|
||||
int opcode;
|
||||
|
||||
#if 0
|
||||
/* print stats about opcodes */
|
||||
{
|
||||
const ASMInstr *pa;
|
||||
int freq[4];
|
||||
int op_vals[500];
|
||||
int nb_op_vals, i, j;
|
||||
|
||||
nb_op_vals = 0;
|
||||
memset(freq, 0, sizeof(freq));
|
||||
for(pa = asm_instrs; pa->sym != 0; pa++) {
|
||||
freq[pa->nb_ops]++;
|
||||
for(i=0;i<pa->nb_ops;i++) {
|
||||
for(j=0;j<nb_op_vals;j++) {
|
||||
if (pa->op_type[i] == op_vals[j])
|
||||
goto found;
|
||||
}
|
||||
op_vals[nb_op_vals++] = pa->op_type[i];
|
||||
found: ;
|
||||
}
|
||||
}
|
||||
for(i=0;i<nb_op_vals;i++) {
|
||||
int v = op_vals[i];
|
||||
if ((v & (v - 1)) != 0)
|
||||
printf("%3d: %08x\n", i, v);
|
||||
}
|
||||
printf("size=%d nb=%d f0=%d f1=%d f2=%d f3=%d\n",
|
||||
sizeof(asm_instrs), sizeof(asm_instrs) / sizeof(ASMInstr),
|
||||
freq[0], freq[1], freq[2], freq[3]);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* XXX: undefine C labels */
|
||||
|
||||
ch = file->buf_ptr[0];
|
||||
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
|
||||
parse_flags = PARSE_FLAG_ASM_COMMENTS;
|
||||
parse_flags = PARSE_FLAG_ASM_FILE | PARSE_FLAG_TOK_STR;
|
||||
set_idnum('.', IS_ID);
|
||||
if (do_preprocess)
|
||||
parse_flags |= PARSE_FLAG_PREPROCESS;
|
||||
next();
|
||||
for(;;) {
|
||||
next();
|
||||
if (tok == TOK_EOF)
|
||||
break;
|
||||
/* generate line number info */
|
||||
if (global && s1->do_debug)
|
||||
tcc_debug_line(s1);
|
||||
parse_flags |= PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
|
||||
redo:
|
||||
if (tok == '#') {
|
||||
/* horrible gas comment */
|
||||
while (tok != TOK_LINEFEED)
|
||||
next();
|
||||
} else if (tok == '.') {
|
||||
asm_parse_directive(s1);
|
||||
} else if (tok >= TOK_ASMDIR_FIRST && tok <= TOK_ASMDIR_LAST) {
|
||||
asm_parse_directive(s1, global);
|
||||
} else if (tok == TOK_PPNUM) {
|
||||
Sym *sym;
|
||||
const char *p;
|
||||
int n;
|
||||
p = tokc.cstr->data;
|
||||
p = tokc.str.data;
|
||||
n = strtoul(p, (char **)&p, 10);
|
||||
if (*p != '\0')
|
||||
expect("':'");
|
||||
/* new local label */
|
||||
asm_new_label(s1, asm_get_local_label_name(s1, n), 1);
|
||||
sym = asm_new_label(s1, asm_get_local_label_name(s1, n), 1);
|
||||
/* Remove the marker for tentative definitions. */
|
||||
sym->type.t &= ~VT_EXTERN;
|
||||
next();
|
||||
skip(':');
|
||||
goto redo;
|
||||
@ -767,30 +961,35 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
|
||||
opcode = tok;
|
||||
next();
|
||||
if (tok == ':') {
|
||||
/* handle "extern void vide(void); __asm__("vide: ret");" as
|
||||
"__asm__("globl vide\nvide: ret");" */
|
||||
Sym *sym = sym_find(opcode);
|
||||
if (sym && (sym->type.t & VT_EXTERN) && global) {
|
||||
sym = label_find(opcode);
|
||||
if (!sym) {
|
||||
sym = label_push(&s1->asm_labels, opcode, 0);
|
||||
sym->type.t = VT_VOID | VT_EXTERN;
|
||||
}
|
||||
}
|
||||
/* new label */
|
||||
asm_new_label(s1, opcode, 0);
|
||||
sym = asm_new_label(s1, opcode, 0);
|
||||
sym->type.t &= ~VT_EXTERN;
|
||||
next();
|
||||
goto redo;
|
||||
} else if (tok == '=') {
|
||||
int n;
|
||||
next();
|
||||
n = asm_int_expr(s1);
|
||||
asm_new_label1(s1, opcode, 0, SHN_ABS, n);
|
||||
set_symbol(s1, opcode);
|
||||
goto redo;
|
||||
} else {
|
||||
asm_opcode(s1, opcode);
|
||||
}
|
||||
}
|
||||
/* end of line */
|
||||
if (tok != ';' && tok != TOK_LINEFEED){
|
||||
if (tok != ';' && tok != TOK_LINEFEED)
|
||||
expect("end of line");
|
||||
}
|
||||
parse_flags &= ~PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
|
||||
next();
|
||||
}
|
||||
|
||||
asm_free_labels(s1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -800,26 +999,21 @@ ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess)
|
||||
Sym *define_start;
|
||||
int ret;
|
||||
|
||||
preprocess_init(s1);
|
||||
define_start = define_stack;
|
||||
preprocess_start(s1);
|
||||
tcc_debug_start(s1);
|
||||
|
||||
/* default section is text */
|
||||
cur_text_section = text_section;
|
||||
ind = cur_text_section->data_offset;
|
||||
nocode_wanted = 0;
|
||||
|
||||
define_start = define_stack;
|
||||
|
||||
/* an elf symbol of type STT_FILE must be put so that STB_LOCAL
|
||||
symbols can be safely used */
|
||||
put_elf_sym(symtab_section, 0, 0,
|
||||
ELFW(ST_INFO)(STB_LOCAL, STT_FILE), 0,
|
||||
SHN_ABS, file->filename);
|
||||
|
||||
ret = tcc_assemble_internal(s1, do_preprocess);
|
||||
ret = tcc_assemble_internal(s1, do_preprocess, 1);
|
||||
|
||||
cur_text_section->data_offset = ind;
|
||||
|
||||
tcc_debug_end(s1);
|
||||
free_defines(define_start);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -829,7 +1023,7 @@ ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess)
|
||||
/* assemble the string 'str' in the current C compilation unit without
|
||||
C preprocessing. NOTE: str is modified by modifying the '\0' at the
|
||||
end */
|
||||
static void tcc_assemble_inline(TCCState *s1, char *str, int len)
|
||||
static void tcc_assemble_inline(TCCState *s1, char *str, int len, int global)
|
||||
{
|
||||
int saved_parse_flags;
|
||||
const int *saved_macro_ptr;
|
||||
@ -841,10 +1035,11 @@ static void tcc_assemble_inline(TCCState *s1, char *str, int len)
|
||||
memcpy(file->buffer, str, len);
|
||||
|
||||
macro_ptr = NULL;
|
||||
tcc_assemble_internal(s1, 0);
|
||||
tcc_assemble_internal(s1, 0, global);
|
||||
tcc_close();
|
||||
|
||||
parse_flags = saved_parse_flags;
|
||||
set_idnum('.', (parse_flags & PARSE_FLAG_ASM_FILE) ? IS_ID : 0);
|
||||
macro_ptr = saved_macro_ptr;
|
||||
}
|
||||
|
||||
@ -909,7 +1104,11 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands,
|
||||
}
|
||||
modifier = 0;
|
||||
if (*str == 'c' || *str == 'n' ||
|
||||
*str == 'b' || *str == 'w' || *str == 'h')
|
||||
*str == 'b' || *str == 'w' || *str == 'h' || *str == 'k' ||
|
||||
*str == 'q' ||
|
||||
/* P in GCC would add "@PLT" to symbol refs in PIC mode,
|
||||
and make literal operands not be decorated with '$'. */
|
||||
*str == 'P')
|
||||
modifier = *str++;
|
||||
index = find_constraint(operands, nb_operands, str, &str);
|
||||
if (index < 0)
|
||||
@ -941,6 +1140,7 @@ static void parse_asm_operands(ASMOperand *operands, int *nb_operands_ptr,
|
||||
if (tok != ':') {
|
||||
nb_operands = *nb_operands_ptr;
|
||||
for(;;) {
|
||||
CString astr;
|
||||
if (nb_operands >= MAX_ASM_OPERANDS)
|
||||
tcc_error("too many asm operands");
|
||||
op = &operands[nb_operands++];
|
||||
@ -953,15 +1153,15 @@ static void parse_asm_operands(ASMOperand *operands, int *nb_operands_ptr,
|
||||
next();
|
||||
skip(']');
|
||||
}
|
||||
if (tok != TOK_STR)
|
||||
expect("string constant");
|
||||
op->constraint = tcc_malloc(tokc.cstr->size);
|
||||
strcpy(op->constraint, tokc.cstr->data);
|
||||
next();
|
||||
parse_mult_str(&astr, "string constant");
|
||||
op->constraint = tcc_malloc(astr.size);
|
||||
strcpy(op->constraint, astr.data);
|
||||
cstr_free(&astr);
|
||||
skip('(');
|
||||
gexpr();
|
||||
if (is_output) {
|
||||
test_lvalue();
|
||||
if (!(vtop->type.t & VT_ARRAY))
|
||||
test_lvalue();
|
||||
} else {
|
||||
/* we want to avoid LLOCAL case, except when the 'm'
|
||||
constraint is used. Note that it may come from
|
||||
@ -1023,7 +1223,7 @@ ST_FUNC void asm_instr(void)
|
||||
for(;;) {
|
||||
if (tok != TOK_STR)
|
||||
expect("string constant");
|
||||
asm_clobber(clobber_regs, tokc.cstr->data);
|
||||
asm_clobber(clobber_regs, tokc.str.data);
|
||||
next();
|
||||
if (tok == ',') {
|
||||
next();
|
||||
@ -1068,7 +1268,7 @@ ST_FUNC void asm_instr(void)
|
||||
clobber_regs, out_reg);
|
||||
|
||||
/* assemble the string with tcc internal assembler */
|
||||
tcc_assemble_inline(tcc_state, astr1.data, astr1.size - 1);
|
||||
tcc_assemble_inline(tcc_state, astr1.data, astr1.size - 1, 0);
|
||||
|
||||
/* restore the current C token */
|
||||
next();
|
||||
@ -1090,7 +1290,10 @@ ST_FUNC void asm_instr(void)
|
||||
ST_FUNC void asm_global_instr(void)
|
||||
{
|
||||
CString astr;
|
||||
int saved_nocode_wanted = nocode_wanted;
|
||||
|
||||
/* Global asm blocks are always emitted. */
|
||||
nocode_wanted = 0;
|
||||
next();
|
||||
parse_asm_str(&astr);
|
||||
skip(')');
|
||||
@ -1106,7 +1309,7 @@ ST_FUNC void asm_global_instr(void)
|
||||
ind = cur_text_section->data_offset;
|
||||
|
||||
/* assemble the string with tcc internal assembler */
|
||||
tcc_assemble_inline(tcc_state, astr.data, astr.size - 1);
|
||||
tcc_assemble_inline(tcc_state, astr.data, astr.size - 1, 1);
|
||||
|
||||
cur_text_section->data_offset = ind;
|
||||
|
||||
@ -1114,5 +1317,6 @@ ST_FUNC void asm_global_instr(void)
|
||||
next();
|
||||
|
||||
cstr_free(&astr);
|
||||
nocode_wanted = saved_nocode_wanted;
|
||||
}
|
||||
#endif /* CONFIG_TCC_ASM */
|
||||
|
||||
@ -39,6 +39,7 @@ int getchar(void);
|
||||
char *gets(char *s);
|
||||
int ungetc(int c, FILE *stream);
|
||||
int fflush(FILE *stream);
|
||||
int putchar (int c);
|
||||
|
||||
int printf(const char *format, ...);
|
||||
int fprintf(FILE *stream, const char *format, ...);
|
||||
@ -64,6 +65,7 @@ void *memcpy(void *dest, const void *src, size_t n);
|
||||
void *memmove(void *dest, const void *src, size_t n);
|
||||
void *memset(void *s, int c, size_t n);
|
||||
char *strdup(const char *s);
|
||||
size_t strlen(const char *s);
|
||||
|
||||
/* dlfcn.h */
|
||||
#define RTLD_LAZY 0x001
|
||||
519
tccpe.c
519
tccpe.c
@ -20,6 +20,9 @@
|
||||
|
||||
#include "tcc.h"
|
||||
|
||||
#define PE_MERGE_DATA
|
||||
/* #define PE_PRINT_SECTIONS */
|
||||
|
||||
#ifndef _WIN32
|
||||
#define stricmp strcasecmp
|
||||
#define strnicmp strncasecmp
|
||||
@ -29,15 +32,33 @@
|
||||
#define MAX_PATH 260
|
||||
#endif
|
||||
|
||||
#define PE_MERGE_DATA
|
||||
// #define PE_PRINT_SECTIONS
|
||||
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
# define ADDR3264 ULONGLONG
|
||||
#else
|
||||
# define REL_TYPE_DIRECT R_X86_64_64
|
||||
# define R_XXX_THUNKFIX R_X86_64_PC32
|
||||
# define R_XXX_RELATIVE R_X86_64_RELATIVE
|
||||
# define IMAGE_FILE_MACHINE 0x8664
|
||||
# define RSRC_RELTYPE 3
|
||||
|
||||
#elif defined TCC_TARGET_ARM
|
||||
# define ADDR3264 DWORD
|
||||
# define REL_TYPE_DIRECT R_ARM_ABS32
|
||||
# define R_XXX_THUNKFIX R_ARM_ABS32
|
||||
# define R_XXX_RELATIVE R_ARM_RELATIVE
|
||||
# define IMAGE_FILE_MACHINE 0x01C0
|
||||
# define RSRC_RELTYPE 7 /* ??? (not tested) */
|
||||
|
||||
#elif defined TCC_TARGET_I386
|
||||
# define ADDR3264 DWORD
|
||||
# define REL_TYPE_DIRECT R_386_32
|
||||
# define R_XXX_THUNKFIX R_386_32
|
||||
# define R_XXX_RELATIVE R_386_RELATIVE
|
||||
# define IMAGE_FILE_MACHINE 0x014C
|
||||
# define RSRC_RELTYPE 7 /* DIR32NB */
|
||||
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#ifdef _WIN32
|
||||
void dbg_printf (const char *fmt, ...)
|
||||
{
|
||||
@ -50,6 +71,7 @@ void dbg_printf (const char *fmt, ...)
|
||||
OutputDebugString(buffer);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
#ifndef IMAGE_NT_SIGNATURE
|
||||
@ -336,6 +358,7 @@ struct pe_info {
|
||||
int type;
|
||||
DWORD sizeofheaders;
|
||||
ADDR3264 imagebase;
|
||||
const char *start_symbol;
|
||||
DWORD start_addr;
|
||||
DWORD imp_offs;
|
||||
DWORD imp_size;
|
||||
@ -363,7 +386,7 @@ struct pe_info {
|
||||
static const char *pe_export_name(TCCState *s1, ElfW(Sym) *sym)
|
||||
{
|
||||
const char *name = symtab_section->link->data + sym->st_name;
|
||||
if (s1->leading_underscore && name[0] == '_' && !(sym->st_other & 2))
|
||||
if (s1->leading_underscore && name[0] == '_' && !(sym->st_other & ST_PE_STDCALL))
|
||||
return name + 1;
|
||||
return name;
|
||||
}
|
||||
@ -373,12 +396,14 @@ static int pe_find_import(TCCState * s1, ElfW(Sym) *sym)
|
||||
char buffer[200];
|
||||
const char *s, *p;
|
||||
int sym_index = 0, n = 0;
|
||||
int a, err = 0;
|
||||
|
||||
do {
|
||||
s = pe_export_name(s1, sym);
|
||||
a = 0;
|
||||
if (n) {
|
||||
/* second try: */
|
||||
if (sym->st_other & 2) {
|
||||
if (sym->st_other & ST_PE_STDCALL) {
|
||||
/* try w/0 stdcall deco (windows API convention) */
|
||||
p = strrchr(s, '@');
|
||||
if (!p || s[0] != '_')
|
||||
@ -386,19 +411,24 @@ static int pe_find_import(TCCState * s1, ElfW(Sym) *sym)
|
||||
strcpy(buffer, s+1)[p-s-1] = 0;
|
||||
} else if (s[0] != '_') { /* try non-ansi function */
|
||||
buffer[0] = '_', strcpy(buffer + 1, s);
|
||||
} else if (0 == memcmp(s, "__imp__", 7)) { /* mingw 2.0 */
|
||||
strcpy(buffer, s + 6);
|
||||
} else if (0 == memcmp(s, "_imp___", 7)) { /* mingw 3.7 */
|
||||
strcpy(buffer, s + 6);
|
||||
} else if (0 == memcmp(s, "__imp_", 6)) { /* mingw 2.0 */
|
||||
strcpy(buffer, s + 6), a = 1;
|
||||
} else if (0 == memcmp(s, "_imp__", 6)) { /* mingw 3.7 */
|
||||
strcpy(buffer, s + 6), a = 1;
|
||||
} else {
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
s = buffer;
|
||||
}
|
||||
sym_index = find_elf_sym(s1->dynsymtab_section, s);
|
||||
// printf("find (%d) %d %s\n", n, sym_index, s);
|
||||
if (sym_index
|
||||
&& ELFW(ST_TYPE)(sym->st_info) == STT_OBJECT
|
||||
&& 0 == (sym->st_other & ST_PE_IMPORT)
|
||||
&& 0 == a
|
||||
) err = -1, sym_index = 0;
|
||||
} while (0 == sym_index && ++n < 2);
|
||||
return sym_index;
|
||||
return n == 2 ? err : sym_index;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
@ -507,13 +537,7 @@ static int pe_write(struct pe_info *pe)
|
||||
0x00004550, /* DWORD nt_sig = IMAGE_NT_SIGNATURE */
|
||||
{
|
||||
/* IMAGE_FILE_HEADER filehdr */
|
||||
#if defined(TCC_TARGET_I386)
|
||||
0x014C, /*WORD Machine; */
|
||||
#elif defined(TCC_TARGET_X86_64)
|
||||
0x8664, /*WORD Machine; */
|
||||
#elif defined(TCC_TARGET_ARM)
|
||||
0x01C0, /*WORD Machine; */
|
||||
#endif
|
||||
IMAGE_FILE_MACHINE, /*WORD Machine; */
|
||||
0x0003, /*WORD NumberOfSections; */
|
||||
0x00000000, /*DWORD TimeDateStamp; */
|
||||
0x00000000, /*DWORD PointerToSymbolTable; */
|
||||
@ -622,7 +646,6 @@ static int pe_write(struct pe_info *pe)
|
||||
switch (si->cls) {
|
||||
case sec_text:
|
||||
pe_header.opthdr.BaseOfCode = addr;
|
||||
pe_header.opthdr.AddressOfEntryPoint = addr + pe->start_addr;
|
||||
break;
|
||||
|
||||
case sec_data:
|
||||
@ -663,7 +686,7 @@ static int pe_write(struct pe_info *pe)
|
||||
}
|
||||
}
|
||||
|
||||
pstrcpy((char*)psh->Name, sizeof psh->Name, sh_name);
|
||||
strncpy((char*)psh->Name, sh_name, sizeof psh->Name);
|
||||
|
||||
psh->Characteristics = pe_sec_flags[si->cls];
|
||||
psh->VirtualAddress = addr;
|
||||
@ -675,11 +698,16 @@ static int pe_write(struct pe_info *pe)
|
||||
psh->PointerToRawData = file_offset;
|
||||
file_offset = pe_file_align(pe, file_offset + si->data_size);
|
||||
psh->SizeOfRawData = file_offset - psh->PointerToRawData;
|
||||
if (si->cls == sec_text)
|
||||
pe_header.opthdr.SizeOfCode += psh->SizeOfRawData;
|
||||
else
|
||||
pe_header.opthdr.SizeOfInitializedData += psh->SizeOfRawData;
|
||||
}
|
||||
}
|
||||
|
||||
//pe_header.filehdr.TimeDateStamp = time(NULL);
|
||||
pe_header.filehdr.NumberOfSections = pe->sec_count;
|
||||
pe_header.opthdr.AddressOfEntryPoint = pe->start_addr;
|
||||
pe_header.opthdr.SizeOfHeaders = pe->sizeofheaders;
|
||||
pe_header.opthdr.ImageBase = pe->imagebase;
|
||||
pe_header.opthdr.Subsystem = pe->subsystem;
|
||||
@ -687,6 +715,7 @@ static int pe_write(struct pe_info *pe)
|
||||
pe_header.opthdr.SizeOfStackReserve = pe->s1->pe_stack_size;
|
||||
if (PE_DLL == pe->type)
|
||||
pe_header.filehdr.Characteristics = CHARACTERISTICS_DLL;
|
||||
pe_header.filehdr.Characteristics |= pe->s1->pe_characteristics;
|
||||
|
||||
sum = 0;
|
||||
pe_fwrite(&pe_header, sizeof pe_header, op, &sum);
|
||||
@ -718,24 +747,6 @@ static int pe_write(struct pe_info *pe)
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#if defined(TCC_TARGET_X86_64)
|
||||
#define REL_TYPE_DIRECT R_X86_64_64
|
||||
#define R_XXX_THUNKFIX R_X86_64_PC32
|
||||
#define R_XXX_RELATIVE R_X86_64_RELATIVE
|
||||
|
||||
#elif defined(TCC_TARGET_I386)
|
||||
#define REL_TYPE_DIRECT R_386_32
|
||||
#define R_XXX_THUNKFIX R_386_32
|
||||
#define R_XXX_RELATIVE R_386_RELATIVE
|
||||
|
||||
#elif defined(TCC_TARGET_ARM)
|
||||
#define REL_TYPE_DIRECT R_ARM_ABS32
|
||||
#define R_XXX_THUNKFIX R_ARM_ABS32
|
||||
#define R_XXX_RELATIVE R_ARM_RELATIVE
|
||||
|
||||
#endif
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
static struct import_symbol *pe_add_import(struct pe_info *pe, int sym_index)
|
||||
{
|
||||
int i;
|
||||
@ -754,7 +765,7 @@ static struct import_symbol *pe_add_import(struct pe_info *pe, int sym_index)
|
||||
}
|
||||
p = tcc_mallocz(sizeof *p);
|
||||
p->dll_index = dll_index;
|
||||
dynarray_add((void***)&pe->imp_info, &pe->imp_count, p);
|
||||
dynarray_add(&pe->imp_info, &pe->imp_count, p);
|
||||
|
||||
found_dll:
|
||||
i = dynarray_assoc ((void**)p->symbols, p->sym_count, sym_index);
|
||||
@ -762,11 +773,21 @@ found_dll:
|
||||
return p->symbols[i];
|
||||
|
||||
s = tcc_mallocz(sizeof *s);
|
||||
dynarray_add((void***)&p->symbols, &p->sym_count, s);
|
||||
dynarray_add(&p->symbols, &p->sym_count, s);
|
||||
s->sym_index = sym_index;
|
||||
return s;
|
||||
}
|
||||
|
||||
void pe_free_imports(struct pe_info *pe)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < pe->imp_count; ++i) {
|
||||
struct pe_import_info *p = pe->imp_info[i];
|
||||
dynarray_reset(&p->symbols, &p->sym_count);
|
||||
}
|
||||
dynarray_reset(&pe->imp_info, &pe->imp_count);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static void pe_build_imports(struct pe_info *pe)
|
||||
{
|
||||
@ -819,36 +840,46 @@ static void pe_build_imports(struct pe_info *pe)
|
||||
ElfW(Sym) *imp_sym = (ElfW(Sym) *)pe->s1->dynsymtab_section->data + sym_index;
|
||||
ElfW(Sym) *org_sym = (ElfW(Sym) *)symtab_section->data + iat_index;
|
||||
const char *name = pe->s1->dynsymtab_section->link->data + imp_sym->st_name;
|
||||
int ordinal;
|
||||
|
||||
org_sym->st_value = thk_ptr;
|
||||
org_sym->st_shndx = pe->thunk->sh_num;
|
||||
v = pe->thunk->data_offset + rva_base;
|
||||
section_ptr_add(pe->thunk, sizeof(WORD)); /* hint, not used */
|
||||
put_elf_str(pe->thunk, name);
|
||||
|
||||
if (dllref)
|
||||
v = 0, ordinal = imp_sym->st_value; /* ordinal from pe_load_def */
|
||||
else
|
||||
ordinal = 0, v = imp_sym->st_value; /* address from tcc_add_symbol() */
|
||||
|
||||
#ifdef TCC_IS_NATIVE
|
||||
if (pe->type == PE_RUN) {
|
||||
v = imp_sym->st_value;
|
||||
if (dllref) {
|
||||
if ( !dllref->handle )
|
||||
dllref->handle = LoadLibrary(dllref->name);
|
||||
v = (ADDR3264)GetProcAddress(dllref->handle, name);
|
||||
v = (ADDR3264)GetProcAddress(dllref->handle, ordinal?(char*)0+ordinal:name);
|
||||
}
|
||||
if (!v)
|
||||
tcc_error_noabort("undefined symbol '%s'", name);
|
||||
}
|
||||
tcc_error_noabort("can't build symbol '%s'", name);
|
||||
} else
|
||||
#endif
|
||||
if (ordinal) {
|
||||
v = ordinal | (ADDR3264)1 << (sizeof(ADDR3264)*8 - 1);
|
||||
} else {
|
||||
v = pe->thunk->data_offset + rva_base;
|
||||
section_ptr_add(pe->thunk, sizeof(WORD)); /* hint, not used */
|
||||
put_elf_str(pe->thunk, name);
|
||||
}
|
||||
|
||||
} else {
|
||||
v = 0; /* last entry is zero */
|
||||
}
|
||||
|
||||
*(ADDR3264*)(pe->thunk->data+thk_ptr) =
|
||||
*(ADDR3264*)(pe->thunk->data+ent_ptr) = v;
|
||||
thk_ptr += sizeof (ADDR3264);
|
||||
ent_ptr += sizeof (ADDR3264);
|
||||
}
|
||||
dll_ptr += sizeof(IMAGE_IMPORT_DESCRIPTOR);
|
||||
dynarray_reset(&p->symbols, &p->sym_count);
|
||||
}
|
||||
dynarray_reset(&pe->imp_info, &pe->imp_count);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
@ -887,18 +918,18 @@ static void pe_build_exports(struct pe_info *pe)
|
||||
for (sym_index = 1; sym_index < sym_end; ++sym_index) {
|
||||
sym = (ElfW(Sym)*)symtab_section->data + sym_index;
|
||||
name = pe_export_name(pe->s1, sym);
|
||||
if ((sym->st_other & 1)
|
||||
if ((sym->st_other & ST_PE_EXPORT)
|
||||
/* export only symbols from actually written sections */
|
||||
&& pe->s1->sections[sym->st_shndx]->sh_addr) {
|
||||
p = tcc_malloc(sizeof *p);
|
||||
p->index = sym_index;
|
||||
p->name = name;
|
||||
dynarray_add((void***)&sorted, &sym_count, p);
|
||||
dynarray_add(&sorted, &sym_count, p);
|
||||
}
|
||||
#if 0
|
||||
if (sym->st_other & 1)
|
||||
if (sym->st_other & ST_PE_EXPORT)
|
||||
printf("export: %s\n", name);
|
||||
if (sym->st_other & 2)
|
||||
if (sym->st_other & ST_PE_STDCALL)
|
||||
printf("stdcall: %s\n", name);
|
||||
#endif
|
||||
}
|
||||
@ -938,7 +969,7 @@ static void pe_build_exports(struct pe_info *pe)
|
||||
} else {
|
||||
fprintf(op, "LIBRARY %s\n\nEXPORTS\n", dllname);
|
||||
if (pe->s1->verbose)
|
||||
printf("<- %s (%d symbols)\n", buf, sym_count);
|
||||
printf("<- %s (%d symbol%s)\n", buf, sym_count, "s" + (sym_count < 2));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1064,6 +1095,9 @@ static int pe_assign_addresses (struct pe_info *pe)
|
||||
struct section_info *si;
|
||||
Section *s;
|
||||
|
||||
if (PE_DLL == pe->type)
|
||||
pe->reloc = new_section(pe->s1, ".reloc", SHT_PROGBITS, 0);
|
||||
|
||||
// pe->thunk = new_section(pe->s1, ".iedat", SHT_PROGBITS, SHF_ALLOC);
|
||||
|
||||
section_order = tcc_malloc(pe->s1->nb_sections * sizeof (int));
|
||||
@ -1212,7 +1246,7 @@ static int pe_check_symbols(struct pe_info *pe)
|
||||
int imp_sym = pe_find_import(pe->s1, sym);
|
||||
struct import_symbol *is;
|
||||
|
||||
if (0 == imp_sym)
|
||||
if (imp_sym <= 0)
|
||||
goto not_found;
|
||||
|
||||
if (type == STT_NOTYPE) {
|
||||
@ -1270,7 +1304,7 @@ static int pe_check_symbols(struct pe_info *pe)
|
||||
/* patch the original symbol */
|
||||
sym->st_value = offset;
|
||||
sym->st_shndx = text_section->sh_num;
|
||||
sym->st_other &= ~1; /* do not export */
|
||||
sym->st_other &= ~ST_PE_EXPORT; /* do not export */
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1283,13 +1317,17 @@ static int pe_check_symbols(struct pe_info *pe)
|
||||
}
|
||||
|
||||
not_found:
|
||||
tcc_error_noabort("undefined symbol '%s'", name);
|
||||
if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK)
|
||||
/* STB_WEAK undefined symbols are accepted */
|
||||
continue;
|
||||
tcc_error_noabort("undefined symbol '%s'%s", name,
|
||||
imp_sym < 0 ? ", missing __declspec(dllimport)?":"");
|
||||
ret = -1;
|
||||
|
||||
} else if (pe->s1->rdynamic
|
||||
&& ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
|
||||
/* if -rdynamic option, then export all non local symbols */
|
||||
sym->st_other |= 1;
|
||||
sym->st_other |= ST_PE_EXPORT;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
@ -1437,25 +1475,15 @@ static void pe_print_sections(TCCState *s1, const char *fname)
|
||||
/* ------------------------------------------------------------- */
|
||||
/* helper function for load/store to insert one more indirection */
|
||||
|
||||
#ifndef TCC_TARGET_ARM
|
||||
ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2)
|
||||
{
|
||||
Sym *sym;
|
||||
ElfW(Sym) *esym;
|
||||
int r2;
|
||||
|
||||
if ((sv->r & (VT_VALMASK|VT_SYM)) != (VT_CONST|VT_SYM) || (sv->r2 != VT_CONST))
|
||||
return sv;
|
||||
sym = sv->sym;
|
||||
if ((sym->type.t & (VT_EXTERN|VT_STATIC)) != VT_EXTERN)
|
||||
if (!(sv->sym->type.t & VT_IMPORT))
|
||||
return sv;
|
||||
if (!sym->c)
|
||||
put_extern_sym(sym, NULL, 0, 0);
|
||||
esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
|
||||
if (!(esym->st_other & 4))
|
||||
return sv;
|
||||
|
||||
// printf("import %04x %04x %04x %s\n", sv->type.t, sym->type.t, sv->r, get_tok_str(sv->sym->v, NULL));
|
||||
|
||||
// printf("import %04x %04x %04x %s\n", sv->type.t, sv->sym->type.t, sv->r, get_tok_str(sv->sym->v, NULL));
|
||||
memset(v2, 0, sizeof *v2);
|
||||
v2->type.t = VT_PTR;
|
||||
v2->r = VT_CONST | VT_SYM | VT_LVAL;
|
||||
@ -1464,22 +1492,21 @@ ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2)
|
||||
r2 = get_reg(RC_INT);
|
||||
load(r2, v2);
|
||||
v2->r = r2;
|
||||
|
||||
if (sv->c.ui) {
|
||||
if ((uint32_t)sv->c.i) {
|
||||
vpushv(v2);
|
||||
vpushi(sv->c.ui);
|
||||
vpushi(sv->c.i);
|
||||
gen_opi('+');
|
||||
*v2 = *vtop--;
|
||||
}
|
||||
|
||||
v2->type.t = sv->type.t;
|
||||
v2->r |= sv->r & VT_LVAL;
|
||||
return v2;
|
||||
}
|
||||
#endif
|
||||
|
||||
ST_FUNC int pe_putimport(TCCState *s1, int dllindex, const char *name, addr_t value)
|
||||
{
|
||||
return add_elf_sym(
|
||||
return set_elf_sym(
|
||||
s1->dynsymtab_section,
|
||||
value,
|
||||
dllindex, /* st_size */
|
||||
@ -1499,7 +1526,7 @@ static int add_dllref(TCCState *s1, const char *dllname)
|
||||
return i + 1;
|
||||
dllref = tcc_mallocz(sizeof(DLLReference) + strlen(dllname));
|
||||
strcpy(dllref->name, dllname);
|
||||
dynarray_add((void ***) &s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);
|
||||
dynarray_add(&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);
|
||||
return s1->nb_loaded_dlls;
|
||||
}
|
||||
|
||||
@ -1511,6 +1538,102 @@ static int read_mem(int fd, unsigned offset, void *buffer, unsigned len)
|
||||
return len == read(fd, buffer, len);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
||||
PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp)
|
||||
{
|
||||
int l, i, n, n0, ret;
|
||||
char *p;
|
||||
int fd;
|
||||
|
||||
IMAGE_SECTION_HEADER ish;
|
||||
IMAGE_EXPORT_DIRECTORY ied;
|
||||
IMAGE_DOS_HEADER dh;
|
||||
IMAGE_FILE_HEADER ih;
|
||||
DWORD sig, ref, addr, ptr, namep;
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
IMAGE_OPTIONAL_HEADER64 oh;
|
||||
#else
|
||||
IMAGE_OPTIONAL_HEADER32 oh;
|
||||
#endif
|
||||
int pef_hdroffset, opt_hdroffset, sec_hdroffset;
|
||||
|
||||
n = n0 = 0;
|
||||
p = NULL;
|
||||
ret = -1;
|
||||
|
||||
fd = open(filename, O_RDONLY | O_BINARY);
|
||||
if (fd < 0)
|
||||
goto the_end_1;
|
||||
ret = 1;
|
||||
|
||||
if (!read_mem(fd, 0, &dh, sizeof dh))
|
||||
goto the_end;
|
||||
if (!read_mem(fd, dh.e_lfanew, &sig, sizeof sig))
|
||||
goto the_end;
|
||||
if (sig != 0x00004550)
|
||||
goto the_end;
|
||||
pef_hdroffset = dh.e_lfanew + sizeof sig;
|
||||
if (!read_mem(fd, pef_hdroffset, &ih, sizeof ih))
|
||||
goto the_end;
|
||||
if (IMAGE_FILE_MACHINE != ih.Machine) {
|
||||
if (ih.Machine == 0x014C)
|
||||
ret = 32;
|
||||
else if (ih.Machine == 0x8664)
|
||||
ret = 64;
|
||||
goto the_end;
|
||||
}
|
||||
opt_hdroffset = pef_hdroffset + sizeof ih;
|
||||
sec_hdroffset = opt_hdroffset + sizeof oh;
|
||||
if (!read_mem(fd, opt_hdroffset, &oh, sizeof oh))
|
||||
goto the_end;
|
||||
|
||||
if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes)
|
||||
goto the_end_0;
|
||||
|
||||
addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
||||
//printf("addr: %08x\n", addr);
|
||||
for (i = 0; i < ih.NumberOfSections; ++i) {
|
||||
if (!read_mem(fd, sec_hdroffset + i * sizeof ish, &ish, sizeof ish))
|
||||
goto the_end;
|
||||
//printf("vaddr: %08x\n", ish.VirtualAddress);
|
||||
if (addr >= ish.VirtualAddress && addr < ish.VirtualAddress + ish.SizeOfRawData)
|
||||
goto found;
|
||||
}
|
||||
goto the_end_0;
|
||||
|
||||
found:
|
||||
ref = ish.VirtualAddress - ish.PointerToRawData;
|
||||
if (!read_mem(fd, addr - ref, &ied, sizeof ied))
|
||||
goto the_end;
|
||||
|
||||
namep = ied.AddressOfNames - ref;
|
||||
for (i = 0; i < ied.NumberOfNames; ++i) {
|
||||
if (!read_mem(fd, namep, &ptr, sizeof ptr))
|
||||
goto the_end;
|
||||
namep += sizeof ptr;
|
||||
for (l = 0;;) {
|
||||
if (n+1 >= n0)
|
||||
p = tcc_realloc(p, n0 = n0 ? n0 * 2 : 256);
|
||||
if (!read_mem(fd, ptr - ref + l++, p + n, 1)) {
|
||||
tcc_free(p), p = NULL;
|
||||
goto the_end;
|
||||
}
|
||||
if (p[n++] == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (p)
|
||||
p[n] = 0;
|
||||
the_end_0:
|
||||
ret = 0;
|
||||
the_end:
|
||||
close(fd);
|
||||
the_end_1:
|
||||
*pp = p;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------
|
||||
* This is for compiled windows resources in 'coff' format
|
||||
* as generated by 'windres.exe -O coff ...'.
|
||||
@ -1527,7 +1650,7 @@ static int pe_load_res(TCCState *s1, int fd)
|
||||
if (!read_mem(fd, 0, &hdr, sizeof hdr))
|
||||
goto quit;
|
||||
|
||||
if (hdr.filehdr.Machine != 0x014C
|
||||
if (hdr.filehdr.Machine != IMAGE_FILE_MACHINE
|
||||
|| hdr.filehdr.NumberOfSections != 1
|
||||
|| strcmp(hdr.sectionhdr.Name, ".rsrc") != 0)
|
||||
goto quit;
|
||||
@ -1544,7 +1667,7 @@ static int pe_load_res(TCCState *s1, int fd)
|
||||
if (!read_mem(fd, offs, &rel, sizeof rel))
|
||||
goto quit;
|
||||
// printf("rsrc_reloc: %x %x %x\n", rel.offset, rel.size, rel.type);
|
||||
if (rel.type != 7) /* DIR32NB */
|
||||
if (rel.type != RSRC_RELTYPE)
|
||||
goto quit;
|
||||
put_elf_reloc(symtab_section, rsrc_section,
|
||||
rel.offset, R_XXX_RELATIVE, 0);
|
||||
@ -1556,45 +1679,36 @@ quit:
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
||||
static char *trimfront(char *p)
|
||||
{
|
||||
while (*p && (unsigned char)*p <= ' ')
|
||||
++p;
|
||||
++p;
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *trimback(char *a, char *e)
|
||||
{
|
||||
while (e > a && (unsigned char)e[-1] <= ' ')
|
||||
--e;
|
||||
--e;
|
||||
*e = 0;;
|
||||
return a;
|
||||
}
|
||||
|
||||
static char *get_line(char *line, int size, int fd)
|
||||
{
|
||||
int n;
|
||||
for (n = 0; n < size - 1; )
|
||||
if (read(fd, line + n, 1) < 1 || line[n++] == '\n')
|
||||
break;
|
||||
if (0 == n)
|
||||
return NULL;
|
||||
trimback(line, line + n);
|
||||
return trimfront(line);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
static int pe_load_def(TCCState *s1, int fd)
|
||||
{
|
||||
int state = 0, ret = -1, dllindex = 0;
|
||||
char line[400], dllname[80], *p;
|
||||
int state = 0, ret = -1, dllindex = 0, ord;
|
||||
char line[400], dllname[80], *p, *x;
|
||||
FILE *fp;
|
||||
|
||||
for (;;) {
|
||||
p = get_line(line, sizeof line, fd);
|
||||
if (NULL == p)
|
||||
break;
|
||||
fp = fdopen(dup(fd), "rb");
|
||||
while (fgets(line, sizeof line, fp))
|
||||
{
|
||||
p = trimfront(trimback(line, strchr(line, 0)));
|
||||
if (0 == *p || ';' == *p)
|
||||
continue;
|
||||
|
||||
switch (state) {
|
||||
case 0:
|
||||
if (0 != strnicmp(p, "LIBRARY", 7))
|
||||
@ -1612,32 +1726,45 @@ static int pe_load_def(TCCState *s1, int fd)
|
||||
case 2:
|
||||
dllindex = add_dllref(s1, dllname);
|
||||
++state;
|
||||
|
||||
/* fall through */
|
||||
default:
|
||||
pe_putimport(s1, dllindex, p, 0);
|
||||
/* get ordinal and will store in sym->st_value */
|
||||
ord = 0;
|
||||
x = strchr(p, ' ');
|
||||
if (x) {
|
||||
*x = 0, x = strrchr(x + 1, '@');
|
||||
if (x) {
|
||||
char *d;
|
||||
ord = (int)strtol(x + 1, &d, 10);
|
||||
if (*d)
|
||||
ord = 0;
|
||||
}
|
||||
}
|
||||
pe_putimport(s1, dllindex, p, ord);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
quit:
|
||||
fclose(fp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
#define TINY_IMPDEF_GET_EXPORT_NAMES_ONLY
|
||||
#include "win32/tools/tiny_impdef.c"
|
||||
|
||||
static int pe_load_dll(TCCState *s1, const char *dllname, int fd)
|
||||
static int pe_load_dll(TCCState *s1, const char *filename)
|
||||
{
|
||||
char *p, *q;
|
||||
int index;
|
||||
p = get_export_names(fd);
|
||||
if (!p)
|
||||
int index, ret;
|
||||
|
||||
ret = tcc_get_dllexports(filename, &p);
|
||||
if (ret) {
|
||||
return -1;
|
||||
index = add_dllref(s1, dllname);
|
||||
for (q = p; *q; q += 1 + strlen(q))
|
||||
pe_putimport(s1, index, q, 0);
|
||||
tcc_free(p);
|
||||
} else if (p) {
|
||||
index = add_dllref(s1, tcc_basename(filename));
|
||||
for (q = p; *q; q += 1 + strlen(q))
|
||||
pe_putimport(s1, index, q, 0);
|
||||
tcc_free(p);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1650,8 +1777,8 @@ ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd)
|
||||
ret = pe_load_def(s1, fd);
|
||||
else if (pe_load_res(s1, fd) == 0)
|
||||
ret = 0;
|
||||
else if (read_mem(fd, 0, buf, sizeof buf) && 0 == strncmp(buf, "MZ", 2))
|
||||
ret = pe_load_dll(s1, tcc_basename(filename), fd);
|
||||
else if (read_mem(fd, 0, buf, 4) && 0 == memcmp(buf, "MZ\220", 4))
|
||||
ret = pe_load_dll(s1, filename);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1726,74 +1853,122 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack)
|
||||
static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
|
||||
{
|
||||
const char *start_symbol;
|
||||
ADDR3264 addr = 0;
|
||||
int pe_type = 0;
|
||||
int unicode_entry = 0;
|
||||
|
||||
if (find_elf_sym(symtab_section, PE_STDSYM("WinMain","@16")))
|
||||
pe_type = PE_GUI;
|
||||
else
|
||||
if (find_elf_sym(symtab_section, PE_STDSYM("wWinMain","@16"))) {
|
||||
pe_type = PE_GUI;
|
||||
unicode_entry = PE_GUI;
|
||||
}
|
||||
else
|
||||
if (TCC_OUTPUT_DLL == s1->output_type) {
|
||||
pe_type = PE_DLL;
|
||||
/* need this for 'tccelf.c:relocate_section()' */
|
||||
s1->output_type = TCC_OUTPUT_EXE;
|
||||
}
|
||||
else
|
||||
else {
|
||||
pe_type = PE_EXE;
|
||||
if (find_elf_sym(symtab_section, "wmain"))
|
||||
unicode_entry = PE_EXE;
|
||||
}
|
||||
|
||||
start_symbol =
|
||||
TCC_OUTPUT_MEMORY == s1->output_type
|
||||
? PE_GUI == pe_type ? "__runwinmain" : "_main"
|
||||
? PE_GUI == pe_type ? (unicode_entry ? "__runwwinmain" : "__runwinmain")
|
||||
: (unicode_entry ? "__runwmain" : "__runmain")
|
||||
: PE_DLL == pe_type ? PE_STDSYM("__dllstart","@12")
|
||||
: PE_GUI == pe_type ? "__winstart" : "__start"
|
||||
: PE_GUI == pe_type ? (unicode_entry ? "__wwinstart": "__winstart")
|
||||
: (unicode_entry ? "__wstart" : "__start")
|
||||
;
|
||||
|
||||
if (!s1->leading_underscore || strchr(start_symbol, '@')) {
|
||||
if (!s1->leading_underscore || strchr(start_symbol, '@'))
|
||||
++start_symbol;
|
||||
if (start_symbol[0] != '_')
|
||||
start_symbol = NULL;
|
||||
}
|
||||
|
||||
/* grab the startup code from libtcc1 */
|
||||
if (start_symbol)
|
||||
add_elf_sym(symtab_section,
|
||||
0, 0,
|
||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
||||
SHN_UNDEF, start_symbol);
|
||||
#ifdef TCC_IS_NATIVE
|
||||
if (TCC_OUTPUT_MEMORY != s1->output_type || s1->runtime_main)
|
||||
#endif
|
||||
set_elf_sym(symtab_section,
|
||||
0, 0,
|
||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
||||
SHN_UNDEF, start_symbol);
|
||||
|
||||
tcc_add_pragma_libs(s1);
|
||||
|
||||
if (0 == s1->nostdlib) {
|
||||
static const char *libs[] = {
|
||||
"libtcc1.a", "msvcrt", "kernel32", "", "user32", "gdi32", NULL
|
||||
TCC_LIBTCC1, "msvcrt", "kernel32", "", "user32", "gdi32", NULL
|
||||
};
|
||||
const char **pp, *p;
|
||||
for (pp = libs; 0 != (p = *pp); ++pp) {
|
||||
if (0 == *p) {
|
||||
if (PE_DLL != pe_type && PE_GUI != pe_type)
|
||||
break;
|
||||
} else if (pp == libs ? tcc_add_dll(s1, p, 0) : tcc_add_library(s1, p)) {
|
||||
tcc_error_noabort("cannot find library: %s", p);
|
||||
break;
|
||||
} else if (pp == libs && tcc_add_dll(s1, p, 0) >= 0) {
|
||||
continue;
|
||||
} else {
|
||||
tcc_add_library_err(s1, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (TCC_OUTPUT_MEMORY == s1->output_type)
|
||||
pe_type = PE_RUN;
|
||||
|
||||
if (start_symbol) {
|
||||
addr = get_elf_sym_addr(s1, start_symbol, 1);
|
||||
if (PE_RUN == pe_type && addr)
|
||||
/* for -run GUI's, put '_runwinmain' instead of 'main' */
|
||||
add_elf_sym(symtab_section,
|
||||
addr, 0,
|
||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
||||
text_section->sh_num, "main");
|
||||
}
|
||||
|
||||
pe->type = pe_type;
|
||||
pe->start_addr = addr;
|
||||
pe->start_symbol = start_symbol;
|
||||
}
|
||||
|
||||
ST_FUNC int pe_output_file(TCCState * s1, const char *filename)
|
||||
static void pe_set_options(TCCState * s1, struct pe_info *pe)
|
||||
{
|
||||
if (PE_DLL == pe->type) {
|
||||
/* XXX: check if is correct for arm-pe target */
|
||||
pe->imagebase = 0x10000000;
|
||||
} else {
|
||||
#if defined(TCC_TARGET_ARM)
|
||||
pe->imagebase = 0x00010000;
|
||||
#else
|
||||
pe->imagebase = 0x00400000;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(TCC_TARGET_ARM)
|
||||
/* we use "console" subsystem by default */
|
||||
pe->subsystem = 9;
|
||||
#else
|
||||
if (PE_DLL == pe->type || PE_GUI == pe->type)
|
||||
pe->subsystem = 2;
|
||||
else
|
||||
pe->subsystem = 3;
|
||||
#endif
|
||||
/* Allow override via -Wl,-subsystem=... option */
|
||||
if (s1->pe_subsystem != 0)
|
||||
pe->subsystem = s1->pe_subsystem;
|
||||
|
||||
/* set default file/section alignment */
|
||||
if (pe->subsystem == 1) {
|
||||
pe->section_align = 0x20;
|
||||
pe->file_align = 0x20;
|
||||
} else {
|
||||
pe->section_align = 0x1000;
|
||||
pe->file_align = 0x200;
|
||||
}
|
||||
|
||||
if (s1->section_align != 0)
|
||||
pe->section_align = s1->section_align;
|
||||
if (s1->pe_file_align != 0)
|
||||
pe->file_align = s1->pe_file_align;
|
||||
|
||||
if ((pe->subsystem >= 10) && (pe->subsystem <= 12))
|
||||
pe->imagebase = 0;
|
||||
|
||||
if (s1->has_text_addr)
|
||||
pe->imagebase = s1->text_addr;
|
||||
}
|
||||
|
||||
ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
|
||||
{
|
||||
int ret;
|
||||
struct pe_info pe;
|
||||
@ -1807,58 +1982,14 @@ ST_FUNC int pe_output_file(TCCState * s1, const char *filename)
|
||||
pe_add_runtime(s1, &pe);
|
||||
relocate_common_syms(); /* assign bss adresses */
|
||||
tcc_add_linker_symbols(s1);
|
||||
pe_set_options(s1, &pe);
|
||||
|
||||
ret = pe_check_symbols(&pe);
|
||||
if (ret)
|
||||
;
|
||||
else if (filename) {
|
||||
if (PE_DLL == pe.type) {
|
||||
pe.reloc = new_section(pe.s1, ".reloc", SHT_PROGBITS, 0);
|
||||
/* XXX: check if is correct for arm-pe target */
|
||||
pe.imagebase = 0x10000000;
|
||||
} else {
|
||||
#if defined(TCC_TARGET_ARM)
|
||||
pe.imagebase = 0x00010000;
|
||||
#else
|
||||
pe.imagebase = 0x00400000;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(TCC_TARGET_ARM)
|
||||
/* we use "console" subsystem by default */
|
||||
pe.subsystem = 9;
|
||||
#else
|
||||
if (PE_DLL == pe.type || PE_GUI == pe.type)
|
||||
pe.subsystem = 2;
|
||||
else
|
||||
pe.subsystem = 3;
|
||||
#endif
|
||||
/* Allow override via -Wl,-subsystem=... option */
|
||||
if (s1->pe_subsystem != 0)
|
||||
pe.subsystem = s1->pe_subsystem;
|
||||
|
||||
/* set default file/section alignment */
|
||||
if (pe.subsystem == 1) {
|
||||
pe.section_align = 0x20;
|
||||
pe.file_align = 0x20;
|
||||
} else {
|
||||
pe.section_align = 0x1000;
|
||||
pe.file_align = 0x200;
|
||||
}
|
||||
|
||||
if (s1->section_align != 0)
|
||||
pe.section_align = s1->section_align;
|
||||
if (s1->pe_file_align != 0)
|
||||
pe.file_align = s1->pe_file_align;
|
||||
|
||||
if ((pe.subsystem >= 10) && (pe.subsystem <= 12))
|
||||
pe.imagebase = 0;
|
||||
|
||||
if (s1->has_text_addr)
|
||||
pe.imagebase = s1->text_addr;
|
||||
|
||||
pe_assign_addresses(&pe);
|
||||
relocate_syms(s1, 0);
|
||||
relocate_syms(s1, s1->symtab, 0);
|
||||
for (i = 1; i < s1->nb_sections; ++i) {
|
||||
Section *s = s1->sections[i];
|
||||
if (s->reloc) {
|
||||
@ -1866,6 +1997,9 @@ ST_FUNC int pe_output_file(TCCState * s1, const char *filename)
|
||||
pe_relocate_rva(&pe, s);
|
||||
}
|
||||
}
|
||||
pe.start_addr = (DWORD)
|
||||
((uintptr_t)tcc_get_symbol_err(s1, pe.start_symbol)
|
||||
- pe.imagebase);
|
||||
if (s1->nb_errors)
|
||||
ret = -1;
|
||||
else
|
||||
@ -1875,9 +2009,12 @@ ST_FUNC int pe_output_file(TCCState * s1, const char *filename)
|
||||
#ifdef TCC_IS_NATIVE
|
||||
pe.thunk = data_section;
|
||||
pe_build_imports(&pe);
|
||||
s1->runtime_main = pe.start_symbol;
|
||||
#endif
|
||||
}
|
||||
|
||||
pe_free_imports(&pe);
|
||||
|
||||
#ifdef PE_PRINT_SECTIONS
|
||||
pe_print_sections(s1, "tcc.log");
|
||||
#endif
|
||||
|
||||
287
tccrun.c
287
tccrun.c
@ -23,81 +23,94 @@
|
||||
/* only native compiler supports -run */
|
||||
#ifdef TCC_IS_NATIVE
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TCC_BACKTRACE
|
||||
# ifndef _WIN32
|
||||
# include <signal.h>
|
||||
# ifndef __OpenBSD__
|
||||
# include <sys/ucontext.h>
|
||||
# endif
|
||||
# else
|
||||
# define ucontext_t CONTEXT
|
||||
# endif
|
||||
ST_DATA int rt_num_callers = 6;
|
||||
ST_DATA const char **rt_bound_error_msg;
|
||||
ST_DATA void *rt_prog_main;
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define ucontext_t CONTEXT
|
||||
static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level);
|
||||
static void rt_error(ucontext_t *uc, const char *fmt, ...);
|
||||
static void set_exception_handler(void);
|
||||
#endif
|
||||
|
||||
static void set_pages_executable(void *ptr, unsigned long length);
|
||||
static void set_exception_handler(void);
|
||||
static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level);
|
||||
static void rt_error(ucontext_t *uc, const char *fmt, ...);
|
||||
static int tcc_relocate_ex(TCCState *s1, void *ptr);
|
||||
|
||||
#ifdef _WIN64
|
||||
static void win64_add_function_table(TCCState *s1);
|
||||
static void *win64_add_function_table(TCCState *s1);
|
||||
static void win64_del_function_table(void *);
|
||||
#endif
|
||||
|
||||
// #define HAVE_SELINUX
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
/* Do all relocations (needed before using tcc_get_symbol())
|
||||
Returns -1 on error. */
|
||||
|
||||
LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr)
|
||||
{
|
||||
int ret;
|
||||
int size;
|
||||
|
||||
if (TCC_RELOCATE_AUTO != ptr)
|
||||
return tcc_relocate_ex(s1, ptr);
|
||||
|
||||
ret = tcc_relocate_ex(s1, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
size = tcc_relocate_ex(s1, NULL);
|
||||
if (size < 0)
|
||||
return -1;
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
{ /* Use mmap instead of malloc for Selinux. Ref:
|
||||
http://www.gnu.org/s/libc/manual/html_node/File-Size.html */
|
||||
|
||||
char tmpfname[] = "/tmp/.tccrunXXXXXX";
|
||||
int fd = mkstemp (tmpfname);
|
||||
|
||||
s1->mem_size = ret;
|
||||
unlink (tmpfname);
|
||||
ftruncate (fd, s1->mem_size);
|
||||
|
||||
s1->write_mem = mmap (NULL, ret, PROT_READ|PROT_WRITE,
|
||||
MAP_SHARED, fd, 0);
|
||||
if (s1->write_mem == MAP_FAILED)
|
||||
tcc_error("/tmp not writeable");
|
||||
|
||||
s1->runtime_mem = mmap (NULL, ret, PROT_READ|PROT_EXEC,
|
||||
MAP_SHARED, fd, 0);
|
||||
if (s1->runtime_mem == MAP_FAILED)
|
||||
tcc_error("/tmp not executable");
|
||||
|
||||
ret = tcc_relocate_ex(s1, s1->write_mem);
|
||||
}
|
||||
/* Use mmap instead of malloc for Selinux. */
|
||||
ptr = mmap (NULL, size, PROT_READ|PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (ptr == MAP_FAILED)
|
||||
tcc_error("tccrun: could not map memory");
|
||||
dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, (void*)(addr_t)size);
|
||||
#else
|
||||
s1->runtime_mem = tcc_malloc(ret);
|
||||
ret = tcc_relocate_ex(s1, s1->runtime_mem);
|
||||
ptr = tcc_malloc(size);
|
||||
#endif
|
||||
return ret;
|
||||
tcc_relocate_ex(s1, ptr); /* no more errors expected */
|
||||
dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ST_FUNC void tcc_run_free(TCCState *s1)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s1->nb_runtime_mem; ++i) {
|
||||
#ifdef HAVE_SELINUX
|
||||
unsigned size = (unsigned)(addr_t)s1->runtime_mem[i++];
|
||||
munmap(s1->runtime_mem[i], size);
|
||||
#else
|
||||
#ifdef _WIN64
|
||||
win64_del_function_table(*(void**)s1->runtime_mem[i]);
|
||||
#endif
|
||||
tcc_free(s1->runtime_mem[i]);
|
||||
#endif
|
||||
}
|
||||
tcc_free(s1->runtime_mem);
|
||||
}
|
||||
|
||||
/* launch the compiled program with the given arguments */
|
||||
LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
|
||||
{
|
||||
int (*prog_main)(int, char **);
|
||||
int ret;
|
||||
|
||||
s1->runtime_main = "main";
|
||||
if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
|
||||
return -1;
|
||||
|
||||
prog_main = tcc_get_symbol_err(s1, "main");
|
||||
prog_main = tcc_get_symbol_err(s1, s1->runtime_main);
|
||||
|
||||
#ifdef CONFIG_TCC_BACKTRACE
|
||||
if (s1->do_debug) {
|
||||
@ -106,32 +119,56 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
|
||||
}
|
||||
#endif
|
||||
|
||||
errno = 0; /* clean errno value */
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (s1->do_bounds_check) {
|
||||
void (*bound_init)(void);
|
||||
void (*bound_exit)(void);
|
||||
void (*bound_new_region)(void *p, addr_t size);
|
||||
int (*bound_delete_region)(void *p);
|
||||
int i, ret;
|
||||
|
||||
/* set error function */
|
||||
rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
|
||||
/* XXX: use .init section so that it also work in binary ? */
|
||||
bound_init = tcc_get_symbol_err(s1, "__bound_init");
|
||||
bound_exit = tcc_get_symbol_err(s1, "__bound_exit");
|
||||
bound_new_region = tcc_get_symbol_err(s1, "__bound_new_region");
|
||||
bound_delete_region = tcc_get_symbol_err(s1, "__bound_delete_region");
|
||||
|
||||
bound_init();
|
||||
/* mark argv area as valid */
|
||||
bound_new_region(argv, argc*sizeof(argv[0]));
|
||||
for (i=0; i<argc; ++i)
|
||||
bound_new_region(argv[i], strlen(argv[i]) + 1);
|
||||
|
||||
ret = (*prog_main)(argc, argv);
|
||||
|
||||
/* unmark argv area */
|
||||
for (i=0; i<argc; ++i)
|
||||
bound_delete_region(argv[i]);
|
||||
bound_delete_region(argv);
|
||||
bound_exit();
|
||||
} else
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
ret = (*prog_main)(argc, argv);
|
||||
return ret;
|
||||
return (*prog_main)(argc, argv);
|
||||
}
|
||||
|
||||
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
|
||||
#define RUN_SECTION_ALIGNMENT 63
|
||||
#else
|
||||
#define RUN_SECTION_ALIGNMENT 15
|
||||
#endif
|
||||
|
||||
/* relocate code. Return -1 on error, required size if ptr is NULL,
|
||||
otherwise copy code into buffer passed by the caller */
|
||||
static int tcc_relocate_ex(TCCState *s1, void *ptr)
|
||||
{
|
||||
Section *s;
|
||||
unsigned long offset, length;
|
||||
unsigned offset, length, fill, i, k;
|
||||
addr_t mem;
|
||||
int i;
|
||||
|
||||
if (NULL == ptr) {
|
||||
s1->nb_errors = 0;
|
||||
@ -148,31 +185,42 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr)
|
||||
}
|
||||
|
||||
offset = 0, mem = (addr_t)ptr;
|
||||
for(i = 1; i < s1->nb_sections; i++) {
|
||||
s = s1->sections[i];
|
||||
if (0 == (s->sh_flags & SHF_ALLOC))
|
||||
continue;
|
||||
length = s->data_offset;
|
||||
s->sh_addr = mem ? (mem + offset + 15) & ~15 : 0;
|
||||
offset = (offset + length + 15) & ~15;
|
||||
fill = -mem & RUN_SECTION_ALIGNMENT;
|
||||
#ifdef _WIN64
|
||||
offset += sizeof (void*);
|
||||
#endif
|
||||
for (k = 0; k < 2; ++k) {
|
||||
for(i = 1; i < s1->nb_sections; i++) {
|
||||
s = s1->sections[i];
|
||||
if (0 == (s->sh_flags & SHF_ALLOC))
|
||||
continue;
|
||||
if (k != !(s->sh_flags & SHF_EXECINSTR))
|
||||
continue;
|
||||
offset += fill;
|
||||
s->sh_addr = mem ? mem + offset : 0;
|
||||
#if 0
|
||||
if (mem)
|
||||
printf("%-16s +%02lx %p %04x\n",
|
||||
s->name, fill, (void*)s->sh_addr, (unsigned)s->data_offset);
|
||||
#endif
|
||||
offset += s->data_offset;
|
||||
fill = -(mem + offset) & 15;
|
||||
}
|
||||
#if RUN_SECTION_ALIGNMENT > 15
|
||||
/* To avoid that x86 processors would reload cached instructions each time
|
||||
when data is written in the near, we need to make sure that code and data
|
||||
do not share the same 64 byte unit */
|
||||
fill = -(mem + offset) & RUN_SECTION_ALIGNMENT;
|
||||
#endif
|
||||
}
|
||||
offset += 16;
|
||||
|
||||
/* relocate symbols */
|
||||
relocate_syms(s1, 1);
|
||||
relocate_syms(s1, s1->symtab, 1);
|
||||
if (s1->nb_errors)
|
||||
return -1;
|
||||
|
||||
#ifdef TCC_HAS_RUNTIME_PLTGOT
|
||||
s1->runtime_plt_and_got_offset = 0;
|
||||
s1->runtime_plt_and_got = (char *)(mem + offset);
|
||||
/* double the size of the buffer for got and plt entries
|
||||
XXX: calculate exact size for them? */
|
||||
offset *= 2;
|
||||
#endif
|
||||
|
||||
if (0 == mem)
|
||||
return offset;
|
||||
return offset + RUN_SECTION_ALIGNMENT;
|
||||
|
||||
/* relocate each section */
|
||||
for(i = 1; i < s1->nb_sections; i++) {
|
||||
@ -180,13 +228,17 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr)
|
||||
if (s->reloc)
|
||||
relocate_section(s1, s);
|
||||
}
|
||||
relocate_plt(s1);
|
||||
|
||||
#ifdef _WIN64
|
||||
*(void**)ptr = win64_add_function_table(s1);
|
||||
#endif
|
||||
|
||||
for(i = 1; i < s1->nb_sections; i++) {
|
||||
s = s1->sections[i];
|
||||
if (0 == (s->sh_flags & SHF_ALLOC))
|
||||
continue;
|
||||
length = s->data_offset;
|
||||
// printf("%-12s %08x %04x\n", s->name, s->sh_addr, length);
|
||||
ptr = (void*)s->sh_addr;
|
||||
if (NULL == s->data || s->sh_type == SHT_NOBITS)
|
||||
memset(ptr, 0, length);
|
||||
@ -196,15 +248,6 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr)
|
||||
if (s->sh_flags & SHF_EXECINSTR)
|
||||
set_pages_executable(ptr, length);
|
||||
}
|
||||
|
||||
#ifdef TCC_HAS_RUNTIME_PLTGOT
|
||||
set_pages_executable(s1->runtime_plt_and_got,
|
||||
s1->runtime_plt_and_got_offset);
|
||||
#endif
|
||||
|
||||
#ifdef _WIN64
|
||||
win64_add_function_table(s1);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -217,17 +260,46 @@ static void set_pages_executable(void *ptr, unsigned long length)
|
||||
unsigned long old_protect;
|
||||
VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect);
|
||||
#else
|
||||
void __clear_cache(void *beginning, void *end);
|
||||
addr_t start, end;
|
||||
#ifndef PAGESIZE
|
||||
# define PAGESIZE 4096
|
||||
#endif
|
||||
addr_t start, end;
|
||||
start = (addr_t)ptr & ~(PAGESIZE - 1);
|
||||
end = (addr_t)ptr + length;
|
||||
end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1);
|
||||
mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
if (mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC))
|
||||
tcc_error("mprotect failed: did you mean to configure --with-selinux?");
|
||||
# if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64
|
||||
__clear_cache(ptr, (char *)ptr + length);
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
static void *win64_add_function_table(TCCState *s1)
|
||||
{
|
||||
void *p = NULL;
|
||||
if (s1->uw_pdata) {
|
||||
p = (void*)s1->uw_pdata->sh_addr;
|
||||
RtlAddFunctionTable(
|
||||
(RUNTIME_FUNCTION*)p,
|
||||
s1->uw_pdata->data_offset / sizeof (RUNTIME_FUNCTION),
|
||||
text_section->sh_addr
|
||||
);
|
||||
s1->uw_pdata = NULL;
|
||||
}
|
||||
return p;;
|
||||
}
|
||||
|
||||
static void win64_del_function_table(void *p)
|
||||
{
|
||||
if (p) {
|
||||
RtlDeleteFunctionTable((RUNTIME_FUNCTION*)p);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
#ifdef CONFIG_TCC_BACKTRACE
|
||||
|
||||
@ -253,7 +325,7 @@ static addr_t rt_printline(addr_t wanted_pc, const char *msg)
|
||||
if (stab_section) {
|
||||
stab_len = stab_section->data_offset;
|
||||
stab_sym = (Stab_Sym *)stab_section->data;
|
||||
stab_str = stabstr_section->data;
|
||||
stab_str = (char *) stabstr_section->data;
|
||||
}
|
||||
|
||||
func_name[0] = '\0';
|
||||
@ -346,7 +418,7 @@ no_stabs:
|
||||
if (wanted_pc >= sym->st_value &&
|
||||
wanted_pc < sym->st_value + sym->st_size) {
|
||||
pstrcpy(last_func_name, sizeof(last_func_name),
|
||||
strtab_section->data + sym->st_name);
|
||||
(char *) strtab_section->data + sym->st_name);
|
||||
func_addr = sym->st_value;
|
||||
goto found;
|
||||
}
|
||||
@ -479,10 +551,14 @@ static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
|
||||
if (level == 0) {
|
||||
#if defined(__APPLE__)
|
||||
*paddr = uc->uc_mcontext->__ss.__eip;
|
||||
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
|
||||
*paddr = uc->uc_mcontext.mc_eip;
|
||||
#elif defined(__dietlibc__)
|
||||
*paddr = uc->uc_mcontext.eip;
|
||||
#elif defined(__NetBSD__)
|
||||
*paddr = uc->uc_mcontext.__gregs[_REG_EIP];
|
||||
#elif defined(__OpenBSD__)
|
||||
*paddr = uc->sc_eip;
|
||||
#else
|
||||
*paddr = uc->uc_mcontext.gregs[REG_EIP];
|
||||
#endif
|
||||
@ -490,10 +566,14 @@ static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
|
||||
} else {
|
||||
#if defined(__APPLE__)
|
||||
fp = uc->uc_mcontext->__ss.__ebp;
|
||||
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
|
||||
fp = uc->uc_mcontext.mc_ebp;
|
||||
#elif defined(__dietlibc__)
|
||||
fp = uc->uc_mcontext.ebp;
|
||||
#elif defined(__NetBSD__)
|
||||
fp = uc->uc_mcontext.__gregs[_REG_EBP];
|
||||
#elif defined(__OpenBSD__)
|
||||
*paddr = uc->sc_ebp;
|
||||
#else
|
||||
fp = uc->uc_mcontext.gregs[REG_EBP];
|
||||
#endif
|
||||
@ -521,8 +601,10 @@ static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
|
||||
/* XXX: only support linux */
|
||||
#if defined(__APPLE__)
|
||||
*paddr = uc->uc_mcontext->__ss.__rip;
|
||||
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
|
||||
*paddr = uc->uc_mcontext.mc_rip;
|
||||
#elif defined(__NetBSD__)
|
||||
*paddr = uc->uc_mcontext.__gregs[_REG_RIP];
|
||||
#else
|
||||
*paddr = uc->uc_mcontext.gregs[REG_RIP];
|
||||
#endif
|
||||
@ -530,8 +612,10 @@ static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
|
||||
} else {
|
||||
#if defined(__APPLE__)
|
||||
fp = uc->uc_mcontext->__ss.__rbp;
|
||||
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
|
||||
fp = uc->uc_mcontext.mc_rbp;
|
||||
#elif defined(__NetBSD__)
|
||||
fp = uc->uc_mcontext.__gregs[_REG_RBP];
|
||||
#else
|
||||
fp = uc->uc_mcontext.gregs[REG_RBP];
|
||||
#endif
|
||||
@ -589,6 +673,27 @@ static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
#elif defined(__aarch64__)
|
||||
|
||||
static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
|
||||
{
|
||||
if (level < 0)
|
||||
return -1;
|
||||
else if (level == 0) {
|
||||
*paddr = uc->uc_mcontext.pc;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
addr_t *fp = (addr_t *)uc->uc_mcontext.regs[29];
|
||||
int i;
|
||||
for (i = 1; i < level; i++)
|
||||
fp = (addr_t *)fp[0];
|
||||
*paddr = fp[1];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
#else
|
||||
|
||||
@ -633,17 +738,6 @@ static void set_exception_handler(void)
|
||||
SetUnhandledExceptionFilter(cpu_exception_handler);
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
static void win64_add_function_table(TCCState *s1)
|
||||
{
|
||||
RtlAddFunctionTable(
|
||||
(RUNTIME_FUNCTION*)s1->uw_pdata->sh_addr,
|
||||
s1->uw_pdata->data_offset / sizeof (RUNTIME_FUNCTION),
|
||||
text_section->sh_addr
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* return the PC at frame level 'level'. Return non zero if not found */
|
||||
static int rt_get_caller_pc(addr_t *paddr, CONTEXT *uc, int level)
|
||||
{
|
||||
@ -708,7 +802,7 @@ static TCCSyms tcc_syms[] = {
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
ST_FUNC void *resolve_sym(TCCState *s1, const char *symbol)
|
||||
ST_FUNC void *dlsym(void *handle, const char *symbol)
|
||||
{
|
||||
TCCSyms *p;
|
||||
p = tcc_syms;
|
||||
@ -720,13 +814,6 @@ ST_FUNC void *resolve_sym(TCCState *s1, const char *symbol)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#elif !defined(_WIN32)
|
||||
|
||||
ST_FUNC void *resolve_sym(TCCState *s1, const char *sym)
|
||||
{
|
||||
return dlsym(RTLD_DEFAULT, sym);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_TCC_STATIC */
|
||||
#endif /* TCC_IS_NATIVE */
|
||||
/* ------------------------------------------------------------- */
|
||||
|
||||
234
tcctok.h
234
tcctok.h
@ -59,6 +59,10 @@
|
||||
DEF(TOK_ASM2, "__asm")
|
||||
DEF(TOK_ASM3, "__asm__")
|
||||
|
||||
#ifdef TCC_TARGET_ARM64
|
||||
DEF(TOK_UINT128, "__uint128_t")
|
||||
#endif
|
||||
|
||||
/*********************************************************************/
|
||||
/* the following are not keywords. They are included to ease parsing */
|
||||
/* preprocessor only */
|
||||
@ -113,23 +117,41 @@
|
||||
DEF(TOK_FASTCALL1, "fastcall")
|
||||
DEF(TOK_FASTCALL2, "__fastcall")
|
||||
DEF(TOK_FASTCALL3, "__fastcall__")
|
||||
|
||||
DEF(TOK_MODE, "__mode__")
|
||||
DEF(TOK_MODE_QI, "__QI__")
|
||||
DEF(TOK_MODE_DI, "__DI__")
|
||||
DEF(TOK_MODE_HI, "__HI__")
|
||||
DEF(TOK_MODE_SI, "__SI__")
|
||||
DEF(TOK_MODE_word, "__word__")
|
||||
|
||||
DEF(TOK_DLLEXPORT, "dllexport")
|
||||
DEF(TOK_DLLIMPORT, "dllimport")
|
||||
DEF(TOK_NORETURN1, "noreturn")
|
||||
DEF(TOK_NORETURN2, "__noreturn__")
|
||||
DEF(TOK_VISIBILITY1, "visibility")
|
||||
DEF(TOK_VISIBILITY2, "__visibility__")
|
||||
DEF(TOK_builtin_types_compatible_p, "__builtin_types_compatible_p")
|
||||
DEF(TOK_builtin_choose_expr, "__builtin_choose_expr")
|
||||
DEF(TOK_builtin_constant_p, "__builtin_constant_p")
|
||||
DEF(TOK_builtin_frame_address, "__builtin_frame_address")
|
||||
DEF(TOK_builtin_return_address, "__builtin_return_address")
|
||||
DEF(TOK_builtin_expect, "__builtin_expect")
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
#ifdef TCC_TARGET_PE
|
||||
DEF(TOK_builtin_va_start, "__builtin_va_start")
|
||||
#else
|
||||
DEF(TOK_builtin_va_arg_types, "__builtin_va_arg_types")
|
||||
#endif
|
||||
#endif
|
||||
DEF(TOK_REGPARM1, "regparm")
|
||||
DEF(TOK_REGPARM2, "__regparm__")
|
||||
|
||||
#ifdef TCC_TARGET_ARM64
|
||||
DEF(TOK___va_start, "__va_start")
|
||||
DEF(TOK___va_arg, "__va_arg")
|
||||
#endif
|
||||
|
||||
/* pragma */
|
||||
DEF(TOK_pack, "pack")
|
||||
#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_X86_64)
|
||||
@ -137,25 +159,43 @@
|
||||
DEF(TOK_ASM_push, "push")
|
||||
DEF(TOK_ASM_pop, "pop")
|
||||
#endif
|
||||
DEF(TOK_comment, "comment")
|
||||
DEF(TOK_lib, "lib")
|
||||
DEF(TOK_push_macro, "push_macro")
|
||||
DEF(TOK_pop_macro, "pop_macro")
|
||||
DEF(TOK_once, "once")
|
||||
|
||||
/* builtin functions or variables */
|
||||
#ifdef TCC_ARM_EABI
|
||||
DEF(TOK_memcpy, "__aeabi_memcpy")
|
||||
DEF(TOK_memcpy4, "__aeabi_memcpy4")
|
||||
DEF(TOK_memcpy8, "__aeabi_memcpy8")
|
||||
DEF(TOK_memset, "__aeabi_memset")
|
||||
DEF(TOK___aeabi_ldivmod, "__aeabi_ldivmod")
|
||||
DEF(TOK___aeabi_uldivmod, "__aeabi_uldivmod")
|
||||
#else
|
||||
#ifndef TCC_ARM_EABI
|
||||
DEF(TOK_memcpy, "memcpy")
|
||||
DEF(TOK_memmove, "memmove")
|
||||
DEF(TOK_memset, "memset")
|
||||
DEF(TOK___divdi3, "__divdi3")
|
||||
DEF(TOK___moddi3, "__moddi3")
|
||||
DEF(TOK___udivdi3, "__udivdi3")
|
||||
DEF(TOK___umoddi3, "__umoddi3")
|
||||
DEF(TOK___ashrdi3, "__ashrdi3")
|
||||
DEF(TOK___lshrdi3, "__lshrdi3")
|
||||
DEF(TOK___ashldi3, "__ashldi3")
|
||||
DEF(TOK___floatundisf, "__floatundisf")
|
||||
DEF(TOK___floatundidf, "__floatundidf")
|
||||
# ifndef TCC_ARM_VFP
|
||||
DEF(TOK___floatundixf, "__floatundixf")
|
||||
DEF(TOK___fixunsxfdi, "__fixunsxfdi")
|
||||
# endif
|
||||
DEF(TOK___fixunssfdi, "__fixunssfdi")
|
||||
DEF(TOK___fixunsdfdi, "__fixunsdfdi")
|
||||
#endif
|
||||
#if defined(TCC_TARGET_ARM)
|
||||
#ifdef TCC_ARM_EABI
|
||||
|
||||
#if defined TCC_TARGET_ARM
|
||||
# ifdef TCC_ARM_EABI
|
||||
DEF(TOK_memcpy, "__aeabi_memcpy")
|
||||
DEF(TOK_memcpy4, "__aeabi_memcpy4")
|
||||
DEF(TOK_memcpy8, "__aeabi_memcpy8")
|
||||
DEF(TOK_memmove, "__aeabi_memmove")
|
||||
DEF(TOK_memset, "__aeabi_memset")
|
||||
DEF(TOK___aeabi_ldivmod, "__aeabi_ldivmod")
|
||||
DEF(TOK___aeabi_uldivmod, "__aeabi_uldivmod")
|
||||
DEF(TOK___aeabi_idivmod, "__aeabi_idivmod")
|
||||
DEF(TOK___aeabi_uidivmod, "__aeabi_uidivmod")
|
||||
DEF(TOK___divsi3, "__aeabi_idiv")
|
||||
@ -164,36 +204,6 @@
|
||||
DEF(TOK___floatdidf, "__aeabi_l2d")
|
||||
DEF(TOK___fixsfdi, "__aeabi_f2lz")
|
||||
DEF(TOK___fixdfdi, "__aeabi_d2lz")
|
||||
#else
|
||||
DEF(TOK___modsi3, "__modsi3")
|
||||
DEF(TOK___umodsi3, "__umodsi3")
|
||||
DEF(TOK___divsi3, "__divsi3")
|
||||
DEF(TOK___udivsi3, "__udivsi3")
|
||||
DEF(TOK___floatdisf, "__floatdisf")
|
||||
DEF(TOK___floatdidf, "__floatdidf")
|
||||
#ifndef TCC_ARM_VFP
|
||||
DEF(TOK___floatdixf, "__floatdixf")
|
||||
DEF(TOK___fixunssfsi, "__fixunssfsi")
|
||||
DEF(TOK___fixunsdfsi, "__fixunsdfsi")
|
||||
DEF(TOK___fixunsxfsi, "__fixunsxfsi")
|
||||
DEF(TOK___fixxfdi, "__fixxfdi")
|
||||
#endif
|
||||
DEF(TOK___fixsfdi, "__fixsfdi")
|
||||
DEF(TOK___fixdfdi, "__fixdfdi")
|
||||
#endif
|
||||
#elif defined(TCC_TARGET_C67)
|
||||
DEF(TOK__divi, "_divi")
|
||||
DEF(TOK__divu, "_divu")
|
||||
DEF(TOK__divf, "_divf")
|
||||
DEF(TOK__divd, "_divd")
|
||||
DEF(TOK__remi, "_remi")
|
||||
DEF(TOK__remu, "_remu")
|
||||
#endif
|
||||
#ifdef TCC_TARGET_I386
|
||||
DEF(TOK___tcc_int_fpu_control, "__tcc_int_fpu_control")
|
||||
DEF(TOK___tcc_fpu_control, "__tcc_fpu_control")
|
||||
#endif
|
||||
#ifdef TCC_ARM_EABI
|
||||
DEF(TOK___ashrdi3, "__aeabi_lasr")
|
||||
DEF(TOK___lshrdi3, "__aeabi_llsr")
|
||||
DEF(TOK___ashldi3, "__aeabi_llsl")
|
||||
@ -201,22 +211,72 @@
|
||||
DEF(TOK___floatundidf, "__aeabi_ul2d")
|
||||
DEF(TOK___fixunssfdi, "__aeabi_f2ulz")
|
||||
DEF(TOK___fixunsdfdi, "__aeabi_d2ulz")
|
||||
#else
|
||||
DEF(TOK___ashrdi3, "__ashrdi3")
|
||||
DEF(TOK___lshrdi3, "__lshrdi3")
|
||||
DEF(TOK___ashldi3, "__ashldi3")
|
||||
DEF(TOK___floatundisf, "__floatundisf")
|
||||
DEF(TOK___floatundidf, "__floatundidf")
|
||||
#ifndef TCC_ARM_VFP
|
||||
DEF(TOK___floatundixf, "__floatundixf")
|
||||
DEF(TOK___fixunsxfdi, "__fixunsxfdi")
|
||||
# else
|
||||
DEF(TOK___modsi3, "__modsi3")
|
||||
DEF(TOK___umodsi3, "__umodsi3")
|
||||
DEF(TOK___divsi3, "__divsi3")
|
||||
DEF(TOK___udivsi3, "__udivsi3")
|
||||
DEF(TOK___floatdisf, "__floatdisf")
|
||||
DEF(TOK___floatdidf, "__floatdidf")
|
||||
# ifndef TCC_ARM_VFP
|
||||
DEF(TOK___floatdixf, "__floatdixf")
|
||||
DEF(TOK___fixunssfsi, "__fixunssfsi")
|
||||
DEF(TOK___fixunsdfsi, "__fixunsdfsi")
|
||||
DEF(TOK___fixunsxfsi, "__fixunsxfsi")
|
||||
DEF(TOK___fixxfdi, "__fixxfdi")
|
||||
# endif
|
||||
DEF(TOK___fixsfdi, "__fixsfdi")
|
||||
DEF(TOK___fixdfdi, "__fixdfdi")
|
||||
# endif
|
||||
#endif
|
||||
DEF(TOK___fixunssfdi, "__fixunssfdi")
|
||||
DEF(TOK___fixunsdfdi, "__fixunsdfdi")
|
||||
|
||||
#if defined TCC_TARGET_C67
|
||||
DEF(TOK__divi, "_divi")
|
||||
DEF(TOK__divu, "_divu")
|
||||
DEF(TOK__divf, "_divf")
|
||||
DEF(TOK__divd, "_divd")
|
||||
DEF(TOK__remi, "_remi")
|
||||
DEF(TOK__remu, "_remu")
|
||||
#endif
|
||||
#ifdef TCC_TARGET_PE
|
||||
|
||||
#if defined TCC_TARGET_I386
|
||||
DEF(TOK___fixsfdi, "__fixsfdi")
|
||||
DEF(TOK___fixdfdi, "__fixdfdi")
|
||||
DEF(TOK___fixxfdi, "__fixxfdi")
|
||||
#endif
|
||||
|
||||
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
|
||||
DEF(TOK_alloca, "alloca")
|
||||
#endif
|
||||
|
||||
#if defined TCC_TARGET_PE
|
||||
DEF(TOK___chkstk, "__chkstk")
|
||||
#endif
|
||||
#ifdef TCC_TARGET_ARM64
|
||||
DEF(TOK___arm64_clear_cache, "__arm64_clear_cache")
|
||||
DEF(TOK___addtf3, "__addtf3")
|
||||
DEF(TOK___subtf3, "__subtf3")
|
||||
DEF(TOK___multf3, "__multf3")
|
||||
DEF(TOK___divtf3, "__divtf3")
|
||||
DEF(TOK___extendsftf2, "__extendsftf2")
|
||||
DEF(TOK___extenddftf2, "__extenddftf2")
|
||||
DEF(TOK___trunctfsf2, "__trunctfsf2")
|
||||
DEF(TOK___trunctfdf2, "__trunctfdf2")
|
||||
DEF(TOK___fixtfsi, "__fixtfsi")
|
||||
DEF(TOK___fixtfdi, "__fixtfdi")
|
||||
DEF(TOK___fixunstfsi, "__fixunstfsi")
|
||||
DEF(TOK___fixunstfdi, "__fixunstfdi")
|
||||
DEF(TOK___floatsitf, "__floatsitf")
|
||||
DEF(TOK___floatditf, "__floatditf")
|
||||
DEF(TOK___floatunsitf, "__floatunsitf")
|
||||
DEF(TOK___floatunditf, "__floatunditf")
|
||||
DEF(TOK___eqtf2, "__eqtf2")
|
||||
DEF(TOK___netf2, "__netf2")
|
||||
DEF(TOK___lttf2, "__lttf2")
|
||||
DEF(TOK___letf2, "__letf2")
|
||||
DEF(TOK___gttf2, "__gttf2")
|
||||
DEF(TOK___getf2, "__getf2")
|
||||
#endif
|
||||
|
||||
/* bound checking symbols */
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
@ -227,51 +287,61 @@
|
||||
DEF(TOK___bound_ptr_indir8, "__bound_ptr_indir8")
|
||||
DEF(TOK___bound_ptr_indir12, "__bound_ptr_indir12")
|
||||
DEF(TOK___bound_ptr_indir16, "__bound_ptr_indir16")
|
||||
DEF(TOK___bound_main_arg, "__bound_main_arg")
|
||||
DEF(TOK___bound_local_new, "__bound_local_new")
|
||||
DEF(TOK___bound_local_delete, "__bound_local_delete")
|
||||
#ifdef TCC_TARGET_PE
|
||||
# ifdef TCC_TARGET_PE
|
||||
DEF(TOK_malloc, "malloc")
|
||||
DEF(TOK_free, "free")
|
||||
DEF(TOK_realloc, "realloc")
|
||||
DEF(TOK_memalign, "memalign")
|
||||
DEF(TOK_calloc, "calloc")
|
||||
#endif
|
||||
DEF(TOK_memmove, "memmove")
|
||||
# endif
|
||||
DEF(TOK_strlen, "strlen")
|
||||
DEF(TOK_strcpy, "strcpy")
|
||||
#endif
|
||||
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
|
||||
DEF(TOK_alloca, "alloca")
|
||||
#endif
|
||||
|
||||
/* Tiny Assembler */
|
||||
DEF_ASM(byte)
|
||||
DEF_ASM(word)
|
||||
DEF_ASM(align)
|
||||
DEF_ASM(skip)
|
||||
DEF_ASM(space)
|
||||
DEF_ASM(string)
|
||||
DEF_ASM(asciz)
|
||||
DEF_ASM(ascii)
|
||||
DEF_ASM(file)
|
||||
DEF_ASM(globl)
|
||||
DEF_ASM(global)
|
||||
DEF_ASM(ident)
|
||||
DEF_ASM(size)
|
||||
DEF_ASM(type)
|
||||
DEF_ASM(text)
|
||||
DEF_ASM(data)
|
||||
DEF_ASM(bss)
|
||||
DEF_ASM(previous)
|
||||
DEF_ASM(fill)
|
||||
DEF_ASM(org)
|
||||
DEF_ASM(quad)
|
||||
DEF_ASMDIR(byte) /* must be first directive */
|
||||
DEF_ASMDIR(word)
|
||||
DEF_ASMDIR(align)
|
||||
DEF_ASMDIR(balign)
|
||||
DEF_ASMDIR(p2align)
|
||||
DEF_ASMDIR(set)
|
||||
DEF_ASMDIR(skip)
|
||||
DEF_ASMDIR(space)
|
||||
DEF_ASMDIR(string)
|
||||
DEF_ASMDIR(asciz)
|
||||
DEF_ASMDIR(ascii)
|
||||
DEF_ASMDIR(file)
|
||||
DEF_ASMDIR(globl)
|
||||
DEF_ASMDIR(global)
|
||||
DEF_ASMDIR(weak)
|
||||
DEF_ASMDIR(hidden)
|
||||
DEF_ASMDIR(ident)
|
||||
DEF_ASMDIR(size)
|
||||
DEF_ASMDIR(type)
|
||||
DEF_ASMDIR(text)
|
||||
DEF_ASMDIR(data)
|
||||
DEF_ASMDIR(bss)
|
||||
DEF_ASMDIR(previous)
|
||||
DEF_ASMDIR(pushsection)
|
||||
DEF_ASMDIR(popsection)
|
||||
DEF_ASMDIR(fill)
|
||||
DEF_ASMDIR(rept)
|
||||
DEF_ASMDIR(endr)
|
||||
DEF_ASMDIR(org)
|
||||
DEF_ASMDIR(quad)
|
||||
#if defined(TCC_TARGET_I386)
|
||||
DEF_ASM(code16)
|
||||
DEF_ASM(code32)
|
||||
DEF_ASMDIR(code16)
|
||||
DEF_ASMDIR(code32)
|
||||
#elif defined(TCC_TARGET_X86_64)
|
||||
DEF_ASM(code64)
|
||||
DEF_ASMDIR(code64)
|
||||
#endif
|
||||
DEF_ASMDIR(short)
|
||||
DEF_ASMDIR(long)
|
||||
DEF_ASMDIR(int)
|
||||
DEF_ASMDIR(section) /* must be last directive */
|
||||
|
||||
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
|
||||
#include "i386-tok.h"
|
||||
|
||||
547
tcctools.c
Normal file
547
tcctools.c
Normal file
@ -0,0 +1,547 @@
|
||||
/* -------------------------------------------------------------- */
|
||||
/*
|
||||
* TCC - Tiny C Compiler
|
||||
*
|
||||
* tcctools.c - extra tools and and -m32/64 support
|
||||
*
|
||||
*/
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
/*
|
||||
* This program is for making libtcc1.a without ar
|
||||
* tiny_libmaker - tiny elf lib maker
|
||||
* usage: tiny_libmaker [lib] files...
|
||||
* Copyright (c) 2007 Timppa
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "tcc.h"
|
||||
|
||||
//#define ARMAG "!<arch>\n"
|
||||
#define ARFMAG "`\n"
|
||||
|
||||
typedef struct {
|
||||
char ar_name[16];
|
||||
char ar_date[12];
|
||||
char ar_uid[6];
|
||||
char ar_gid[6];
|
||||
char ar_mode[8];
|
||||
char ar_size[10];
|
||||
char ar_fmag[2];
|
||||
} ArHdr;
|
||||
|
||||
static unsigned long le2belong(unsigned long ul) {
|
||||
return ((ul & 0xFF0000)>>8)+((ul & 0xFF000000)>>24) +
|
||||
((ul & 0xFF)<<24)+((ul & 0xFF00)<<8);
|
||||
}
|
||||
|
||||
/* Returns 1 if s contains any of the chars of list, else 0 */
|
||||
static int contains_any(const char *s, const char *list) {
|
||||
const char *l;
|
||||
for (; *s; s++) {
|
||||
for (l = list; *l; l++) {
|
||||
if (*s == *l)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ar_usage(int ret) {
|
||||
fprintf(stderr, "usage: tcc -ar [rcsv] lib file...\n");
|
||||
fprintf(stderr, "create library ([abdioptxN] not supported).\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ST_FUNC int tcc_tool_ar(TCCState *s1, int argc, char **argv)
|
||||
{
|
||||
static ArHdr arhdr = {
|
||||
"/ ",
|
||||
" ",
|
||||
"0 ",
|
||||
"0 ",
|
||||
"0 ",
|
||||
" ",
|
||||
ARFMAG
|
||||
};
|
||||
|
||||
static ArHdr arhdro = {
|
||||
" ",
|
||||
" ",
|
||||
"0 ",
|
||||
"0 ",
|
||||
"0 ",
|
||||
" ",
|
||||
ARFMAG
|
||||
};
|
||||
|
||||
FILE *fi, *fh = NULL, *fo = NULL;
|
||||
ElfW(Ehdr) *ehdr;
|
||||
ElfW(Shdr) *shdr;
|
||||
ElfW(Sym) *sym;
|
||||
int i, fsize, i_lib, i_obj;
|
||||
char *buf, *shstr, *symtab = NULL, *strtab = NULL;
|
||||
int symtabsize = 0;//, strtabsize = 0;
|
||||
char *anames = NULL;
|
||||
int *afpos = NULL;
|
||||
int istrlen, strpos = 0, fpos = 0, funccnt = 0, funcmax, hofs;
|
||||
char tfile[260], stmp[20];
|
||||
char *file, *name;
|
||||
int ret = 2;
|
||||
char *ops_conflict = "habdioptxN"; // unsupported but destructive if ignored.
|
||||
int verbose = 0;
|
||||
|
||||
i_lib = 0; i_obj = 0; // will hold the index of the lib and first obj
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *a = argv[i];
|
||||
if (*a == '-' && strstr(a, "."))
|
||||
ret = 1; // -x.y is always invalid (same as gnu ar)
|
||||
if ((*a == '-') || (i == 1 && !strstr(a, "."))) { // options argument
|
||||
if (contains_any(a, ops_conflict))
|
||||
ret = 1;
|
||||
if (strstr(a, "v"))
|
||||
verbose = 1;
|
||||
} else { // lib or obj files: don't abort - keep validating all args.
|
||||
if (!i_lib) // first file is the lib
|
||||
i_lib = i;
|
||||
else if (!i_obj) // second file is the first obj
|
||||
i_obj = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (!i_obj) // i_obj implies also i_lib. we require both.
|
||||
ret = 1;
|
||||
|
||||
if (ret == 1)
|
||||
return ar_usage(ret);
|
||||
|
||||
if ((fh = fopen(argv[i_lib], "wb")) == NULL)
|
||||
{
|
||||
fprintf(stderr, "tcc: ar: can't open file %s \n", argv[i_lib]);
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
sprintf(tfile, "%s.tmp", argv[i_lib]);
|
||||
if ((fo = fopen(tfile, "wb+")) == NULL)
|
||||
{
|
||||
fprintf(stderr, "tcc: ar: can't create temporary file %s\n", tfile);
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
funcmax = 250;
|
||||
afpos = tcc_realloc(NULL, funcmax * sizeof *afpos); // 250 func
|
||||
memcpy(&arhdro.ar_mode, "100666", 6);
|
||||
|
||||
// i_obj = first input object file
|
||||
while (i_obj < argc)
|
||||
{
|
||||
if (*argv[i_obj] == '-') { // by now, all options start with '-'
|
||||
i_obj++;
|
||||
continue;
|
||||
}
|
||||
if ((fi = fopen(argv[i_obj], "rb")) == NULL) {
|
||||
fprintf(stderr, "tcc: ar: can't open file %s \n", argv[i_obj]);
|
||||
goto the_end;
|
||||
}
|
||||
if (verbose)
|
||||
printf("a - %s\n", argv[i_obj]);
|
||||
|
||||
fseek(fi, 0, SEEK_END);
|
||||
fsize = ftell(fi);
|
||||
fseek(fi, 0, SEEK_SET);
|
||||
buf = tcc_malloc(fsize + 1);
|
||||
fread(buf, fsize, 1, fi);
|
||||
fclose(fi);
|
||||
|
||||
// elf header
|
||||
ehdr = (ElfW(Ehdr) *)buf;
|
||||
if (ehdr->e_ident[4] != ELFCLASSW)
|
||||
{
|
||||
fprintf(stderr, "tcc: ar: Unsupported Elf Class: %s\n", argv[i_obj]);
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
shdr = (ElfW(Shdr) *) (buf + ehdr->e_shoff + ehdr->e_shstrndx * ehdr->e_shentsize);
|
||||
shstr = (char *)(buf + shdr->sh_offset);
|
||||
for (i = 0; i < ehdr->e_shnum; i++)
|
||||
{
|
||||
shdr = (ElfW(Shdr) *) (buf + ehdr->e_shoff + i * ehdr->e_shentsize);
|
||||
if (!shdr->sh_offset)
|
||||
continue;
|
||||
if (shdr->sh_type == SHT_SYMTAB)
|
||||
{
|
||||
symtab = (char *)(buf + shdr->sh_offset);
|
||||
symtabsize = shdr->sh_size;
|
||||
}
|
||||
if (shdr->sh_type == SHT_STRTAB)
|
||||
{
|
||||
if (!strcmp(shstr + shdr->sh_name, ".strtab"))
|
||||
{
|
||||
strtab = (char *)(buf + shdr->sh_offset);
|
||||
//strtabsize = shdr->sh_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (symtab && symtabsize)
|
||||
{
|
||||
int nsym = symtabsize / sizeof(ElfW(Sym));
|
||||
//printf("symtab: info size shndx name\n");
|
||||
for (i = 1; i < nsym; i++)
|
||||
{
|
||||
sym = (ElfW(Sym) *) (symtab + i * sizeof(ElfW(Sym)));
|
||||
if (sym->st_shndx &&
|
||||
(sym->st_info == 0x10
|
||||
|| sym->st_info == 0x11
|
||||
|| sym->st_info == 0x12
|
||||
)) {
|
||||
//printf("symtab: %2Xh %4Xh %2Xh %s\n", sym->st_info, sym->st_size, sym->st_shndx, strtab + sym->st_name);
|
||||
istrlen = strlen(strtab + sym->st_name)+1;
|
||||
anames = tcc_realloc(anames, strpos+istrlen);
|
||||
strcpy(anames + strpos, strtab + sym->st_name);
|
||||
strpos += istrlen;
|
||||
if (++funccnt >= funcmax) {
|
||||
funcmax += 250;
|
||||
afpos = tcc_realloc(afpos, funcmax * sizeof *afpos); // 250 func more
|
||||
}
|
||||
afpos[funccnt] = fpos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file = argv[i_obj];
|
||||
for (name = strchr(file, 0);
|
||||
name > file && name[-1] != '/' && name[-1] != '\\';
|
||||
--name);
|
||||
istrlen = strlen(name);
|
||||
if (istrlen >= sizeof(arhdro.ar_name))
|
||||
istrlen = sizeof(arhdro.ar_name) - 1;
|
||||
memset(arhdro.ar_name, ' ', sizeof(arhdro.ar_name));
|
||||
memcpy(arhdro.ar_name, name, istrlen);
|
||||
arhdro.ar_name[istrlen] = '/';
|
||||
sprintf(stmp, "%-10d", fsize);
|
||||
memcpy(&arhdro.ar_size, stmp, 10);
|
||||
fwrite(&arhdro, sizeof(arhdro), 1, fo);
|
||||
fwrite(buf, fsize, 1, fo);
|
||||
tcc_free(buf);
|
||||
i_obj++;
|
||||
fpos += (fsize + sizeof(arhdro));
|
||||
}
|
||||
hofs = 8 + sizeof(arhdr) + strpos + (funccnt+1) * sizeof(int);
|
||||
fpos = 0;
|
||||
if ((hofs & 1)) // align
|
||||
hofs++, fpos = 1;
|
||||
// write header
|
||||
fwrite("!<arch>\n", 8, 1, fh);
|
||||
sprintf(stmp, "%-10d", (int)(strpos + (funccnt+1) * sizeof(int)));
|
||||
memcpy(&arhdr.ar_size, stmp, 10);
|
||||
fwrite(&arhdr, sizeof(arhdr), 1, fh);
|
||||
afpos[0] = le2belong(funccnt);
|
||||
for (i=1; i<=funccnt; i++)
|
||||
afpos[i] = le2belong(afpos[i] + hofs);
|
||||
fwrite(afpos, (funccnt+1) * sizeof(int), 1, fh);
|
||||
fwrite(anames, strpos, 1, fh);
|
||||
if (fpos)
|
||||
fwrite("", 1, 1, fh);
|
||||
// write objects
|
||||
fseek(fo, 0, SEEK_END);
|
||||
fsize = ftell(fo);
|
||||
fseek(fo, 0, SEEK_SET);
|
||||
buf = tcc_malloc(fsize + 1);
|
||||
fread(buf, fsize, 1, fo);
|
||||
fwrite(buf, fsize, 1, fh);
|
||||
tcc_free(buf);
|
||||
ret = 0;
|
||||
the_end:
|
||||
if (anames)
|
||||
tcc_free(anames);
|
||||
if (afpos)
|
||||
tcc_free(afpos);
|
||||
if (fh)
|
||||
fclose(fh);
|
||||
if (fo)
|
||||
fclose(fo), remove(tfile);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
/*
|
||||
* tiny_impdef creates an export definition file (.def) from a dll
|
||||
* on MS-Windows. Usage: tiny_impdef library.dll [-o outputfile]"
|
||||
*
|
||||
* Copyright (c) 2005,2007 grischka
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
|
||||
ST_FUNC int tcc_tool_impdef(TCCState *s1, int argc, char **argv)
|
||||
{
|
||||
int ret, v, i;
|
||||
char infile[MAX_PATH];
|
||||
char outfile[MAX_PATH];
|
||||
|
||||
const char *file;
|
||||
char *p, *q;
|
||||
FILE *fp, *op;
|
||||
|
||||
#ifdef _WIN32
|
||||
char path[MAX_PATH];
|
||||
#endif
|
||||
|
||||
infile[0] = outfile[0] = 0;
|
||||
fp = op = NULL;
|
||||
ret = 1;
|
||||
p = NULL;
|
||||
v = 0;
|
||||
|
||||
for (i = 1; i < argc; ++i) {
|
||||
const char *a = argv[i];
|
||||
if ('-' == a[0]) {
|
||||
if (0 == strcmp(a, "-v")) {
|
||||
v = 1;
|
||||
} else if (0 == strcmp(a, "-o")) {
|
||||
if (++i == argc)
|
||||
goto usage;
|
||||
strcpy(outfile, argv[i]);
|
||||
} else
|
||||
goto usage;
|
||||
} else if (0 == infile[0])
|
||||
strcpy(infile, a);
|
||||
else
|
||||
goto usage;
|
||||
}
|
||||
|
||||
if (0 == infile[0]) {
|
||||
usage:
|
||||
fprintf(stderr,
|
||||
"usage: tcc -impdef library.dll [-v] [-o outputfile]\n"
|
||||
"create export definition file (.def) from dll\n"
|
||||
);
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
if (0 == outfile[0]) {
|
||||
strcpy(outfile, tcc_basename(infile));
|
||||
q = strrchr(outfile, '.');
|
||||
if (NULL == q)
|
||||
q = strchr(outfile, 0);
|
||||
strcpy(q, ".def");
|
||||
}
|
||||
|
||||
file = infile;
|
||||
#ifdef _WIN32
|
||||
if (SearchPath(NULL, file, ".dll", sizeof path, path, NULL))
|
||||
file = path;
|
||||
#endif
|
||||
ret = tcc_get_dllexports(file, &p);
|
||||
if (ret || !p) {
|
||||
fprintf(stderr, "tcc: impdef: %s '%s'\n",
|
||||
ret == 32 ? "can't read symbols from 32bit" :
|
||||
ret == 64 ? "can't read symbols from 64bit" :
|
||||
ret == -1 ? "can't find file" :
|
||||
ret == 0 ? "no symbols found in" :
|
||||
"unknown file type", file);
|
||||
ret = 1;
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
if (v)
|
||||
printf("-> %s\n", file);
|
||||
|
||||
op = fopen(outfile, "w");
|
||||
if (NULL == op) {
|
||||
fprintf(stderr, "tcc: impdef: could not create output file: %s\n", outfile);
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
fprintf(op, "LIBRARY %s\n\nEXPORTS\n", tcc_basename(file));
|
||||
for (q = p, i = 0; *q; ++i) {
|
||||
fprintf(op, "%s\n", q);
|
||||
q += strlen(q) + 1;
|
||||
}
|
||||
|
||||
if (v)
|
||||
printf("<- %s (%d symbol%s)\n", outfile, i, "s" + (i<2));
|
||||
|
||||
ret = 0;
|
||||
|
||||
the_end:
|
||||
/* cannot free memory received from tcc_get_dllexports
|
||||
if it came from a dll */
|
||||
/* if (p)
|
||||
tcc_free(p); */
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
if (op)
|
||||
fclose(op);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* TCC_TARGET_PE */
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
/*
|
||||
* TCC - Tiny C Compiler
|
||||
*
|
||||
* Copyright (c) 2001-2004 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* re-execute the i386/x86_64 cross-compilers with tcc -m32/-m64: */
|
||||
|
||||
#if !defined TCC_TARGET_I386 && !defined TCC_TARGET_X86_64
|
||||
|
||||
ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int option)
|
||||
{
|
||||
tcc_error("-m%d not implemented.", option);
|
||||
}
|
||||
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
#include <process.h>
|
||||
|
||||
static char *str_replace(const char *str, const char *p, const char *r)
|
||||
{
|
||||
const char *s, *s0;
|
||||
char *d, *d0;
|
||||
int sl, pl, rl;
|
||||
|
||||
sl = strlen(str);
|
||||
pl = strlen(p);
|
||||
rl = strlen(r);
|
||||
for (d0 = NULL;; d0 = tcc_malloc(sl + 1)) {
|
||||
for (d = d0, s = str; s0 = s, s = strstr(s, p), s; s += pl) {
|
||||
if (d) {
|
||||
memcpy(d, s0, sl = s - s0), d += sl;
|
||||
memcpy(d, r, rl), d += rl;
|
||||
} else
|
||||
sl += rl - pl;
|
||||
}
|
||||
if (d) {
|
||||
strcpy(d, s0);
|
||||
return d0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int execvp_win32(const char *prog, char **argv)
|
||||
{
|
||||
int ret; char **p;
|
||||
/* replace all " by \" */
|
||||
for (p = argv; *p; ++p)
|
||||
if (strchr(*p, '"'))
|
||||
*p = str_replace(*p, "\"", "\\\"");
|
||||
ret = _spawnvp(P_NOWAIT, prog, (const char *const*)argv);
|
||||
if (-1 == ret)
|
||||
return ret;
|
||||
_cwait(&ret, ret, WAIT_CHILD);
|
||||
exit(ret);
|
||||
}
|
||||
#define execvp execvp_win32
|
||||
#endif /* _WIN32 */
|
||||
|
||||
ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int target)
|
||||
{
|
||||
char program[4096];
|
||||
char *a0 = argv[0];
|
||||
int prefix = tcc_basename(a0) - a0;
|
||||
|
||||
snprintf(program, sizeof program,
|
||||
"%.*s%s"
|
||||
#ifdef TCC_TARGET_PE
|
||||
"-win32"
|
||||
#endif
|
||||
"-tcc"
|
||||
#ifdef _WIN32
|
||||
".exe"
|
||||
#endif
|
||||
, prefix, a0, target == 64 ? "x86_64" : "i386");
|
||||
|
||||
if (strcmp(a0, program))
|
||||
execvp(argv[0] = program, argv);
|
||||
tcc_error("could not run '%s'", program);
|
||||
}
|
||||
|
||||
#endif /* TCC_TARGET_I386 && TCC_TARGET_X86_64 */
|
||||
/* -------------------------------------------------------------- */
|
||||
/* enable commandline wildcard expansion (tcc -o x.exe *.c) */
|
||||
|
||||
#ifdef _WIN32
|
||||
int _CRT_glob = 1;
|
||||
#ifndef _CRT_glob
|
||||
int _dowildcard = 1;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
/* generate xxx.d file */
|
||||
|
||||
ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename)
|
||||
{
|
||||
FILE *depout;
|
||||
char buf[1024];
|
||||
int i;
|
||||
|
||||
if (!filename) {
|
||||
/* compute filename automatically: dir/file.o -> dir/file.d */
|
||||
snprintf(buf, sizeof buf, "%.*s.d",
|
||||
(int)(tcc_fileextension(target) - target), target);
|
||||
filename = buf;
|
||||
}
|
||||
|
||||
if (s->verbose)
|
||||
printf("<- %s\n", filename);
|
||||
|
||||
/* XXX return err codes instead of error() ? */
|
||||
depout = fopen(filename, "w");
|
||||
if (!depout)
|
||||
tcc_error("could not open '%s'", filename);
|
||||
|
||||
fprintf(depout, "%s: \\\n", target);
|
||||
for (i=0; i<s->nb_target_deps; ++i)
|
||||
fprintf(depout, " %s \\\n", s->target_deps[i]);
|
||||
fprintf(depout, "\n");
|
||||
fclose(depout);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
13
tests/42test.h
Normal file
13
tests/42test.h
Normal file
@ -0,0 +1,13 @@
|
||||
/* This file is to test compute #include directives. It's named so
|
||||
that it starts with a pre-processing number which isn't a valid
|
||||
number (42test.h). Including this must work. */
|
||||
#ifndef INC42_FIRST
|
||||
int have_included_42test_h;
|
||||
#define INC42_FIRST
|
||||
#elif !defined INC42_SECOND
|
||||
#define INC42_SECOND
|
||||
int have_included_42test_h_second;
|
||||
#else
|
||||
#define INC42_THIRD
|
||||
int have_included_42test_h_third;
|
||||
#endif
|
||||
207
tests/Makefile
207
tests/Makefile
@ -4,7 +4,8 @@
|
||||
|
||||
TOP = ..
|
||||
include $(TOP)/Makefile
|
||||
VPATH = $(top_srcdir)/tests
|
||||
VPATH = $(TOPSRC)/tests $(TOPSRC) $(TOP)
|
||||
CFLAGS := $(filter-out -W% -g% -O%,$(CFLAGS)) -I$(TOPSRC)
|
||||
|
||||
# what tests to run
|
||||
TESTS = \
|
||||
@ -12,51 +13,58 @@ TESTS = \
|
||||
hello-run \
|
||||
libtest \
|
||||
test3 \
|
||||
moretests
|
||||
memtest \
|
||||
dlltest \
|
||||
abitest \
|
||||
vla_test-run \
|
||||
cross-test \
|
||||
tests2-dir \
|
||||
pp-dir
|
||||
|
||||
BTESTS = test1b test3b btest
|
||||
|
||||
# test4 -- problem with -static
|
||||
# asmtest -- minor differences with gcc
|
||||
# asmtest / asmtest2 -- minor differences with gcc
|
||||
# btest -- works on i386 (including win32)
|
||||
# test3 -- win32 does not know how to printf long doubles
|
||||
|
||||
# bounds-checking is supported only on i386
|
||||
ifneq ($(ARCH),i386)
|
||||
TESTS := $(filter-out btest,$(TESTS))
|
||||
TESTS := $(filter-out $(BTESTS),$(TESTS))
|
||||
endif
|
||||
ifdef CONFIG_WIN32
|
||||
TESTS := $(filter-out $(BTESTS),$(TESTS))
|
||||
endif
|
||||
ifeq ($(TARGETOS),Darwin)
|
||||
TESTS := $(filter-out hello-exe test3 $(BTESTS),$(TESTS))
|
||||
endif
|
||||
ifeq (,$(filter arm64 i386 x86_64,$(ARCH)))
|
||||
TESTS := $(filter-out vla_test-run,$(TESTS))
|
||||
endif
|
||||
ifeq ($(CONFIG_arm_eabi),yes)
|
||||
TESTS := $(filter-out test3,$(TESTS))
|
||||
endif
|
||||
ifeq ($(TARGETOS),Darwin)
|
||||
TESTS := $(filter-out hello-exe test3 btest,$(TESTS))
|
||||
ifeq (,$(filter i386 x86_64,$(ARCH)))
|
||||
TESTS := $(filter-out dlltest,$(TESTS))
|
||||
endif
|
||||
ifndef CONFIG_CROSS
|
||||
TESTS := $(filter-out cross-%,$(TESTS))
|
||||
endif
|
||||
|
||||
ifdef DISABLE_STATIC
|
||||
export LD_LIBRARY_PATH:=$(CURDIR)/..
|
||||
endif
|
||||
|
||||
ifeq ($(TARGETOS),Darwin)
|
||||
CFLAGS+=-Wl,-flat_namespace,-undefined,warning
|
||||
export MACOSX_DEPLOYMENT_TARGET:=10.2
|
||||
NATIVE_DEFINES+=-D_ANSI_SOURCE
|
||||
endif
|
||||
|
||||
# run local version of tcc with local libraries and includes
|
||||
TCCFLAGS = -B$(TOP)
|
||||
ifdef CONFIG_WIN32
|
||||
TCCFLAGS = -B$(top_srcdir)/win32 -I$(top_srcdir)/include -L$(TOP)
|
||||
PATH := $(CURDIR)/$(TOP):$(PATH) # for libtcc_test to find libtcc.dll
|
||||
endif
|
||||
|
||||
TCC = $(TOP)/tcc $(TCCFLAGS)
|
||||
RUN_TCC = $(NATIVE_DEFINES) -DONE_SOURCE -run $(TOP)/tcc.c $(TCCFLAGS)
|
||||
ifeq ($(TARGETOS),Darwin)
|
||||
CFLAGS += -Wl,-flat_namespace,-undefined,warning
|
||||
TCCFLAGS += -D_ANSI_SOURCE
|
||||
export MACOSX_DEPLOYMENT_TARGET:=10.2
|
||||
endif
|
||||
|
||||
RUN_TCC = $(NATIVE_DEFINES) -DONE_SOURCE -run $(TOPSRC)/tcc.c $(TCCFLAGS)
|
||||
|
||||
DISAS = objdump -d
|
||||
|
||||
# libtcc test
|
||||
ifdef LIBTCC1
|
||||
LIBTCC1:=$(TOP)/$(LIBTCC1)
|
||||
endif
|
||||
|
||||
all test : $(TESTS)
|
||||
all test : clean-s $(TESTS)
|
||||
|
||||
hello-exe: ../examples/ex1.c
|
||||
@echo ------------ $@ ------------
|
||||
@ -66,63 +74,85 @@ hello-run: ../examples/ex1.c
|
||||
@echo ------------ $@ ------------
|
||||
$(TCC) -run $<
|
||||
|
||||
libtest: libtcc_test$(EXESUF) $(LIBTCC1)
|
||||
libtest: libtcc_test$(EXESUF)
|
||||
@echo ------------ $@ ------------
|
||||
./libtcc_test$(EXESUF) lib_path=..
|
||||
./libtcc_test$(EXESUF) $(TCCFLAGS)
|
||||
|
||||
libtcc_test$(EXESUF): libtcc_test.c $(top_builddir)/$(LIBTCC)
|
||||
$(CC) -o $@ $^ $(CPPFLAGS) $(CFLAGS) $(NATIVE_DEFINES) $(LIBS) $(LINK_LIBTCC) $(LDFLAGS)
|
||||
libtcc_test$(EXESUF): libtcc_test.c $(LIBTCC)
|
||||
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
|
||||
|
||||
moretests:
|
||||
%-dir:
|
||||
@echo ------------ $@ ------------
|
||||
$(MAKE) -C tests2
|
||||
$(MAKE) -k -C $*
|
||||
|
||||
# test.ref - generate using gcc
|
||||
# copy only tcclib.h so GCC's stddef and stdarg will be used
|
||||
# test.ref - generate using cc
|
||||
test.ref: tcctest.c
|
||||
cp ../include/tcclib.h .
|
||||
gcc -o tcctest.gcc $< -I. $(CPPFLAGS) -w $(CFLAGS) $(NATIVE_DEFINES) -std=gnu99 -O0 -fno-omit-frame-pointer $(LDFLAGS)
|
||||
$(CC) -o tcctest.gcc $< $(NATIVE_DEFINES) $(CFLAGS) -w -O0 -std=gnu99 -fno-omit-frame-pointer
|
||||
./tcctest.gcc > $@
|
||||
|
||||
# auto test
|
||||
test1: test.ref
|
||||
test1 test1b: tcctest.c test.ref
|
||||
@echo ------------ $@ ------------
|
||||
$(TCC) -run tcctest.c > test.out1
|
||||
@if diff -u test.ref test.out1 ; then echo "Auto Test OK"; fi
|
||||
$(TCC) -run $< > test.out1
|
||||
@diff -u test.ref test.out1 && echo "Auto Test OK"
|
||||
|
||||
# iterated test2 (compile tcc then compile tcctest.c !)
|
||||
test2: test.ref
|
||||
test2 test2b: tcctest.c test.ref
|
||||
@echo ------------ $@ ------------
|
||||
$(TCC) $(RUN_TCC) $(RUN_TCC) -run tcctest.c > test.out2
|
||||
@if diff -u test.ref test.out2 ; then echo "Auto Test2 OK"; fi
|
||||
$(TCC) $(RUN_TCC) $(RUN_TCC) -run $< > test.out2
|
||||
@diff -u test.ref test.out2 && echo "Auto Test2 OK"
|
||||
|
||||
# iterated test3 (compile tcc then compile tcc then compile tcctest.c !)
|
||||
test3: test.ref
|
||||
test3 test3b: tcctest.c test.ref
|
||||
@echo ------------ $@ ------------
|
||||
$(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -run tcctest.c > test.out3
|
||||
@if diff -u test.ref test.out3 ; then echo "Auto Test3 OK"; fi
|
||||
$(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -run $< > test.out3
|
||||
@diff -u test.ref test.out3 && echo "Auto Test3 OK"
|
||||
|
||||
test%b : TCCFLAGS += -b
|
||||
|
||||
# binary output test
|
||||
test4: test.ref
|
||||
test4: tcctest.c test.ref
|
||||
@echo ------------ $@ ------------
|
||||
# object + link output
|
||||
$(TCC) -c -o tcctest3.o tcctest.c
|
||||
$(TCC) -c -o tcctest3.o $<
|
||||
$(TCC) -o tcctest3 tcctest3.o
|
||||
./tcctest3 > test3.out
|
||||
@if diff -u test.ref test3.out ; then echo "Object Auto Test OK"; fi
|
||||
# dynamic output
|
||||
$(TCC) -o tcctest1 tcctest.c
|
||||
$(TCC) -o tcctest1 $<
|
||||
./tcctest1 > test1.out
|
||||
@if diff -u test.ref test1.out ; then echo "Dynamic Auto Test OK"; fi
|
||||
# dynamic output + bound check
|
||||
$(TCC) -b -o tcctest4 tcctest.c
|
||||
$(TCC) -b -o tcctest4 $<
|
||||
./tcctest4 > test4.out
|
||||
@if diff -u test.ref test4.out ; then echo "BCheck Auto Test OK"; fi
|
||||
# static output
|
||||
$(TCC) -static -o tcctest2 tcctest.c
|
||||
$(TCC) -static -o tcctest2 $<
|
||||
./tcctest2 > test2.out
|
||||
@if diff -u test.ref test2.out ; then echo "Static Auto Test OK"; fi
|
||||
|
||||
# use tcc to create libtcc.so/.dll and the tcc(.exe) frontend and run them
|
||||
dlltest:
|
||||
@echo ------------ $@ ------------
|
||||
$(TCC) -DONE_SOURCE $(NATIVE_DEFINES) -DLIBTCC_AS_DLL $(TOPSRC)/libtcc.c $(LIBS) -shared -o libtcc2$(DLLSUF)
|
||||
$(TCC) $(NATIVE_DEFINES) $(TOPSRC)/tcc.c libtcc2$(DLLSUF) $(LIBS) -Wl,-rpath=. -o tcc2$(EXESUF)
|
||||
./tcc2$(EXESUF) $(TCCFLAGS) $(RUN_TCC) -run $(TOPSRC)/examples/ex1.c
|
||||
ifndef CONFIG_WIN32
|
||||
@echo ------------ $@ with PIC ------------
|
||||
$(CC) $(CFLAGS) -fPIC -DONE_SOURCE $(NATIVE_DEFINES) -DLIBTCC_AS_DLL -c $(TOPSRC)/libtcc.c
|
||||
$(TCC) libtcc.o $(LIBS) -shared -o libtcc2$(DLLSUF)
|
||||
$(TCC) $(NATIVE_DEFINES) $(TOPSRC)/tcc.c libtcc2$(DLLSUF) $(LIBS) -Wl,-rpath=. -o tcc2$(EXESUF)
|
||||
./tcc2$(EXESUF) $(TCCFLAGS) $(RUN_TCC) -run $(TOPSRC)/examples/ex1.c
|
||||
endif
|
||||
@rm tcc2$(EXESUF) libtcc2$(DLLSUF)
|
||||
|
||||
memtest:
|
||||
@echo ------------ $@ ------------
|
||||
$(CC) $(CFLAGS) $(NATIVE_DEFINES) -DONE_SOURCE -DMEM_DEBUG=2 $(TOPSRC)/tcc.c $(LIBS) -o memtest-tcc$(EXESUF)
|
||||
./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -DONE_SOURCE $(TOPSRC)/tcc.c $(LIBS)
|
||||
./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -DONE_SOURCE -run $(TOPSRC)/tcc.c $(TCCFLAGS) $(TOPSRC)/tests/tcctest.c
|
||||
|
||||
|
||||
# memory and bound check auto test
|
||||
BOUNDS_OK = 1 4 8 10 14
|
||||
BOUNDS_FAIL= 2 5 7 9 11 12 13 15
|
||||
@ -131,15 +161,15 @@ btest: boundtest.c
|
||||
@echo ------------ $@ ------------
|
||||
@for i in $(BOUNDS_OK); do \
|
||||
echo ; echo --- boundtest $$i ---; \
|
||||
if $(TCC) -b -run boundtest.c $$i ; then \
|
||||
echo succeded as expected; \
|
||||
if $(TCC) -b -run $< $$i ; then \
|
||||
echo succeeded as expected; \
|
||||
else\
|
||||
echo Failed positive test $$i ; exit 1 ; \
|
||||
fi ;\
|
||||
done ;\
|
||||
for i in $(BOUNDS_FAIL); do \
|
||||
echo ; echo --- boundtest $$i ---; \
|
||||
if $(TCC) -b -run boundtest.c $$i ; then \
|
||||
if $(TCC) -b -run $< $$i ; then \
|
||||
echo Failed negative test $$i ; exit 1 ;\
|
||||
else\
|
||||
echo failed as expected; \
|
||||
@ -151,31 +181,71 @@ btest: boundtest.c
|
||||
speedtest: ex2 ex3
|
||||
@echo ------------ $@ ------------
|
||||
time ./ex2 1238 2 3 4 10 13 4
|
||||
time $(TCC) -run $(top_srcdir)/examples/ex2.c 1238 2 3 4 10 13 4
|
||||
time $(TCC) -run $(TOPSRC)/examples/ex2.c 1238 2 3 4 10 13 4
|
||||
time ./ex3 35
|
||||
time $(TCC) -run $(top_srcdir)/examples/ex3.c 35
|
||||
time $(TCC) -run $(TOPSRC)/examples/ex3.c 35
|
||||
|
||||
weaktest: test.ref
|
||||
$(TCC) -c tcctest.c -o weaktest.tcc.o $(CPPFLAGS) $(CFLAGS)
|
||||
$(CC) -c tcctest.c -o weaktest.gcc.o -I. $(CPPFLAGS) -w $(CFLAGS)
|
||||
weaktest: tcctest.c test.ref
|
||||
$(TCC) -c $< -o weaktest.tcc.o
|
||||
$(CC) -c $< -o weaktest.gcc.o $(NATIVE_DEFINES) $(CFLAGS) -w -O0 -std=gnu99 -fno-omit-frame-pointer
|
||||
objdump -t weaktest.tcc.o | grep ' w ' | sed -e 's/.* \([a-zA-Z0-9_]*\)$$/\1/' | LC_ALL=C sort > weaktest.tcc.o.txt
|
||||
objdump -t weaktest.gcc.o | grep ' w ' | sed -e 's/.* \([a-zA-Z0-9_]*\)$$/\1/' | LC_ALL=C sort > weaktest.gcc.o.txt
|
||||
diff weaktest.gcc.o.txt weaktest.tcc.o.txt && echo "Weak Auto Test OK"
|
||||
|
||||
ex%: $(top_srcdir)/examples/ex%.c
|
||||
$(CC) -o $@ $< $(CPPFLAGS) $(CFLAGS) $(LDFLAGS)
|
||||
ex%: $(TOPSRC)/examples/ex%.c
|
||||
$(CC) -o $@ $< $(CFLAGS)
|
||||
|
||||
# tiny assembler testing
|
||||
asmtest.ref: asmtest.S
|
||||
$(CC) -Wa,-W -o asmtest.ref.o -c asmtest.S
|
||||
objdump -D asmtest.ref.o > asmtest.ref
|
||||
|
||||
asmtest: asmtest.ref
|
||||
asmtest asmtest2: asmtest.ref
|
||||
@echo ------------ $@ ------------
|
||||
$(TCC) -c asmtest.S
|
||||
$(TCC) $(MAYBE_RUN_TCC) -c asmtest.S
|
||||
objdump -D asmtest.o > asmtest.out
|
||||
@if diff -u --ignore-matching-lines="file format" asmtest.ref asmtest.out ; then echo "ASM Auto Test OK"; fi
|
||||
|
||||
# test assembler with tcc compiled by itself
|
||||
asmtest2: MAYBE_RUN_TCC = $(RUN_TCC)
|
||||
|
||||
# Check that code generated by libtcc is binary compatible with
|
||||
# that generated by CC
|
||||
abitest-cc$(EXESUF): abitest.c $(LIBTCC)
|
||||
$(CC) -o $@ $^ $(CFLAGS) $(LIBS) -w
|
||||
|
||||
abitest-tcc$(EXESUF): abitest.c libtcc.c
|
||||
$(TCC) -o $@ $^ $(NATIVE_DEFINES) -DONE_SOURCE $(LIBS)
|
||||
|
||||
ABITESTS := abitest-cc$(EXESUF)
|
||||
ifneq ($(CONFIG_arm_eabi),yes) # not ARM soft-float
|
||||
ABITESTS += abitest-tcc$(EXESUF)
|
||||
endif
|
||||
|
||||
abitest: $(ABITESTS)
|
||||
@echo ------------ $@ ------------
|
||||
./abitest-cc$(EXESUF) $(TCCFLAGS)
|
||||
ifneq ($(CONFIG_arm_eabi),yes) # not ARM soft-float
|
||||
./abitest-tcc$(EXESUF) $(TCCFLAGS)
|
||||
endif
|
||||
|
||||
vla_test$(EXESUF): vla_test.c
|
||||
$(TCC) -o $@ $^
|
||||
|
||||
vla_test-run: vla_test$(EXESUF)
|
||||
@echo ------------ $@ ------------
|
||||
./vla_test$(EXESUF)
|
||||
|
||||
cross-test :
|
||||
@echo ------------ $@ ------------
|
||||
$(TOP)/i386-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
|
||||
$(TOP)/x86_64-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
|
||||
$(TOP)/arm-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
|
||||
$(TOP)/c67-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
|
||||
$(TOP)/i386-win32-tcc$(EXESUF) $(TCCFLAGS-win) $(TOPSRC)/win32/examples/hello_win.c && echo "ok"
|
||||
$(TOP)/x86_64-win32-tcc$(EXESUF) $(TCCFLAGS-win) $(TOPSRC)/win32/examples/hello_win.c && echo "ok"
|
||||
$(TOP)/arm-wince-tcc$(EXESUF) $(TCCFLAGS-win) -c $(TOPSRC)/win32/examples/hello_win.c && echo "ok"
|
||||
|
||||
# targets for development
|
||||
%.bin: %.c tcc
|
||||
$(TCC) -g -o $@ $<
|
||||
@ -193,7 +263,12 @@ cache: tcc_g
|
||||
|
||||
# clean
|
||||
clean:
|
||||
rm -f *~ *.o *.a *.bin *.i *.ref *.out *.out? *.out?b *.cc *.gcc \
|
||||
*-cc *-gcc *-tcc *.exe hello libtcc_test vla_test tcctest[1234] \
|
||||
ex? tcc_g *.def weaktest.*.txt
|
||||
$(MAKE) -C tests2 $@
|
||||
rm -vf *~ *.o *.a *.bin *.i *.ref *.out *.out? *.out?b *.gcc *.exe \
|
||||
hello libtcc_test tcctest[1234] ex? tcc_g tcclib.h
|
||||
$(MAKE) -C pp $@
|
||||
|
||||
# silent clean, used before running tests
|
||||
clean-s:
|
||||
@$(MAKE) -s --no-print-directory clean
|
||||
|
||||
657
tests/abitest.c
Normal file
657
tests/abitest.c
Normal file
@ -0,0 +1,657 @@
|
||||
#include <libtcc.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
// MinGW has 80-bit rather than 64-bit long double which isn't compatible with TCC or MSVC
|
||||
#if defined(_WIN32) && defined(__GNUC__)
|
||||
#define LONG_DOUBLE double
|
||||
#define LONG_DOUBLE_LITERAL(x) x
|
||||
#else
|
||||
#define LONG_DOUBLE long double
|
||||
#define LONG_DOUBLE_LITERAL(x) x ## L
|
||||
#endif
|
||||
|
||||
static int g_argc;
|
||||
static char **g_argv;
|
||||
|
||||
static void set_options(TCCState *s, int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
for (i = 1; i < argc; ++i) {
|
||||
char *a = argv[i];
|
||||
if (a[0] == '-') {
|
||||
if (a[1] == 'B')
|
||||
tcc_set_lib_path(s, a+2);
|
||||
else if (a[1] == 'I')
|
||||
tcc_add_include_path(s, a+2);
|
||||
else if (a[1] == 'L')
|
||||
tcc_add_library_path(s, a+2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef int (*callback_type) (void*);
|
||||
|
||||
/*
|
||||
* Compile source code and call a callback with a pointer to the symbol "f".
|
||||
*/
|
||||
static int run_callback(const char *src, callback_type callback) {
|
||||
TCCState *s;
|
||||
int result;
|
||||
void *ptr;
|
||||
|
||||
s = tcc_new();
|
||||
if (!s)
|
||||
return -1;
|
||||
|
||||
set_options(s, g_argc, g_argv);
|
||||
|
||||
if (tcc_set_output_type(s, TCC_OUTPUT_MEMORY) == -1)
|
||||
return -1;
|
||||
if (tcc_compile_string(s, src) == -1)
|
||||
return -1;
|
||||
if (tcc_relocate(s, TCC_RELOCATE_AUTO) == -1)
|
||||
return -1;
|
||||
|
||||
ptr = tcc_get_symbol(s, "f");
|
||||
if (!ptr)
|
||||
return -1;
|
||||
result = callback(ptr);
|
||||
|
||||
tcc_delete(s);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#define STR2(x) #x
|
||||
#define STR(x) STR2(x)
|
||||
|
||||
#define RET_PRIMITIVE_TEST(name, type, val) \
|
||||
static int ret_ ## name ## _test_callback(void *ptr) { \
|
||||
type (*callback) (type) = (type(*)(type))ptr; \
|
||||
type x = val; \
|
||||
type y = callback(x); \
|
||||
return (y == x+x) ? 0 : -1; \
|
||||
} \
|
||||
\
|
||||
static int ret_ ## name ## _test(void) { \
|
||||
const char *src = STR(type) " f(" STR(type) " x) {return x+x;}"; \
|
||||
return run_callback(src, ret_ ## name ## _test_callback); \
|
||||
}
|
||||
|
||||
RET_PRIMITIVE_TEST(int, int, 70000)
|
||||
RET_PRIMITIVE_TEST(longlong, long long, 4333369356528LL)
|
||||
RET_PRIMITIVE_TEST(float, float, 63.0)
|
||||
RET_PRIMITIVE_TEST(double, double, 14789798.0)
|
||||
RET_PRIMITIVE_TEST(longdouble, LONG_DOUBLE, LONG_DOUBLE_LITERAL(378943892.0))
|
||||
|
||||
/*
|
||||
* ret_2float_test:
|
||||
*
|
||||
* On x86-64, a struct with 2 floats should be packed into a single
|
||||
* SSE register (VT_DOUBLE is used for this purpose).
|
||||
*/
|
||||
typedef struct ret_2float_test_type_s {float x, y;} ret_2float_test_type;
|
||||
typedef ret_2float_test_type (*ret_2float_test_function_type) (ret_2float_test_type);
|
||||
|
||||
static int ret_2float_test_callback(void *ptr) {
|
||||
ret_2float_test_function_type f = (ret_2float_test_function_type)ptr;
|
||||
ret_2float_test_type a = {10, 35};
|
||||
ret_2float_test_type r;
|
||||
r = f(a);
|
||||
return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int ret_2float_test(void) {
|
||||
const char *src =
|
||||
"typedef struct ret_2float_test_type_s {float x, y;} ret_2float_test_type;"
|
||||
"ret_2float_test_type f(ret_2float_test_type a) {\n"
|
||||
" ret_2float_test_type r = {a.x*5, a.y*3};\n"
|
||||
" return r;\n"
|
||||
"}\n";
|
||||
|
||||
return run_callback(src, ret_2float_test_callback);
|
||||
}
|
||||
|
||||
/*
|
||||
* ret_2double_test:
|
||||
*
|
||||
* On x86-64, a struct with 2 doubles should be passed in two SSE
|
||||
* registers.
|
||||
*/
|
||||
typedef struct ret_2double_test_type_s {double x, y;} ret_2double_test_type;
|
||||
typedef ret_2double_test_type (*ret_2double_test_function_type) (ret_2double_test_type);
|
||||
|
||||
static int ret_2double_test_callback(void *ptr) {
|
||||
ret_2double_test_function_type f = (ret_2double_test_function_type)ptr;
|
||||
ret_2double_test_type a = {10, 35};
|
||||
ret_2double_test_type r;
|
||||
r = f(a);
|
||||
return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int ret_2double_test(void) {
|
||||
const char *src =
|
||||
"typedef struct ret_2double_test_type_s {double x, y;} ret_2double_test_type;"
|
||||
"ret_2double_test_type f(ret_2double_test_type a) {\n"
|
||||
" ret_2double_test_type r = {a.x*5, a.y*3};\n"
|
||||
" return r;\n"
|
||||
"}\n";
|
||||
|
||||
return run_callback(src, ret_2double_test_callback);
|
||||
}
|
||||
|
||||
/*
|
||||
* ret_8plus2double_test:
|
||||
*
|
||||
* This catches a corner case in the x86_64 ABI code: the first 7
|
||||
* arguments fit into registers, the 8th doesn't, but the 9th argument
|
||||
* fits into the 8th XMM register.
|
||||
*
|
||||
* Note that the purpose of the 10th argument is to avoid a situation
|
||||
* in which gcc would accidentally put the double at the right
|
||||
* address, thus causing a success message even though TCC actually
|
||||
* generated incorrect code.
|
||||
*/
|
||||
typedef ret_2double_test_type (*ret_8plus2double_test_function_type) (double, double, double, double, double, double, double, ret_2double_test_type, double, double);
|
||||
|
||||
static int ret_8plus2double_test_callback(void *ptr) {
|
||||
ret_8plus2double_test_function_type f = (ret_8plus2double_test_function_type)ptr;
|
||||
ret_2double_test_type a = {10, 35};
|
||||
ret_2double_test_type r;
|
||||
r = f(0, 0, 0, 0, 0, 0, 0, a, 37, 38);
|
||||
return ((r.x == 37) && (r.y == 37)) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int ret_8plus2double_test(void) {
|
||||
const char *src =
|
||||
"typedef struct ret_2double_test_type_s {double x, y;} ret_2double_test_type;"
|
||||
"ret_2double_test_type f(double x1, double x2, double x3, double x4, double x5, double x6, double x7, ret_2double_test_type a, double x8, double x9) {\n"
|
||||
" ret_2double_test_type r = { x8, x8 };\n"
|
||||
" return r;\n"
|
||||
"}\n";
|
||||
|
||||
return run_callback(src, ret_8plus2double_test_callback);
|
||||
}
|
||||
|
||||
/*
|
||||
* ret_mixed_test:
|
||||
*
|
||||
* On x86-64, a struct with a double and a 64-bit integer should be
|
||||
* passed in one SSE register and one integer register.
|
||||
*/
|
||||
typedef struct ret_mixed_test_type_s {double x; long long y;} ret_mixed_test_type;
|
||||
typedef ret_mixed_test_type (*ret_mixed_test_function_type) (ret_mixed_test_type);
|
||||
|
||||
static int ret_mixed_test_callback(void *ptr) {
|
||||
ret_mixed_test_function_type f = (ret_mixed_test_function_type)ptr;
|
||||
ret_mixed_test_type a = {10, 35};
|
||||
ret_mixed_test_type r;
|
||||
r = f(a);
|
||||
return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int ret_mixed_test(void) {
|
||||
const char *src =
|
||||
"typedef struct ret_mixed_test_type_s {double x; long long y;} ret_mixed_test_type;"
|
||||
"ret_mixed_test_type f(ret_mixed_test_type a) {\n"
|
||||
" ret_mixed_test_type r = {a.x*5, a.y*3};\n"
|
||||
" return r;\n"
|
||||
"}\n";
|
||||
|
||||
return run_callback(src, ret_mixed_test_callback);
|
||||
}
|
||||
|
||||
/*
|
||||
* ret_mixed2_test:
|
||||
*
|
||||
* On x86-64, a struct with two floats and two 32-bit integers should
|
||||
* be passed in one SSE register and one integer register.
|
||||
*/
|
||||
typedef struct ret_mixed2_test_type_s {float x,x2; int y,y2;} ret_mixed2_test_type;
|
||||
typedef ret_mixed2_test_type (*ret_mixed2_test_function_type) (ret_mixed2_test_type);
|
||||
|
||||
static int ret_mixed2_test_callback(void *ptr) {
|
||||
ret_mixed2_test_function_type f = (ret_mixed2_test_function_type)ptr;
|
||||
ret_mixed2_test_type a = {10, 5, 35, 7 };
|
||||
ret_mixed2_test_type r;
|
||||
r = f(a);
|
||||
return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int ret_mixed2_test(void) {
|
||||
const char *src =
|
||||
"typedef struct ret_mixed2_test_type_s {float x, x2; int y,y2;} ret_mixed2_test_type;"
|
||||
"ret_mixed2_test_type f(ret_mixed2_test_type a) {\n"
|
||||
" ret_mixed2_test_type r = {a.x*5, 0, a.y*3, 0};\n"
|
||||
" return r;\n"
|
||||
"}\n";
|
||||
|
||||
return run_callback(src, ret_mixed2_test_callback);
|
||||
}
|
||||
|
||||
/*
|
||||
* ret_mixed3_test:
|
||||
*
|
||||
* On x86-64, this struct should be passed in two integer registers.
|
||||
*/
|
||||
typedef struct ret_mixed3_test_type_s {float x; int y; float x2; int y2;} ret_mixed3_test_type;
|
||||
typedef ret_mixed3_test_type (*ret_mixed3_test_function_type) (ret_mixed3_test_type);
|
||||
|
||||
static int ret_mixed3_test_callback(void *ptr) {
|
||||
ret_mixed3_test_function_type f = (ret_mixed3_test_function_type)ptr;
|
||||
ret_mixed3_test_type a = {10, 5, 35, 7 };
|
||||
ret_mixed3_test_type r;
|
||||
r = f(a);
|
||||
return ((r.x == a.x*5) && (r.y2 == a.y*3)) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int ret_mixed3_test(void) {
|
||||
const char *src =
|
||||
"typedef struct ret_mixed3_test_type_s {float x; int y; float x2; int y2;} ret_mixed3_test_type;"
|
||||
"ret_mixed3_test_type f(ret_mixed3_test_type a) {\n"
|
||||
" ret_mixed3_test_type r = {a.x*5, 0, 0, a.y*3};\n"
|
||||
" return r;\n"
|
||||
"}\n";
|
||||
|
||||
return run_callback(src, ret_mixed3_test_callback);
|
||||
}
|
||||
|
||||
/*
|
||||
* reg_pack_test: return a small struct which should be packed into
|
||||
* registers (Win32) during return.
|
||||
*/
|
||||
typedef struct reg_pack_test_type_s {int x, y;} reg_pack_test_type;
|
||||
typedef reg_pack_test_type (*reg_pack_test_function_type) (reg_pack_test_type);
|
||||
|
||||
static int reg_pack_test_callback(void *ptr) {
|
||||
reg_pack_test_function_type f = (reg_pack_test_function_type)ptr;
|
||||
reg_pack_test_type a = {10, 35};
|
||||
reg_pack_test_type r;
|
||||
r = f(a);
|
||||
return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int reg_pack_test(void) {
|
||||
const char *src =
|
||||
"typedef struct reg_pack_test_type_s {int x, y;} reg_pack_test_type;"
|
||||
"reg_pack_test_type f(reg_pack_test_type a) {\n"
|
||||
" reg_pack_test_type r = {a.x*5, a.y*3};\n"
|
||||
" return r;\n"
|
||||
"}\n";
|
||||
|
||||
return run_callback(src, reg_pack_test_callback);
|
||||
}
|
||||
|
||||
/*
|
||||
* reg_pack_longlong_test: return a small struct which should be packed into
|
||||
* registers (x86-64) during return.
|
||||
*/
|
||||
typedef struct reg_pack_longlong_test_type_s {long long x, y;} reg_pack_longlong_test_type;
|
||||
typedef reg_pack_longlong_test_type (*reg_pack_longlong_test_function_type) (reg_pack_longlong_test_type);
|
||||
|
||||
static int reg_pack_longlong_test_callback(void *ptr) {
|
||||
reg_pack_longlong_test_function_type f = (reg_pack_longlong_test_function_type)ptr;
|
||||
reg_pack_longlong_test_type a = {10, 35};
|
||||
reg_pack_longlong_test_type r;
|
||||
r = f(a);
|
||||
return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int reg_pack_longlong_test(void) {
|
||||
const char *src =
|
||||
"typedef struct reg_pack_longlong_test_type_s {long long x, y;} reg_pack_longlong_test_type;"
|
||||
"reg_pack_longlong_test_type f(reg_pack_longlong_test_type a) {\n"
|
||||
" reg_pack_longlong_test_type r = {a.x*5, a.y*3};\n"
|
||||
" return r;\n"
|
||||
"}\n";
|
||||
|
||||
return run_callback(src, reg_pack_longlong_test_callback);
|
||||
}
|
||||
|
||||
/*
|
||||
* ret_6plus2longlong_test:
|
||||
*
|
||||
* This catches a corner case in the x86_64 ABI code: the first 5
|
||||
* arguments fit into registers, the 6th doesn't, but the 7th argument
|
||||
* fits into the 6th argument integer register, %r9.
|
||||
*
|
||||
* Note that the purpose of the 10th argument is to avoid a situation
|
||||
* in which gcc would accidentally put the longlong at the right
|
||||
* address, thus causing a success message even though TCC actually
|
||||
* generated incorrect code.
|
||||
*/
|
||||
typedef reg_pack_longlong_test_type (*ret_6plus2longlong_test_function_type) (long long, long long, long long, long long, long long, reg_pack_longlong_test_type, long long, long long);
|
||||
|
||||
static int ret_6plus2longlong_test_callback(void *ptr) {
|
||||
ret_6plus2longlong_test_function_type f = (ret_6plus2longlong_test_function_type)ptr;
|
||||
reg_pack_longlong_test_type a = {10, 35};
|
||||
reg_pack_longlong_test_type r;
|
||||
r = f(0, 0, 0, 0, 0, a, 37, 38);
|
||||
return ((r.x == 37) && (r.y == 37)) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int ret_6plus2longlong_test(void) {
|
||||
const char *src =
|
||||
"typedef struct reg_pack_longlong_test_type_s {long long x, y;} reg_pack_longlong_test_type;"
|
||||
"reg_pack_longlong_test_type f(long long x1, long long x2, long long x3, long long x4, long long x5, reg_pack_longlong_test_type a, long long x8, long long x9) {\n"
|
||||
" reg_pack_longlong_test_type r = { x8, x8 };\n"
|
||||
" return r;\n"
|
||||
"}\n";
|
||||
|
||||
return run_callback(src, ret_6plus2longlong_test_callback);
|
||||
}
|
||||
|
||||
/*
|
||||
* sret_test: Create a struct large enough to be returned via sret
|
||||
* (hidden pointer as first function argument)
|
||||
*/
|
||||
typedef struct sret_test_type_s {long long a, b, c;} sret_test_type;
|
||||
typedef sret_test_type (*sret_test_function_type) (sret_test_type);
|
||||
|
||||
static int sret_test_callback(void *ptr) {
|
||||
sret_test_function_type f = (sret_test_function_type)(ptr);
|
||||
sret_test_type x = {5436LL, 658277698LL, 43878957LL};
|
||||
sret_test_type r = f(x);
|
||||
return ((r.a==x.a*35)&&(r.b==x.b*19)&&(r.c==x.c*21)) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int sret_test(void) {
|
||||
const char *src =
|
||||
"typedef struct sret_test_type_s {long long a, b, c;} sret_test_type;\n"
|
||||
"sret_test_type f(sret_test_type x) {\n"
|
||||
" sret_test_type r = {x.a*35, x.b*19, x.c*21};\n"
|
||||
" return r;\n"
|
||||
"}\n";
|
||||
|
||||
return run_callback(src, sret_test_callback);
|
||||
}
|
||||
|
||||
/*
|
||||
* one_member_union_test:
|
||||
*
|
||||
* In the x86-64 ABI a union should always be passed on the stack. However
|
||||
* it appears that a single member union is treated by GCC as its member.
|
||||
*/
|
||||
typedef union one_member_union_test_type_u {int x;} one_member_union_test_type;
|
||||
typedef one_member_union_test_type (*one_member_union_test_function_type) (one_member_union_test_type);
|
||||
|
||||
static int one_member_union_test_callback(void *ptr) {
|
||||
one_member_union_test_function_type f = (one_member_union_test_function_type)ptr;
|
||||
one_member_union_test_type a, b;
|
||||
a.x = 34;
|
||||
b = f(a);
|
||||
return (b.x == a.x*2) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int one_member_union_test(void) {
|
||||
const char *src =
|
||||
"typedef union one_member_union_test_type_u {int x;} one_member_union_test_type;\n"
|
||||
"one_member_union_test_type f(one_member_union_test_type a) {\n"
|
||||
" one_member_union_test_type b;\n"
|
||||
" b.x = a.x * 2;\n"
|
||||
" return b;\n"
|
||||
"}\n";
|
||||
return run_callback(src, one_member_union_test_callback);
|
||||
}
|
||||
|
||||
/*
|
||||
* two_member_union_test:
|
||||
*
|
||||
* In the x86-64 ABI a union should always be passed on the stack.
|
||||
*/
|
||||
typedef union two_member_union_test_type_u {int x; long y;} two_member_union_test_type;
|
||||
typedef two_member_union_test_type (*two_member_union_test_function_type) (two_member_union_test_type);
|
||||
|
||||
static int two_member_union_test_callback(void *ptr) {
|
||||
two_member_union_test_function_type f = (two_member_union_test_function_type)ptr;
|
||||
two_member_union_test_type a, b;
|
||||
a.x = 34;
|
||||
b = f(a);
|
||||
return (b.x == a.x*2) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int two_member_union_test(void) {
|
||||
const char *src =
|
||||
"typedef union two_member_union_test_type_u {int x; long y;} two_member_union_test_type;\n"
|
||||
"two_member_union_test_type f(two_member_union_test_type a) {\n"
|
||||
" two_member_union_test_type b;\n"
|
||||
" b.x = a.x * 2;\n"
|
||||
" return b;\n"
|
||||
"}\n";
|
||||
return run_callback(src, two_member_union_test_callback);
|
||||
}
|
||||
|
||||
/*
|
||||
* Win64 calling convetntion test.
|
||||
*/
|
||||
|
||||
typedef struct many_struct_test_type_s {long long a, b, c;} many_struct_test_type;
|
||||
typedef many_struct_test_type (*many_struct_test_function_type) (many_struct_test_type,many_struct_test_type,many_struct_test_type,many_struct_test_type,many_struct_test_type,many_struct_test_type);
|
||||
|
||||
static int many_struct_test_callback(void *ptr) {
|
||||
many_struct_test_function_type f = (many_struct_test_function_type)ptr;
|
||||
many_struct_test_type v = {1, 2, 3};
|
||||
many_struct_test_type r = f(v,v,v,v,v,v);
|
||||
return ((r.a == 6) && (r.b == 12) && (r.c == 18))?0:-1;
|
||||
}
|
||||
|
||||
static int many_struct_test(void) {
|
||||
const char *src =
|
||||
"typedef struct many_struct_test_type_s {long long a, b, c;} many_struct_test_type;\n"
|
||||
"many_struct_test_type f(many_struct_test_type x1, many_struct_test_type x2, many_struct_test_type x3, many_struct_test_type x4, many_struct_test_type x5, many_struct_test_type x6) {\n"
|
||||
" many_struct_test_type y;\n"
|
||||
" y.a = x1.a + x2.a + x3.a + x4.a + x5.a + x6.a;\n"
|
||||
" y.b = x1.b + x2.b + x3.b + x4.b + x5.b + x6.b;\n"
|
||||
" y.c = x1.c + x2.c + x3.c + x4.c + x5.c + x6.c;\n"
|
||||
" return y;\n"
|
||||
"}\n";
|
||||
return run_callback(src, many_struct_test_callback);
|
||||
}
|
||||
|
||||
/*
|
||||
* Win64 calling convention test.
|
||||
*/
|
||||
|
||||
typedef struct many_struct_test_2_type_s {int a, b;} many_struct_test_2_type;
|
||||
typedef many_struct_test_2_type (*many_struct_test_2_function_type) (many_struct_test_2_type,many_struct_test_2_type,many_struct_test_2_type,many_struct_test_2_type,many_struct_test_2_type,many_struct_test_2_type);
|
||||
|
||||
static int many_struct_test_2_callback(void *ptr) {
|
||||
many_struct_test_2_function_type f = (many_struct_test_2_function_type)ptr;
|
||||
many_struct_test_2_type v = {1,2};
|
||||
many_struct_test_2_type r = f(v,v,v,v,v,v);
|
||||
return ((r.a == 6) && (r.b == 12))?0:-1;
|
||||
}
|
||||
|
||||
static int many_struct_test_2(void) {
|
||||
const char *src =
|
||||
"typedef struct many_struct_test_2_type_s {int a, b;} many_struct_test_2_type;\n"
|
||||
"many_struct_test_2_type f(many_struct_test_2_type x1, many_struct_test_2_type x2, many_struct_test_2_type x3, many_struct_test_2_type x4, many_struct_test_2_type x5, many_struct_test_2_type x6) {\n"
|
||||
" many_struct_test_2_type y;\n"
|
||||
" y.a = x1.a + x2.a + x3.a + x4.a + x5.a + x6.a;\n"
|
||||
" y.b = x1.b + x2.b + x3.b + x4.b + x5.b + x6.b;\n"
|
||||
" return y;\n"
|
||||
"}\n";
|
||||
return run_callback(src, many_struct_test_2_callback);
|
||||
}
|
||||
|
||||
/*
|
||||
* Win64 calling convention test.
|
||||
*/
|
||||
|
||||
typedef struct many_struct_test_3_type_s {int a, b;} many_struct_test_3_type;
|
||||
typedef many_struct_test_3_type (*many_struct_test_3_function_type) (many_struct_test_3_type,many_struct_test_3_type,many_struct_test_3_type,many_struct_test_3_type,many_struct_test_3_type,many_struct_test_3_type, ...);
|
||||
typedef struct many_struct_test_3_struct_type { many_struct_test_3_function_type f; many_struct_test_3_function_type *f2; } many_struct_test_3_struct_type;
|
||||
|
||||
static void many_struct_test_3_dummy(double d, ...)
|
||||
{
|
||||
volatile double x = d;
|
||||
}
|
||||
|
||||
static int many_struct_test_3_callback(void *ptr) {
|
||||
many_struct_test_3_struct_type s = { ptr, };
|
||||
many_struct_test_3_struct_type *s2 = &s;
|
||||
s2->f2 = &s2->f;
|
||||
many_struct_test_3_dummy(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, &s2);
|
||||
many_struct_test_3_function_type f = *(s2->f2);
|
||||
many_struct_test_3_type v = {1,2};
|
||||
many_struct_test_3_type r = (*((s2->f2=&f)+0))(v,v,v,v,v,v,1.0);
|
||||
return ((r.a == 6) && (r.b == 12))?0:-1;
|
||||
}
|
||||
|
||||
static int many_struct_test_3(void) {
|
||||
const char *src =
|
||||
"typedef struct many_struct_test_3_type_s {int a, b;} many_struct_test_3_type;\n"
|
||||
"many_struct_test_3_type f(many_struct_test_3_type x1, many_struct_test_3_type x2, many_struct_test_3_type x3, many_struct_test_3_type x4, many_struct_test_3_type x5, many_struct_test_3_type x6, ...) {\n"
|
||||
" many_struct_test_3_type y;\n"
|
||||
" y.a = x1.a + x2.a + x3.a + x4.a + x5.a + x6.a;\n"
|
||||
" y.b = x1.b + x2.b + x3.b + x4.b + x5.b + x6.b;\n"
|
||||
" return y;\n"
|
||||
"}\n";
|
||||
return run_callback(src, many_struct_test_3_callback);
|
||||
}
|
||||
|
||||
/*
|
||||
* stdarg_test: Test variable argument list ABI
|
||||
*/
|
||||
|
||||
typedef struct {long long a, b, c;} stdarg_test_struct_type;
|
||||
typedef void (*stdarg_test_function_type) (int,int,int,...);
|
||||
|
||||
static int stdarg_test_callback(void *ptr) {
|
||||
stdarg_test_function_type f = (stdarg_test_function_type)ptr;
|
||||
int x;
|
||||
double y;
|
||||
stdarg_test_struct_type z = {1, 2, 3}, w;
|
||||
f(10, 10, 5,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, &x,
|
||||
1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, &y,
|
||||
z, z, z, z, z, &w);
|
||||
return ((x == 55) && (y == 55) && (w.a == 5) && (w.b == 10) && (w.c == 15)) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int stdarg_test(void) {
|
||||
const char *src =
|
||||
"#include <stdarg.h>\n"
|
||||
"typedef struct {long long a, b, c;} stdarg_test_struct_type;\n"
|
||||
"void f(int n_int, int n_float, int n_struct, ...) {\n"
|
||||
" int i, ti = 0;\n"
|
||||
" double td = 0.0;\n"
|
||||
" stdarg_test_struct_type ts = {0,0,0}, tmp;\n"
|
||||
" va_list ap;\n"
|
||||
" va_start(ap, n_struct);\n"
|
||||
" for (i = 0, ti = 0; i < n_int; ++i)\n"
|
||||
" ti += va_arg(ap, int);\n"
|
||||
" *va_arg(ap, int*) = ti;\n"
|
||||
" for (i = 0, td = 0; i < n_float; ++i)\n"
|
||||
" td += va_arg(ap, double);\n"
|
||||
" *va_arg(ap, double*) = td;\n"
|
||||
" for (i = 0; i < n_struct; ++i) {\n"
|
||||
" tmp = va_arg(ap, stdarg_test_struct_type);\n"
|
||||
" ts.a += tmp.a; ts.b += tmp.b; ts.c += tmp.c;"
|
||||
" }\n"
|
||||
" *va_arg(ap, stdarg_test_struct_type*) = ts;\n"
|
||||
" va_end(ap);"
|
||||
"}\n";
|
||||
return run_callback(src, stdarg_test_callback);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test Win32 stdarg handling, since the calling convention will pass a pointer
|
||||
* to the struct and the stdarg pointer must point to that pointer initially.
|
||||
*/
|
||||
|
||||
typedef struct {long long a, b, c;} stdarg_struct_test_struct_type;
|
||||
typedef int (*stdarg_struct_test_function_type) (stdarg_struct_test_struct_type a, ...);
|
||||
|
||||
static int stdarg_struct_test_callback(void *ptr) {
|
||||
stdarg_struct_test_function_type f = (stdarg_struct_test_function_type)ptr;
|
||||
stdarg_struct_test_struct_type v = {10, 35, 99};
|
||||
int x = f(v, 234);
|
||||
return (x == 378) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int stdarg_struct_test(void) {
|
||||
const char *src =
|
||||
"#include <stdarg.h>\n"
|
||||
"typedef struct {long long a, b, c;} stdarg_struct_test_struct_type;\n"
|
||||
"int f(stdarg_struct_test_struct_type a, ...) {\n"
|
||||
" va_list ap;\n"
|
||||
" va_start(ap, a);\n"
|
||||
" int z = va_arg(ap, int);\n"
|
||||
" va_end(ap);\n"
|
||||
" return z + a.a + a.b + a.c;\n"
|
||||
"}\n";
|
||||
return run_callback(src, stdarg_struct_test_callback);
|
||||
}
|
||||
|
||||
/* Test that x86-64 arranges the stack correctly for arguments with alignment >8 bytes */
|
||||
|
||||
typedef LONG_DOUBLE (*arg_align_test_callback_type) (LONG_DOUBLE,int,LONG_DOUBLE,int,LONG_DOUBLE);
|
||||
|
||||
static int arg_align_test_callback(void *ptr) {
|
||||
arg_align_test_callback_type f = (arg_align_test_callback_type)ptr;
|
||||
long double x = f(12, 0, 25, 0, 37);
|
||||
return (x == 74) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int arg_align_test(void) {
|
||||
const char *src =
|
||||
"long double f(long double a, int b, long double c, int d, long double e) {\n"
|
||||
" return a + c + e;\n"
|
||||
"}\n";
|
||||
return run_callback(src, arg_align_test_callback);
|
||||
}
|
||||
|
||||
#define RUN_TEST(t) \
|
||||
if (!testname || (strcmp(#t, testname) == 0)) { \
|
||||
fputs(#t "... ", stdout); \
|
||||
fflush(stdout); \
|
||||
if (t() == 0) { \
|
||||
fputs("success\n", stdout); \
|
||||
} else { \
|
||||
fputs("failure\n", stdout); \
|
||||
retval = EXIT_FAILURE; \
|
||||
} \
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int i;
|
||||
const char *testname = NULL;
|
||||
int retval = EXIT_SUCCESS;
|
||||
|
||||
/* if tcclib.h and libtcc1.a are not installed, where can we find them */
|
||||
for (i = 1; i < argc; ++i) {
|
||||
if (!memcmp(argv[i], "run_test=", 9))
|
||||
testname = argv[i] + 9;
|
||||
}
|
||||
|
||||
g_argv = argv, g_argc = argc;
|
||||
|
||||
RUN_TEST(ret_int_test);
|
||||
RUN_TEST(ret_longlong_test);
|
||||
RUN_TEST(ret_float_test);
|
||||
RUN_TEST(ret_double_test);
|
||||
RUN_TEST(ret_longdouble_test);
|
||||
RUN_TEST(ret_2float_test);
|
||||
RUN_TEST(ret_2double_test);
|
||||
/* RUN_TEST(ret_8plus2double_test); currently broken on x86_64 */
|
||||
/* RUN_TEST(ret_6plus2longlong_test); currently broken on x86_64 */
|
||||
/* RUN_TEST(ret_mixed_test); currently broken on x86_64 */
|
||||
/* RUN_TEST(ret_mixed2_test); currently broken on x86_64 */
|
||||
RUN_TEST(ret_mixed3_test);
|
||||
RUN_TEST(reg_pack_test);
|
||||
RUN_TEST(reg_pack_longlong_test);
|
||||
RUN_TEST(sret_test);
|
||||
RUN_TEST(one_member_union_test);
|
||||
RUN_TEST(two_member_union_test);
|
||||
RUN_TEST(many_struct_test);
|
||||
RUN_TEST(many_struct_test_2);
|
||||
RUN_TEST(many_struct_test_3);
|
||||
RUN_TEST(stdarg_test);
|
||||
RUN_TEST(stdarg_struct_test);
|
||||
RUN_TEST(arg_align_test);
|
||||
return retval;
|
||||
}
|
||||
398
tests/asmtest.S
398
tests/asmtest.S
@ -11,14 +11,22 @@
|
||||
.align 8
|
||||
.byte 1
|
||||
/* .align 16, 0x90 gas is too clever for us with 0x90 fill */
|
||||
.balign 4, 0x92
|
||||
.align 16, 0x91 /* 0x91 tests the non-clever behaviour */
|
||||
.skip 3
|
||||
.skip 15, 0x90
|
||||
.string "hello\0world"
|
||||
/* Macro expansion should work like with C, the #n shouldn't be parsed
|
||||
as asm line comment */
|
||||
#define __stringify(n) #n
|
||||
#define stringify(n) __stringify(n)
|
||||
.skip 8,0x90
|
||||
.asciz stringify(BLA)
|
||||
.skip 8,0x90
|
||||
|
||||
# 28 "asmtest.S" # a line directive (and a line comment)
|
||||
movl %eax, %ebx # some more asm comment
|
||||
/* some label tests */
|
||||
|
||||
movl %eax, %ebx
|
||||
L1:
|
||||
movl %eax, %ebx
|
||||
mov 0x10000, %eax
|
||||
@ -38,7 +46,7 @@ mov %al, 0x10000
|
||||
|
||||
mov $1, %edx
|
||||
mov $1, %dx
|
||||
mov $1, %dl
|
||||
mov $1, %cl
|
||||
movb $2, 0x100(%ebx,%edx,2)
|
||||
movw $2, 0x100(%ebx,%edx,2)
|
||||
movl $2, 0x100(%ebx,%edx,2)
|
||||
@ -46,17 +54,55 @@ movl %eax, 0x100(%ebx,%edx,2)
|
||||
movl 0x100(%ebx,%edx,2), %edx
|
||||
movw %ax, 0x100(%ebx,%edx,2)
|
||||
|
||||
movw $0x1122,%si
|
||||
movl $0x112233,%edx
|
||||
movl $0x80000000, %esi
|
||||
movl $-0x7fffffff, %edi
|
||||
#ifdef __x86_64__
|
||||
mov $0x11223344,%rbx
|
||||
movq $0x11223344,%rbx
|
||||
mov $0x1122334455,%rbx
|
||||
movq $0x1122334455,%rbx
|
||||
movl $0x11334455,(%rbx)
|
||||
#endif
|
||||
|
||||
mov %eax, 0x12(,%edx,2)
|
||||
|
||||
#ifdef __i386__
|
||||
mov %cr3, %edx
|
||||
mov %ecx, %cr3
|
||||
movl %cr3, %eax
|
||||
movl %tr3, %eax
|
||||
movl %db3, %ebx
|
||||
movl %dr6, %eax
|
||||
#else
|
||||
mov %cr3, %rdx
|
||||
mov %rcx, %cr3
|
||||
movq %cr3, %rax
|
||||
movq %db3, %rbx
|
||||
movq %dr6, %rax
|
||||
mov %cr8, %rsi
|
||||
mov %rdi, %cr8
|
||||
#endif
|
||||
movl %fs, %ecx
|
||||
movl %ebx, %fs
|
||||
|
||||
#ifdef __x86_64__
|
||||
movq %r8, %r9
|
||||
movq %r10, %r11
|
||||
movq %r12, %r13
|
||||
movq %r14, %r15
|
||||
movq %rax, %r9
|
||||
movq %r15, %rsi
|
||||
inc %r9b
|
||||
dec %r10w
|
||||
not %r11d
|
||||
negq %r12
|
||||
decb %r13b
|
||||
incw %r14w
|
||||
notl %r15d
|
||||
#endif
|
||||
|
||||
movsbl 0x1000, %eax
|
||||
movsbw 0x1000, %ax
|
||||
movswl 0x1000, %eax
|
||||
@ -68,19 +114,47 @@ movl %ebx, %fs
|
||||
movzb 0x1000, %eax
|
||||
movzb 0x1000, %ax
|
||||
|
||||
mov $0x12345678,%eax
|
||||
|
||||
#ifdef __x86_64__
|
||||
movzb 0x1000, %rax
|
||||
movzbq 0x1000, %rbx
|
||||
movsbq 0x1000, %rdx
|
||||
movzwq 0x1000, %rdi
|
||||
movswq 0x1000, %rdx
|
||||
movslq %eax, %rcx
|
||||
mov $0x12345678,%rax
|
||||
mov $0x12345678,%rdx
|
||||
mov $0x12345678,%r10
|
||||
mov $0x123456789abcdef0,%rax
|
||||
mov $0x123456789abcdef0,%rcx
|
||||
mov $0x123456789abcdef0,%r11
|
||||
#endif
|
||||
|
||||
#ifdef __i386__
|
||||
pushl %eax
|
||||
pushw %ax
|
||||
push %eax
|
||||
push %cs
|
||||
#else
|
||||
pushq %rax
|
||||
push %rax
|
||||
#endif
|
||||
pushw %ax
|
||||
push %gs
|
||||
push $1
|
||||
push $100
|
||||
push 0x42(%eax)
|
||||
pop 0x43(%esi)
|
||||
|
||||
#ifdef __i386__
|
||||
popl %eax
|
||||
popw %ax
|
||||
pop %eax
|
||||
pop %ds
|
||||
#else
|
||||
popq %rax
|
||||
pop %rax
|
||||
#endif
|
||||
popw %ax
|
||||
pop %fs
|
||||
|
||||
xchg %eax, %ecx
|
||||
@ -111,14 +185,34 @@ movl %ebx, %fs
|
||||
leal 0x1000(%ebx), %ecx
|
||||
lea 0x1000(%ebx), %ecx
|
||||
|
||||
#ifdef __i386__
|
||||
les 0x2000, %eax
|
||||
lds 0x2000, %ebx
|
||||
lss 0x2000, %edx
|
||||
#endif
|
||||
lfs 0x2000, %ecx
|
||||
lgs 0x2000, %edx
|
||||
lss 0x2000, %edx
|
||||
|
||||
addl $0x123, %eax
|
||||
add $0x123, %ebx
|
||||
add $-16, %ecx
|
||||
add $-0x123, %esi
|
||||
add $1, %bx
|
||||
add $1, %ebx
|
||||
add $-1, %bx
|
||||
add $-1, %ebx
|
||||
add $127, %bx
|
||||
addl $127, %ebx
|
||||
addl $-128, %ebx
|
||||
addl $-128, %ebx
|
||||
addl $-129, %ebx
|
||||
addl $128, %ebx
|
||||
addl $255, %ebx
|
||||
addl $256, %ebx
|
||||
andb $0xf, %ah
|
||||
andb $-15, %cl
|
||||
xorb $127, %dh
|
||||
cmpb $42, (%eax)
|
||||
addl $0x123, 0x100
|
||||
addl $0x123, 0x100(%ebx)
|
||||
addl $0x123, 0x100(%ebx,%edx,2)
|
||||
@ -128,6 +222,24 @@ addl $0x123, (%ebp)
|
||||
addl $0x123, (%esp)
|
||||
cmpl $0x123, (%esp)
|
||||
|
||||
#ifdef __x86_64__
|
||||
xor %bl,%ah
|
||||
xor %bl,%r8b
|
||||
xor %r9b,%bl
|
||||
xor %sil,%cl
|
||||
add %eax,(%r8d)
|
||||
add %ebx,(%r9)
|
||||
add %edx,(%r10d,%r11d)
|
||||
add %ecx,(%r12,%r13)
|
||||
add %esi,(%r14,%r15,4)
|
||||
add %edi,0x1000(%rbx,%r12,8)
|
||||
add %r11,0x1000(%ebp,%r9d,8)
|
||||
movb $12, %ah
|
||||
movb $13, %bpl
|
||||
movb $14, %dil
|
||||
movb $15, %r12b
|
||||
#endif
|
||||
|
||||
add %eax, (%ebx)
|
||||
add (%ebx), %eax
|
||||
|
||||
@ -179,6 +291,8 @@ add (%ebx), %dl
|
||||
div %bl
|
||||
div %ecx, %eax
|
||||
|
||||
and $15,%bx
|
||||
and $-20,%edx
|
||||
|
||||
shl %edx
|
||||
shl $10, %edx
|
||||
@ -195,7 +309,11 @@ shrd %eax, %edx
|
||||
L4:
|
||||
call 0x1000
|
||||
call L4
|
||||
#ifdef __i386__
|
||||
call *%eax
|
||||
#else
|
||||
call *%rax
|
||||
#endif
|
||||
call *0x1000
|
||||
call func1
|
||||
|
||||
@ -204,19 +322,40 @@ call func1
|
||||
L5:
|
||||
L6:
|
||||
|
||||
#ifdef __i386__
|
||||
lcall $0x100, $0x1000
|
||||
#else
|
||||
lcall *0x100
|
||||
lcall *(%rax)
|
||||
#endif
|
||||
|
||||
jmp 0x1000
|
||||
jmp *(%edi)
|
||||
#ifdef __i386__
|
||||
jmp *%eax
|
||||
#else
|
||||
jmp *%rax
|
||||
#endif
|
||||
jmp *0x1000
|
||||
|
||||
#ifdef __i386__
|
||||
ljmp $0x100, $0x1000
|
||||
#else
|
||||
ljmp *0x100
|
||||
ljmp *(%rdi)
|
||||
ljmpl *(%esi)
|
||||
ljmpw *(%esi)
|
||||
#endif
|
||||
|
||||
ret
|
||||
retl
|
||||
|
||||
ret $10
|
||||
#ifdef __i386__
|
||||
retl
|
||||
retl $10
|
||||
#else
|
||||
retq
|
||||
retq $10
|
||||
#endif
|
||||
|
||||
lret
|
||||
|
||||
@ -244,6 +383,8 @@ L3:
|
||||
|
||||
|
||||
seto %al
|
||||
setc %al
|
||||
setcb %al
|
||||
setnp 0x1000
|
||||
setl 0xaaaa
|
||||
setg %dl
|
||||
@ -401,6 +542,7 @@ L3:
|
||||
fwait
|
||||
|
||||
bswap %edx
|
||||
bswapl %ecx
|
||||
xadd %ecx, %edx
|
||||
xaddb %dl, 0x1000
|
||||
xaddw %ax, 0x1000
|
||||
@ -411,6 +553,10 @@ cmpxchgw %ax, 0x1000
|
||||
cmpxchgl %eax, 0x1000
|
||||
invlpg 0x1000
|
||||
cmpxchg8b 0x1002
|
||||
#ifdef __x86_64__
|
||||
cmpxchg16b (%rax)
|
||||
cmpxchg16b (%r10,%r11)
|
||||
#endif
|
||||
|
||||
fcmovb %st(5), %st
|
||||
fcmove %st(5), %st
|
||||
@ -430,32 +576,48 @@ fucomip %st(5), %st
|
||||
cmovo 0x1000, %eax
|
||||
cmovs 0x1000, %eax
|
||||
cmovns %edx, %edi
|
||||
cmovne %ax, %si
|
||||
#ifdef __x86_64__
|
||||
bswapq %rsi
|
||||
bswapq %r10
|
||||
cmovz %rdi,%rbx
|
||||
#endif
|
||||
|
||||
int $3
|
||||
int $0x10
|
||||
|
||||
#ifdef __i386__
|
||||
pusha
|
||||
popa
|
||||
clc
|
||||
cld
|
||||
#endif
|
||||
clc # another comment
|
||||
cld # a comment with embedded ' tick
|
||||
cli
|
||||
clts
|
||||
cmc
|
||||
lahf
|
||||
sahf
|
||||
#ifdef __i386__
|
||||
pushfl
|
||||
popfl
|
||||
#else
|
||||
pushfq
|
||||
popfq
|
||||
#endif
|
||||
pushf
|
||||
popf
|
||||
stc
|
||||
std
|
||||
sti
|
||||
#ifdef __i386__
|
||||
aaa
|
||||
aas
|
||||
daa
|
||||
das
|
||||
aad
|
||||
aam
|
||||
into
|
||||
#endif
|
||||
cbw
|
||||
cwd
|
||||
cwde
|
||||
@ -466,7 +628,6 @@ int $0x10
|
||||
cltd
|
||||
leave
|
||||
int3
|
||||
into
|
||||
iret
|
||||
rsm
|
||||
hlt
|
||||
@ -511,7 +672,34 @@ int $0x10
|
||||
rdmsr
|
||||
rdpmc
|
||||
ud2
|
||||
#ifdef __x86_64__
|
||||
syscall
|
||||
sysret
|
||||
sysretq
|
||||
lfence
|
||||
mfence
|
||||
sfence
|
||||
prefetchnta 0x18(%rdx)
|
||||
prefetcht0 (%rcx)
|
||||
prefetcht1 (%rsi)
|
||||
prefetcht2 (%rdi)
|
||||
prefetchw (%rdi)
|
||||
clflush 0x1000(%rax,%rcx)
|
||||
fxsaveq (%rdx)
|
||||
fxsaveq (%r11)
|
||||
fxrstorq (%rcx)
|
||||
fxrstorq (%r10)
|
||||
|
||||
#endif
|
||||
|
||||
lar %ax,%dx
|
||||
lar %eax,%dx
|
||||
lar %ax,%edx
|
||||
lar %eax,%edx
|
||||
#ifdef __x86_64__
|
||||
lar %ax,%rdx
|
||||
lar %eax,%rdx
|
||||
#endif
|
||||
emms
|
||||
movd %edx, %mm3
|
||||
movd 0x1000, %mm2
|
||||
@ -556,36 +744,58 @@ int $0x10
|
||||
|
||||
|
||||
|
||||
#ifdef __i386__
|
||||
boundl %edx, 0x10000
|
||||
boundw %bx, 0x1000
|
||||
|
||||
|
||||
arpl %bx, 0x1000
|
||||
#endif
|
||||
lar 0x1000, %eax
|
||||
lgdt 0x1000
|
||||
lidt 0x1000
|
||||
lldt 0x1000
|
||||
lmsw 0x1000
|
||||
lsl 0x1000, %ecx
|
||||
ltr 0x1000
|
||||
|
||||
sgdt 0x1000
|
||||
sidt 0x1000
|
||||
sldt 0x1000
|
||||
#ifdef __x86_64__
|
||||
lgdtq 0x1000
|
||||
lidtq 0x1000
|
||||
sgdtq 0x1000
|
||||
sidtq 0x1000
|
||||
|
||||
swapgs
|
||||
|
||||
str %rdx
|
||||
str %r9
|
||||
#endif
|
||||
|
||||
lmsw 0x1000
|
||||
lsl 0x1000, %ecx
|
||||
ltr 0x1000
|
||||
ltr %si
|
||||
smsw 0x1000
|
||||
str 0x1000
|
||||
str %ecx
|
||||
str %dx
|
||||
|
||||
verr 0x1000
|
||||
verw 0x1000
|
||||
|
||||
#ifdef __i386__
|
||||
push %ds
|
||||
pushw %ds
|
||||
pushl %ds
|
||||
pop %ds
|
||||
popw %ds
|
||||
popl %ds
|
||||
#endif
|
||||
fxsave 1(%ebx)
|
||||
fxrstor 1(%ecx)
|
||||
#ifdef __i386__
|
||||
pushl $1
|
||||
#else
|
||||
pushq $1
|
||||
#endif
|
||||
pushw $1
|
||||
push $1
|
||||
|
||||
@ -593,6 +803,7 @@ int $0x10
|
||||
inc %eax
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
ft1: ft2: ft3: ft4: ft5: ft6: ft7: ft8: ft9:
|
||||
xor %eax, %eax
|
||||
ret
|
||||
@ -605,5 +816,160 @@ ft1: ft2: ft3: ft4: ft5: ft6: ft7: ft8: ft9:
|
||||
.type ft6,@function
|
||||
.type ft7,%function
|
||||
.type ft8,"function"
|
||||
#endif
|
||||
|
||||
pause
|
||||
.rept 6
|
||||
nop
|
||||
.endr
|
||||
.fill 4,1,0x90
|
||||
|
||||
.section .text.one,"ax"
|
||||
nop
|
||||
.previous
|
||||
.pushsection .text.one,"ax"
|
||||
nop
|
||||
.pushsection .text.two,"ax"
|
||||
nop
|
||||
.popsection
|
||||
.popsection
|
||||
|
||||
1: ud2
|
||||
.pushsection __bug_table,"a"
|
||||
.align 8
|
||||
2: .long 1b - 2b
|
||||
.long 0x600000 - 2b
|
||||
.long 1b + 42
|
||||
.long 43 + 1b
|
||||
.long 2b + 144
|
||||
.long 145 + 2b
|
||||
.word 164, 0
|
||||
.org 2b+32
|
||||
#ifdef __x86_64__
|
||||
.quad 1b
|
||||
#else
|
||||
.long 1b
|
||||
#endif
|
||||
.popsection
|
||||
3: mov %eax,%ecx
|
||||
4:
|
||||
.pushsection .text.three, "ax"
|
||||
nop
|
||||
.skip (-((4b-3b) > 0) * 2) , 0x90
|
||||
.popsection
|
||||
|
||||
.globl overrideme
|
||||
.weak overrideme
|
||||
nop
|
||||
.globl notimplemented
|
||||
notimplemented:
|
||||
ret
|
||||
.set overrideme, notimplemented
|
||||
overrideme = notimplemented
|
||||
overrideme:
|
||||
ret
|
||||
|
||||
movd %esi, %mm1
|
||||
movd %edi, %xmm2
|
||||
movd (%ebx), %mm3
|
||||
movd (%ebx), %xmm3
|
||||
movd %mm1, %esi
|
||||
movd %xmm2, %edi
|
||||
movd %mm3, (%edx)
|
||||
movd %xmm3, (%edx)
|
||||
#ifdef __x86_64__
|
||||
movd %rsi, %mm1
|
||||
movd %rdi, %xmm2
|
||||
movd (%rbx), %mm3
|
||||
movd (%rbx), %xmm3
|
||||
movd %mm1, %r12
|
||||
movd %xmm2, %rdi
|
||||
movd %mm3, (%r8)
|
||||
movd %xmm3, (%r13)
|
||||
#endif
|
||||
|
||||
movq (%ebp), %mm1
|
||||
movq %mm2, (%edi)
|
||||
movq (%edi), %xmm3
|
||||
movq %mm4, %mm5
|
||||
#ifdef __x86_64__
|
||||
movq %rcx, %mm1
|
||||
movq %rdx, %xmm2
|
||||
movq %r13, %xmm3
|
||||
/* movq mem64->xmm is encoded as f30f7e by GAS, but as
|
||||
660f6e by tcc (which really is a movd and would need
|
||||
a REX.W prefix to be movq). */
|
||||
movq (%rsi), %xmm3
|
||||
movq %mm1, %rdx
|
||||
movq %xmm3, %rcx
|
||||
movq %xmm4, (%rsi)
|
||||
#endif
|
||||
|
||||
#define TEST_MMX_SSE(insn) \
|
||||
insn %mm1, %mm2; \
|
||||
insn %xmm2, %xmm3; \
|
||||
insn (%ebx), %xmm3;
|
||||
#define TEST_MMX_SSE_I8(insn) \
|
||||
TEST_MMX_SSE(insn) \
|
||||
insn $0x42, %mm4; \
|
||||
insn $0x42, %xmm4;
|
||||
|
||||
TEST_MMX_SSE(packssdw)
|
||||
TEST_MMX_SSE(packsswb)
|
||||
TEST_MMX_SSE(packuswb)
|
||||
TEST_MMX_SSE(paddb)
|
||||
TEST_MMX_SSE(paddw)
|
||||
TEST_MMX_SSE(paddd)
|
||||
TEST_MMX_SSE(paddsb)
|
||||
TEST_MMX_SSE(paddsw)
|
||||
TEST_MMX_SSE(paddusb)
|
||||
TEST_MMX_SSE(paddusw)
|
||||
TEST_MMX_SSE(pand)
|
||||
TEST_MMX_SSE(pandn)
|
||||
TEST_MMX_SSE(pcmpeqb)
|
||||
TEST_MMX_SSE(pcmpeqw)
|
||||
TEST_MMX_SSE(pcmpeqd)
|
||||
TEST_MMX_SSE(pcmpgtb)
|
||||
TEST_MMX_SSE(pcmpgtw)
|
||||
TEST_MMX_SSE(pcmpgtd)
|
||||
TEST_MMX_SSE(pmaddwd)
|
||||
TEST_MMX_SSE(pmulhw)
|
||||
TEST_MMX_SSE(pmullw)
|
||||
TEST_MMX_SSE(por)
|
||||
TEST_MMX_SSE(psllw)
|
||||
TEST_MMX_SSE_I8(psllw)
|
||||
TEST_MMX_SSE(pslld)
|
||||
TEST_MMX_SSE_I8(pslld)
|
||||
TEST_MMX_SSE(psllq)
|
||||
TEST_MMX_SSE_I8(psllq)
|
||||
TEST_MMX_SSE(psraw)
|
||||
TEST_MMX_SSE_I8(psraw)
|
||||
TEST_MMX_SSE(psrad)
|
||||
TEST_MMX_SSE_I8(psrad)
|
||||
TEST_MMX_SSE(psrlw)
|
||||
TEST_MMX_SSE_I8(psrlw)
|
||||
TEST_MMX_SSE(psrld)
|
||||
TEST_MMX_SSE_I8(psrld)
|
||||
TEST_MMX_SSE(psrlq)
|
||||
TEST_MMX_SSE_I8(psrlq)
|
||||
TEST_MMX_SSE(psubb)
|
||||
TEST_MMX_SSE(psubw)
|
||||
TEST_MMX_SSE(psubd)
|
||||
TEST_MMX_SSE(psubsb)
|
||||
TEST_MMX_SSE(psubsw)
|
||||
TEST_MMX_SSE(psubusb)
|
||||
TEST_MMX_SSE(psubusw)
|
||||
TEST_MMX_SSE(punpckhbw)
|
||||
TEST_MMX_SSE(punpckhwd)
|
||||
TEST_MMX_SSE(punpckhdq)
|
||||
TEST_MMX_SSE(punpcklbw)
|
||||
TEST_MMX_SSE(punpcklwd)
|
||||
TEST_MMX_SSE(punpckldq)
|
||||
TEST_MMX_SSE(pxor)
|
||||
|
||||
cvtpi2ps %mm1, %xmm2
|
||||
cvtpi2ps (%ebx), %xmm2
|
||||
TEST_MMX_SSE(pmaxsw)
|
||||
TEST_MMX_SSE(pmaxub)
|
||||
TEST_MMX_SSE(pminsw)
|
||||
TEST_MMX_SSE(pminub)
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define NB_ITS 1000000
|
||||
//#define NB_ITS 1
|
||||
@ -49,12 +50,15 @@ int test4(void)
|
||||
int i, sum = 0;
|
||||
int *tab4;
|
||||
|
||||
fprintf(stderr, "%s start\n", __FUNCTION__);
|
||||
|
||||
tab4 = malloc(20 * sizeof(int));
|
||||
for(i=0;i<20;i++) {
|
||||
sum += tab4[i];
|
||||
}
|
||||
free(tab4);
|
||||
|
||||
fprintf(stderr, "%s end\n", __FUNCTION__);
|
||||
return sum;
|
||||
}
|
||||
|
||||
@ -64,12 +68,15 @@ int test5(void)
|
||||
int i, sum = 0;
|
||||
int *tab4;
|
||||
|
||||
fprintf(stderr, "%s start\n", __FUNCTION__);
|
||||
|
||||
tab4 = malloc(20 * sizeof(int));
|
||||
for(i=0;i<21;i++) {
|
||||
sum += tab4[i];
|
||||
}
|
||||
free(tab4);
|
||||
|
||||
fprintf(stderr, "%s end\n", __FUNCTION__);
|
||||
return sum;
|
||||
}
|
||||
|
||||
@ -186,8 +193,43 @@ int test15(void)
|
||||
return strlen(p);
|
||||
}
|
||||
|
||||
/* ok */
|
||||
int test16()
|
||||
{
|
||||
char *demo = "This is only a test.";
|
||||
char *p;
|
||||
|
||||
fprintf(stderr, "%s start\n", __FUNCTION__);
|
||||
|
||||
p = alloca(16);
|
||||
strcpy(p,"12345678901234");
|
||||
printf("alloca: p is %s\n", p);
|
||||
|
||||
/* Test alloca embedded in a larger expression */
|
||||
printf("alloca: %s\n", strcpy(alloca(strlen(demo)+1),demo) );
|
||||
|
||||
fprintf(stderr, "%s end\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
/* error */
|
||||
int test17()
|
||||
{
|
||||
char *demo = "This is only a test.";
|
||||
char *p;
|
||||
|
||||
fprintf(stderr, "%s start\n", __FUNCTION__);
|
||||
|
||||
p = alloca(16);
|
||||
strcpy(p,"12345678901234");
|
||||
printf("alloca: p is %s\n", p);
|
||||
|
||||
/* Test alloca embedded in a larger expression */
|
||||
printf("alloca: %s\n", strcpy(alloca(strlen(demo)),demo) );
|
||||
|
||||
fprintf(stderr, "%s end\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
int (*table_test[])(void) = {
|
||||
test1,
|
||||
test1,
|
||||
test2,
|
||||
test3,
|
||||
@ -203,23 +245,33 @@ int (*table_test[])(void) = {
|
||||
test13,
|
||||
test14,
|
||||
test15,
|
||||
test16,
|
||||
test17,
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int index;
|
||||
int (*ftest)(void);
|
||||
int index_max = sizeof(table_test)/sizeof(table_test[0]);
|
||||
|
||||
if (argc < 2) {
|
||||
printf("usage: boundtest n\n"
|
||||
"test TCC bound checking system\n"
|
||||
);
|
||||
printf(
|
||||
"test TCC bound checking system\n"
|
||||
"usage: boundtest N\n"
|
||||
" 1 <= N <= %d\n", index_max);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
index = 0;
|
||||
if (argc >= 2)
|
||||
index = atoi(argv[1]);
|
||||
index = atoi(argv[1]) - 1;
|
||||
|
||||
if ((index < 0) || (index >= index_max)) {
|
||||
printf("N is outside of the valid range (%d)\n", index);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
/* well, we also use bounds on this ! */
|
||||
ftest = table_test[index];
|
||||
ftest();
|
||||
|
||||
@ -15,7 +15,16 @@ int add(int a, int b)
|
||||
return a + b;
|
||||
}
|
||||
|
||||
/* this strinc is referenced by the generated code */
|
||||
const char hello[] = "Hello World!";
|
||||
|
||||
char my_program[] =
|
||||
"#include <tcclib.h>\n" /* include the "Simple libc header for TCC" */
|
||||
"extern int add(int a, int b);\n"
|
||||
"#ifdef _WIN32\n" /* dynamically linked data needs 'dllimport' */
|
||||
" __attribute__((dllimport))\n"
|
||||
"#endif\n"
|
||||
"extern const char hello[];\n"
|
||||
"int fib(int n)\n"
|
||||
"{\n"
|
||||
" if (n <= 2)\n"
|
||||
@ -26,7 +35,7 @@ char my_program[] =
|
||||
"\n"
|
||||
"int foo(int n)\n"
|
||||
"{\n"
|
||||
" printf(\"Hello World!\\n\");\n"
|
||||
" printf(\"%s\\n\", hello);\n"
|
||||
" printf(\"fib(%d) = %d\\n\", n, fib(n));\n"
|
||||
" printf(\"add(%d, %d) = %d\\n\", n, 2 * n, add(n, 2 * n));\n"
|
||||
" return 0;\n"
|
||||
@ -35,6 +44,7 @@ char my_program[] =
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
TCCState *s;
|
||||
int i;
|
||||
int (*func)(int);
|
||||
|
||||
s = tcc_new();
|
||||
@ -44,8 +54,17 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
/* if tcclib.h and libtcc1.a are not installed, where can we find them */
|
||||
if (argc == 2 && !memcmp(argv[1], "lib_path=",9))
|
||||
tcc_set_lib_path(s, argv[1]+9);
|
||||
for (i = 1; i < argc; ++i) {
|
||||
char *a = argv[i];
|
||||
if (a[0] == '-') {
|
||||
if (a[1] == 'B')
|
||||
tcc_set_lib_path(s, a+2);
|
||||
else if (a[1] == 'I')
|
||||
tcc_add_include_path(s, a+2);
|
||||
else if (a[1] == 'L')
|
||||
tcc_add_library_path(s, a+2);
|
||||
}
|
||||
}
|
||||
|
||||
/* MUST BE CALLED before any compilation */
|
||||
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
|
||||
@ -53,9 +72,10 @@ int main(int argc, char **argv)
|
||||
if (tcc_compile_string(s, my_program) == -1)
|
||||
return 1;
|
||||
|
||||
/* as a test, we add a symbol that the compiled program can use.
|
||||
/* as a test, we add symbols that the compiled program can use.
|
||||
You may also open a dll with tcc_add_dll() and use symbols from that */
|
||||
tcc_add_symbol(s, "add", add);
|
||||
tcc_add_symbol(s, "hello", hello);
|
||||
|
||||
/* relocate the code */
|
||||
if (tcc_relocate(s, TCC_RELOCATE_AUTO) < 0)
|
||||
|
||||
6
tests/pp/01.c
Normal file
6
tests/pp/01.c
Normal file
@ -0,0 +1,6 @@
|
||||
#define hash_hash # ## #
|
||||
#define mkstr(a) # a
|
||||
#define in_between(a) mkstr(a)
|
||||
#define join(c, d) in_between(c hash_hash d)
|
||||
char p[] = join(x, y);
|
||||
// char p[] = "x ## y";
|
||||
1
tests/pp/01.expect
Normal file
1
tests/pp/01.expect
Normal file
@ -0,0 +1 @@
|
||||
char p[] = "x ## y";
|
||||
28
tests/pp/02.c
Normal file
28
tests/pp/02.c
Normal file
@ -0,0 +1,28 @@
|
||||
#define x 3
|
||||
#define f(a) f(x * (a))
|
||||
#undef x
|
||||
#define x 2
|
||||
#define g f
|
||||
#define z z[0]
|
||||
#define h g(~
|
||||
#define m(a) a(w)
|
||||
#define w 0,1
|
||||
#define t(a) a
|
||||
#define p() int
|
||||
#define q(x) x
|
||||
#define r(x,y) x ## y
|
||||
#define str(x) # x
|
||||
f(y+1) + f(f(z)) % t(t(g)(0) + t)(1);
|
||||
g(x+(3,4)-w) | h 5) & m
|
||||
(f)^m(m);
|
||||
char c[2][6] = { str(hello), str() };
|
||||
/*
|
||||
* f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);
|
||||
* f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1);
|
||||
* char c[2][6] = { "hello", "" };
|
||||
*/
|
||||
#define L21 f(y+1) + f(f(z)) % t(t(g)(0) + t)(1);
|
||||
#define L22 g(x+(3,4)-w) | h 5) & m\
|
||||
(f)^m(m);
|
||||
L21
|
||||
L22
|
||||
5
tests/pp/02.expect
Normal file
5
tests/pp/02.expect
Normal file
@ -0,0 +1,5 @@
|
||||
f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);
|
||||
f(2 * (2 +(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1);
|
||||
char c[2][6] = { "hello", "" };
|
||||
f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);
|
||||
f(2 * (2 +(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1);
|
||||
15
tests/pp/03.c
Normal file
15
tests/pp/03.c
Normal file
@ -0,0 +1,15 @@
|
||||
#define str(s) # s
|
||||
#define xstr(s) str(s)
|
||||
#define debug(s, t) printf("x" # s "= %d, x" # t "= %s", \
|
||||
x ## s, x ## t)
|
||||
#define INCFILE(n) vers ## n
|
||||
#define glue(a, b) a ## b
|
||||
#define xglue(a, b) glue(a, b)
|
||||
#define HIGHLOW "hello"
|
||||
#define LOW LOW ", world"
|
||||
debug(1, 2);
|
||||
fputs(str(strncmp("abc\0d", "abc", '\4') // this goes away
|
||||
== 0) str(: @\n), s);
|
||||
\#include xstr(INCFILE(2).h)
|
||||
glue(HIGH, LOW);
|
||||
xglue(HIGH, LOW)
|
||||
5
tests/pp/03.expect
Normal file
5
tests/pp/03.expect
Normal file
@ -0,0 +1,5 @@
|
||||
printf("x" "1" "= %d, x" "2" "= %s", x1, x2);
|
||||
fputs("strncmp(\"abc\\0d\", \"abc\", '\\4') == 0" ": @\n", s);
|
||||
\#include "vers2.h"
|
||||
"hello";
|
||||
"hello" ", world"
|
||||
4
tests/pp/04.c
Normal file
4
tests/pp/04.c
Normal file
@ -0,0 +1,4 @@
|
||||
#define foobar 1
|
||||
#define C(x,y) x##y
|
||||
#define D(x) (C(x,bar))
|
||||
D(foo)
|
||||
1
tests/pp/04.expect
Normal file
1
tests/pp/04.expect
Normal file
@ -0,0 +1 @@
|
||||
(1)
|
||||
7
tests/pp/05.c
Normal file
7
tests/pp/05.c
Normal file
@ -0,0 +1,7 @@
|
||||
#define t(x,y,z) x ## y ## z
|
||||
#define xxx(s) int s[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,), \
|
||||
t(10,,), t(,11,), t(,,12), t(,,) };
|
||||
|
||||
int j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,),
|
||||
t(10,,), t(,11,), t(,,12), t(,,) };
|
||||
xxx(j)
|
||||
3
tests/pp/05.expect
Normal file
3
tests/pp/05.expect
Normal file
@ -0,0 +1,3 @@
|
||||
int j[] = { 123, 45, 67, 89,
|
||||
10, 11, 12, };
|
||||
int j[] = { 123, 45, 67, 89, 10, 11, 12, };
|
||||
5
tests/pp/06.c
Normal file
5
tests/pp/06.c
Normal file
@ -0,0 +1,5 @@
|
||||
#define X(a,b, \
|
||||
c,d) \
|
||||
foo
|
||||
|
||||
X(1,2,3,4)
|
||||
1
tests/pp/06.expect
Normal file
1
tests/pp/06.expect
Normal file
@ -0,0 +1 @@
|
||||
foo
|
||||
4
tests/pp/07.c
Normal file
4
tests/pp/07.c
Normal file
@ -0,0 +1,4 @@
|
||||
#define a() YES
|
||||
#define b() a
|
||||
b()
|
||||
b()()
|
||||
2
tests/pp/07.expect
Normal file
2
tests/pp/07.expect
Normal file
@ -0,0 +1,2 @@
|
||||
a
|
||||
YES
|
||||
4
tests/pp/08.c
Normal file
4
tests/pp/08.c
Normal file
@ -0,0 +1,4 @@
|
||||
// test macro expansion in arguments
|
||||
#define s_pos s_s.s_pos
|
||||
#define foo(x) (x)
|
||||
foo(hej.s_pos)
|
||||
1
tests/pp/08.expect
Normal file
1
tests/pp/08.expect
Normal file
@ -0,0 +1 @@
|
||||
(hej.s_s.s_pos)
|
||||
4
tests/pp/09.c
Normal file
4
tests/pp/09.c
Normal file
@ -0,0 +1,4 @@
|
||||
#define C(a,b,c) a##b##c
|
||||
#define N(x,y) C(x,_,y)
|
||||
#define A_O aaaaoooo
|
||||
N(A,O)
|
||||
1
tests/pp/09.expect
Normal file
1
tests/pp/09.expect
Normal file
@ -0,0 +1 @@
|
||||
aaaaoooo
|
||||
10
tests/pp/10.c
Normal file
10
tests/pp/10.c
Normal file
@ -0,0 +1,10 @@
|
||||
#define f(x) x
|
||||
#define g(x) f(x) f(x
|
||||
#define i(x) g(x)) g(x
|
||||
#define h(x) i(x))) i(x
|
||||
#define k(x) i(x))) i(x))))
|
||||
f(x)
|
||||
g(x))
|
||||
i(x)))
|
||||
h(x))))
|
||||
k(x))))
|
||||
5
tests/pp/10.expect
Normal file
5
tests/pp/10.expect
Normal file
@ -0,0 +1,5 @@
|
||||
x
|
||||
x x
|
||||
x x x x
|
||||
x x x x x x x x
|
||||
x x x x x x x x))))
|
||||
31
tests/pp/11.c
Normal file
31
tests/pp/11.c
Normal file
@ -0,0 +1,31 @@
|
||||
#define D1(s, ...) s
|
||||
#define D2(s, ...) s D1(__VA_ARGS__)
|
||||
#define D3(s, ...) s D2(__VA_ARGS__)
|
||||
#define D4(s, ...) s D3(__VA_ARGS__)
|
||||
|
||||
D1(a)
|
||||
D2(a, b)
|
||||
D3(a, b, c)
|
||||
D4(a, b, c, d)
|
||||
|
||||
x D4(a, b, c, d) y
|
||||
x D4(a, b, c) y
|
||||
x D4(a, b) y
|
||||
x D4(a) y
|
||||
x D4() y
|
||||
|
||||
#define GNU_COMMA(X,Y...) X,## Y
|
||||
|
||||
x GNU_COMMA(A,B,C) y
|
||||
x GNU_COMMA(A,B) y
|
||||
x GNU_COMMA(A) y
|
||||
x GNU_COMMA() y
|
||||
|
||||
#define __sun_attr___noreturn__ __attribute__((__noreturn__))
|
||||
#define ___sun_attr_inner(__a) __sun_attr_##__a
|
||||
#define __sun_attr__(__a) ___sun_attr_inner __a
|
||||
#define __NORETURN __sun_attr__((__noreturn__))
|
||||
__NORETURN
|
||||
#define X(...)
|
||||
#define Y(...) 1 __VA_ARGS__ 2
|
||||
Y(X X() ())
|
||||
15
tests/pp/11.expect
Normal file
15
tests/pp/11.expect
Normal file
@ -0,0 +1,15 @@
|
||||
a
|
||||
a b
|
||||
a b c
|
||||
a b c d
|
||||
x a b c d y
|
||||
x a b c y
|
||||
x a b y
|
||||
x a y
|
||||
x y
|
||||
x A,B,C y
|
||||
x A,B y
|
||||
x A y
|
||||
x y
|
||||
__attribute__((__noreturn__))
|
||||
1 2
|
||||
8
tests/pp/12.S
Normal file
8
tests/pp/12.S
Normal file
@ -0,0 +1,8 @@
|
||||
#define SRC(y...) \
|
||||
9999: y; \
|
||||
.section __ex_table, "a"; \
|
||||
.long 9999b, 6001f ; \
|
||||
// .previous
|
||||
|
||||
SRC(1: movw (%esi), %bx)
|
||||
6001:
|
||||
2
tests/pp/12.expect
Normal file
2
tests/pp/12.expect
Normal file
@ -0,0 +1,2 @@
|
||||
9999: 1: movw (%esi), %bx; .section __ex_table, "a"; .long 9999b, 6001f ;
|
||||
6001:
|
||||
6
tests/pp/13.S
Normal file
6
tests/pp/13.S
Normal file
@ -0,0 +1,6 @@
|
||||
# `modelist' label. Each video mode record looks like:
|
||||
#ifdef AAA
|
||||
# modelist' label. Each video mode record looks like:
|
||||
#endif
|
||||
.text
|
||||
endtext:
|
||||
3
tests/pp/13.expect
Normal file
3
tests/pp/13.expect
Normal file
@ -0,0 +1,3 @@
|
||||
# `modelist' label. Each video mode record looks like:
|
||||
.text
|
||||
endtext:
|
||||
13
tests/pp/14.c
Normal file
13
tests/pp/14.c
Normal file
@ -0,0 +1,13 @@
|
||||
#define W Z
|
||||
#define Z(X) W(X,2)
|
||||
#define Y(X) Z(X)
|
||||
#define X Y
|
||||
return X(X(1));
|
||||
|
||||
#define P Q
|
||||
#define Q(n) P(n,2)
|
||||
return P(1);
|
||||
|
||||
#define A (B * B)
|
||||
#define B (A + A)
|
||||
return A + B;
|
||||
3
tests/pp/14.expect
Normal file
3
tests/pp/14.expect
Normal file
@ -0,0 +1,3 @@
|
||||
return Z(Z(1,2),2);
|
||||
return Q(1,2);
|
||||
return ((A + A) * (A + A)) + ((B * B) + (B * B));
|
||||
18
tests/pp/15.c
Normal file
18
tests/pp/15.c
Normal file
@ -0,0 +1,18 @@
|
||||
// insert a space between two tokens if otherwise they
|
||||
// would form a single token when read back
|
||||
|
||||
#define n(x) x
|
||||
|
||||
return (n(long)n(double))d;
|
||||
return n(A)n(++)n(+)n(B);
|
||||
return n(A)n(+)n(++)n(B);
|
||||
return n(A)n(++)n(+)n(+)n(B);
|
||||
|
||||
// not a hex float
|
||||
return n(0x1E)n(-1);
|
||||
|
||||
// unlike gcc but correct
|
||||
XXX: return n(x)+n(x)-n(1)+n(1)-2;
|
||||
|
||||
// unlile gcc, but cannot appear in valid C
|
||||
XXX: return n(x)n(x)n(1)n(2)n(x);
|
||||
7
tests/pp/15.expect
Normal file
7
tests/pp/15.expect
Normal file
@ -0,0 +1,7 @@
|
||||
return (long double)d;
|
||||
return A+++B;
|
||||
return A+ ++B;
|
||||
return A+++ +B;
|
||||
return 0x1E -1;
|
||||
XXX: return x+x-1 +1 -2;
|
||||
XXX: return x x 1 2 x;
|
||||
3
tests/pp/16.c
Normal file
3
tests/pp/16.c
Normal file
@ -0,0 +1,3 @@
|
||||
/* The following should warn */
|
||||
#define A ...
|
||||
#define A <<=
|
||||
2
tests/pp/16.expect
Normal file
2
tests/pp/16.expect
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
16.c:3: warning: A redefined
|
||||
14
tests/pp/17.c
Normal file
14
tests/pp/17.c
Normal file
@ -0,0 +1,14 @@
|
||||
#define STR1(u) # u
|
||||
#define pass(a) a
|
||||
#define __ASM_REG(reg) STR1(one##reg)
|
||||
#define _ASM_DX __ASM_REG(tok)
|
||||
X162 pass(__ASM_REG(tok))
|
||||
X161 pass(_ASM_DX)
|
||||
X163 pass(STR1(one##tok))
|
||||
|
||||
X170 pass(x ## y)
|
||||
X171 pass(x pass(##) y)
|
||||
|
||||
#define Y(x) Z(x)
|
||||
#define X Y
|
||||
X180 return X(X(1));
|
||||
6
tests/pp/17.expect
Normal file
6
tests/pp/17.expect
Normal file
@ -0,0 +1,6 @@
|
||||
X162 "onetok"
|
||||
X161 "onetok"
|
||||
X163 "one##tok"
|
||||
X170 x ## y
|
||||
X171 x ## y
|
||||
X180 return Z(Z(1));
|
||||
52
tests/pp/Makefile
Normal file
52
tests/pp/Makefile
Normal file
@ -0,0 +1,52 @@
|
||||
#
|
||||
# credits: 01..13.c from the pcc cpp-tests suite
|
||||
#
|
||||
|
||||
TOP = ../..
|
||||
include $(TOP)/Makefile
|
||||
SRC = $(TOPSRC)/tests/pp
|
||||
VPATH = $(SRC)
|
||||
|
||||
files = $(patsubst %.$1,%.test,$(notdir $(wildcard $(SRC)/*.$1)))
|
||||
TESTS = $(call files,c) $(call files,S)
|
||||
|
||||
all test : $(sort $(TESTS))
|
||||
|
||||
DIFF_OPTS = -Nu -b -B -I "^\#"
|
||||
|
||||
# Filter source directory in warnings/errors (out-of-tree builds)
|
||||
FILTER = 2>&1 | sed 's,$(SRC)/,,g'
|
||||
|
||||
%.test: %.c %.expect
|
||||
@echo PPTest $* ...
|
||||
-@$(TCC) -E -P $< $(FILTER) >$*.output 2>&1 ; \
|
||||
diff $(DIFF_OPTS) $(SRC)/$*.expect $*.output \
|
||||
&& rm -f $*.output
|
||||
|
||||
%.test: %.S %.expect
|
||||
@echo PPTest $* ...
|
||||
-@$(TCC) -E -P $< $(FILTER) >$*.output 2>&1 ; \
|
||||
diff $(DIFF_OPTS) $(SRC)/$*.expect $*.output \
|
||||
&& rm -f $*.output
|
||||
|
||||
# automatically generate .expect files with gcc:
|
||||
%.expect: # %.c
|
||||
gcc -E -P $< >$*.expect 2>&1
|
||||
|
||||
%.expect: # %.S
|
||||
gcc -E -P $< >$*.expect 2>&1
|
||||
|
||||
# tell make not to delete
|
||||
.PRECIOUS: %.expect
|
||||
|
||||
clean:
|
||||
rm -f *.output
|
||||
|
||||
02.test : DIFF_OPTS += -w
|
||||
15.test : DIFF_OPTS += -I"^XXX:"
|
||||
|
||||
# diff options:
|
||||
# -b ighore space changes
|
||||
# -w ighore all whitespace
|
||||
# -B ignore blank lines
|
||||
# -I <RE> ignore lines matching RE
|
||||
1182
tests/tcctest.c
1182
tests/tcctest.c
File diff suppressed because it is too large
Load Diff
9
tests/tcctest.h
Normal file
9
tests/tcctest.h
Normal file
@ -0,0 +1,9 @@
|
||||
static inline const char *get_basefile_from_header(void)
|
||||
{
|
||||
return __BASE_FILE__;
|
||||
}
|
||||
|
||||
static inline const char *get_file_from_header(void)
|
||||
{
|
||||
return __FILE__;
|
||||
}
|
||||
510
tests/testfp.c
Normal file
510
tests/testfp.c
Normal file
@ -0,0 +1,510 @@
|
||||
/*
|
||||
* Test 128-bit floating-point arithmetic on arm64:
|
||||
* build with two different compilers and compare the output.
|
||||
*
|
||||
* Copyright (c) 2015 Edmund Grimley Evans
|
||||
*
|
||||
* Copying and distribution of this file, with or without modification,
|
||||
* are permitted in any medium without royalty provided the copyright
|
||||
* notice and this notice are preserved. This file is offered as-is,
|
||||
* without any warranty.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define check(x) ((x) ? (void)0 : check_fail(#x, __FILE__, __LINE__))
|
||||
|
||||
void check_fail(const char *assertion, const char *file, unsigned int line)
|
||||
{
|
||||
printf("%s:%d: Check (%s) failed.", file, line, assertion);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
unsigned long long x0, x1;
|
||||
} u128_t;
|
||||
|
||||
float copy_fi(uint32_t x)
|
||||
{
|
||||
float f;
|
||||
memcpy(&f, &x, 4);
|
||||
return f;
|
||||
}
|
||||
|
||||
double copy_di(uint64_t x)
|
||||
{
|
||||
double f;
|
||||
memcpy(&f, &x, 8);
|
||||
return f;
|
||||
}
|
||||
|
||||
long double copy_ldi(u128_t x)
|
||||
{
|
||||
long double f;
|
||||
memcpy(&f, &x, 16);
|
||||
return f;
|
||||
}
|
||||
|
||||
uint32_t copy_if(float f)
|
||||
{
|
||||
uint32_t x;
|
||||
memcpy(&x, &f, 4);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint64_t copy_id(double f)
|
||||
{
|
||||
uint64_t x;
|
||||
memcpy(&x, &f, 8);
|
||||
return x;
|
||||
}
|
||||
|
||||
u128_t copy_ild(long double f)
|
||||
{
|
||||
u128_t x;
|
||||
memcpy(&x, &f, 16);
|
||||
return x;
|
||||
}
|
||||
|
||||
long double make(int sgn, int exp, uint64_t high, uint64_t low)
|
||||
{
|
||||
u128_t x = { low,
|
||||
(0x0000ffffffffffff & high) |
|
||||
(0x7fff000000000000 & (uint64_t)exp << 48) |
|
||||
(0x8000000000000000 & (uint64_t)sgn << 63) };
|
||||
return copy_ldi(x);
|
||||
}
|
||||
|
||||
void cmp(long double a, long double b)
|
||||
{
|
||||
u128_t ax = copy_ild(a);
|
||||
u128_t bx = copy_ild(b);
|
||||
int eq = (a == b);
|
||||
int ne = (a != b);
|
||||
int lt = (a < b);
|
||||
int le = (a <= b);
|
||||
int gt = (a > b);
|
||||
int ge = (a >= b);
|
||||
|
||||
check(eq == 0 || eq == 1);
|
||||
check(lt == 0 || lt == 1);
|
||||
check(gt == 0 || gt == 1);
|
||||
check(ne == !eq && le == (lt | eq) && ge == (gt | eq));
|
||||
check(eq + lt + gt < 2);
|
||||
|
||||
printf("cmp %016llx%016llx %016llx%016llx %d %d %d\n",
|
||||
ax.x1, ax.x0, bx.x1, bx.x0, lt, eq, gt);
|
||||
}
|
||||
|
||||
void cmps(void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
for (j = 0; j < 2; j++)
|
||||
cmp(make(i, 0, 0, 0), make(j, 0, 0, 0));
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
for (j = 0; j < 64; j++) {
|
||||
long double f1 = make(i, 32767, (uint64_t)1 << j, 0);
|
||||
long double f2 = make(i, 32767, 0, (uint64_t)1 << j);
|
||||
cmp(f1, 0);
|
||||
cmp(f2, 0);
|
||||
cmp(0, f1);
|
||||
cmp(0, f2);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
for (j = 0; j < 6; j++)
|
||||
cmp(make(i & 1, i >> 1, 0, 0),
|
||||
make(j & 1, j >> 1, 0, 0));
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
for (j = 0; j < 2; j++) {
|
||||
int a, b;
|
||||
for (a = 0; a < 2; a++) {
|
||||
for (b = 0; b < 2; b++) {
|
||||
cmp(make(i, j, a, b), make(i, j, 0, 0));
|
||||
cmp(make(i, j, 0, 0), make(i, j, a, b));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void xop(const char *name, long double a, long double b, long double c)
|
||||
{
|
||||
u128_t ax = copy_ild(a);
|
||||
u128_t bx = copy_ild(b);
|
||||
u128_t cx = copy_ild(c);
|
||||
printf("%s %016llx%016llx %016llx%016llx %016llx%016llx\n",
|
||||
name, ax.x1, ax.x0, bx.x1, bx.x0, cx.x1, cx.x0);
|
||||
}
|
||||
|
||||
void fadd(long double a, long double b)
|
||||
{
|
||||
xop("add", a, b, a + b);
|
||||
}
|
||||
|
||||
void fsub(long double a, long double b)
|
||||
{
|
||||
xop("sub", a, b, a - b);
|
||||
}
|
||||
|
||||
void fmul(long double a, long double b)
|
||||
{
|
||||
xop("mul", a, b, a * b);
|
||||
}
|
||||
|
||||
void fdiv(long double a, long double b)
|
||||
{
|
||||
xop("div", a, b, a / b);
|
||||
}
|
||||
|
||||
void nanz(void)
|
||||
{
|
||||
// Check NaNs:
|
||||
{
|
||||
long double x[7];
|
||||
int i, j, n = 0;
|
||||
x[n++] = make(0, 32000, 0x95132b76effc, 0xd79035214b4f8d53);
|
||||
x[n++] = make(1, 32001, 0xbe71d7a51587, 0x30601c6815d6c3ac);
|
||||
x[n++] = make(0, 32767, 0, 1);
|
||||
x[n++] = make(0, 32767, (uint64_t)1 << 46, 0);
|
||||
x[n++] = make(1, 32767, (uint64_t)1 << 47, 0);
|
||||
x[n++] = make(1, 32767, 0x7596c7099ad5, 0xe25fed2c58f73fc9);
|
||||
x[n++] = make(0, 32767, 0x835d143360f9, 0x5e315efb35630666);
|
||||
check(n == sizeof(x) / sizeof(*x));
|
||||
for (i = 0; i < n; i++) {
|
||||
for (j = 0; j < n; j++) {
|
||||
fadd(x[i], x[j]);
|
||||
fsub(x[i], x[j]);
|
||||
fmul(x[i], x[j]);
|
||||
fdiv(x[i], x[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check infinities and zeroes:
|
||||
{
|
||||
long double x[6];
|
||||
int i, j, n = 0;
|
||||
x[n++] = make(1, 32000, 0x62acda85f700, 0x47b6c9f35edc4044);
|
||||
x[n++] = make(0, 32001, 0x94b7abf55af7, 0x9f425fe354428e19);
|
||||
x[n++] = make(0, 32767, 0, 0);
|
||||
x[n++] = make(1, 32767, 0, 0);
|
||||
x[n++] = make(0, 0, 0, 0);
|
||||
x[n++] = make(1, 0, 0, 0);
|
||||
check(n == sizeof(x) / sizeof(*x));
|
||||
for (i = 0; i < n; i++) {
|
||||
for (j = 0; j < n; j++) {
|
||||
fadd(x[i], x[j]);
|
||||
fsub(x[i], x[j]);
|
||||
fmul(x[i], x[j]);
|
||||
fdiv(x[i], x[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void adds(void)
|
||||
{
|
||||
// Check shifting and add/sub:
|
||||
{
|
||||
int i;
|
||||
for (i = -130; i <= 130; i++) {
|
||||
int s1 = (uint32_t)i % 3 < 1;
|
||||
int s2 = (uint32_t)i % 5 < 2;
|
||||
fadd(make(s1, 16384 , 0x502c065e4f71a65d, 0xd2f9bdb031f4f031),
|
||||
make(s2, 16384 + i, 0xae267395a9bc1033, 0xb56b5800da1ba448));
|
||||
}
|
||||
}
|
||||
|
||||
// Check normalisation:
|
||||
{
|
||||
uint64_t a0 = 0xc6bab0a6afbef5ed;
|
||||
uint64_t a1 = 0x4f84136c4a2e9b52;
|
||||
int ee[] = { 0, 1, 10000 };
|
||||
int e, i;
|
||||
for (e = 0; e < sizeof(ee) / sizeof(*ee); e++) {
|
||||
int exp = ee[e];
|
||||
fsub(make(0, exp, a1, a0), make(0, 0, 0, 0));
|
||||
for (i = 63; i >= 0; i--)
|
||||
fsub(make(0, exp, a1 | (uint64_t)1 << i >> 1, a0),
|
||||
make(0, exp, a1 >> i << i, 0));
|
||||
for (i = 63; i >=0; i--)
|
||||
fsub(make(0, exp, a1, a0 | (uint64_t)1 << i >> 1),
|
||||
make(0, exp, a1, a0 >> i << i));
|
||||
}
|
||||
}
|
||||
|
||||
// Carry/overflow from rounding:
|
||||
{
|
||||
fadd(make(0, 114, -1, -1), make(0, 1, 0, 0));
|
||||
fadd(make(0, 32766, -1, -1), make(0, 32653, 0, 0));
|
||||
fsub(make(1, 32766, -1, -1), make(0, 32653, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
void muls(void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
{
|
||||
long double max = make(0, 32766, -1, -1);
|
||||
long double min = make(0, 0, 0, 1);
|
||||
fmul(max, max);
|
||||
fmul(max, min);
|
||||
fmul(min, min);
|
||||
}
|
||||
|
||||
for (i = 117; i > 0; i--)
|
||||
fmul(make(0, 16268, 0x643dcea76edc, 0xe0877a598403627a),
|
||||
make(i & 1, i, 0, 0));
|
||||
|
||||
fmul(make(0, 16383, -1, -3), make(0, 16383, 0, 1));
|
||||
// Round to next exponent:
|
||||
fmul(make(0, 16383, -1, -2), make(0, 16383, 0, 1));
|
||||
// Round from subnormal to normal:
|
||||
fmul(make(0, 1, -1, -1), make(0, 16382, 0, 0));
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
for (j = 0; j < 112; j++)
|
||||
fmul(make(0, 16383, (uint64_t)1 << i, 0),
|
||||
make(0, 16383,
|
||||
j < 64 ? 0 : (uint64_t)1 << (j - 64),
|
||||
j < 64 ? (uint64_t)1 << j : 0));
|
||||
}
|
||||
|
||||
void divs(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
{
|
||||
long double max = make(0, 32766, -1, -1);
|
||||
long double min = make(0, 0, 0, 1);
|
||||
fdiv(max, max);
|
||||
fdiv(max, min);
|
||||
fdiv(min, max);
|
||||
fdiv(min, min);
|
||||
}
|
||||
|
||||
for (i = 0; i < 64; i++)
|
||||
fdiv(make(0, 16383, -1, -1), make(0, 16383, -1, -(uint64_t)1 << i));
|
||||
for (i = 0; i < 48; i++)
|
||||
fdiv(make(0, 16383, -1, -1), make(0, 16383, -(uint64_t)1 << i, 0));
|
||||
}
|
||||
|
||||
void cvtlsw(int32_t a)
|
||||
{
|
||||
long double f = a;
|
||||
u128_t x = copy_ild(f);
|
||||
printf("cvtlsw %08lx %016llx%016llx\n", (long)(uint32_t)a, x.x1, x.x0);
|
||||
}
|
||||
|
||||
void cvtlsx(int64_t a)
|
||||
{
|
||||
long double f = a;
|
||||
u128_t x = copy_ild(f);
|
||||
printf("cvtlsx %016llx %016llx%016llx\n",
|
||||
(long long)(uint64_t)a, x.x1, x.x0);
|
||||
}
|
||||
|
||||
void cvtluw(uint32_t a)
|
||||
{
|
||||
long double f = a;
|
||||
u128_t x = copy_ild(f);
|
||||
printf("cvtluw %08lx %016llx%016llx\n", (long)a, x.x1, x.x0);
|
||||
}
|
||||
|
||||
void cvtlux(uint64_t a)
|
||||
{
|
||||
long double f = a;
|
||||
u128_t x = copy_ild(f);
|
||||
printf("cvtlux %016llx %016llx%016llx\n", (long long)a, x.x1, x.x0);
|
||||
}
|
||||
|
||||
void cvtil(long double a)
|
||||
{
|
||||
u128_t x = copy_ild(a);
|
||||
int32_t b1 = a;
|
||||
int64_t b2 = a;
|
||||
uint32_t b3 = a;
|
||||
uint64_t b4 = a;
|
||||
printf("cvtswl %016llx%016llx %08lx\n",
|
||||
x.x1, x.x0, (long)(uint32_t)b1);
|
||||
printf("cvtsxl %016llx%016llx %016llx\n",
|
||||
x.x1, x.x0, (long long)(uint64_t)b2);
|
||||
printf("cvtuwl %016llx%016llx %08lx\n",
|
||||
x.x1, x.x0, (long)b3);
|
||||
printf("cvtuxl %016llx%016llx %016llx\n",
|
||||
x.x1, x.x0, (long long)b4);
|
||||
}
|
||||
|
||||
void cvtlf(float a)
|
||||
{
|
||||
uint32_t ax = copy_if(a);
|
||||
long double b = a;
|
||||
u128_t bx = copy_ild(b);
|
||||
printf("cvtlf %08lx %016llx%016llx\n", (long)ax, bx.x1, bx.x0);
|
||||
}
|
||||
|
||||
void cvtld(double a)
|
||||
{
|
||||
uint64_t ax = copy_id(a);
|
||||
long double b = a;
|
||||
u128_t bx = copy_ild(b);
|
||||
printf("cvtld %016llx %016llx%016llx\n", (long long)ax, bx.x1, bx.x0);
|
||||
}
|
||||
|
||||
void cvtfl(long double a)
|
||||
{
|
||||
u128_t ax = copy_ild(a);
|
||||
float b = a;
|
||||
uint32_t bx = copy_if(b);
|
||||
printf("cvtfl %016llx%016llx %08lx\n", ax.x1, ax.x0, (long)bx);
|
||||
}
|
||||
|
||||
void cvtdl(long double a)
|
||||
{
|
||||
u128_t ax = copy_ild(a);
|
||||
double b = a;
|
||||
uint64_t bx = copy_id(b);
|
||||
printf("cvtdl %016llx%016llx %016llx\n", ax.x1, ax.x0, (long long)bx);
|
||||
}
|
||||
|
||||
void cvts(void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
{
|
||||
uint32_t x = 0xad040c5b;
|
||||
cvtlsw(0);
|
||||
for (i = 0; i < 31; i++)
|
||||
cvtlsw(x >> (31 - i));
|
||||
for (i = 0; i < 31; i++)
|
||||
cvtlsw(-(x >> (31 - i)));
|
||||
cvtlsw(0x80000000);
|
||||
}
|
||||
{
|
||||
uint64_t x = 0xb630a248cad9afd2;
|
||||
cvtlsx(0);
|
||||
for (i = 0; i < 63; i++)
|
||||
cvtlsx(x >> (63 - i));
|
||||
for (i = 0; i < 63; i++)
|
||||
cvtlsx(-(x >> (63 - i)));
|
||||
cvtlsx(0x8000000000000000);
|
||||
}
|
||||
{
|
||||
uint32_t x = 0xad040c5b;
|
||||
cvtluw(0);
|
||||
for (i = 0; i < 32; i++)
|
||||
cvtluw(x >> (31 - i));
|
||||
}
|
||||
{
|
||||
uint64_t x = 0xb630a248cad9afd2;
|
||||
cvtlux(0);
|
||||
for (i = 0; i < 64; i++)
|
||||
cvtlux(x >> (63 - i));
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
cvtil(make(i, 32767, 0, 1));
|
||||
cvtil(make(i, 32767, (uint64_t)1 << 47, 0));
|
||||
cvtil(make(i, 32767, 123, 456));
|
||||
cvtil(make(i, 32767, 0, 0));
|
||||
cvtil(make(i, 16382, -1, -1));
|
||||
cvtil(make(i, 16383, -1, -1));
|
||||
cvtil(make(i, 16384, 0x7fffffffffff, -1));
|
||||
cvtil(make(i, 16384, 0x800000000000, 0));
|
||||
for (j = 0; j < 68; j++)
|
||||
cvtil(make(i, 16381 + j, 0xd4822c0a10ec, 0x1fe2f8b2669f5c9d));
|
||||
}
|
||||
|
||||
cvtlf(copy_fi(0x00000000));
|
||||
cvtlf(copy_fi(0x456789ab));
|
||||
cvtlf(copy_fi(0x7f800000));
|
||||
cvtlf(copy_fi(0x7f923456));
|
||||
cvtlf(copy_fi(0x7fdbcdef));
|
||||
cvtlf(copy_fi(0x80000000));
|
||||
cvtlf(copy_fi(0xabcdef12));
|
||||
cvtlf(copy_fi(0xff800000));
|
||||
cvtlf(copy_fi(0xff923456));
|
||||
cvtlf(copy_fi(0xffdbcdef));
|
||||
|
||||
cvtld(copy_di(0x0000000000000000));
|
||||
cvtld(copy_di(0x456789abcdef0123));
|
||||
cvtld(copy_di(0x7ff0000000000000));
|
||||
cvtld(copy_di(0x7ff123456789abcd));
|
||||
cvtld(copy_di(0x7ffabcdef1234567));
|
||||
cvtld(copy_di(0x8000000000000000));
|
||||
cvtld(copy_di(0xcdef123456789abc));
|
||||
cvtld(copy_di(0xfff0000000000000));
|
||||
cvtld(copy_di(0xfff123456789abcd));
|
||||
cvtld(copy_di(0xfffabcdef1234567));
|
||||
|
||||
for (i = 0; i < 2; i++) { \
|
||||
cvtfl(make(i, 0, 0, 0));
|
||||
cvtfl(make(i, 16232, -1, -1));
|
||||
cvtfl(make(i, 16233, 0, 0));
|
||||
cvtfl(make(i, 16233, 0, 1));
|
||||
cvtfl(make(i, 16383, 0xab0ffd000000, 0));
|
||||
cvtfl(make(i, 16383, 0xab0ffd000001, 0));
|
||||
cvtfl(make(i, 16383, 0xab0ffeffffff, 0));
|
||||
cvtfl(make(i, 16383, 0xab0fff000000, 0));
|
||||
cvtfl(make(i, 16383, 0xab0fff000001, 0));
|
||||
cvtfl(make(i, 16510, 0xfffffeffffff, -1));
|
||||
cvtfl(make(i, 16510, 0xffffff000000, 0));
|
||||
cvtfl(make(i, 16511, 0, 0));
|
||||
cvtfl(make(i, 32767, 0, 0));
|
||||
cvtfl(make(i, 32767, 0, 1));
|
||||
cvtfl(make(i, 32767, 0x4cbe01ac5f40, 0x75cee3c6afbb00b5));
|
||||
cvtfl(make(i, 32767, 0x800000000000, 1));
|
||||
cvtfl(make(i, 32767, 0xa11caaaf6a52, 0x696033e871eab099));
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
cvtdl(make(i, 0, 0, 0));
|
||||
cvtdl(make(i, 15307, -1, -1));
|
||||
cvtdl(make(i, 15308, 0, 0));
|
||||
cvtdl(make(i, 15308, 0, 1));
|
||||
cvtdl(make(i, 16383, 0xabc123abc0ff, 0xe800000000000000));
|
||||
cvtdl(make(i, 16383, 0xabc123abc0ff, 0xe800000000000001));
|
||||
cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf7ffffffffffffff));
|
||||
cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf800000000000000));
|
||||
cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf800000000000001));
|
||||
cvtdl(make(i, 17406, 0xffffffffffff, 0xf7ffffffffffffff));
|
||||
cvtdl(make(i, 17406, 0xffffffffffff, 0xf800000000000000));
|
||||
cvtdl(make(i, 17407, 0, 0));
|
||||
cvtdl(make(i, 32767, 0, 0));
|
||||
cvtdl(make(i, 32767, 0, 1));
|
||||
cvtdl(make(i, 32767, 0x4cbe01ac5f40, 0x75cee3c6afbb00b5));
|
||||
cvtdl(make(i, 32767, 0x800000000000, 1));
|
||||
cvtdl(make(i, 32767, 0xa11caaaf6a52, 0x696033e871eab099));
|
||||
}
|
||||
}
|
||||
|
||||
void tests(void)
|
||||
{
|
||||
cmps();
|
||||
nanz();
|
||||
adds();
|
||||
muls();
|
||||
divs();
|
||||
cvts();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
#ifdef __aarch64__
|
||||
tests();
|
||||
#else
|
||||
printf("This test program is intended for a little-endian architecture\n"
|
||||
"with an IEEE-standard 128-bit long double.\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@ -6,7 +6,7 @@ struct fred
|
||||
int natasha;
|
||||
};
|
||||
|
||||
void main()
|
||||
int main()
|
||||
{
|
||||
struct fred bloggs;
|
||||
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
#define _ISOC99_SOURCE 1
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user