diff options
Diffstat (limited to 'tinycc')
70 files changed, 0 insertions, 57098 deletions
diff --git a/tinycc/.gitignore b/tinycc/.gitignore deleted file mode 100644 index 3bff153..0000000 --- a/tinycc/.gitignore +++ /dev/null @@ -1,64 +0,0 @@ -*~ -\#* -.#* -*.o -*.a -*.exe -*.dll -*.obj -*.pdb -*.lib -*.exp -*.log -*.bz2 -*.zip -.gdb_history -a.out -tcc_g -tcc -*-tcc -libtcc*.def - -config*.h -*_.h -config*.mak -config.texi -conftest* -c2str -tags -TAGS -tcc.1 -*.pod -tcc-doc.html -tcc-doc.info - -win32/doc -win32/examples/libtcc_test.c -win32/libtcc -win32/lib/32 -win32/lib/64 -win32/include/float.h -win32/include/stdalign.h -win32/include/stdarg.h -win32/include/stdbool.h -win32/include/stddef.h -win32/include/stdnoreturn.h -win32/include/varargs.h -win32/include/tcclib.h - -tests/tcctest[1234] -tests/tcctest.gcc -tests/*.out* -tests/*.ref -tests/*.txt -tests/*.gcc -tests/*-cc* -tests/*-tcc* -tests/libtcc_test -tests/libtcc_test_mt -tests/asm-c-connect -tests/asm-c-connect-sep -tests/vla_test -tests/hello -tests/tests2/fred.txt -libtcc.dylib diff --git a/tinycc/COPYING b/tinycc/COPYING deleted file mode 100644 index 223ede7..0000000 --- a/tinycc/COPYING +++ /dev/null @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - <one line to give the library's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - 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 - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - <signature of Ty Coon>, 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/tinycc/Changelog b/tinycc/Changelog deleted file mode 100644 index 342484c..0000000 --- a/tinycc/Changelog +++ /dev/null @@ -1,456 +0,0 @@ -version 0.9.28: - -User interface: -- new tcc -ar x and t flags (herman ten brugge) - -Platforms: -- new RISC-V (riscv64) target -- native macOS support for x86_64/arm64 (Herman ten Brugge) - -Features: -- Improved support for C11 -- C11 _Static_assert support (matthias) - -Fixes: -- fix preprocessor line (#line) directive (Herman ten Brugge) -Many more! see also git shortlog release_0_9_27...HEAD - -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 LIBRARY_PATH environment variables support - (Andrew Aladjev, Urs Janssen) - -Platforms: -- 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) -- Bootstrap native Windows 32/64 compiler using Cygwin+gcc (Christian Jullien) - -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) -- UTF8 in string literals supported (Zdenek Pavlas) -_ _Generic(...) supported (Matthias Gatto) - -Licensing: -- TinyCC partly relicensed to MIT license (See RELICENSING file). - -version 0.9.26: - -User interface: -- -MD/-MF (automatically generate dependencies for make) -- -pthread option (same as -D_REENTRANT -lpthread) (Henry Kroll III) -- -m32/-m64 to re-exec cross compiler (Henry Kroll III) -- -Wl, Mimic all GNU -option forms supported by ld (Kirill Smelkov) -- new LIBTCCAPI tcc_set_options() (grischka) - -Platforms: -- Many improvements for x86-64 target (Shinichiro Hamaji, Michael Matz, grischka) -- x86-64 assembler (Frederic Feret) -- 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) -- Support Debian GNU/kFreeBSD kernels (Pierre Chifflier) -- Support GNU/Hurd kernels (Thomas Preud'homme) -- Support OSX (tcc -run only) (Milutin Jovanovic) -- Support multiarch configuration (Thomas Preud'homme) -- Support out-of-tree build (Akim Demaille) - -Features: -- C99 variable length arrays (Thomas Preud'homme & Joe Soroka) -- Asm labels for variables and functions (Thomas Preud'homme) -- STT_GNU_IFUNC (Indirect functions as externals) (Thomas Preud'homme) -- More tests (tests2) (Milutin Jovanovic) - -version 0.9.25: - -- first support for x86-64 target (Shinichiro Hamaji) -- 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 -- fix bitfields with non-int types and in unions -- improve ARM cross-compiling (Daniel Glöckner) -- link stabstr sections from multiple objects -- better (still limited) support for multiple TCCStates - -version 0.9.24: - -- added verbosity levels -v, -vv, -vvv -- Accept standard input as an inputstream (Hanzac Chen) -- Support c89 compilers other than gcc (Hanzac Chen) -- -soname linker option (Marc Andre Tanner) -- Just warn about unknown directives, ignore quotes in #error/#warning -- Define __STDC_VERSION__=199901L (477) -- Switch to newer tccpe.c (includes support for resources) -- Handle backslashes within #include/#error/#warning -- Import changesets (part 4) 428,457,460,467: defines for openbsd etc. -- Use _WIN32 for a windows hosted tcc and define it for the PE target, - otherwise define __unix / __linux (Detlef Riekenberg) -- Import changesets (part 3) 409,410: ARM EABI by Daniel Glöckner -- Some in-between fixes: - TCC -E no longer hangs with macro calls involving newlines. - (next_nomacro1 now advances the read-pointer with TOK_LINEFEED) - Global cast (int g_i = 1LL;) no longer crashes tcc. - (nocode_wanted is initially 1, and only 0 for gen_function) - On win32 now tcc.exe finds 'include' & 'lib' even if itself is in 'bin'. - (new function w32_tcc_lib_path removes 'bin' if detected) - Added quick build batch file for mingw (win32/build-tcc.bat) - Last added case label optimization (455) produced wrong code. Reverted. - -- Import more changesets from Rob Landley's fork (part 2): - 487: Handle long long constants in gen_opic() (Rob Landley) - 484: Handle parentheses within __attribute__((...)) (Rob Landley) - 480: Remove a goto in decl_initializer_alloc (Rob Landley) - 475: Fix dereferences in inline assembly output (Joshua Phillips) - 474: Cast ptrs to ints of different sizes correctly (Joshua Phillips) - 473: Fix size of structs with empty array member (Joshua Phillips) - 470: No warning for && and || with mixed pointers/integers (Rob Landley) - 469: Fix symbol visibility problems in the linker (Vincent Pit) - 468: Allow && and || involving pointer arguments (Rob Landley) - 455: Optimize case labels with no code in between (Zdenek Pavlas) - 450: Implement alloca for x86 (grischka) - 415: Parse unicode escape sequences (Axel Liljencrantz) - 407: Add a simple va_copy() in stdarg.h (Hasso Tepper) - 400: Allow typedef names as symbols (Dave Dodge) - -- Import some changesets from Rob Landley's fork (part 1): - 462: Use LGPL with bcheck.c and il-gen.c - 458: Fix global compound literals (in unary: case '&':) (Andrew Johnson) - 456: Use return code from tcc_output_file in main() (Michael Somos) - 442: Fix indirections with function pointers (***fn)() (grischka) - 441: Fix LL left shift in libtcc1.c:__shldi3 (grischka) - 440: Pass structures and function ptrs through ?: (grischka) - 439: Keep rvalue in bit assignment (bit2 = bit1 = x) (grischka) - 438: Degrade nonportable pointer assignment to warning (grischka) - 437: Call 'saveregs()' before jumping with logical and/or/not (grischka) - 435: Put local static variables into global memory (grischka) - 432/434: Cast double and ptr to bool (grischka) - 420: Zero pad x87 tenbyte long doubles (Felix Nawothnig) - 417: Make 'sizeof' unsigned (Rob Landley) - 397: Fix save_reg for longlongs (Daniel Glöckner) - 396: Fix "invalid relocation entry" problem on ubuntu - (Bernhard Fischer) - -- ignore AS_NEEDED ld command -- mark executable sections as executable when running in memory -- added support for win32 wchar_t (Filip Navara) -- segment override prefix support (Filip Navara) -- normalized slashes in paths (Filip Navara) -- windows style fastcall (Filip Navara) -- support for empty input register section in asm (Filip Navara) -- anonymous union/struct support (Filip Navara) -- fixed parsing of function parameters -- workaround for function pointers in conditional expressions (Dave Dodge) -- initial '-E' option support to use the C preprocessor alone -- discard type qualifiers when comparing function parameters (Dave Dodge) -- Bug fix: A long long value used as a test expression ignores the - upper 32 bits at runtime (Dave Dodge) -- fixed multiple concatenation of PPNUM tokens (initial patch by Dave Dodge) -- fixed multiple typedef specifiers handling -- fixed sign extension in some type conversions (Dave Dodge) - -version 0.9.23: - -- initial PE executable format for windows version (grischka) -- '#pragma pack' support (grischka) -- '#include_next' support (Bernhard Fischer) -- ignore '-pipe' option -- added -f[no-]leading-underscore -- preprocessor function macro parsing fix (grischka) - -version 0.9.22: - -- simple memory optimisations: kernel compilation is 30% faster -- linker symbol definitions fixes -- gcc 3.4 fixes -- fixed value stack full error -- 'packed' attribute support for variables and structure fields -- ignore 'const' and 'volatile' in function prototypes -- allow '_Bool' in bit fields - -version 0.9.21: - -- ARM target support (Daniel Glöckner) -- added '-funsigned-char, '-fsigned-char' and - '-Wimplicit-function-declaration' -- fixed assignment of const struct in struct -- line comment fix (reported by Bertram Felgenhauer) -- initial TMS320C67xx target support (TK) -- win32 configure -- regparm() attribute -- many built-in assembler fixes -- added '.org', '.fill' and '.previous' assembler directives -- '-fno-common' option -- '-Ttext' linker option -- section alignment fixes -- bit fields fixes -- do not generate code for unused inline functions -- '-oformat' linker option. -- added 'binary' output format. - -version 0.9.20: - -- added '-w' option -- added '.gnu.linkonce' ELF sections support -- fixed libc linking when running in memory (avoid 'stat' function - errors). -- extended '-run' option to be able to give several arguments to a C - script. - -version 0.9.19: - -- "alacarte" linking (Dave Long) -- simpler function call -- more strict type checks -- added 'const' and 'volatile' support and associated warnings -- added -Werror, -Wunsupported, -Wwrite-strings, -Wall. -- added __builtin_types_compatible_p() and __builtin_constant_p() -- chars support in assembler (Dave Long) -- .string, .globl, .section, .text, .data and .bss asm directive - support (Dave Long) -- man page generated from tcc-doc.texi -- fixed macro argument substitution -- fixed zero argument macro parsing -- changed license to LGPL -- added -rdynamic option support - -version 0.9.18: - -- header fix (time.h) -- fixed inline asm without operand case -- fixed 'default:' or 'case x:' with '}' after (incorrect C construct accepted - by gcc) -- added 'A' inline asm constraint. - -version 0.9.17: - -- PLT generation fix -- tcc doc fixes (Peter Lund) -- struct parse fix (signaled by Pedro A. Aranda Gutierrez) -- better _Bool lvalue support (signaled by Alex Measday) -- function parameters must be converted to pointers (signaled by Neil Brown) -- sanitized string and character constant parsing -- fixed comment parse (signaled by Damian M Gryski) -- fixed macro function bug (signaled by Philippe Ribet) -- added configure (initial patch by Mitchell N Charity) -- added '-run' and '-v' options (initial patch by vlindos) -- added real date report in __DATE__ and __TIME__ macros - -version 0.9.16: - -- added assembler language support -- added GCC inline asm() support -- fixed multiple variable definitions : uninitialized variables are - created as COMMON symbols. -- optimized macro processing -- added GCC statement expressions support -- added GCC local labels support -- fixed array declaration in old style function parameters -- support casts in static structure initializations -- added various __xxx[__] keywords for GCC compatibility -- ignore __extension__ GCC in an expression or in a type (still not perfect) -- added '? :' GCC extension support - -version 0.9.15: - -- compilation fixes for glibc 2.2, gcc 2.95.3 and gcc 3.2. -- FreeBSD compile fixes. Makefile patches still missing (Carl Drougge). -- fixed file type guessing if '.' is in the path. -- fixed tcc_compile_string() -- add a dummy page in ELF files to fix RX/RW accesses (pageexec at - freemail dot hu). - -version 0.9.14: - -- added #warning. error message if invalid preprocessing directive. -- added CType structure to ease typing (faster parse). -- suppressed secondary hash tables (faster parse). -- rewrote parser by optimizing common cases (faster parse). -- fixed signed long long comparisons. -- fixed 'int a(), b();' declaration case. -- fixed structure init without '{}'. -- correct alignment support in structures. -- empty structures support. -- gcc testsuite now supported. -- output only warning if implicit integer/pointer conversions. -- added static bitfield init. - -version 0.9.13: - -- correct preprocessing token pasting (## operator) in all cases (added - preprocessing number token). -- fixed long long register spill. -- fixed signed long long '>>'. -- removed memory leaks. -- better error handling : processing can continue on link errors. A - custom callback can be added to display error messages. Most - errors do not call exit() now. -- ignore -O, -W, -m and -f options -- added old style function declarations -- added GCC __alignof__ support. -- added GCC typeof support. -- added GCC computed gotos support. -- added stack backtrace in runtime error message. Improved runtime - error position display. - -version 0.9.12: - -- more fixes for || and && handling. -- improved '? :' type handling. -- fixed bound checking generation with structures -- force '#endif' to be in same file as matching '#if' -- #include file optimization with '#ifndef #endif' construct detection -- macro handling optimization -- added tcc_relocate() and tcc_get_symbol() in libtcc. - -version 0.9.11: - -- stdarg.h fix for double type (thanks to Philippe Ribet). -- correct white space characters and added MSDOS newline support. -- fixed invalid implicit function call type declaration. -- special macros such as __LINE__ are defined if tested with defined(). -- fixed '!' operator with relocated address. -- added symbol + offset relocation (fixes some static variable initializers) -- '-l' option can be specified anywhere. '-c' option yields default - output name. added '-r' option for relocatable output. -- fixed '\nnn' octal parsing. -- fixed local extern variables declarations. - -version 0.9.10: - -- fixed lvalue type when saved in local stack. -- fixed '#include' syntax when using macros. -- fixed '#line' bug. -- removed size limit on strings. Unified string constants handling - with variable declarations. -- added correct support for '\xX' in wchar_t strings. -- added support for bound checking in generated executables -- fixed -I include order. -- fixed incorrect function displayed in runtime error. - -version 0.9.9: - -- fixed preprocessor expression parsing for #if/#elif. -- relocated debug info (.stab section). -- relocated bounds info (.bounds section). -- fixed cast to char of char constants ('\377' is -1 instead of 255) -- fixed implicit cast for unary plus. -- strings and '__func__' have now 'char[]' type instead of 'char *' - (fixes sizeof() return value). -- added __start_xxx and __stop_xxx symbols in linker. -- better DLL creation support (option -shared begins to work). -- ELF sections and hash tables are resized dynamically. -- executables and DLLs are stripped by default. - -version 0.9.8: - -- First version of full ELF linking support (generate objects, static - executable, dynamic executable, dynamic libraries). Dynamic library - support is not finished (need PIC support in compiler and some - patches in symbol exporting). -- First version of ELF loader for object (.o) and archive (.a) files. -- Support of simple GNU ld scripts (GROUP and FILE commands) -- Separated runtime library and bound check code from TCC (smaller - compiler core). -- fixed register reload in float compare. -- fixed implicit char/short to int casting. -- allow array type for address of ('&') operator. -- fixed unused || or && result. -- added GCC style variadic macro support. -- optimized bound checking code for array access. -- tcc includes are now in $(prefix)/lib/tcc/include. -- more command line options - more consistent handling of multiple - input files. -- added tcc man page (thanks to Cyril Bouthors). -- uClibc Makefile update -- converted documentation to texinfo format. -- added developper's guide in documentation. - -version 0.9.7: - -- added library API for easy dynamic compilation (see libtcc.h - first - draft). -- fixed long long register spill bug. -- fixed '? :' register spill bug. - -version 0.9.6: - -- added floating point constant propagation (fixes negative floating - point constants bug). - -version 0.9.5: - - - uClibc patches (submitted by Alfonso Martone). - - error reporting fix - - added CONFIG_TCC_BCHECK to get smaller code if needed. - -version 0.9.4: - - - windows port (currently cannot use -g, -b and dll functions). - - faster and simpler I/O handling. - - '-D' option works in all cases. - - preprocessor fixes (#elif and empty macro args) - - floating point fixes - - first code for CIL generation (does not work yet) - -version 0.9.3: - - - better and smaller code generator. - - full ISOC99 64 bit 'long long' support. - - full 32 bit 'float', 64 bit 'double' and 96 bit 'long double' support. - - added '-U' option. - - added assembly sections support. - - even faster startup time by mmaping sections instead of mallocing them. - - added GNUC __attribute__ keyword support (currently supports - 'section' and 'aligned' attributes). - - added ELF file output (only usable for debugging now) - - added debug symbol generation (STAB format). - - added integrated runtime error analysis ('-g' option: print clear - run time error messages instead of "Segmentation fault"). - - added first version of tiny memory and bound checker ('-b' option). - -version 0.9.2: - - - even faster parsing. - - various syntax parsing fixes. - - fixed external relocation handling for variables or functions pointers. - - better function pointers type handling. - - can compile multiple files (-i option). - - ANSI C bit fields are supported. - - beginning of float/double/long double support. - - beginning of long long support. - -version 0.9.1: - - - full ISOC99 initializers handling. - - compound literals. - - structures handle in assignments and as function param or return value. - - wide chars and strings. - - macro bug fix - -version 0.9: - - initial version. diff --git a/tinycc/CodingStyle b/tinycc/CodingStyle deleted file mode 100644 index 93d1324..0000000 --- a/tinycc/CodingStyle +++ /dev/null @@ -1,71 +0,0 @@ - -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.) diff --git a/tinycc/README b/tinycc/README deleted file mode 100644 index 809dd8d..0000000 --- a/tinycc/README +++ /dev/null @@ -1,96 +0,0 @@ -Tiny C Compiler - C Scripting Everywhere - The Smallest ANSI C compiler ------------------------------------------------------------------------ - -Features: --------- - -- SMALL! You can compile and execute C code everywhere, for example on - rescue disks. - -- FAST! tcc generates optimized x86 code. No byte code - overhead. Compile, assemble and link about 7 times faster than 'gcc - -O0'. - -- UNLIMITED! Any C dynamic library can be used directly. TCC is - heading toward full ISOC99 compliance. TCC can of course compile - itself. - -- SAFE! tcc includes an optional memory and bound checker. Bound - checked code can be mixed freely with standard code. - -- Compile and execute C source directly. No linking or assembly - necessary. Full C preprocessor included. - -- C script supported : just add '#!/usr/local/bin/tcc -run' at the first - line of your C source, and execute it directly from the command - line. - -Documentation: -------------- - -1) Installation on a i386/x86_64/arm/aarch64/riscv64 - Linux/macOS/FreeBSD/NetBSD/OpenBSD hosts. - - ./configure - make - make test - make install - - Notes: For FreeBSD, NetBSD and OpenBSD, gmake should be used instead of make. - For Windows read tcc-win32.txt. - -makeinfo must be installed to compile the doc. By default, tcc is -installed in /usr/local/bin. ./configure --help shows configuration -options. - - -2) Introduction - -We assume here that you know ANSI C. Look at the example ex1.c to know -what the programs look like. - -The include file <tcclib.h> can be used if you want a small basic libc -include support (especially useful for floppy disks). Of course, you -can also use standard headers, although they are slower to compile. - -You can begin your C script with '#!/usr/local/bin/tcc -run' on the first -line and set its execute bits (chmod a+x your_script). Then, you can -launch the C code as a shell or perl script :-) The command line -arguments are put in 'argc' and 'argv' of the main functions, as in -ANSI C. - -3) Examples - -ex1.c: simplest example (hello world). Can also be launched directly -as a script: './ex1.c'. - -ex2.c: more complicated example: find a number with the four -operations given a list of numbers (benchmark). - -ex3.c: compute fibonacci numbers (benchmark). - -ex4.c: more complicated: X11 program. Very complicated test in fact -because standard headers are being used ! As for ex1.c, can also be launched -directly as a script: './ex4.c'. - -ex5.c: 'hello world' with standard glibc headers. - -tcc.c: TCC can of course compile itself. Used to check the code -generator. - -tcctest.c: auto test for TCC which tests many subtle possible bugs. Used -when doing 'make test'. - -4) Full Documentation - -Please read tcc-doc.html to have all the features of TCC. - -Additional information is available for the Windows port in tcc-win32.txt. - -License: -------- - -TCC is distributed under the GNU Lesser General Public License (see -COPYING file). - -Fabrice Bellard. diff --git a/tinycc/RELICENSING b/tinycc/RELICENSING deleted file mode 100644 index 6c69612..0000000 --- a/tinycc/RELICENSING +++ /dev/null @@ -1,63 +0,0 @@ - - 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 - Danny Milosavljevic YES arm-asm.c riscv64-asm.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 - Herman ten Brugge 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 - Tyge Løvset YES tgmath.h, Windows tcc_libm.h math.h - 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. diff --git a/tinycc/TODO b/tinycc/TODO deleted file mode 100644 index 9a38b6b..0000000 --- a/tinycc/TODO +++ /dev/null @@ -1,106 +0,0 @@ -TODO list: - -Releases: -- release tcc on a regular basis (which interval? 3 months?) - -Bugs: - -- i386 fastcall is mostly wrong -- FPU st(0) is left unclean (kwisatz haderach). Incompatible with - optimized gcc/msc code -- 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) -- handle '? x, y : z' in unsized variable initialization (',' is - considered incorrectly as separator in preparser) -- transform functions to function pointers in function parameters - (net/ipv4/ip_output.c) -- fix function pointer type display -- check section alignment in C -- fix invalid cast in comparison 'if (v == (int8_t)v)' -- finish varargs.h support (gcc 3.2 testsuite issue) -- fix static functions declared inside block -- fix multiple unions init -- 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 sort of work - works with musl libc - glibc requires libc.so even when statically linked (very bad, but not - up to tcc) - -Bound checking: - -- 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 - only for local arrays). -- bound checking and float/long long/struct copy code. bound - checking and symbol + offset optimization - -Missing features: - -- disable-asm and disable-bcheck options -- __builtin_expect() -- atexit (Nigel Horne) -- C99: add complex types (gcc 3.2 testsuite issue) -- postfix compound literals (see 20010124-1.c) -- interactive mode / integrated debugger - -Optimizations: - -- suppress specific anonymous symbol handling -- more parse optimizations (=even faster compilation) -- memory alloc optimizations (=even faster compilation) -- optimize VT_LOCAL + const -- better local variables handling (needed for other targets) - -Not critical: - -- C99: fix multiple compound literals inits in blocks (ISOC99 - normative example - only relevant when using gotos! -> must add - boolean variable to tell if compound literal was already - initialized). -- add PowerPC generator and improve codegen for RISC (need - to suppress VT_LOCAL and use a base register instead). -- fix preprocessor symbol redefinition -- 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): - -- bug with defines: - #define spin_lock(lock) do { } while (0) - #define wq_spin_lock spin_lock - #define TEST() wq_spin_lock(a) -- typedefs can be structure fields -- see bugfixes.diff + improvement.diff from Daniel Glockner -- long long constant evaluation -- add alloca() -- gcc '-E' option. -- #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. diff --git a/tinycc/USES b/tinycc/USES deleted file mode 100644 index 6d7a2d1..0000000 --- a/tinycc/USES +++ /dev/null @@ -1,20 +0,0 @@ -The following software are known to use or support tcc builds. -Feel free to complete this list (*). - -Name Short Description ----- ----------------- -bigz An infinite precision Z & Q library. -gawk GNU awk. -gmp Library for arbitrary precision arithmetic. -gnumake GNU makefile. -mpfr Multiple-precision floating-point library. -mpc Complex floating-point library with exact rounding. -mpv A free, open source, and cross-platform media player. -openlisp ISLISP ISO/IEC 13816 Lisp interpreter and compiler. -s-nail BSD Mail/POSIX mailx: send and receive Internet mail. -sqlite Embbedable SQL engine. -st Simple Terminal. -tcc Tiny CC which compiles itself. -zlib Lossless data-compression library. - -(*) This list is ordered by name. diff --git a/tinycc/VERSION b/tinycc/VERSION deleted file mode 100644 index 9a54223..0000000 --- a/tinycc/VERSION +++ /dev/null @@ -1 +0,0 @@ -0.9.27 diff --git a/tinycc/coff.h b/tinycc/coff.h deleted file mode 100644 index e8e6185..0000000 --- a/tinycc/coff.h +++ /dev/null @@ -1,446 +0,0 @@ -/**************************************************************************/ -/* COFF.H */ -/* COFF data structures and related definitions used by the linker */ -/**************************************************************************/ - -/*------------------------------------------------------------------------*/ -/* COFF FILE HEADER */ -/*------------------------------------------------------------------------*/ -struct filehdr { - unsigned short f_magic; /* magic number */ - unsigned short f_nscns; /* number of sections */ - long f_timdat; /* time & date stamp */ - long f_symptr; /* file pointer to symtab */ - long f_nsyms; /* number of symtab entries */ - unsigned short f_opthdr; /* sizeof(optional hdr) */ - unsigned short f_flags; /* flags */ - unsigned short f_TargetID; /* for C6x = 0x0099 */ - }; - -/*------------------------------------------------------------------------*/ -/* File header flags */ -/*------------------------------------------------------------------------*/ -#define F_RELFLG 0x01 /* relocation info stripped from file */ -#define F_EXEC 0x02 /* file is executable (no unresolved refs) */ -#define F_LNNO 0x04 /* line numbers stripped from file */ -#define F_LSYMS 0x08 /* local symbols stripped from file */ -#define F_GSP10 0x10 /* 34010 version */ -#define F_GSP20 0x20 /* 34020 version */ -#define F_SWABD 0x40 /* bytes swabbed (in names) */ -#define F_AR16WR 0x80 /* byte ordering of an AR16WR (PDP-11) */ -#define F_LITTLE 0x100 /* byte ordering of an AR32WR (vax) */ -#define F_BIG 0x200 /* byte ordering of an AR32W (3B, maxi) */ -#define F_PATCH 0x400 /* contains "patch" list in optional header */ -#define F_NODF 0x400 - -#define F_VERSION (F_GSP10 | F_GSP20) -#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 COFF_C67_MAGIC 0x00c2 - -/*------------------------------------------------------------------------*/ -/* Macros to recognize magic numbers */ -/*------------------------------------------------------------------------*/ -#define ISMAGIC(x) (((unsigned short)(x))==(unsigned short)magic) -#define ISARCHIVE(x) ((((unsigned short)(x))==(unsigned short)ARTYPE)) -#define BADMAGIC(x) (((unsigned short)(x) & 0x8080) && !ISMAGIC(x)) - - -/*------------------------------------------------------------------------*/ -/* OPTIONAL FILE HEADER */ -/*------------------------------------------------------------------------*/ -typedef struct aouthdr { - short magic; /* see magic.h */ - short vstamp; /* version stamp */ - long tsize; /* text size in bytes, padded to FW bdry*/ - long dsize; /* initialized data " " */ - long bsize; /* uninitialized data " " */ - long entrypt; /* entry pt. */ - long text_start; /* base of text used for this file */ - long data_start; /* base of data used for this file */ -} AOUTHDR; - -#define AOUTSZ sizeof(AOUTHDR) - -/*----------------------------------------------------------------------*/ -/* When a UNIX aout header is to be built in the optional header, */ -/* the following magic numbers can appear in that header: */ -/* */ -/* AOUT1MAGIC : default : readonly sharable text segment */ -/* AOUT2MAGIC: : writable text segment */ -/* PAGEMAGIC : : configured for paging */ -/*----------------------------------------------------------------------*/ -#define AOUT1MAGIC 0410 -#define AOUT2MAGIC 0407 -#define PAGEMAGIC 0413 - - -/*------------------------------------------------------------------------*/ -/* COMMON ARCHIVE FILE STRUCTURES */ -/* */ -/* ARCHIVE File Organization: */ -/* _______________________________________________ */ -/* |__________ARCHIVE_MAGIC_STRING_______________| */ -/* |__________ARCHIVE_FILE_MEMBER_1______________| */ -/* | | */ -/* | Archive File Header "ar_hdr" | */ -/* |.............................................| */ -/* | Member Contents | */ -/* | 1. External symbol directory | */ -/* | 2. Text file | */ -/* |_____________________________________________| */ -/* |________ARCHIVE_FILE_MEMBER_2________________| */ -/* | "ar_hdr" | */ -/* |.............................................| */ -/* | Member Contents (.o or text file) | */ -/* |_____________________________________________| */ -/* | . . . | */ -/* | . . . | */ -/* | . . . | */ -/* |_____________________________________________| */ -/* |________ARCHIVE_FILE_MEMBER_n________________| */ -/* | "ar_hdr" | */ -/* |.............................................| */ -/* | Member Contents | */ -/* |_____________________________________________| */ -/* */ -/*------------------------------------------------------------------------*/ - -#define COFF_ARMAG "!<arch>\n" -#define SARMAG 8 -#define ARFMAG "`\n" - -struct ar_hdr /* archive file member header - printable ascii */ -{ - char ar_name[16]; /* file member name - `/' terminated */ - char ar_date[12]; /* file member date - decimal */ - char ar_uid[6]; /* file member user id - decimal */ - char ar_gid[6]; /* file member group id - decimal */ - char ar_mode[8]; /* file member mode - octal */ - char ar_size[10]; /* file member size - decimal */ - char ar_fmag[2]; /* ARFMAG - string to end header */ -}; - - -/*------------------------------------------------------------------------*/ -/* SECTION HEADER */ -/*------------------------------------------------------------------------*/ -struct scnhdr { - char s_name[8]; /* section name */ - long s_paddr; /* physical address */ - long s_vaddr; /* virtual address */ - long s_size; /* section size */ - long s_scnptr; /* file ptr to raw data for section */ - long s_relptr; /* file ptr to relocation */ - long s_lnnoptr; /* file ptr to line numbers */ - unsigned int s_nreloc; /* number of relocation entries */ - unsigned int s_nlnno; /* number of line number entries */ - unsigned int s_flags; /* flags */ - unsigned short s_reserved; /* reserved byte */ - unsigned short s_page; /* memory page id */ - }; - -#define SCNHDR struct scnhdr -#define SCNHSZ sizeof(SCNHDR) - -/*------------------------------------------------------------------------*/ -/* Define constants for names of "special" sections */ -/*------------------------------------------------------------------------*/ -/* #define _TEXT ".text" */ -#define _DATA ".data" -#define _BSS ".bss" -#define _CINIT ".cinit" -#define _TV ".tv" - -/*------------------------------------------------------------------------*/ -/* The low 4 bits of s_flags is used as a section "type" */ -/*------------------------------------------------------------------------*/ -#define STYP_REG 0x00 /* "regular" : allocated, relocated, loaded */ -#define STYP_DSECT 0x01 /* "dummy" : not allocated, relocated, not loaded */ -#define STYP_NOLOAD 0x02 /* "noload" : allocated, relocated, not loaded */ -#define STYP_GROUP 0x04 /* "grouped" : formed of input sections */ -#define STYP_PAD 0x08 /* "padding" : not allocated, not relocated, loaded */ -#define STYP_COPY 0x10 /* "copy" : used for C init tables - - not allocated, relocated, - loaded; reloc & lineno - entries processed normally */ -#define STYP_TEXT 0x20 /* section contains text only */ -#define STYP_DATA 0x40 /* section contains data only */ -#define STYP_BSS 0x80 /* section contains bss only */ - -#define STYP_ALIGN 0x100 /* align flag passed by old version assemblers */ -#define ALIGN_MASK 0x0F00 /* part of s_flags that is used for align vals */ -#define ALIGNSIZE(x) (1 << ((x & ALIGN_MASK) >> 8)) - - -/*------------------------------------------------------------------------*/ -/* RELOCATION ENTRIES */ -/*------------------------------------------------------------------------*/ -struct reloc -{ - long r_vaddr; /* (virtual) address of reference */ - short r_symndx; /* index into symbol table */ - unsigned short r_disp; /* additional bits for address calculation */ - unsigned short r_type; /* relocation type */ -}; - -#define RELOC struct reloc -#define RELSZ 10 /* sizeof(RELOC) */ - -/*--------------------------------------------------------------------------*/ -/* define all relocation types */ -/*--------------------------------------------------------------------------*/ - -#define R_ABS 0 /* absolute address - no relocation */ -#define R_DIR16 01 /* UNUSED */ -#define R_REL16 02 /* UNUSED */ -#define R_DIR24 04 /* UNUSED */ -#define R_REL24 05 /* 24 bits, direct */ -#define R_DIR32 06 /* UNUSED */ -#define R_RELBYTE 017 /* 8 bits, direct */ -#define R_RELWORD 020 /* 16 bits, direct */ -#define R_RELLONG 021 /* 32 bits, direct */ -#define R_PCRBYTE 022 /* 8 bits, PC-relative */ -#define R_PCRWORD 023 /* 16 bits, PC-relative */ -#define R_PCRLONG 024 /* 32 bits, PC-relative */ -#define R_OCRLONG 030 /* GSP: 32 bits, one's complement direct */ -#define R_GSPPCR16 031 /* GSP: 16 bits, PC relative (in words) */ -#define R_GSPOPR32 032 /* GSP: 32 bits, direct big-endian */ -#define R_PARTLS16 040 /* Brahma: 16 bit offset of 24 bit address*/ -#define R_PARTMS8 041 /* Brahma: 8 bit page of 24 bit address */ -#define R_PARTLS7 050 /* DSP: 7 bit offset of 16 bit address */ -#define R_PARTMS9 051 /* DSP: 9 bit page of 16 bit address */ -#define R_REL13 052 /* DSP: 13 bits, direct */ - - -/*------------------------------------------------------------------------*/ -/* LINE NUMBER ENTRIES */ -/*------------------------------------------------------------------------*/ -struct lineno -{ - union - { - long l_symndx ; /* sym. table index of function name - iff l_lnno == 0 */ - long l_paddr ; /* (physical) address of line number */ - } l_addr ; - unsigned short l_lnno ; /* line number */ -}; - -#define LINENO struct lineno -#define LINESZ 6 /* sizeof(LINENO) */ - - -/*------------------------------------------------------------------------*/ -/* STORAGE CLASSES */ -/*------------------------------------------------------------------------*/ -#define C_EFCN -1 /* physical end of function */ -#define C_NULL 0 -#define C_AUTO 1 /* automatic variable */ -#define C_EXT 2 /* external symbol */ -#define C_STAT 3 /* static */ -#define C_REG 4 /* register variable */ -#define C_EXTDEF 5 /* external definition */ -#define C_LABEL 6 /* label */ -#define C_ULABEL 7 /* undefined label */ -#define C_MOS 8 /* member of structure */ -#define C_ARG 9 /* function argument */ -#define C_STRTAG 10 /* structure tag */ -#define C_MOU 11 /* member of union */ -#define C_UNTAG 12 /* union tag */ -#define C_TPDEF 13 /* type definition */ -#define C_USTATIC 14 /* undefined static */ -#define C_ENTAG 15 /* enumeration tag */ -#define C_MOE 16 /* member of enumeration */ -#define C_REGPARM 17 /* register parameter */ -#define C_FIELD 18 /* bit field */ - -#define C_BLOCK 100 /* ".bb" or ".eb" */ -#define C_FCN 101 /* ".bf" or ".ef" */ -#define C_EOS 102 /* end of structure */ -#define C_FILE 103 /* file name */ -#define C_LINE 104 /* dummy sclass for line number entry */ -#define C_ALIAS 105 /* duplicate tag */ -#define C_HIDDEN 106 /* special storage class for external */ - /* symbols in dmert public libraries */ - -/*------------------------------------------------------------------------*/ -/* SYMBOL TABLE ENTRIES */ -/*------------------------------------------------------------------------*/ - -#define SYMNMLEN 8 /* Number of characters in a symbol name */ -#define FILNMLEN 14 /* Number of characters in a file name */ -#define DIMNUM 4 /* Number of array dimensions in auxiliary entry */ - - -struct syment -{ - union - { - char _n_name[SYMNMLEN]; /* old COFF version */ - struct - { - long _n_zeroes; /* new == 0 */ - long _n_offset; /* offset into string table */ - } _n_n; - char *_n_nptr[2]; /* allows for overlaying */ - } _n; - long n_value; /* value of symbol */ - short n_scnum; /* section number */ - unsigned short n_type; /* type and derived type */ - char n_sclass; /* storage class */ - char n_numaux; /* number of aux. entries */ -}; - -#define n_name _n._n_name -#define n_nptr _n._n_nptr[1] -#define n_zeroes _n._n_n._n_zeroes -#define n_offset _n._n_n._n_offset - -/*------------------------------------------------------------------------*/ -/* Relocatable symbols have a section number of the */ -/* section in which they are defined. Otherwise, section */ -/* numbers have the following meanings: */ -/*------------------------------------------------------------------------*/ -#define N_UNDEF 0 /* undefined symbol */ -#define N_ABS -1 /* value of symbol is absolute */ -#define N_DEBUG -2 /* special debugging symbol */ -#define N_TV (unsigned short)-3 /* needs transfer vector (preload) */ -#define P_TV (unsigned short)-4 /* needs transfer vector (postload) */ - - -/*------------------------------------------------------------------------*/ -/* The fundamental type of a symbol packed into the low */ -/* 4 bits of the word. */ -/*------------------------------------------------------------------------*/ -#define _EF ".ef" - -#define T_NULL 0 /* no type info */ -#define T_ARG 1 /* function argument (only used by compiler) */ -#define T_CHAR 2 /* character */ -#define T_SHORT 3 /* short integer */ -#define T_INT 4 /* integer */ -#define T_LONG 5 /* long integer */ -#define T_FLOAT 6 /* floating point */ -#define T_DOUBLE 7 /* double word */ -#define T_STRUCT 8 /* structure */ -#define T_UNION 9 /* union */ -#define T_ENUM 10 /* enumeration */ -#define T_MOE 11 /* member of enumeration */ -#define T_UCHAR 12 /* unsigned character */ -#define T_USHORT 13 /* unsigned short */ -#define T_UINT 14 /* unsigned integer */ -#define T_ULONG 15 /* unsigned long */ - -/*------------------------------------------------------------------------*/ -/* derived types are: */ -/*------------------------------------------------------------------------*/ -#define DT_NON 0 /* no derived type */ -#define DT_PTR 1 /* pointer */ -#define DT_FCN 2 /* function */ -#define DT_ARY 3 /* array */ - -#define MKTYPE(basic, d1,d2,d3,d4,d5,d6) \ - ((basic) | ((d1) << 4) | ((d2) << 6) | ((d3) << 8) |\ - ((d4) << 10) | ((d5) << 12) | ((d6) << 14)) - -/*------------------------------------------------------------------------*/ -/* type packing constants and macros */ -/*------------------------------------------------------------------------*/ -#define N_BTMASK_COFF 017 -#define N_TMASK_COFF 060 -#define N_TMASK1_COFF 0300 -#define N_TMASK2_COFF 0360 -#define N_BTSHFT_COFF 4 -#define N_TSHIFT_COFF 2 - -#define BTYPE_COFF(x) ((x) & N_BTMASK_COFF) -#define ISINT(x) (((x) >= T_CHAR && (x) <= T_LONG) || \ - ((x) >= T_UCHAR && (x) <= T_ULONG) || (x) == T_ENUM) -#define ISFLT_COFF(x) ((x) == T_DOUBLE || (x) == T_FLOAT) -#define ISPTR_COFF(x) (((x) & N_TMASK_COFF) == (DT_PTR << N_BTSHFT_COFF)) -#define ISFCN_COFF(x) (((x) & N_TMASK_COFF) == (DT_FCN << N_BTSHFT_COFF)) -#define ISARY_COFF(x) (((x) & N_TMASK_COFF) == (DT_ARY << N_BTSHFT_COFF)) -#define ISTAG_COFF(x) ((x)==C_STRTAG || (x)==C_UNTAG || (x)==C_ENTAG) - -#define INCREF_COFF(x) ((((x)&~N_BTMASK_COFF)<<N_TSHIFT_COFF)|(DT_PTR<<N_BTSHFT_COFF)|(x&N_BTMASK_COFF)) -#define DECREF_COFF(x) ((((x)>>N_TSHIFT_COFF)&~N_BTMASK_COFF)|((x)&N_BTMASK_COFF)) - - -/*------------------------------------------------------------------------*/ -/* AUXILIARY SYMBOL ENTRY */ -/*------------------------------------------------------------------------*/ -union auxent -{ - struct - { - long x_tagndx; /* str, un, or enum tag indx */ - union - { - struct - { - unsigned short x_lnno; /* declaration line number */ - unsigned short x_size; /* str, union, array size */ - } x_lnsz; - long x_fsize; /* size of function */ - } x_misc; - union - { - struct /* if ISFCN, tag, or .bb */ - { - long x_lnnoptr; /* ptr to fcn line # */ - long x_endndx; /* entry ndx past block end */ - } x_fcn; - struct /* if ISARY, up to 4 dimen. */ - { - unsigned short x_dimen[DIMNUM]; - } x_ary; - } x_fcnary; - unsigned short x_regcount; /* number of registers used by func */ - } x_sym; - struct - { - char x_fname[FILNMLEN]; - } x_file; - struct - { - long x_scnlen; /* section length */ - unsigned short x_nreloc; /* number of relocation entries */ - unsigned short x_nlinno; /* number of line numbers */ - } x_scn; -}; - -#define SYMENT struct syment -#define SYMESZ 18 /* sizeof(SYMENT) */ - -#define AUXENT union auxent -#define AUXESZ 18 /* sizeof(AUXENT) */ - -/*------------------------------------------------------------------------*/ -/* NAMES OF "SPECIAL" SYMBOLS */ -/*------------------------------------------------------------------------*/ -#define _STEXT ".text" -#define _ETEXT "etext" -#define _SDATA ".data" -#define _EDATA "edata" -#define _SBSS ".bss" -#define _END "end" -#define _CINITPTR "cinit" - -/*--------------------------------------------------------------------------*/ -/* ENTRY POINT SYMBOLS */ -/*--------------------------------------------------------------------------*/ -#define _START "_start" -#define _MAIN "_main" - /* _CSTART "_c_int00" (defined in params.h) */ - - -#define _TVORIG "_tvorig" -#define _TORIGIN "_torigin" -#define _DORIGIN "_dorigin" - -#define _SORIGIN "_sorigin" diff --git a/tinycc/configure b/tinycc/configure deleted file mode 100644 index 6ec98f3..0000000 --- a/tinycc/configure +++ /dev/null @@ -1,602 +0,0 @@ -#!/bin/sh -# -# tcc configure script (c) 2003 Fabrice Bellard - -# set temporary file name -# if test ! -z "$TMPDIR" ; then -# TMPDIR1="${TMPDIR}" -# elif test ! -z "$TEMPDIR" ; then -# TMPDIR1="${TEMPDIR}" -# else -# TMPDIR1="/tmp" -# fi -# -# bashism: TMPN="${TMPDIR1}/tcc-conf-${RANDOM}-$$-${RANDOM}.c" - -TMPN="./conftest-$$" -TMPH=$TMPN.h - -# default parameters -prefix="" -execprefix="" -bindir="" -libdir="" -tccdir="" -includedir="" -mandir="" -infodir="" -sysroot="" -cross_prefix="" -cc="gcc" -ar="ar" -bigendian="no" -mingw32="no" -LIBSUF=".a" -EXESUF="" -DLLSUF=".so" -tcc_usrinclude="" -tcc_sysincludepaths="" -tcc_libpaths="" -tcc_crtprefix="" -tcc_elfinterp="" -triplet= -tcc_lddir= -confvars= -suggest="yes" -gcc_major=0 -gcc_minor=0 -cc_name="gcc" -ar_set= -darwin= -cpuver= -dwarf= - -# use CC from environment when set -test -n "$CC" && cc="$CC" - -# OS specific -cpu=`uname -m` -cpu_sys="$cpu" -targetos=`uname` -if test "$targetos" = "Linux" ; then - test "$(uname -o)" = "Android" && targetos=Android -fi - -case $targetos in - Darwin) - darwin=yes - dwarf=4 - confvars="$confvars OSX" - cc=`command -v cc` - cc=`readlink $cc || echo clang` - tcc_usrinclude="`xcrun --show-sdk-path`/usr/include" - DLLSUF=".dylib" - case $* in *--config-new_macho*) ;; *) - # if new_macho was not specified and (known) ver <= 10, use old (=no) - osxver=$(sw_vers -productVersion 2>/dev/null) # X.Y.Z - osxver=${osxver%%.*} # major version (or empty on sw_vers error) - [ "${osxver:-11}" -ge 11 ] || confvars="$confvars new_macho=no" - esac - ;; - Windows_NT|MINGW*|MSYS*|CYGWIN*) - mingw32=yes - targetos=WIN32 - ;; - DragonFly|OpenBSD|FreeBSD|NetBSD) - confvars="$confvars BSD ldl=no" - ;; - Android) - confvars="$confvars Android pie new-dtags" - if test -n "$TERMUX_VERSION"; then - prefix="$PREFIX" # "/data/data/com.termux/files/usr" - sysroot="$PREFIX" - test "$cpu" = "aarch64" -o "$cpu" = "x86_64" && S="64" || S="" - tcc_sysincludepaths="{B}/include:{R}/include/\\\"CONFIG_TRIPLET\\\":{R}/include" - tcc_libpaths="{B}:{R}/lib:/system/lib${S}" - tcc_crtprefix="{R}/lib" - tcc_elfinterp="/system/bin/linker${S}" - use_triplet="yes" - tcc_switches="-Wl,-rpath=$sysroot/lib,-section-alignment=0x1000" - fi - ;; - *) - ;; -esac - -# find source path -source_path=${0%configure} -source_path=${source_path%/} -source_path_used="yes" -if test -z "$source_path" -o "$source_path" = "." ; then - source_path=`pwd` - source_path_used="no" -fi - -for opt do - eval opt=\"$opt\" - case "$opt" in - --prefix=*) prefix=`echo $opt | cut -d '=' -f 2-` - ;; - --exec-prefix=*) execprefix=`echo $opt | cut -d '=' -f 2-` - ;; - --tccdir=*) tccdir=`echo $opt | cut -d '=' -f 2-` - ;; - --bindir=*) bindir=`echo $opt | cut -d '=' -f 2-` - ;; - --libdir=*) libdir=`echo $opt | cut -d '=' -f 2-` - ;; - --includedir=*) includedir=`echo $opt | cut -d '=' -f 2-` - ;; - --sharedir=*) sharedir=`echo $opt | cut -d '=' -f 2-` - ;; - --mandir=*) mandir=`echo $opt | cut -d '=' -f 2-` - ;; - --infodir=*) infodir=`echo $opt | cut -d '=' -f 2-` - ;; - --docdir=*) docdir=`echo $opt | cut -d '=' -f 2-` - ;; - --sysroot=*) sysroot=`echo $opt | cut -d '=' -f 2-` - ;; - --source-path=*) source_path=`echo $opt | cut -d '=' -f 2-` - ;; - --cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2-` - ;; - --cc=*) cc=`echo $opt | cut -d '=' -f 2-` - ;; - --ar=*) ar=`echo $opt | cut -d '=' -f 2-` ; ar_set="yes" - ;; - --extra-cflags=*) CFLAGS="${opt#--extra-cflags=}" - ;; - --extra-ldflags=*) LDFLAGS="${opt#--extra-ldflags=}" - ;; - --extra-libs=*) extralibs="${opt#--extra-libs=}" - ;; - --sysincludepaths=*) tcc_sysincludepaths=`echo $opt | cut -d '=' -f 2-` - ;; - --libpaths=*) tcc_libpaths=`echo $opt | cut -d '=' -f 2-` - ;; - --crtprefix=*) tcc_crtprefix=`echo $opt | cut -d '=' -f 2-` - ;; - --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-` - ;; - --dwarf=*) dwarf=`echo $opt | cut -d '=' -f 2-` - ;; - --enable-cross) confvars="$confvars cross" - ;; - --disable-static) confvars="$confvars static=no" - ;; - --enable-static) confvars="$confvars static" - ;; - --disable-rpath) confvars="$confvars rpath=no" - ;; - --debug) confvars="$confvars debug" - ;; - --with-libgcc) confvars="$confvars libgcc" - ;; - --with-selinux) confvars="$confvars selinux" - ;; - --tcc-switches=*) tcc_switches=`echo $opt | cut -d '=' -f 2-` - ;; - --config-mingw32*) mingw32=$(echo "$opt=yes" | cut -d '=' -f 2) - ;; - --config-*) confvars="$confvars ${opt#--config-}"; suggest="no" - ;; - --help|-h) show_help="yes" - ;; - *) echo "configure: WARNING: unrecognized option $opt" - ;; - esac -done - -cc="${cross_prefix}${cc}" -ar="${cross_prefix}${ar}" - -# Checking for CFLAGS -test -z "$CFLAGS" && CFLAGS="-Wall -O2" - -# on OSX M1 with --cpu=x86_64, build a tcc to run under rosetta entirely -if test "$darwin" = "yes" -a "$cpu" = "x86_64" -a "$cpu_sys" = "arm64"; then - CFLAGS="$CFLAGS -arch $cpu" - LDFLAGS="$LDFLAGS -arch $cpu" -fi - -case "$cpu" in - x86|i386|i486|i586|i686|i86pc|BePC|i686-AT386) - cpu="i386" - ;; - x86_64|amd64|x86-64) - cpu="x86_64" - ;; - evbarm) - case "`uname -p`" in - aarch64|arm64) - cpu="arm64" - ;; - earmv*) - cpu="arm" - ;; - esac - ;; - aarch64|arm64|evbarm) - cpu="arm64" - ;; - arm*) - case "$cpu" in - arm|armv4l) - cpuver=4 - ;; - armv5tel|armv5tejl) - cpuver=5 - ;; - armv6j|armv6l) - cpuver=6 - ;; - armv7|armv7a|armv7l) - cpuver=7 - ;; - esac - cpu="arm" - ;; - alpha) - cpu="alpha" - ;; - "Power Macintosh"|ppc|ppc64) - cpu="ppc" - ;; - mips) - cpu="mips" - ;; - s390) - cpu="s390" - ;; - riscv64) - cpu="riscv64" - ;; - *) - echo "Unsupported CPU" - exit 1 - ;; -esac - -if test "$mingw32" = "yes" ; then - if test "$source_path_used" = "no"; then - source_path="." - fi - test -z "$prefix" && prefix="C:/Program Files/tcc" - test -z "$tccdir" && tccdir="${prefix}" && tccdir_auto="yes" - test -z "$bindir" && bindir="${tccdir}" - test -z "$docdir" && docdir="${tccdir}/doc" - test -z "$libdir" && libdir="${tccdir}/libtcc" - confvars="$confvars WIN32" - LIBSUF=".lib" - EXESUF=".exe" - DLLSUF=".dll" -else - if test -z "$prefix" ; then - prefix="/usr/local" - fi - if test -z "$sharedir" ; then - sharedir="${prefix}/share" - fi - if test x"$execprefix" = x""; then - execprefix="${prefix}" - fi - if test x"$libdir" = x""; then - libdir="${execprefix}/lib" - fi - if test x"$bindir" = x""; then - bindir="${execprefix}/bin" - fi - if test x"$docdir" = x""; then - docdir="${sharedir}/doc" - fi - if test x"$mandir" = x""; then - mandir="${sharedir}/man" - fi - if test x"$infodir" = x""; then - infodir="${sharedir}/info" - fi - if test x"$tccdir" = x""; then - tccdir="${libdir}/tcc" - fi - if test x"$includedir" = x""; then - includedir="${prefix}/include" - fi -fi # mingw32 - -if test x"$show_help" = "xyes" ; then -cat << EOF -Usage: configure [options] -Options: [defaults in brackets after descriptions] - -Standard options: - --help print this message - --prefix=PREFIX install in PREFIX [$prefix] - --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - [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] - --includedir=DIR C header files in DIR [PREFIX/include] - --sharedir=DIR documentation root DIR [PREFIX/share] - --docdir=DIR documentation in DIR [SHAREDIR/doc/tcc] - --mandir=DIR man documentation in DIR [SHAREDIR/man] - --infodir=DIR info documentation in DIR [SHAREDIR/info] - -Advanced options (experts only): - --source-path=PATH path of source code [$source_path] - --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix] - --sysroot=PREFIX prepend PREFIX to library/include paths [$sysroot] - --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 [$LDFLAGS] - --cpu=CPU CPU [$cpu] - - --debug include debug info with 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 libtcc.so - --with-libgcc use libgcc_s.so.1 instead of libtcc1.a - --with-selinux use mmap for executable memory (tcc -run) - --enable-cross build cross compilers (see also 'make help') - - --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 - --tcc-switches=... specify implicit switches passed to tcc - - --config-uClibc,-musl enable system specific configurations - --config-mingw32 build on windows using msys, busybox, etc. - --config-backtrace=no disable stack backtraces (with -run or -bt) - --config-bcheck=no disable bounds checker (-b) - --config-predefs=no do not compile tccdefs.h, instead just include - --config-new_macho=no|yes Force apple object format (autodetect osx <= 10) - --config-codesign Use codesign on apple to sign executables - --dwarf=x Use dwarf debug info instead of stabs (x=2..5) -EOF -exit 1 -fi - -if test -z "$cross_prefix" ; then - CONFTEST=./conftest$EXESUF - if ! $cc -o $CONFTEST $source_path/conftest.c ; then - echo "configure: error: '$cc' failed to compile conftest.c." - else - cc_name="$($CONFTEST compiler)" - gcc_major="$($CONFTEST version)" - gcc_minor="$($CONFTEST minor)" - bigendian="$($CONFTEST bigendian)" - _triplet="$($CONFTEST triplet)" - fi - if test "$mingw32" = "no" ; then - - if test -z "$triplet" -a -n "$_triplet"; then - if test -f "/usr/lib/$_triplet/crti.o" -o -n "$use_triplet" ; then - triplet="$_triplet" - fi - fi - - if test -z "$triplet"; then - if test $cpu = "x86_64" -o $cpu = "arm64" -o $cpu = "riscv64" ; then - if test -f "/usr/lib64/crti.o" ; then - tcc_lddir="lib64" - fi - fi - fi - - if test "$cpu" = "arm" ; then - if test "${triplet%eabihf}" != "$triplet" ; then - confvars="$confvars arm_eabihf arm_vfp" - elif test "${triplet%eabi}" != "$triplet" ; then - confvars="$confvars arm_eabi arm_vfp" - elif test "${_triplet%eabihf}" != "$_triplet" ; then - confvars="$confvars arm_eabihf arm_vfp" - elif test "${_triplet%eabi}" != "$_triplet" ; then - confvars="$confvars arm_eabi arm_vfp" - elif grep -s -q "^Features.* \(vfp\|iwmmxt\) " /proc/cpuinfo ; then - confvars="$confvars arm_vfp" - fi - fi - - if test "$suggest" = "yes"; then - if test -f "/lib/ld-uClibc.so.0" ; then - echo "Perhaps you want ./configure --config-uClibc" - fi - if test -f "/lib/ld-musl-$cpu.so.1"; then - echo "Perhaps you want ./configure --config-musl" - fi - fi - else # mingw32 = yes - if test "$cc_name" = "gcc"; then - # avoid mingw dependencies such as 'libgcc_s_dw2-1.dll' - test -z "$LDFLAGS" && LDFLAGS="-static" - fi - fi -else - # if cross compiling, cannot launch a program, so make a static guess - case $cpu in - ppc|mips|s390) bigendian=yes;; - esac -fi - -if test "$bigendian" = "yes" ; then - confvars="$confvars BIGENDIAN" -fi - -# a final configuration tuning -if test "$cc_name" != "tcc"; then - OPT1="-Wdeclaration-after-statement -fno-strict-aliasing" - # we want -Wno- but gcc does not always reject unknown -Wno- options - OPT2="-Wpointer-sign -Wsign-compare -Wunused-result -Wformat-truncation" - OPT2="$OPT2 -Wstringop-truncation" - if test "$cc_name" = "clang"; then - OPT1="$OPT1 -fheinous-gnu-extensions" - OPT2="$OPT2 -Wstring-plus-int" - fi - $cc $OPT1 $OPT2 -o a.out -c -xc - < /dev/null > cc_msg.txt 2>&1 - for o in $OPT1; do # enable these options - if ! grep -q -- $o cc_msg.txt; then CFLAGS="$CFLAGS $o"; fi - done - for o in $OPT2; do # disable these options - if ! grep -q -- $o cc_msg.txt; then CFLAGS="$CFLAGS -Wno-${o#-W*}"; fi - done - # cat cc_msg.txt - # echo $CFLAGS - rm -f cc_msg.txt a.out -else # cc is tcc - test "$ar_set" || ar="$cc -ar" -fi - -fcho() { if test -n "$2"; then echo "$1$2"; fi } - -fcho "Binary directory " "$bindir" -fcho "TinyCC directory " "$tccdir" -fcho "Library directory " "$libdir" -fcho "Include directory " "$includedir" -fcho "Manual directory " "$mandir" -fcho "Info directory " "$infodir" -fcho "Doc directory " "$docdir" -fcho "Target root prefix " "$sysroot" -fcho "/usr/include dir " "$tcc_usrinclude" -echo "Source path $source_path" -echo "C compiler $cc ($gcc_major.$gcc_minor)" -echo "Target OS $targetos" -echo "CPU $cpu" -fcho "Triplet " "$triplet" -fcho "Config " "${confvars# }" -echo "Creating config.mak and config.h" - -cat >config.mak <<EOF -# Automatically generated by configure - do not modify -prefix=$prefix -bindir=\$(DESTDIR)$bindir -tccdir=\$(DESTDIR)$tccdir -libdir=\$(DESTDIR)$libdir -includedir=\$(DESTDIR)$includedir -mandir=\$(DESTDIR)$mandir -infodir=\$(DESTDIR)$infodir -docdir=\$(DESTDIR)$docdir -CC=$cc -CC_NAME=$cc_name -GCC_MAJOR=$gcc_major -GCC_MINOR=$gcc_minor -AR=$ar -CFLAGS=$CFLAGS -LDFLAGS=$LDFLAGS -LIBSUF=$LIBSUF -EXESUF=$EXESUF -DLLSUF=$DLLSUF -EOF - -print_inc() { - local v="$2" - if test -n "$v"; then - test "$3" = "num" || v="\"$v\"" - echo "#ifndef $1" >> $TMPH - echo "# define $1 $v" >> $TMPH - echo "#endif" >> $TMPH - fi -} - -print_mak() { - local v="$2" - if test -n "$v"; then - test "$3" = "num" || v="\"\\\"$v\\\"\"" - echo "NATIVE_DEFINES+=-D$1=$v" >> config.mak - fi -} - -echo "/* Automatically generated by configure - do not modify */" > $TMPH - -print_inc CONFIG_SYSROOT "$sysroot" -test "$tccdir_auto" = "yes" || print_inc CONFIG_TCCDIR "$tccdir" -print_inc DWARF_VERSION "$dwarf" num -print_mak CONFIG_USR_INCLUDE "$tcc_usrinclude" -print_mak CONFIG_TCC_SYSINCLUDEPATHS "$tcc_sysincludepaths" -print_mak CONFIG_TCC_LIBPATHS "$tcc_libpaths" -print_mak CONFIG_TCC_CRTPREFIX "$tcc_crtprefix" -print_mak CONFIG_TCC_ELFINTERP "$tcc_elfinterp" -print_mak CONFIG_TCC_SWITCHES "$tcc_switches" -print_mak CONFIG_LDDIR "$tcc_lddir" -print_mak CONFIG_TRIPLET "$triplet" -print_mak TCC_CPU_VERSION "$cpuver" num - -echo "ARCH=$cpu" >> config.mak -echo "TARGETOS=$targetos" >> config.mak - -predefs="1" -for v in $confvars ; do - test "$v" = "predefs=no" && predefs="" - if test "${v%=*}" = "$v"; then - echo "CONFIG_$v=yes" >> config.mak - else - echo "CONFIG_$v" >> config.mak - fi -done -print_inc CONFIG_TCC_PREDEFS "$predefs" num - -version=`head $source_path/VERSION` -echo "VERSION = $version" >> config.mak -echo "#define TCC_VERSION \"$version\"" >> $TMPH -echo "@set VERSION $version" > config.texi - -if test "$source_path_used" = "yes" ; then - case $source_path in - /*) echo "TOPSRC=$source_path";; - *) echo "TOPSRC=\$(TOP)/$source_path";; - esac >>config.mak -else - echo 'TOPSRC=$(TOP)' >>config.mak -fi -cat >>$TMPH <<EOF -#define GCC_MAJOR $gcc_major -#define GCC_MINOR $gcc_minor -#define CC_NAME CC_${cc_name} -EOF - -diff $TMPH config.h >/dev/null 2>&1 -if test $? -ne 0 ; then - mv -f $TMPH config.h -else - echo "config.h is unchanged" -fi - -rm -f $TMPN* $CONFTEST - -# --------------------------------------------------------------------------- -# build tree in object directory if source path is different from current one - -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 - ;; - esac - - 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 tests/pp/Makefile" - for f in $FILES ; do - fn_makelink $source_path $f - done -fi - -# --------------------------------------------------------------------------- diff --git a/tinycc/dwarf.h b/tinycc/dwarf.h deleted file mode 100644 index c961bc3..0000000 --- a/tinycc/dwarf.h +++ /dev/null @@ -1,1046 +0,0 @@ -/* This file defines standard DWARF types, structures, and macros. - Copyright (C) 2000-2011, 2014, 2016, 2017, 2018 Red Hat, Inc. - This file is part of elfutils. - - This file is free software; you can redistribute it and/or modify - it under the terms of either - - * the GNU Lesser General Public License as published by the Free - Software Foundation; either version 3 of the License, or (at - your option) any later version - - or - - * 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 - - or both in parallel, as here. - - elfutils 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 copies of the GNU General Public License and - the GNU Lesser General Public License along with this program. If - not, see <http://www.gnu.org/licenses/>. */ - -#ifndef _DWARF_H -#define _DWARF_H 1 - -/* DWARF Unit Header Types. */ -enum - { - DW_UT_compile = 0x01, - DW_UT_type = 0x02, - DW_UT_partial = 0x03, - DW_UT_skeleton = 0x04, - DW_UT_split_compile = 0x05, - DW_UT_split_type = 0x06, - - DW_UT_lo_user = 0x80, - DW_UT_hi_user = 0xff - }; - -/* DWARF tags. */ -enum - { - DW_TAG_array_type = 0x01, - DW_TAG_class_type = 0x02, - DW_TAG_entry_point = 0x03, - DW_TAG_enumeration_type = 0x04, - DW_TAG_formal_parameter = 0x05, - /* 0x06 reserved. */ - /* 0x07 reserved. */ - DW_TAG_imported_declaration = 0x08, - /* 0x09 reserved. */ - DW_TAG_label = 0x0a, - DW_TAG_lexical_block = 0x0b, - /* 0x0c reserved. */ - DW_TAG_member = 0x0d, - /* 0x0e reserved. */ - DW_TAG_pointer_type = 0x0f, - DW_TAG_reference_type = 0x10, - DW_TAG_compile_unit = 0x11, - DW_TAG_string_type = 0x12, - DW_TAG_structure_type = 0x13, - /* 0x14 reserved. */ - DW_TAG_subroutine_type = 0x15, - DW_TAG_typedef = 0x16, - DW_TAG_union_type = 0x17, - DW_TAG_unspecified_parameters = 0x18, - DW_TAG_variant = 0x19, - DW_TAG_common_block = 0x1a, - DW_TAG_common_inclusion = 0x1b, - DW_TAG_inheritance = 0x1c, - DW_TAG_inlined_subroutine = 0x1d, - DW_TAG_module = 0x1e, - DW_TAG_ptr_to_member_type = 0x1f, - DW_TAG_set_type = 0x20, - DW_TAG_subrange_type = 0x21, - DW_TAG_with_stmt = 0x22, - DW_TAG_access_declaration = 0x23, - DW_TAG_base_type = 0x24, - DW_TAG_catch_block = 0x25, - DW_TAG_const_type = 0x26, - DW_TAG_constant = 0x27, - DW_TAG_enumerator = 0x28, - DW_TAG_file_type = 0x29, - DW_TAG_friend = 0x2a, - DW_TAG_namelist = 0x2b, - DW_TAG_namelist_item = 0x2c, - DW_TAG_packed_type = 0x2d, - DW_TAG_subprogram = 0x2e, - DW_TAG_template_type_parameter = 0x2f, - DW_TAG_template_value_parameter = 0x30, - DW_TAG_thrown_type = 0x31, - DW_TAG_try_block = 0x32, - DW_TAG_variant_part = 0x33, - DW_TAG_variable = 0x34, - DW_TAG_volatile_type = 0x35, - DW_TAG_dwarf_procedure = 0x36, - DW_TAG_restrict_type = 0x37, - DW_TAG_interface_type = 0x38, - DW_TAG_namespace = 0x39, - DW_TAG_imported_module = 0x3a, - DW_TAG_unspecified_type = 0x3b, - DW_TAG_partial_unit = 0x3c, - DW_TAG_imported_unit = 0x3d, - /* 0x3e reserved. Was DW_TAG_mutable_type. */ - DW_TAG_condition = 0x3f, - DW_TAG_shared_type = 0x40, - DW_TAG_type_unit = 0x41, - DW_TAG_rvalue_reference_type = 0x42, - DW_TAG_template_alias = 0x43, - DW_TAG_coarray_type = 0x44, - DW_TAG_generic_subrange = 0x45, - DW_TAG_dynamic_type = 0x46, - DW_TAG_atomic_type = 0x47, - DW_TAG_call_site = 0x48, - DW_TAG_call_site_parameter = 0x49, - DW_TAG_skeleton_unit = 0x4a, - DW_TAG_immutable_type = 0x4b, - - DW_TAG_lo_user = 0x4080, - - DW_TAG_MIPS_loop = 0x4081, - DW_TAG_format_label = 0x4101, - DW_TAG_function_template = 0x4102, - DW_TAG_class_template = 0x4103, - - DW_TAG_GNU_BINCL = 0x4104, - DW_TAG_GNU_EINCL = 0x4105, - - DW_TAG_GNU_template_template_param = 0x4106, - DW_TAG_GNU_template_parameter_pack = 0x4107, - DW_TAG_GNU_formal_parameter_pack = 0x4108, - DW_TAG_GNU_call_site = 0x4109, - DW_TAG_GNU_call_site_parameter = 0x410a, - - DW_TAG_hi_user = 0xffff - }; - - -/* Children determination encodings. */ -enum - { - DW_CHILDREN_no = 0, - DW_CHILDREN_yes = 1 - }; - - -/* DWARF attributes encodings. */ -enum - { - DW_AT_sibling = 0x01, - DW_AT_location = 0x02, - DW_AT_name = 0x03, - /* 0x04 reserved. */ - /* 0x05 reserved. */ - /* 0x06 reserved. */ - /* 0x07 reserved. */ - /* 0x08 reserved. */ - DW_AT_ordering = 0x09, - /* 0x0a reserved. */ - DW_AT_byte_size = 0x0b, - DW_AT_bit_offset = 0x0c, /* Deprecated in DWARF4. */ - DW_AT_bit_size = 0x0d, - /* 0x0e reserved. */ - /* 0x0f reserved. */ - DW_AT_stmt_list = 0x10, - DW_AT_low_pc = 0x11, - DW_AT_high_pc = 0x12, - DW_AT_language = 0x13, - /* 0x14 reserved. */ - DW_AT_discr = 0x15, - DW_AT_discr_value = 0x16, - DW_AT_visibility = 0x17, - DW_AT_import = 0x18, - DW_AT_string_length = 0x19, - DW_AT_common_reference = 0x1a, - DW_AT_comp_dir = 0x1b, - DW_AT_const_value = 0x1c, - DW_AT_containing_type = 0x1d, - DW_AT_default_value = 0x1e, - /* 0x1f reserved. */ - DW_AT_inline = 0x20, - DW_AT_is_optional = 0x21, - DW_AT_lower_bound = 0x22, - /* 0x23 reserved. */ - /* 0x24 reserved. */ - DW_AT_producer = 0x25, - /* 0x26 reserved. */ - DW_AT_prototyped = 0x27, - /* 0x28 reserved. */ - /* 0x29 reserved. */ - DW_AT_return_addr = 0x2a, - /* 0x2b reserved. */ - DW_AT_start_scope = 0x2c, - /* 0x2d reserved. */ - DW_AT_bit_stride = 0x2e, - DW_AT_upper_bound = 0x2f, - /* 0x30 reserved. */ - DW_AT_abstract_origin = 0x31, - DW_AT_accessibility = 0x32, - DW_AT_address_class = 0x33, - DW_AT_artificial = 0x34, - DW_AT_base_types = 0x35, - DW_AT_calling_convention = 0x36, - DW_AT_count = 0x37, - DW_AT_data_member_location = 0x38, - DW_AT_decl_column = 0x39, - DW_AT_decl_file = 0x3a, - DW_AT_decl_line = 0x3b, - DW_AT_declaration = 0x3c, - DW_AT_discr_list = 0x3d, - DW_AT_encoding = 0x3e, - DW_AT_external = 0x3f, - DW_AT_frame_base = 0x40, - DW_AT_friend = 0x41, - DW_AT_identifier_case = 0x42, - DW_AT_macro_info = 0x43, /* Deprecated in DWARF5. */ - DW_AT_namelist_item = 0x44, - DW_AT_priority = 0x45, - DW_AT_segment = 0x46, - DW_AT_specification = 0x47, - DW_AT_static_link = 0x48, - DW_AT_type = 0x49, - DW_AT_use_location = 0x4a, - DW_AT_variable_parameter = 0x4b, - DW_AT_virtuality = 0x4c, - DW_AT_vtable_elem_location = 0x4d, - DW_AT_allocated = 0x4e, - DW_AT_associated = 0x4f, - DW_AT_data_location = 0x50, - DW_AT_byte_stride = 0x51, - DW_AT_entry_pc = 0x52, - DW_AT_use_UTF8 = 0x53, - DW_AT_extension = 0x54, - DW_AT_ranges = 0x55, - DW_AT_trampoline = 0x56, - DW_AT_call_column = 0x57, - DW_AT_call_file = 0x58, - DW_AT_call_line = 0x59, - DW_AT_description = 0x5a, - DW_AT_binary_scale = 0x5b, - DW_AT_decimal_scale = 0x5c, - DW_AT_small = 0x5d, - DW_AT_decimal_sign = 0x5e, - DW_AT_digit_count = 0x5f, - DW_AT_picture_string = 0x60, - DW_AT_mutable = 0x61, - DW_AT_threads_scaled = 0x62, - DW_AT_explicit = 0x63, - DW_AT_object_pointer = 0x64, - DW_AT_endianity = 0x65, - DW_AT_elemental = 0x66, - DW_AT_pure = 0x67, - DW_AT_recursive = 0x68, - DW_AT_signature = 0x69, - DW_AT_main_subprogram = 0x6a, - DW_AT_data_bit_offset = 0x6b, - DW_AT_const_expr = 0x6c, - DW_AT_enum_class = 0x6d, - DW_AT_linkage_name = 0x6e, - DW_AT_string_length_bit_size = 0x6f, - DW_AT_string_length_byte_size = 0x70, - DW_AT_rank = 0x71, - DW_AT_str_offsets_base = 0x72, - DW_AT_addr_base = 0x73, - DW_AT_rnglists_base = 0x74, - /* 0x75 reserved. */ - DW_AT_dwo_name = 0x76, - DW_AT_reference = 0x77, - DW_AT_rvalue_reference = 0x78, - DW_AT_macros = 0x79, - DW_AT_call_all_calls = 0x7a, - DW_AT_call_all_source_calls = 0x7b, - DW_AT_call_all_tail_calls = 0x7c, - DW_AT_call_return_pc = 0x7d, - DW_AT_call_value = 0x7e, - DW_AT_call_origin = 0x7f, - DW_AT_call_parameter = 0x80, - DW_AT_call_pc = 0x81, - DW_AT_call_tail_call = 0x82, - DW_AT_call_target = 0x83, - DW_AT_call_target_clobbered = 0x84, - DW_AT_call_data_location = 0x85, - DW_AT_call_data_value = 0x86, - DW_AT_noreturn = 0x87, - DW_AT_alignment = 0x88, - DW_AT_export_symbols = 0x89, - DW_AT_deleted = 0x8a, - DW_AT_defaulted = 0x8b, - DW_AT_loclists_base = 0x8c, - - DW_AT_lo_user = 0x2000, - - DW_AT_MIPS_fde = 0x2001, - DW_AT_MIPS_loop_begin = 0x2002, - DW_AT_MIPS_tail_loop_begin = 0x2003, - DW_AT_MIPS_epilog_begin = 0x2004, - DW_AT_MIPS_loop_unroll_factor = 0x2005, - DW_AT_MIPS_software_pipeline_depth = 0x2006, - DW_AT_MIPS_linkage_name = 0x2007, - DW_AT_MIPS_stride = 0x2008, - DW_AT_MIPS_abstract_name = 0x2009, - DW_AT_MIPS_clone_origin = 0x200a, - DW_AT_MIPS_has_inlines = 0x200b, - DW_AT_MIPS_stride_byte = 0x200c, - DW_AT_MIPS_stride_elem = 0x200d, - DW_AT_MIPS_ptr_dopetype = 0x200e, - DW_AT_MIPS_allocatable_dopetype = 0x200f, - DW_AT_MIPS_assumed_shape_dopetype = 0x2010, - DW_AT_MIPS_assumed_size = 0x2011, - - /* GNU extensions. */ - DW_AT_sf_names = 0x2101, - DW_AT_src_info = 0x2102, - DW_AT_mac_info = 0x2103, - DW_AT_src_coords = 0x2104, - DW_AT_body_begin = 0x2105, - DW_AT_body_end = 0x2106, - DW_AT_GNU_vector = 0x2107, - DW_AT_GNU_guarded_by = 0x2108, - DW_AT_GNU_pt_guarded_by = 0x2109, - DW_AT_GNU_guarded = 0x210a, - DW_AT_GNU_pt_guarded = 0x210b, - DW_AT_GNU_locks_excluded = 0x210c, - DW_AT_GNU_exclusive_locks_required = 0x210d, - DW_AT_GNU_shared_locks_required = 0x210e, - DW_AT_GNU_odr_signature = 0x210f, - DW_AT_GNU_template_name = 0x2110, - DW_AT_GNU_call_site_value = 0x2111, - DW_AT_GNU_call_site_data_value = 0x2112, - DW_AT_GNU_call_site_target = 0x2113, - DW_AT_GNU_call_site_target_clobbered = 0x2114, - DW_AT_GNU_tail_call = 0x2115, - DW_AT_GNU_all_tail_call_sites = 0x2116, - DW_AT_GNU_all_call_sites = 0x2117, - DW_AT_GNU_all_source_call_sites = 0x2118, - DW_AT_GNU_locviews = 0x2137, - DW_AT_GNU_entry_view = 0x2138, - DW_AT_GNU_macros = 0x2119, - DW_AT_GNU_deleted = 0x211a, - /* GNU Debug Fission extensions. */ - DW_AT_GNU_dwo_name = 0x2130, - DW_AT_GNU_dwo_id = 0x2131, - DW_AT_GNU_ranges_base = 0x2132, - DW_AT_GNU_addr_base = 0x2133, - DW_AT_GNU_pubnames = 0x2134, - DW_AT_GNU_pubtypes = 0x2135, - - /* https://gcc.gnu.org/wiki/DW_AT_GNU_numerator_denominator */ - DW_AT_GNU_numerator = 0x2303, - DW_AT_GNU_denominator = 0x2304, - /* https://gcc.gnu.org/wiki/DW_AT_GNU_bias */ - DW_AT_GNU_bias = 0x2305, - - DW_AT_hi_user = 0x3fff - }; - -/* Old unofficially attribute names. Should not be used. - Will not appear in known-dwarf.h */ - -/* DWARF1 array subscripts and element data types. */ -#define DW_AT_subscr_data 0x0a -/* DWARF1 enumeration literals. */ -#define DW_AT_element_list 0x0f -/* DWARF1 reference for variable to member structure, class or union. */ -#define DW_AT_member 0x14 - -/* DWARF form encodings. */ -enum - { - DW_FORM_addr = 0x01, - DW_FORM_block2 = 0x03, - DW_FORM_block4 = 0x04, - DW_FORM_data2 = 0x05, - DW_FORM_data4 = 0x06, - DW_FORM_data8 = 0x07, - DW_FORM_string = 0x08, - DW_FORM_block = 0x09, - DW_FORM_block1 = 0x0a, - DW_FORM_data1 = 0x0b, - DW_FORM_flag = 0x0c, - DW_FORM_sdata = 0x0d, - DW_FORM_strp = 0x0e, - DW_FORM_udata = 0x0f, - DW_FORM_ref_addr = 0x10, - DW_FORM_ref1 = 0x11, - DW_FORM_ref2 = 0x12, - DW_FORM_ref4 = 0x13, - DW_FORM_ref8 = 0x14, - DW_FORM_ref_udata = 0x15, - DW_FORM_indirect = 0x16, - DW_FORM_sec_offset = 0x17, - DW_FORM_exprloc = 0x18, - DW_FORM_flag_present = 0x19, - DW_FORM_strx = 0x1a, - DW_FORM_addrx = 0x1b, - DW_FORM_ref_sup4 = 0x1c, - DW_FORM_strp_sup = 0x1d, - DW_FORM_data16 = 0x1e, - DW_FORM_line_strp = 0x1f, - DW_FORM_ref_sig8 = 0x20, - DW_FORM_implicit_const = 0x21, - DW_FORM_loclistx = 0x22, - DW_FORM_rnglistx = 0x23, - DW_FORM_ref_sup8 = 0x24, - DW_FORM_strx1 = 0x25, - DW_FORM_strx2 = 0x26, - DW_FORM_strx3 = 0x27, - DW_FORM_strx4 = 0x28, - DW_FORM_addrx1 = 0x29, - DW_FORM_addrx2 = 0x2a, - DW_FORM_addrx3 = 0x2b, - DW_FORM_addrx4 = 0x2c, - - /* GNU Debug Fission extensions. */ - DW_FORM_GNU_addr_index = 0x1f01, - DW_FORM_GNU_str_index = 0x1f02, - - DW_FORM_GNU_ref_alt = 0x1f20, /* offset in alternate .debuginfo. */ - DW_FORM_GNU_strp_alt = 0x1f21 /* offset in alternate .debug_str. */ - }; - - -/* DWARF location operation encodings. */ -enum - { - DW_OP_addr = 0x03, /* Constant address. */ - DW_OP_deref = 0x06, - DW_OP_const1u = 0x08, /* Unsigned 1-byte constant. */ - DW_OP_const1s = 0x09, /* Signed 1-byte constant. */ - DW_OP_const2u = 0x0a, /* Unsigned 2-byte constant. */ - DW_OP_const2s = 0x0b, /* Signed 2-byte constant. */ - DW_OP_const4u = 0x0c, /* Unsigned 4-byte constant. */ - DW_OP_const4s = 0x0d, /* Signed 4-byte constant. */ - DW_OP_const8u = 0x0e, /* Unsigned 8-byte constant. */ - DW_OP_const8s = 0x0f, /* Signed 8-byte constant. */ - DW_OP_constu = 0x10, /* Unsigned LEB128 constant. */ - DW_OP_consts = 0x11, /* Signed LEB128 constant. */ - DW_OP_dup = 0x12, - DW_OP_drop = 0x13, - DW_OP_over = 0x14, - DW_OP_pick = 0x15, /* 1-byte stack index. */ - DW_OP_swap = 0x16, - DW_OP_rot = 0x17, - DW_OP_xderef = 0x18, - DW_OP_abs = 0x19, - DW_OP_and = 0x1a, - DW_OP_div = 0x1b, - DW_OP_minus = 0x1c, - DW_OP_mod = 0x1d, - DW_OP_mul = 0x1e, - DW_OP_neg = 0x1f, - DW_OP_not = 0x20, - DW_OP_or = 0x21, - DW_OP_plus = 0x22, - DW_OP_plus_uconst = 0x23, /* Unsigned LEB128 addend. */ - DW_OP_shl = 0x24, - DW_OP_shr = 0x25, - DW_OP_shra = 0x26, - DW_OP_xor = 0x27, - DW_OP_bra = 0x28, /* Signed 2-byte constant. */ - DW_OP_eq = 0x29, - DW_OP_ge = 0x2a, - DW_OP_gt = 0x2b, - DW_OP_le = 0x2c, - DW_OP_lt = 0x2d, - DW_OP_ne = 0x2e, - DW_OP_skip = 0x2f, /* Signed 2-byte constant. */ - DW_OP_lit0 = 0x30, /* Literal 0. */ - DW_OP_lit1 = 0x31, /* Literal 1. */ - DW_OP_lit2 = 0x32, /* Literal 2. */ - DW_OP_lit3 = 0x33, /* Literal 3. */ - DW_OP_lit4 = 0x34, /* Literal 4. */ - DW_OP_lit5 = 0x35, /* Literal 5. */ - DW_OP_lit6 = 0x36, /* Literal 6. */ - DW_OP_lit7 = 0x37, /* Literal 7. */ - DW_OP_lit8 = 0x38, /* Literal 8. */ - DW_OP_lit9 = 0x39, /* Literal 9. */ - DW_OP_lit10 = 0x3a, /* Literal 10. */ - DW_OP_lit11 = 0x3b, /* Literal 11. */ - DW_OP_lit12 = 0x3c, /* Literal 12. */ - DW_OP_lit13 = 0x3d, /* Literal 13. */ - DW_OP_lit14 = 0x3e, /* Literal 14. */ - DW_OP_lit15 = 0x3f, /* Literal 15. */ - DW_OP_lit16 = 0x40, /* Literal 16. */ - DW_OP_lit17 = 0x41, /* Literal 17. */ - DW_OP_lit18 = 0x42, /* Literal 18. */ - DW_OP_lit19 = 0x43, /* Literal 19. */ - DW_OP_lit20 = 0x44, /* Literal 20. */ - DW_OP_lit21 = 0x45, /* Literal 21. */ - DW_OP_lit22 = 0x46, /* Literal 22. */ - DW_OP_lit23 = 0x47, /* Literal 23. */ - DW_OP_lit24 = 0x48, /* Literal 24. */ - DW_OP_lit25 = 0x49, /* Literal 25. */ - DW_OP_lit26 = 0x4a, /* Literal 26. */ - DW_OP_lit27 = 0x4b, /* Literal 27. */ - DW_OP_lit28 = 0x4c, /* Literal 28. */ - DW_OP_lit29 = 0x4d, /* Literal 29. */ - DW_OP_lit30 = 0x4e, /* Literal 30. */ - DW_OP_lit31 = 0x4f, /* Literal 31. */ - DW_OP_reg0 = 0x50, /* Register 0. */ - DW_OP_reg1 = 0x51, /* Register 1. */ - DW_OP_reg2 = 0x52, /* Register 2. */ - DW_OP_reg3 = 0x53, /* Register 3. */ - DW_OP_reg4 = 0x54, /* Register 4. */ - DW_OP_reg5 = 0x55, /* Register 5. */ - DW_OP_reg6 = 0x56, /* Register 6. */ - DW_OP_reg7 = 0x57, /* Register 7. */ - DW_OP_reg8 = 0x58, /* Register 8. */ - DW_OP_reg9 = 0x59, /* Register 9. */ - DW_OP_reg10 = 0x5a, /* Register 10. */ - DW_OP_reg11 = 0x5b, /* Register 11. */ - DW_OP_reg12 = 0x5c, /* Register 12. */ - DW_OP_reg13 = 0x5d, /* Register 13. */ - DW_OP_reg14 = 0x5e, /* Register 14. */ - DW_OP_reg15 = 0x5f, /* Register 15. */ - DW_OP_reg16 = 0x60, /* Register 16. */ - DW_OP_reg17 = 0x61, /* Register 17. */ - DW_OP_reg18 = 0x62, /* Register 18. */ - DW_OP_reg19 = 0x63, /* Register 19. */ - DW_OP_reg20 = 0x64, /* Register 20. */ - DW_OP_reg21 = 0x65, /* Register 21. */ - DW_OP_reg22 = 0x66, /* Register 22. */ - DW_OP_reg23 = 0x67, /* Register 24. */ - DW_OP_reg24 = 0x68, /* Register 24. */ - DW_OP_reg25 = 0x69, /* Register 25. */ - DW_OP_reg26 = 0x6a, /* Register 26. */ - DW_OP_reg27 = 0x6b, /* Register 27. */ - DW_OP_reg28 = 0x6c, /* Register 28. */ - DW_OP_reg29 = 0x6d, /* Register 29. */ - DW_OP_reg30 = 0x6e, /* Register 30. */ - DW_OP_reg31 = 0x6f, /* Register 31. */ - DW_OP_breg0 = 0x70, /* Base register 0. */ - DW_OP_breg1 = 0x71, /* Base register 1. */ - DW_OP_breg2 = 0x72, /* Base register 2. */ - DW_OP_breg3 = 0x73, /* Base register 3. */ - DW_OP_breg4 = 0x74, /* Base register 4. */ - DW_OP_breg5 = 0x75, /* Base register 5. */ - DW_OP_breg6 = 0x76, /* Base register 6. */ - DW_OP_breg7 = 0x77, /* Base register 7. */ - DW_OP_breg8 = 0x78, /* Base register 8. */ - DW_OP_breg9 = 0x79, /* Base register 9. */ - DW_OP_breg10 = 0x7a, /* Base register 10. */ - DW_OP_breg11 = 0x7b, /* Base register 11. */ - DW_OP_breg12 = 0x7c, /* Base register 12. */ - DW_OP_breg13 = 0x7d, /* Base register 13. */ - DW_OP_breg14 = 0x7e, /* Base register 14. */ - DW_OP_breg15 = 0x7f, /* Base register 15. */ - DW_OP_breg16 = 0x80, /* Base register 16. */ - DW_OP_breg17 = 0x81, /* Base register 17. */ - DW_OP_breg18 = 0x82, /* Base register 18. */ - DW_OP_breg19 = 0x83, /* Base register 19. */ - DW_OP_breg20 = 0x84, /* Base register 20. */ - DW_OP_breg21 = 0x85, /* Base register 21. */ - DW_OP_breg22 = 0x86, /* Base register 22. */ - DW_OP_breg23 = 0x87, /* Base register 23. */ - DW_OP_breg24 = 0x88, /* Base register 24. */ - DW_OP_breg25 = 0x89, /* Base register 25. */ - DW_OP_breg26 = 0x8a, /* Base register 26. */ - DW_OP_breg27 = 0x8b, /* Base register 27. */ - DW_OP_breg28 = 0x8c, /* Base register 28. */ - DW_OP_breg29 = 0x8d, /* Base register 29. */ - DW_OP_breg30 = 0x8e, /* Base register 30. */ - DW_OP_breg31 = 0x8f, /* Base register 31. */ - DW_OP_regx = 0x90, /* Unsigned LEB128 register. */ - DW_OP_fbreg = 0x91, /* Signed LEB128 offset. */ - DW_OP_bregx = 0x92, /* ULEB128 register followed by SLEB128 off. */ - DW_OP_piece = 0x93, /* ULEB128 size of piece addressed. */ - DW_OP_deref_size = 0x94, /* 1-byte size of data retrieved. */ - DW_OP_xderef_size = 0x95, /* 1-byte size of data retrieved. */ - DW_OP_nop = 0x96, - DW_OP_push_object_address = 0x97, - DW_OP_call2 = 0x98, - DW_OP_call4 = 0x99, - DW_OP_call_ref = 0x9a, - DW_OP_form_tls_address = 0x9b,/* TLS offset to address in current thread */ - DW_OP_call_frame_cfa = 0x9c,/* CFA as determined by CFI. */ - DW_OP_bit_piece = 0x9d, /* ULEB128 size and ULEB128 offset in bits. */ - DW_OP_implicit_value = 0x9e, /* DW_FORM_block follows opcode. */ - DW_OP_stack_value = 0x9f, /* No operands, special like DW_OP_piece. */ - - DW_OP_implicit_pointer = 0xa0, - DW_OP_addrx = 0xa1, - DW_OP_constx = 0xa2, - DW_OP_entry_value = 0xa3, - DW_OP_const_type = 0xa4, - DW_OP_regval_type = 0xa5, - DW_OP_deref_type = 0xa6, - DW_OP_xderef_type = 0xa7, - DW_OP_convert = 0xa8, - DW_OP_reinterpret = 0xa9, - - /* GNU extensions. */ - DW_OP_GNU_push_tls_address = 0xe0, - DW_OP_GNU_uninit = 0xf0, - DW_OP_GNU_encoded_addr = 0xf1, - DW_OP_GNU_implicit_pointer = 0xf2, - DW_OP_GNU_entry_value = 0xf3, - DW_OP_GNU_const_type = 0xf4, - DW_OP_GNU_regval_type = 0xf5, - DW_OP_GNU_deref_type = 0xf6, - DW_OP_GNU_convert = 0xf7, - DW_OP_GNU_reinterpret = 0xf9, - DW_OP_GNU_parameter_ref = 0xfa, - - /* GNU Debug Fission extensions. */ - DW_OP_GNU_addr_index = 0xfb, - DW_OP_GNU_const_index = 0xfc, - - DW_OP_GNU_variable_value = 0xfd, - - DW_OP_lo_user = 0xe0, /* Implementation-defined range start. */ - DW_OP_hi_user = 0xff /* Implementation-defined range end. */ - }; - - -/* DWARF base type encodings. */ -enum - { - DW_ATE_void = 0x0, - DW_ATE_address = 0x1, - DW_ATE_boolean = 0x2, - DW_ATE_complex_float = 0x3, - DW_ATE_float = 0x4, - DW_ATE_signed = 0x5, - DW_ATE_signed_char = 0x6, - DW_ATE_unsigned = 0x7, - DW_ATE_unsigned_char = 0x8, - DW_ATE_imaginary_float = 0x9, - DW_ATE_packed_decimal = 0xa, - DW_ATE_numeric_string = 0xb, - DW_ATE_edited = 0xc, - DW_ATE_signed_fixed = 0xd, - DW_ATE_unsigned_fixed = 0xe, - DW_ATE_decimal_float = 0xf, - DW_ATE_UTF = 0x10, - DW_ATE_UCS = 0x11, - DW_ATE_ASCII = 0x12, - - DW_ATE_lo_user = 0x80, - DW_ATE_hi_user = 0xff - }; - - -/* DWARF decimal sign encodings. */ -enum - { - DW_DS_unsigned = 1, - DW_DS_leading_overpunch = 2, - DW_DS_trailing_overpunch = 3, - DW_DS_leading_separate = 4, - DW_DS_trailing_separate = 5, - }; - - -/* DWARF endianity encodings. */ -enum - { - DW_END_default = 0, - DW_END_big = 1, - DW_END_little = 2, - - DW_END_lo_user = 0x40, - DW_END_hi_user = 0xff - }; - - -/* DWARF accessibility encodings. */ -enum - { - DW_ACCESS_public = 1, - DW_ACCESS_protected = 2, - DW_ACCESS_private = 3 - }; - - -/* DWARF visibility encodings. */ -enum - { - DW_VIS_local = 1, - DW_VIS_exported = 2, - DW_VIS_qualified = 3 - }; - - -/* DWARF virtuality encodings. */ -enum - { - DW_VIRTUALITY_none = 0, - DW_VIRTUALITY_virtual = 1, - DW_VIRTUALITY_pure_virtual = 2 - }; - - -/* DWARF language encodings. */ -enum - { - DW_LANG_C89 = 0x0001, /* ISO C:1989 */ - DW_LANG_C = 0x0002, /* C */ - DW_LANG_Ada83 = 0x0003, /* ISO Ada:1983 */ - DW_LANG_C_plus_plus = 0x0004, /* ISO C++:1998 */ - DW_LANG_Cobol74 = 0x0005, /* ISO Cobol:1974 */ - DW_LANG_Cobol85 = 0x0006, /* ISO Cobol:1985 */ - DW_LANG_Fortran77 = 0x0007, /* ISO FORTRAN 77 */ - DW_LANG_Fortran90 = 0x0008, /* ISO Fortran 90 */ - DW_LANG_Pascal83 = 0x0009, /* ISO Pascal:1983 */ - DW_LANG_Modula2 = 0x000a, /* ISO Modula-2:1996 */ - DW_LANG_Java = 0x000b, /* Java */ - DW_LANG_C99 = 0x000c, /* ISO C:1999 */ - DW_LANG_Ada95 = 0x000d, /* ISO Ada:1995 */ - DW_LANG_Fortran95 = 0x000e, /* ISO Fortran 95 */ - DW_LANG_PLI = 0x000f, /* ISO PL/1:1976 */ - DW_LANG_ObjC = 0x0010, /* Objective-C */ - DW_LANG_ObjC_plus_plus = 0x0011, /* Objective-C++ */ - DW_LANG_UPC = 0x0012, /* Unified Parallel C */ - DW_LANG_D = 0x0013, /* D */ - DW_LANG_Python = 0x0014, /* Python */ - DW_LANG_OpenCL = 0x0015, /* OpenCL */ - DW_LANG_Go = 0x0016, /* Go */ - DW_LANG_Modula3 = 0x0017, /* Modula-3 */ - DW_LANG_Haskell = 0x0018, /* Haskell */ - DW_LANG_C_plus_plus_03 = 0x0019, /* ISO C++:2003 */ - DW_LANG_C_plus_plus_11 = 0x001a, /* ISO C++:2011 */ - DW_LANG_OCaml = 0x001b, /* OCaml */ - DW_LANG_Rust = 0x001c, /* Rust */ - DW_LANG_C11 = 0x001d, /* ISO C:2011 */ - DW_LANG_Swift = 0x001e, /* Swift */ - DW_LANG_Julia = 0x001f, /* Julia */ - DW_LANG_Dylan = 0x0020, /* Dylan */ - DW_LANG_C_plus_plus_14 = 0x0021, /* ISO C++:2014 */ - DW_LANG_Fortran03 = 0x0022, /* ISO/IEC 1539-1:2004 */ - DW_LANG_Fortran08 = 0x0023, /* ISO/IEC 1539-1:2010 */ - DW_LANG_RenderScript = 0x0024, /* RenderScript Kernal Language */ - DW_LANG_BLISS = 0x0025, /* BLISS */ - - DW_LANG_lo_user = 0x8000, - DW_LANG_Mips_Assembler = 0x8001, /* Assembler */ - DW_LANG_hi_user = 0xffff - }; - -/* Old (typo) '1' != 'I'. */ -#define DW_LANG_PL1 DW_LANG_PLI - -/* DWARF identifier case encodings. */ -enum - { - DW_ID_case_sensitive = 0, - DW_ID_up_case = 1, - DW_ID_down_case = 2, - DW_ID_case_insensitive = 3 - }; - - -/* DWARF calling conventions encodings. - Used as values of DW_AT_calling_convention for subroutines - (normal, program or nocall) or structures, unions and class types - (normal, reference or value). */ -enum - { - DW_CC_normal = 0x1, - DW_CC_program = 0x2, - DW_CC_nocall = 0x3, - DW_CC_pass_by_reference = 0x4, - DW_CC_pass_by_value = 0x5, - DW_CC_lo_user = 0x40, - DW_CC_hi_user = 0xff - }; - - -/* DWARF inline encodings. */ -enum - { - DW_INL_not_inlined = 0, - DW_INL_inlined = 1, - DW_INL_declared_not_inlined = 2, - DW_INL_declared_inlined = 3 - }; - - -/* DWARF ordering encodings. */ -enum - { - DW_ORD_row_major = 0, - DW_ORD_col_major = 1 - }; - - -/* DWARF discriminant descriptor encodings. */ -enum - { - DW_DSC_label = 0, - DW_DSC_range = 1 - }; - -/* DWARF defaulted member function encodings. */ -enum - { - DW_DEFAULTED_no = 0, - DW_DEFAULTED_in_class = 1, - DW_DEFAULTED_out_of_class = 2 - }; - -/* DWARF line content descriptions. */ -enum - { - DW_LNCT_path = 0x1, - DW_LNCT_directory_index = 0x2, - DW_LNCT_timestamp = 0x3, - DW_LNCT_size = 0x4, - DW_LNCT_MD5 = 0x5, - DW_LNCT_lo_user = 0x2000, - DW_LNCT_hi_user = 0x3fff - }; - -/* DWARF standard opcode encodings. */ -enum - { - DW_LNS_copy = 1, - DW_LNS_advance_pc = 2, - DW_LNS_advance_line = 3, - DW_LNS_set_file = 4, - DW_LNS_set_column = 5, - DW_LNS_negate_stmt = 6, - DW_LNS_set_basic_block = 7, - DW_LNS_const_add_pc = 8, - DW_LNS_fixed_advance_pc = 9, - DW_LNS_set_prologue_end = 10, - DW_LNS_set_epilogue_begin = 11, - DW_LNS_set_isa = 12 - }; - - -/* DWARF extended opcode encodings. */ -enum - { - DW_LNE_end_sequence = 1, - DW_LNE_set_address = 2, - DW_LNE_define_file = 3, - DW_LNE_set_discriminator = 4, - - DW_LNE_lo_user = 128, - - DW_LNE_NVIDIA_inlined_call = 144, - DW_LNE_NVIDIA_set_function_name = 145, - - DW_LNE_hi_user = 255 - }; - - -/* DWARF macinfo type encodings. */ -enum - { - DW_MACINFO_define = 1, - DW_MACINFO_undef = 2, - DW_MACINFO_start_file = 3, - DW_MACINFO_end_file = 4, - DW_MACINFO_vendor_ext = 255 - }; - - -/* DWARF debug_macro type encodings. */ -enum - { - DW_MACRO_define = 0x01, - DW_MACRO_undef = 0x02, - DW_MACRO_start_file = 0x03, - DW_MACRO_end_file = 0x04, - DW_MACRO_define_strp = 0x05, - DW_MACRO_undef_strp = 0x06, - DW_MACRO_import = 0x07, - DW_MACRO_define_sup = 0x08, - DW_MACRO_undef_sup = 0x09, - DW_MACRO_import_sup = 0x0a, - DW_MACRO_define_strx = 0x0b, - DW_MACRO_undef_strx = 0x0c, - DW_MACRO_lo_user = 0xe0, - DW_MACRO_hi_user = 0xff - }; - -/* Old GNU extension names for DWARF5 debug_macro type encodings. - There are no equivalents for the supplementary object file (sup) - and indirect string references (strx). */ -#define DW_MACRO_GNU_define DW_MACRO_define -#define DW_MACRO_GNU_undef DW_MACRO_undef -#define DW_MACRO_GNU_start_file DW_MACRO_start_file -#define DW_MACRO_GNU_end_file DW_MACRO_end_file -#define DW_MACRO_GNU_define_indirect DW_MACRO_define_strp -#define DW_MACRO_GNU_undef_indirect DW_MACRO_undef_strp -#define DW_MACRO_GNU_transparent_include DW_MACRO_import -#define DW_MACRO_GNU_lo_user DW_MACRO_lo_user -#define DW_MACRO_GNU_hi_user DW_MACRO_hi_user - - -/* Range list entry encoding. */ -enum - { - DW_RLE_end_of_list = 0x0, - DW_RLE_base_addressx = 0x1, - DW_RLE_startx_endx = 0x2, - DW_RLE_startx_length = 0x3, - DW_RLE_offset_pair = 0x4, - DW_RLE_base_address = 0x5, - DW_RLE_start_end = 0x6, - DW_RLE_start_length = 0x7 - }; - - -/* Location list entry encoding. */ -enum - { - DW_LLE_end_of_list = 0x0, - DW_LLE_base_addressx = 0x1, - DW_LLE_startx_endx = 0x2, - DW_LLE_startx_length = 0x3, - DW_LLE_offset_pair = 0x4, - DW_LLE_default_location = 0x5, - DW_LLE_base_address = 0x6, - DW_LLE_start_end = 0x7, - DW_LLE_start_length = 0x8 - }; - - -/* GNU DebugFission list entry encodings (.debug_loc.dwo). */ -enum - { - DW_LLE_GNU_end_of_list_entry = 0x0, - DW_LLE_GNU_base_address_selection_entry = 0x1, - DW_LLE_GNU_start_end_entry = 0x2, - DW_LLE_GNU_start_length_entry = 0x3 - }; - -/* DWARF5 package file section identifiers. */ -enum - { - DW_SECT_INFO = 1, - /* Reserved = 2, */ - DW_SECT_ABBREV = 3, - DW_SECT_LINE = 4, - DW_SECT_LOCLISTS = 5, - DW_SECT_STR_OFFSETS = 6, - DW_SECT_MACRO = 7, - DW_SECT_RNGLISTS = 8, - }; - - -/* DWARF call frame instruction encodings. */ -enum - { - DW_CFA_advance_loc = 0x40, - DW_CFA_offset = 0x80, - DW_CFA_restore = 0xc0, - DW_CFA_extended = 0, - - DW_CFA_nop = 0x00, - DW_CFA_set_loc = 0x01, - DW_CFA_advance_loc1 = 0x02, - DW_CFA_advance_loc2 = 0x03, - DW_CFA_advance_loc4 = 0x04, - DW_CFA_offset_extended = 0x05, - DW_CFA_restore_extended = 0x06, - DW_CFA_undefined = 0x07, - DW_CFA_same_value = 0x08, - DW_CFA_register = 0x09, - DW_CFA_remember_state = 0x0a, - DW_CFA_restore_state = 0x0b, - DW_CFA_def_cfa = 0x0c, - DW_CFA_def_cfa_register = 0x0d, - DW_CFA_def_cfa_offset = 0x0e, - DW_CFA_def_cfa_expression = 0x0f, - DW_CFA_expression = 0x10, - DW_CFA_offset_extended_sf = 0x11, - DW_CFA_def_cfa_sf = 0x12, - DW_CFA_def_cfa_offset_sf = 0x13, - DW_CFA_val_offset = 0x14, - DW_CFA_val_offset_sf = 0x15, - DW_CFA_val_expression = 0x16, - - DW_CFA_low_user = 0x1c, - DW_CFA_MIPS_advance_loc8 = 0x1d, - DW_CFA_GNU_window_save = 0x2d, - DW_CFA_AARCH64_negate_ra_state = 0x2d, - DW_CFA_GNU_args_size = 0x2e, - DW_CFA_GNU_negative_offset_extended = 0x2f, - DW_CFA_high_user = 0x3f - }; - -/* ID indicating CIE as opposed to FDE in .debug_frame. */ -enum - { - DW_CIE_ID_32 = 0xffffffffU, /* In 32-bit format CIE header. */ - DW_CIE_ID_64 = 0xffffffffffffffffULL /* In 64-bit format CIE header. */ - }; - - -/* Information for GNU unwind information. */ -enum - { - DW_EH_PE_absptr = 0x00, - DW_EH_PE_omit = 0xff, - - /* FDE data encoding. */ - DW_EH_PE_uleb128 = 0x01, - DW_EH_PE_udata2 = 0x02, - DW_EH_PE_udata4 = 0x03, - DW_EH_PE_udata8 = 0x04, - DW_EH_PE_sleb128 = 0x09, - DW_EH_PE_sdata2 = 0x0a, - DW_EH_PE_sdata4 = 0x0b, - DW_EH_PE_sdata8 = 0x0c, - DW_EH_PE_signed = 0x08, - - /* FDE flags. */ - DW_EH_PE_pcrel = 0x10, - DW_EH_PE_textrel = 0x20, - DW_EH_PE_datarel = 0x30, - DW_EH_PE_funcrel = 0x40, - DW_EH_PE_aligned = 0x50, - - DW_EH_PE_indirect = 0x80 - }; - - -/* DWARF XXX. */ -#define DW_ADDR_none 0 - -/* Section 7.2.2 of the DWARF3 specification defines a range of escape - codes that can appear in the length field of certain DWARF structures. - - These defines enumerate the minimum and maximum values of this range. - Currently only the maximum value is used (to indicate that 64-bit - values are going to be used in the dwarf data that accompanies the - structure). The other values are reserved. - - Note: There is a typo in DWARF3 spec (published Dec 20, 2005). In - sections 7.4, 7.5.1, 7.19, 7.20 the minimum escape code is referred to - as 0xffffff00 whereas in fact it should be 0xfffffff0. */ -#define DWARF3_LENGTH_MIN_ESCAPE_CODE 0xfffffff0u -#define DWARF3_LENGTH_MAX_ESCAPE_CODE 0xffffffffu -#define DWARF3_LENGTH_64_BIT DWARF3_LENGTH_MAX_ESCAPE_CODE - -#endif /* dwarf.h */ diff --git a/tinycc/elf.h b/tinycc/elf.h deleted file mode 100644 index 14cfdcf..0000000 --- a/tinycc/elf.h +++ /dev/null @@ -1,3320 +0,0 @@ -/* This file defines standard ELF types, structures, and macros. - Copyright (C) 1995-2012 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C 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.1 of the License, or (at your option) any later version. - - The GNU C 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 the GNU C Library; if not, see - <http://www.gnu.org/licenses/>. */ - -#ifndef _ELF_H -#define _ELF_H 1 - -#ifndef _WIN32 -#include <inttypes.h> -#else -#ifndef __int8_t_defined -#define __int8_t_defined -typedef signed char int8_t; -typedef short int int16_t; -typedef int int32_t; -typedef long long int int64_t; -typedef unsigned char uint8_t; -typedef unsigned short int uint16_t; -typedef unsigned int uint32_t; -typedef unsigned long long int uint64_t; -#endif -#endif - -/* Standard ELF types. */ - -/* Type for a 16-bit quantity. */ -typedef uint16_t Elf32_Half; -typedef uint16_t Elf64_Half; - -/* Types for signed and unsigned 32-bit quantities. */ -typedef uint32_t Elf32_Word; -typedef int32_t Elf32_Sword; -typedef uint32_t Elf64_Word; -typedef int32_t Elf64_Sword; - -/* Types for signed and unsigned 64-bit quantities. */ -typedef uint64_t Elf32_Xword; -typedef int64_t Elf32_Sxword; -typedef uint64_t Elf64_Xword; -typedef int64_t Elf64_Sxword; - -/* Type of addresses. */ -typedef uint32_t Elf32_Addr; -typedef uint64_t Elf64_Addr; - -/* Type of file offsets. */ -typedef uint32_t Elf32_Off; -typedef uint64_t Elf64_Off; - -/* Type for section indices, which are 16-bit quantities. */ -typedef uint16_t Elf32_Section; -typedef uint16_t Elf64_Section; - -/* Type for version symbol information. */ -typedef Elf32_Half Elf32_Versym; -typedef Elf64_Half Elf64_Versym; - - -/* The ELF file header. This appears at the start of every ELF file. */ - -#define EI_NIDENT (16) - -typedef struct -{ - unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ - Elf32_Half e_type; /* Object file type */ - Elf32_Half e_machine; /* Architecture */ - Elf32_Word e_version; /* Object file version */ - Elf32_Addr e_entry; /* Entry point virtual address */ - Elf32_Off e_phoff; /* Program header table file offset */ - Elf32_Off e_shoff; /* Section header table file offset */ - Elf32_Word e_flags; /* Processor-specific flags */ - Elf32_Half e_ehsize; /* ELF header size in bytes */ - Elf32_Half e_phentsize; /* Program header table entry size */ - Elf32_Half e_phnum; /* Program header table entry count */ - Elf32_Half e_shentsize; /* Section header table entry size */ - Elf32_Half e_shnum; /* Section header table entry count */ - Elf32_Half e_shstrndx; /* Section header string table index */ -} Elf32_Ehdr; - -typedef struct -{ - unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ - Elf64_Half e_type; /* Object file type */ - Elf64_Half e_machine; /* Architecture */ - Elf64_Word e_version; /* Object file version */ - Elf64_Addr e_entry; /* Entry point virtual address */ - Elf64_Off e_phoff; /* Program header table file offset */ - Elf64_Off e_shoff; /* Section header table file offset */ - Elf64_Word e_flags; /* Processor-specific flags */ - Elf64_Half e_ehsize; /* ELF header size in bytes */ - Elf64_Half e_phentsize; /* Program header table entry size */ - Elf64_Half e_phnum; /* Program header table entry count */ - Elf64_Half e_shentsize; /* Section header table entry size */ - Elf64_Half e_shnum; /* Section header table entry count */ - Elf64_Half e_shstrndx; /* Section header string table index */ -} Elf64_Ehdr; - -/* Fields in the e_ident array. The EI_* macros are indices into the - array. The macros under each EI_* macro are the values the byte - may have. */ - -#define EI_MAG0 0 /* File identification byte 0 index */ -#define ELFMAG0 0x7f /* Magic number byte 0 */ - -#define EI_MAG1 1 /* File identification byte 1 index */ -#define ELFMAG1 'E' /* Magic number byte 1 */ - -#define EI_MAG2 2 /* File identification byte 2 index */ -#define ELFMAG2 'L' /* Magic number byte 2 */ - -#define EI_MAG3 3 /* File identification byte 3 index */ -#define ELFMAG3 'F' /* Magic number byte 3 */ - -/* Conglomeration of the identification bytes, for easy testing as a word. */ -#define ELFMAG "\177ELF" -#define SELFMAG 4 - -#define EI_CLASS 4 /* File class byte index */ -#define ELFCLASSNONE 0 /* Invalid class */ -#define ELFCLASS32 1 /* 32-bit objects */ -#define ELFCLASS64 2 /* 64-bit objects */ -#define ELFCLASSNUM 3 - -#define EI_DATA 5 /* Data encoding byte index */ -#define ELFDATANONE 0 /* Invalid data encoding */ -#define ELFDATA2LSB 1 /* 2's complement, little endian */ -#define ELFDATA2MSB 2 /* 2's complement, big endian */ -#define ELFDATANUM 3 - -#define EI_VERSION 6 /* File version byte index */ - /* Value must be EV_CURRENT */ - -#define EI_OSABI 7 /* OS ABI identification */ -#define ELFOSABI_NONE 0 /* UNIX System V ABI */ -#define ELFOSABI_SYSV 0 /* Alias. */ -#define ELFOSABI_HPUX 1 /* HP-UX */ -#define ELFOSABI_NETBSD 2 /* NetBSD. */ -#define ELFOSABI_GNU 3 /* Object uses GNU ELF extensions. */ -#define ELFOSABI_LINUX ELFOSABI_GNU /* Compatibility alias. */ -#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ -#define ELFOSABI_AIX 7 /* IBM AIX. */ -#define ELFOSABI_IRIX 8 /* SGI Irix. */ -#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ -#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ -#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ -#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ -#define ELFOSABI_OPENVMS 13 -#define ELFOSABI_NSK 14 /* Hewlett-Packard Non-Stop Kernel. */ -#define ELFOSABI_AROS 15 /* Amiga Research OS. */ -#define ELFOSABI_FENIXOS 16 /* FenixOS. */ -#define ELFOSABI_ARM_AEABI 64 /* ARM EABI. */ -#define ELFOSABI_C6000_LINUX 65 /* Linux TMS320C6000. */ -#define ELFOSABI_ARM 97 /* ARM */ -#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ - -#define EI_ABIVERSION 8 /* ABI version */ - -#define EI_PAD 9 /* Byte index of padding bytes */ - -/* Legal values for e_type (object file type). */ - -#define ET_NONE 0 /* No file type */ -#define ET_REL 1 /* Relocatable file */ -#define ET_EXEC 2 /* Executable file */ -#define ET_DYN 3 /* Shared object file */ -#define ET_CORE 4 /* Core file */ -#define ET_NUM 5 /* Number of defined types */ -#define ET_LOOS 0xfe00 /* OS-specific range start */ -#define ET_HIOS 0xfeff /* OS-specific range end */ -#define ET_LOPROC 0xff00 /* Processor-specific range start */ -#define ET_HIPROC 0xffff /* Processor-specific range end */ - -/* Legal values for e_machine (architecture). */ - -#define EM_NONE 0 /* No machine */ -#define EM_M32 1 /* AT&T WE 32100 */ -#define EM_SPARC 2 /* SUN SPARC */ -#define EM_386 3 /* Intel 80386 */ -#define EM_68K 4 /* Motorola m68k family */ -#define EM_88K 5 /* Motorola m88k family */ -#define EM_860 7 /* Intel 80860 */ -#define EM_MIPS 8 /* MIPS R3000 big-endian */ -#define EM_S370 9 /* IBM System/370 */ -#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ - -#define EM_PARISC 15 /* HPPA */ -#define EM_VPP500 17 /* Fujitsu VPP500 */ -#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ -#define EM_960 19 /* Intel 80960 */ -#define EM_PPC 20 /* PowerPC */ -#define EM_PPC64 21 /* PowerPC 64-bit */ -#define EM_S390 22 /* IBM S390 */ - -#define EM_V800 36 /* NEC V800 series */ -#define EM_FR20 37 /* Fujitsu FR20 */ -#define EM_RH32 38 /* TRW RH-32 */ -#define EM_RCE 39 /* Motorola RCE */ -#define EM_ARM 40 /* ARM */ -#define EM_FAKE_ALPHA 41 /* Digital Alpha */ -#define EM_SH 42 /* Hitachi SH */ -#define EM_SPARCV9 43 /* SPARC v9 64-bit */ -#define EM_TRICORE 44 /* Siemens Tricore */ -#define EM_ARC 45 /* Argonaut RISC Core */ -#define EM_H8_300 46 /* Hitachi H8/300 */ -#define EM_H8_300H 47 /* Hitachi H8/300H */ -#define EM_H8S 48 /* Hitachi H8S */ -#define EM_H8_500 49 /* Hitachi H8/500 */ -#define EM_IA_64 50 /* Intel Merced */ -#define EM_MIPS_X 51 /* Stanford MIPS-X */ -#define EM_COLDFIRE 52 /* Motorola Coldfire */ -#define EM_68HC12 53 /* Motorola M68HC12 */ -#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ -#define EM_PCP 55 /* Siemens PCP */ -#define EM_NCPU 56 /* Sony nCPU embedded RISC */ -#define EM_NDR1 57 /* Denso NDR1 microprocessor */ -#define EM_STARCORE 58 /* Motorola Start*Core processor */ -#define EM_ME16 59 /* Toyota ME16 processor */ -#define EM_ST100 60 /* STMicroelectronic ST100 processor */ -#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ -#define EM_X86_64 62 /* AMD x86-64 architecture */ -#define EM_PDSP 63 /* Sony DSP Processor */ - -#define EM_FX66 66 /* Siemens FX66 microcontroller */ -#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ -#define EM_ST7 68 /* STMicroelectronics ST7 8 bit mc */ -#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ -#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ -#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ -#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ -#define EM_SVX 73 /* Silicon Graphics SVx */ -#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ -#define EM_VAX 75 /* Digital VAX */ -#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ -#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ -#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ -#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ -#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ -#define EM_HUANY 81 /* Harvard University machine-independent object files */ -#define EM_PRISM 82 /* SiTera Prism */ -#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ -#define EM_FR30 84 /* Fujitsu FR30 */ -#define EM_D10V 85 /* Mitsubishi D10V */ -#define EM_D30V 86 /* Mitsubishi D30V */ -#define EM_V850 87 /* NEC v850 */ -#define EM_M32R 88 /* Mitsubishi M32R */ -#define EM_MN10300 89 /* Matsushita MN10300 */ -#define EM_MN10200 90 /* Matsushita MN10200 */ -#define EM_PJ 91 /* picoJava */ -#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ -#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ -#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ -#define EM_AARCH64 183 /* ARM AARCH64 */ -#define EM_TILEPRO 188 /* Tilera TILEPro */ -#define EM_TILEGX 191 /* Tilera TILE-Gx */ -#define EM_RISCV 243 /* RISC-V */ -#define EM_NUM 253 - -/* If it is necessary to assign new unofficial EM_* values, please - pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the - chances of collision with official or non-GNU unofficial values. */ - -#define EM_ALPHA 0x9026 -#define EM_C60 0x9c60 - -/* Legal values for e_version (version). */ - -#define EV_NONE 0 /* Invalid ELF version */ -#define EV_CURRENT 1 /* Current version */ -#define EV_NUM 2 - -/* Section header. */ - -typedef struct -{ - Elf32_Word sh_name; /* Section name (string tbl index) */ - Elf32_Word sh_type; /* Section type */ - Elf32_Word sh_flags; /* Section flags */ - Elf32_Addr sh_addr; /* Section virtual addr at execution */ - Elf32_Off sh_offset; /* Section file offset */ - Elf32_Word sh_size; /* Section size in bytes */ - Elf32_Word sh_link; /* Link to another section */ - Elf32_Word sh_info; /* Additional section information */ - Elf32_Word sh_addralign; /* Section alignment */ - Elf32_Word sh_entsize; /* Entry size if section holds table */ -} Elf32_Shdr; - -typedef struct -{ - Elf64_Word sh_name; /* Section name (string tbl index) */ - Elf64_Word sh_type; /* Section type */ - Elf64_Xword sh_flags; /* Section flags */ - Elf64_Addr sh_addr; /* Section virtual addr at execution */ - Elf64_Off sh_offset; /* Section file offset */ - Elf64_Xword sh_size; /* Section size in bytes */ - Elf64_Word sh_link; /* Link to another section */ - Elf64_Word sh_info; /* Additional section information */ - Elf64_Xword sh_addralign; /* Section alignment */ - Elf64_Xword sh_entsize; /* Entry size if section holds table */ -} Elf64_Shdr; - -/* Special section indices. */ - -#define SHN_UNDEF 0 /* Undefined section */ -#define SHN_LORESERVE 0xff00 /* Start of reserved indices */ -#define SHN_LOPROC 0xff00 /* Start of processor-specific */ -#define SHN_BEFORE 0xff00 /* Order section before all others - (Solaris). */ -#define SHN_AFTER 0xff01 /* Order section after all others - (Solaris). */ -#define SHN_HIPROC 0xff1f /* End of processor-specific */ -#define SHN_LOOS 0xff20 /* Start of OS-specific */ -#define SHN_HIOS 0xff3f /* End of OS-specific */ -#define SHN_ABS 0xfff1 /* Associated symbol is absolute */ -#define SHN_COMMON 0xfff2 /* Associated symbol is common */ -#define SHN_XINDEX 0xffff /* Index is in extra table. */ -#define SHN_HIRESERVE 0xffff /* End of reserved indices */ - -/* Legal values for sh_type (section type). */ - -#define SHT_NULL 0 /* Section header table entry unused */ -#define SHT_PROGBITS 1 /* Program data */ -#define SHT_SYMTAB 2 /* Symbol table */ -#define SHT_STRTAB 3 /* String table */ -#define SHT_RELA 4 /* Relocation entries with addends */ -#define SHT_HASH 5 /* Symbol hash table */ -#define SHT_DYNAMIC 6 /* Dynamic linking information */ -#define SHT_NOTE 7 /* Notes */ -#define SHT_NOBITS 8 /* Program space with no data (bss) */ -#define SHT_REL 9 /* Relocation entries, no addends */ -#define SHT_SHLIB 10 /* Reserved */ -#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ -#define SHT_INIT_ARRAY 14 /* Array of constructors */ -#define SHT_FINI_ARRAY 15 /* Array of destructors */ -#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ -#define SHT_GROUP 17 /* Section group */ -#define SHT_SYMTAB_SHNDX 18 /* Extended section indices */ -#define SHT_NUM 19 /* Number of defined types. */ -#define SHT_LOOS 0x60000000 /* Start OS-specific. */ -#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */ -#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ -#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ -#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ -#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ -#define SHT_SUNW_move 0x6ffffffa -#define SHT_SUNW_COMDAT 0x6ffffffb -#define SHT_SUNW_syminfo 0x6ffffffc -#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ -#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ -#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ -#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ -#define SHT_HIOS 0x6fffffff /* End OS-specific type */ -#define SHT_LOPROC 0x70000000 /* Start of processor-specific */ -#define SHT_HIPROC 0x7fffffff /* End of processor-specific */ -#define SHT_LOUSER 0x80000000 /* Start of application-specific */ -#define SHT_HIUSER 0x8fffffff /* End of application-specific */ - -/* Legal values for sh_flags (section flags). */ - -#define SHF_WRITE (1 << 0) /* Writable */ -#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ -#define SHF_EXECINSTR (1 << 2) /* Executable */ -#define SHF_MERGE (1 << 4) /* Might be merged */ -#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ -#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ -#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */ -#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling - required */ -#define SHF_GROUP (1 << 9) /* Section is member of a group. */ -#define SHF_TLS (1 << 10) /* Section hold thread-local data. */ -#define SHF_COMPRESSED (1 << 11) /* Section with compressed data. */ -#define SHF_MASKOS 0x0ff00000 /* OS-specific. */ -#define SHF_MASKPROC 0xf0000000 /* Processor-specific */ -#define SHF_ORDERED (1 << 30) /* Special ordering requirement - (Solaris). */ -#define SHF_EXCLUDE (1U << 31) /* Section is excluded unless - referenced or allocated (Solaris).*/ - -/* Section group handling. */ -#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */ - -/* Symbol table entry. */ - -typedef struct -{ - Elf32_Word st_name; /* Symbol name (string tbl index) */ - Elf32_Addr st_value; /* Symbol value */ - Elf32_Word st_size; /* Symbol size */ - unsigned char st_info; /* Symbol type and binding */ - unsigned char st_other; /* Symbol visibility */ - Elf32_Section st_shndx; /* Section index */ -} Elf32_Sym; - -typedef struct -{ - Elf64_Word st_name; /* Symbol name (string tbl index) */ - unsigned char st_info; /* Symbol type and binding */ - unsigned char st_other; /* Symbol visibility */ - Elf64_Section st_shndx; /* Section index */ - Elf64_Addr st_value; /* Symbol value */ - Elf64_Xword st_size; /* Symbol size */ -} Elf64_Sym; - -/* The syminfo section if available contains additional information about - every dynamic symbol. */ - -typedef struct -{ - Elf32_Half si_boundto; /* Direct bindings, symbol bound to */ - Elf32_Half si_flags; /* Per symbol flags */ -} Elf32_Syminfo; - -typedef struct -{ - Elf64_Half si_boundto; /* Direct bindings, symbol bound to */ - Elf64_Half si_flags; /* Per symbol flags */ -} Elf64_Syminfo; - -/* Possible values for si_boundto. */ -#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */ -#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */ -#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */ - -/* Possible bitmasks for si_flags. */ -#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */ -#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */ -#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */ -#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy - loaded */ -/* Syminfo version values. */ -#define SYMINFO_NONE 0 -#define SYMINFO_CURRENT 1 -#define SYMINFO_NUM 2 - - -/* How to extract and insert information held in the st_info field. */ - -#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) -#define ELF32_ST_TYPE(val) ((val) & 0xf) -#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) - -/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ -#define ELF64_ST_BIND(val) ELF32_ST_BIND (val) -#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val) -#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type)) - -/* Legal values for ST_BIND subfield of st_info (symbol binding). */ - -#define STB_LOCAL 0 /* Local symbol */ -#define STB_GLOBAL 1 /* Global symbol */ -#define STB_WEAK 2 /* Weak symbol */ -#define STB_NUM 3 /* Number of defined types. */ -#define STB_LOOS 10 /* Start of OS-specific */ -#define STB_GNU_UNIQUE 10 /* Unique symbol. */ -#define STB_HIOS 12 /* End of OS-specific */ -#define STB_LOPROC 13 /* Start of processor-specific */ -#define STB_HIPROC 15 /* End of processor-specific */ - -/* Legal values for ST_TYPE subfield of st_info (symbol type). */ - -#define STT_NOTYPE 0 /* Symbol type is unspecified */ -#define STT_OBJECT 1 /* Symbol is a data object */ -#define STT_FUNC 2 /* Symbol is a code object */ -#define STT_SECTION 3 /* Symbol associated with a section */ -#define STT_FILE 4 /* Symbol's name is file name */ -#define STT_COMMON 5 /* Symbol is a common data object */ -#define STT_TLS 6 /* Symbol is thread-local data object*/ -#define STT_NUM 7 /* Number of defined types. */ -#define STT_LOOS 10 /* Start of OS-specific */ -#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */ -#define STT_HIOS 12 /* End of OS-specific */ -#define STT_LOPROC 13 /* Start of processor-specific */ -#define STT_HIPROC 15 /* End of processor-specific */ - - -/* Symbol table indices are found in the hash buckets and chain table - of a symbol hash table section. This special index value indicates - the end of a chain, meaning no further symbols are found in that bucket. */ - -#define STN_UNDEF 0 /* End of a chain. */ - - -/* How to extract and insert information held in the st_other field. */ - -#define ELF32_ST_VISIBILITY(o) ((o) & 0x03) - -/* For ELF64 the definitions are the same. */ -#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o) - -/* Symbol visibility specification encoded in the st_other field. */ -#define STV_DEFAULT 0 /* Default symbol visibility rules */ -#define STV_INTERNAL 1 /* Processor specific hidden class */ -#define STV_HIDDEN 2 /* Sym unavailable in other modules */ -#define STV_PROTECTED 3 /* Not preemptible, not exported */ - - -/* Relocation table entry without addend (in section of type SHT_REL). */ - -typedef struct -{ - Elf32_Addr r_offset; /* Address */ - Elf32_Word r_info; /* Relocation type and symbol index */ -} Elf32_Rel; - -/* I have seen two different definitions of the Elf64_Rel and - Elf64_Rela structures, so we'll leave them out until Novell (or - whoever) gets their act together. */ -/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */ - -typedef struct -{ - Elf64_Addr r_offset; /* Address */ - Elf64_Xword r_info; /* Relocation type and symbol index */ -} Elf64_Rel; - -/* Relocation table entry with addend (in section of type SHT_RELA). */ - -typedef struct -{ - Elf32_Addr r_offset; /* Address */ - Elf32_Word r_info; /* Relocation type and symbol index */ - Elf32_Sword r_addend; /* Addend */ -} Elf32_Rela; - -typedef struct -{ - Elf64_Addr r_offset; /* Address */ - Elf64_Xword r_info; /* Relocation type and symbol index */ - Elf64_Sxword r_addend; /* Addend */ -} Elf64_Rela; - -/* How to extract and insert information held in the r_info field. */ - -#define ELF32_R_SYM(val) ((val) >> 8) -#define ELF32_R_TYPE(val) ((val) & 0xff) -#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) - -#define ELF64_R_SYM(i) ((i) >> 32) -#define ELF64_R_TYPE(i) ((i) & 0xffffffff) -#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type)) - -/* Program segment header. */ - -typedef struct -{ - Elf32_Word p_type; /* Segment type */ - Elf32_Off p_offset; /* Segment file offset */ - Elf32_Addr p_vaddr; /* Segment virtual address */ - Elf32_Addr p_paddr; /* Segment physical address */ - Elf32_Word p_filesz; /* Segment size in file */ - Elf32_Word p_memsz; /* Segment size in memory */ - Elf32_Word p_flags; /* Segment flags */ - Elf32_Word p_align; /* Segment alignment */ -} Elf32_Phdr; - -typedef struct -{ - Elf64_Word p_type; /* Segment type */ - Elf64_Word p_flags; /* Segment flags */ - Elf64_Off p_offset; /* Segment file offset */ - Elf64_Addr p_vaddr; /* Segment virtual address */ - Elf64_Addr p_paddr; /* Segment physical address */ - Elf64_Xword p_filesz; /* Segment size in file */ - Elf64_Xword p_memsz; /* Segment size in memory */ - Elf64_Xword p_align; /* Segment alignment */ -} Elf64_Phdr; - -/* Special value for e_phnum. This indicates that the real number of - program headers is too large to fit into e_phnum. Instead the real - value is in the field sh_info of section 0. */ - -#define PN_XNUM 0xffff - -/* Legal values for p_type (segment type). */ - -#define PT_NULL 0 /* Program header table entry unused */ -#define PT_LOAD 1 /* Loadable program segment */ -#define PT_DYNAMIC 2 /* Dynamic linking information */ -#define PT_INTERP 3 /* Program interpreter */ -#define PT_NOTE 4 /* Auxiliary information */ -#define PT_SHLIB 5 /* Reserved */ -#define PT_PHDR 6 /* Entry for header table itself */ -#define PT_TLS 7 /* Thread-local storage segment */ -#define PT_NUM 8 /* Number of defined types */ -#define PT_LOOS 0x60000000 /* Start of OS-specific */ -#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ -#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ -#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ -#define PT_LOSUNW 0x6ffffffa -#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ -#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ -#define PT_HISUNW 0x6fffffff -#define PT_HIOS 0x6fffffff /* End of OS-specific */ -#define PT_LOPROC 0x70000000 /* Start of processor-specific */ -#define PT_HIPROC 0x7fffffff /* End of processor-specific */ - -/* Legal values for p_flags (segment flags). */ - -#define PF_X (1 << 0) /* Segment is executable */ -#define PF_W (1 << 1) /* Segment is writable */ -#define PF_R (1 << 2) /* Segment is readable */ -#define PF_MASKOS 0x0ff00000 /* OS-specific */ -#define PF_MASKPROC 0xf0000000 /* Processor-specific */ - -/* Legal values for note segment descriptor types for core files. */ - -#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ -#define NT_FPREGSET 2 /* Contains copy of fpregset struct */ -#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ -#define NT_PRXREG 4 /* Contains copy of prxregset struct */ -#define NT_TASKSTRUCT 4 /* Contains copy of task structure */ -#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */ -#define NT_AUXV 6 /* Contains copy of auxv array */ -#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */ -#define NT_ASRS 8 /* Contains copy of asrset struct */ -#define NT_PSTATUS 10 /* Contains copy of pstatus struct */ -#define NT_PSINFO 13 /* Contains copy of psinfo struct */ -#define NT_PRCRED 14 /* Contains copy of prcred struct */ -#define NT_UTSNAME 15 /* Contains copy of utsname struct */ -#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */ -#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */ -#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct */ -#define NT_PRXFPREG 0x46e62b7f /* Contains copy of user_fxsr_struct */ -#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ -#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */ -#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ -#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ -#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ -#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ -#define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves */ -#define NT_S390_TIMER 0x301 /* s390 timer register */ -#define NT_S390_TODCMP 0x302 /* s390 TOD clock comparator register */ -#define NT_S390_TODPREG 0x303 /* s390 TOD programmable register */ -#define NT_S390_CTRS 0x304 /* s390 control registers */ -#define NT_S390_PREFIX 0x305 /* s390 prefix register */ -#define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ -#define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ -#define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */ -#define NT_ARM_TLS 0x401 /* ARM TLS register */ -#define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */ -#define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */ - -/* Legal values for the note segment descriptor types for object files. */ - -#define NT_VERSION 1 /* Contains a version string. */ - - -/* Dynamic section entry. */ - -typedef struct -{ - Elf32_Sword d_tag; /* Dynamic entry type */ - union - { - Elf32_Word d_val; /* Integer value */ - Elf32_Addr d_ptr; /* Address value */ - } d_un; -} Elf32_Dyn; - -typedef struct -{ - Elf64_Sxword d_tag; /* Dynamic entry type */ - union - { - Elf64_Xword d_val; /* Integer value */ - Elf64_Addr d_ptr; /* Address value */ - } d_un; -} Elf64_Dyn; - -/* Legal values for d_tag (dynamic entry type). */ - -#define DT_NULL 0 /* Marks end of dynamic section */ -#define DT_NEEDED 1 /* Name of needed library */ -#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ -#define DT_PLTGOT 3 /* Processor defined value */ -#define DT_HASH 4 /* Address of symbol hash table */ -#define DT_STRTAB 5 /* Address of string table */ -#define DT_SYMTAB 6 /* Address of symbol table */ -#define DT_RELA 7 /* Address of Rela relocs */ -#define DT_RELASZ 8 /* Total size of Rela relocs */ -#define DT_RELAENT 9 /* Size of one Rela reloc */ -#define DT_STRSZ 10 /* Size of string table */ -#define DT_SYMENT 11 /* Size of one symbol table entry */ -#define DT_INIT 12 /* Address of init function */ -#define DT_FINI 13 /* Address of termination function */ -#define DT_SONAME 14 /* Name of shared object */ -#define DT_RPATH 15 /* Library search path (deprecated) */ -#define DT_SYMBOLIC 16 /* Start symbol search here */ -#define DT_REL 17 /* Address of Rel relocs */ -#define DT_RELSZ 18 /* Total size of Rel relocs */ -#define DT_RELENT 19 /* Size of one Rel reloc */ -#define DT_PLTREL 20 /* Type of reloc in PLT */ -#define DT_DEBUG 21 /* For debugging; unspecified */ -#define DT_TEXTREL 22 /* Reloc might modify .text */ -#define DT_JMPREL 23 /* Address of PLT relocs */ -#define DT_BIND_NOW 24 /* Process relocations of object */ -#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ -#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ -#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ -#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ -#define DT_RUNPATH 29 /* Library search path */ -#define DT_FLAGS 30 /* Flags for the object being loaded */ -#define DT_ENCODING 32 /* Start of encoded range */ -#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ -#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ -#define DT_NUM 34 /* Number used */ -#define DT_LOOS 0x6000000d /* Start of OS-specific */ -#define DT_HIOS 0x6ffff000 /* End of OS-specific */ -#define DT_LOPROC 0x70000000 /* Start of processor-specific */ -#define DT_HIPROC 0x7fffffff /* End of processor-specific */ -#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */ - -/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the - Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's - approach. */ -#define DT_VALRNGLO 0x6ffffd00 -#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ -#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ -#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ -#define DT_CHECKSUM 0x6ffffdf8 -#define DT_PLTPADSZ 0x6ffffdf9 -#define DT_MOVEENT 0x6ffffdfa -#define DT_MOVESZ 0x6ffffdfb -#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ -#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting - the following DT_* entry. */ -#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ -#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ -#define DT_VALRNGHI 0x6ffffdff -#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ -#define DT_VALNUM 12 - -/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the - Dyn.d_un.d_ptr field of the Elf*_Dyn structure. - - If any adjustment is made to the ELF object after it has been - built these entries will need to be adjusted. */ -#define DT_ADDRRNGLO 0x6ffffe00 -#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */ -#define DT_TLSDESC_PLT 0x6ffffef6 -#define DT_TLSDESC_GOT 0x6ffffef7 -#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ -#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ -#define DT_CONFIG 0x6ffffefa /* Configuration information. */ -#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ -#define DT_AUDIT 0x6ffffefc /* Object auditing. */ -#define DT_PLTPAD 0x6ffffefd /* PLT padding. */ -#define DT_MOVETAB 0x6ffffefe /* Move table. */ -#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ -#define DT_ADDRRNGHI 0x6ffffeff -#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ -#define DT_ADDRNUM 11 - -/* The versioning entry types. The next are defined as part of the - GNU extension. */ -#define DT_VERSYM 0x6ffffff0 - -#define DT_RELACOUNT 0x6ffffff9 -#define DT_RELCOUNT 0x6ffffffa - -/* These were chosen by Sun. */ -#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ -#define DT_VERDEF 0x6ffffffc /* Address of version definition - table */ -#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */ -#define DT_VERNEED 0x6ffffffe /* Address of table with needed - versions */ -#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */ -#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ -#define DT_VERSIONTAGNUM 16 - -/* Sun added these machine-independent extensions in the "processor-specific" - range. Be compatible. */ -#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ -#define DT_FILTER 0x7fffffff /* Shared object to get values from */ -#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) -#define DT_EXTRANUM 3 - -/* Values of `d_un.d_val' in the DT_FLAGS entry. */ -#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */ -#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */ -#define DF_TEXTREL 0x00000004 /* Object contains text relocations */ -#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */ -#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ - -/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 - entry in the dynamic section. */ -#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ -#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */ -#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */ -#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/ -#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/ -#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/ -#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */ -#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */ -#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */ -#define DF_1_TRANS 0x00000200 -#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */ -#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */ -#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */ -#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/ -#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */ -#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */ -#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */ -#define DF_1_NODIRECT 0x00020000 /* Object has no-direct binding. */ -#define DF_1_IGNMULDEF 0x00040000 -#define DF_1_NOKSYMS 0x00080000 -#define DF_1_NOHDR 0x00100000 -#define DF_1_EDITED 0x00200000 /* Object is modified after built. */ -#define DF_1_NORELOC 0x00400000 -#define DF_1_SYMINTPOSE 0x00800000 /* Object has individual interposers. */ -#define DF_1_GLOBAUDIT 0x01000000 /* Global auditing required. */ -#define DF_1_SINGLETON 0x02000000 /* Singleton symbols are used. */ -#define DF_1_PIE 0x08000000 - -/* Flags for the feature selection in DT_FEATURE_1. */ -#define DTF_1_PARINIT 0x00000001 -#define DTF_1_CONFEXP 0x00000002 - -/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */ -#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */ -#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not - generally available. */ - -/* Version definition sections. */ - -typedef struct -{ - Elf32_Half vd_version; /* Version revision */ - Elf32_Half vd_flags; /* Version information */ - Elf32_Half vd_ndx; /* Version Index */ - Elf32_Half vd_cnt; /* Number of associated aux entries */ - Elf32_Word vd_hash; /* Version name hash value */ - Elf32_Word vd_aux; /* Offset in bytes to verdaux array */ - Elf32_Word vd_next; /* Offset in bytes to next verdef - entry */ -} Elf32_Verdef; - -typedef struct -{ - Elf64_Half vd_version; /* Version revision */ - Elf64_Half vd_flags; /* Version information */ - Elf64_Half vd_ndx; /* Version Index */ - Elf64_Half vd_cnt; /* Number of associated aux entries */ - Elf64_Word vd_hash; /* Version name hash value */ - Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ - Elf64_Word vd_next; /* Offset in bytes to next verdef - entry */ -} Elf64_Verdef; - - -/* Legal values for vd_version (version revision). */ -#define VER_DEF_NONE 0 /* No version */ -#define VER_DEF_CURRENT 1 /* Current version */ -#define VER_DEF_NUM 2 /* Given version number */ - -/* Legal values for vd_flags (version information flags). */ -#define VER_FLG_BASE 0x1 /* Version definition of file itself */ -#define VER_FLG_WEAK 0x2 /* Weak version identifier */ - -/* Versym symbol index values. */ -#define VER_NDX_LOCAL 0 /* Symbol is local. */ -#define VER_NDX_GLOBAL 1 /* Symbol is global. */ -#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */ -#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */ - -/* Auxiliary version information. */ - -typedef struct -{ - Elf32_Word vda_name; /* Version or dependency names */ - Elf32_Word vda_next; /* Offset in bytes to next verdaux - entry */ -} Elf32_Verdaux; - -typedef struct -{ - Elf64_Word vda_name; /* Version or dependency names */ - Elf64_Word vda_next; /* Offset in bytes to next verdaux - entry */ -} Elf64_Verdaux; - - -/* Version dependency section. */ - -typedef struct -{ - Elf32_Half vn_version; /* Version of structure */ - Elf32_Half vn_cnt; /* Number of associated aux entries */ - Elf32_Word vn_file; /* Offset of filename for this - dependency */ - Elf32_Word vn_aux; /* Offset in bytes to vernaux array */ - Elf32_Word vn_next; /* Offset in bytes to next verneed - entry */ -} Elf32_Verneed; - -typedef struct -{ - Elf64_Half vn_version; /* Version of structure */ - Elf64_Half vn_cnt; /* Number of associated aux entries */ - Elf64_Word vn_file; /* Offset of filename for this - dependency */ - Elf64_Word vn_aux; /* Offset in bytes to vernaux array */ - Elf64_Word vn_next; /* Offset in bytes to next verneed - entry */ -} Elf64_Verneed; - - -/* Legal values for vn_version (version revision). */ -#define VER_NEED_NONE 0 /* No version */ -#define VER_NEED_CURRENT 1 /* Current version */ -#define VER_NEED_NUM 2 /* Given version number */ - -/* Auxiliary needed version information. */ - -typedef struct -{ - Elf32_Word vna_hash; /* Hash value of dependency name */ - Elf32_Half vna_flags; /* Dependency specific information */ - Elf32_Half vna_other; /* Unused */ - Elf32_Word vna_name; /* Dependency name string offset */ - Elf32_Word vna_next; /* Offset in bytes to next vernaux - entry */ -} Elf32_Vernaux; - -typedef struct -{ - Elf64_Word vna_hash; /* Hash value of dependency name */ - Elf64_Half vna_flags; /* Dependency specific information */ - Elf64_Half vna_other; /* Unused */ - Elf64_Word vna_name; /* Dependency name string offset */ - Elf64_Word vna_next; /* Offset in bytes to next vernaux - entry */ -} Elf64_Vernaux; - - -/* Legal values for vna_flags. */ -#define VER_FLG_WEAK 0x2 /* Weak version identifier */ - - -/* Auxiliary vector. */ - -/* This vector is normally only used by the program interpreter. The - usual definition in an ABI supplement uses the name auxv_t. The - vector is not usually defined in a standard <elf.h> file, but it - can't hurt. We rename it to avoid conflicts. The sizes of these - types are an arrangement between the exec server and the program - interpreter, so we don't fully specify them here. */ - -typedef struct -{ - uint32_t a_type; /* Entry type */ - union - { - uint32_t a_val; /* Integer value */ - /* We use to have pointer elements added here. We cannot do that, - though, since it does not work when using 32-bit definitions - on 64-bit platforms and vice versa. */ - } a_un; -} Elf32_auxv_t; - -typedef struct -{ - uint64_t a_type; /* Entry type */ - union - { - uint64_t a_val; /* Integer value */ - /* We use to have pointer elements added here. We cannot do that, - though, since it does not work when using 32-bit definitions - on 64-bit platforms and vice versa. */ - } a_un; -} Elf64_auxv_t; - -/* Legal values for a_type (entry type). */ - -#define AT_NULL 0 /* End of vector */ -#define AT_IGNORE 1 /* Entry should be ignored */ -#define AT_EXECFD 2 /* File descriptor of program */ -#define AT_PHDR 3 /* Program headers for program */ -#define AT_PHENT 4 /* Size of program header entry */ -#define AT_PHNUM 5 /* Number of program headers */ -#define AT_PAGESZ 6 /* System page size */ -#define AT_BASE 7 /* Base address of interpreter */ -#define AT_FLAGS 8 /* Flags */ -#define AT_ENTRY 9 /* Entry point of program */ -#define AT_NOTELF 10 /* Program is not ELF */ -#define AT_UID 11 /* Real uid */ -#define AT_EUID 12 /* Effective uid */ -#define AT_GID 13 /* Real gid */ -#define AT_EGID 14 /* Effective gid */ -#define AT_CLKTCK 17 /* Frequency of times() */ - -/* Some more special a_type values describing the hardware. */ -#define AT_PLATFORM 15 /* String identifying platform. */ -#define AT_HWCAP 16 /* Machine dependent hints about - processor capabilities. */ - -/* This entry gives some information about the FPU initialization - performed by the kernel. */ -#define AT_FPUCW 18 /* Used FPU control word. */ - -/* Cache block sizes. */ -#define AT_DCACHEBSIZE 19 /* Data cache block size. */ -#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */ -#define AT_UCACHEBSIZE 21 /* Unified cache block size. */ - -/* A special ignored value for PPC, used by the kernel to control the - interpretation of the AUXV. Must be > 16. */ -#define AT_IGNOREPPC 22 /* Entry should be ignored. */ - -#define AT_SECURE 23 /* Boolean, was exec setuid-like? */ - -#define AT_BASE_PLATFORM 24 /* String identifying real platforms.*/ - -#define AT_RANDOM 25 /* Address of 16 random bytes. */ - -#define AT_EXECFN 31 /* Filename of executable. */ - -/* Pointer to the global system page used for system calls and other - nice things. */ -#define AT_SYSINFO 32 -#define AT_SYSINFO_EHDR 33 - -/* Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains - log2 of line size; mask those to get cache size. */ -#define AT_L1I_CACHESHAPE 34 -#define AT_L1D_CACHESHAPE 35 -#define AT_L2_CACHESHAPE 36 -#define AT_L3_CACHESHAPE 37 - -/* Note section contents. Each entry in the note section begins with - a header of a fixed form. */ - -typedef struct -{ - Elf32_Word n_namesz; /* Length of the note's name. */ - Elf32_Word n_descsz; /* Length of the note's descriptor. */ - Elf32_Word n_type; /* Type of the note. */ -} Elf32_Nhdr; - -typedef struct -{ - Elf64_Word n_namesz; /* Length of the note's name. */ - Elf64_Word n_descsz; /* Length of the note's descriptor. */ - Elf64_Word n_type; /* Type of the note. */ -} Elf64_Nhdr; - -/* Known names of notes. */ - -/* Solaris entries in the note section have this name. */ -#define ELF_NOTE_SOLARIS "SUNW Solaris" - -/* Note entries for GNU systems have this name. */ -#define ELF_NOTE_GNU "GNU" - - -/* Defined types of notes for Solaris. */ - -/* Value of descriptor (one word) is desired pagesize for the binary. */ -#define ELF_NOTE_PAGESIZE_HINT 1 - - -/* Defined note types for GNU systems. */ - -/* ABI information. The descriptor consists of words: - word 0: OS descriptor - word 1: major version of the ABI - word 2: minor version of the ABI - word 3: subminor version of the ABI -*/ -#define NT_GNU_ABI_TAG 1 -#define ELF_NOTE_ABI NT_GNU_ABI_TAG /* Old name. */ - -/* Known OSes. These values can appear in word 0 of an - NT_GNU_ABI_TAG note section entry. */ -#define ELF_NOTE_OS_LINUX 0 -#define ELF_NOTE_OS_GNU 1 -#define ELF_NOTE_OS_SOLARIS2 2 -#define ELF_NOTE_OS_FREEBSD 3 - -/* Synthetic hwcap information. The descriptor begins with two words: - word 0: number of entries - word 1: bitmask of enabled entries - Then follow variable-length entries, one byte followed by a - '\0'-terminated hwcap name string. The byte gives the bit - number to test if enabled, (1U << bit) & bitmask. */ -#define NT_GNU_HWCAP 2 - -/* Build ID bits as generated by ld --build-id. - The descriptor consists of any nonzero number of bytes. */ -#define NT_GNU_BUILD_ID 3 - -/* Version note generated by GNU gold containing a version string. */ -#define NT_GNU_GOLD_VERSION 4 - - -/* Move records. */ -typedef struct -{ - Elf32_Xword m_value; /* Symbol value. */ - Elf32_Word m_info; /* Size and index. */ - Elf32_Word m_poffset; /* Symbol offset. */ - Elf32_Half m_repeat; /* Repeat count. */ - Elf32_Half m_stride; /* Stride info. */ -} Elf32_Move; - -typedef struct -{ - Elf64_Xword m_value; /* Symbol value. */ - Elf64_Xword m_info; /* Size and index. */ - Elf64_Xword m_poffset; /* Symbol offset. */ - Elf64_Half m_repeat; /* Repeat count. */ - Elf64_Half m_stride; /* Stride info. */ -} Elf64_Move; - -/* Macro to construct move records. */ -#define ELF32_M_SYM(info) ((info) >> 8) -#define ELF32_M_SIZE(info) ((unsigned char) (info)) -#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size)) - -#define ELF64_M_SYM(info) ELF32_M_SYM (info) -#define ELF64_M_SIZE(info) ELF32_M_SIZE (info) -#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size) - - -/* Motorola 68k specific definitions. */ - -/* Values for Elf32_Ehdr.e_flags. */ -#define EF_CPU32 0x00810000 - -/* m68k relocs. */ - -#define R_68K_NONE 0 /* No reloc */ -#define R_68K_32 1 /* Direct 32 bit */ -#define R_68K_16 2 /* Direct 16 bit */ -#define R_68K_8 3 /* Direct 8 bit */ -#define R_68K_PC32 4 /* PC relative 32 bit */ -#define R_68K_PC16 5 /* PC relative 16 bit */ -#define R_68K_PC8 6 /* PC relative 8 bit */ -#define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */ -#define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */ -#define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */ -#define R_68K_GOT32O 10 /* 32 bit GOT offset */ -#define R_68K_GOT16O 11 /* 16 bit GOT offset */ -#define R_68K_GOT8O 12 /* 8 bit GOT offset */ -#define R_68K_PLT32 13 /* 32 bit PC relative PLT address */ -#define R_68K_PLT16 14 /* 16 bit PC relative PLT address */ -#define R_68K_PLT8 15 /* 8 bit PC relative PLT address */ -#define R_68K_PLT32O 16 /* 32 bit PLT offset */ -#define R_68K_PLT16O 17 /* 16 bit PLT offset */ -#define R_68K_PLT8O 18 /* 8 bit PLT offset */ -#define R_68K_COPY 19 /* Copy symbol at runtime */ -#define R_68K_GLOB_DAT 20 /* Create GOT entry */ -#define R_68K_JMP_SLOT 21 /* Create PLT entry */ -#define R_68K_RELATIVE 22 /* Adjust by program base */ -#define R_68K_TLS_GD32 25 /* 32 bit GOT offset for GD */ -#define R_68K_TLS_GD16 26 /* 16 bit GOT offset for GD */ -#define R_68K_TLS_GD8 27 /* 8 bit GOT offset for GD */ -#define R_68K_TLS_LDM32 28 /* 32 bit GOT offset for LDM */ -#define R_68K_TLS_LDM16 29 /* 16 bit GOT offset for LDM */ -#define R_68K_TLS_LDM8 30 /* 8 bit GOT offset for LDM */ -#define R_68K_TLS_LDO32 31 /* 32 bit module-relative offset */ -#define R_68K_TLS_LDO16 32 /* 16 bit module-relative offset */ -#define R_68K_TLS_LDO8 33 /* 8 bit module-relative offset */ -#define R_68K_TLS_IE32 34 /* 32 bit GOT offset for IE */ -#define R_68K_TLS_IE16 35 /* 16 bit GOT offset for IE */ -#define R_68K_TLS_IE8 36 /* 8 bit GOT offset for IE */ -#define R_68K_TLS_LE32 37 /* 32 bit offset relative to - static TLS block */ -#define R_68K_TLS_LE16 38 /* 16 bit offset relative to - static TLS block */ -#define R_68K_TLS_LE8 39 /* 8 bit offset relative to - static TLS block */ -#define R_68K_TLS_DTPMOD32 40 /* 32 bit module number */ -#define R_68K_TLS_DTPREL32 41 /* 32 bit module-relative offset */ -#define R_68K_TLS_TPREL32 42 /* 32 bit TP-relative offset */ -/* Keep this the last entry. */ -#define R_68K_NUM 43 - -/* Intel 80386 specific definitions. */ - -/* i386 relocs. */ - -#define R_386_NONE 0 /* No reloc */ -#define R_386_32 1 /* Direct 32 bit */ -#define R_386_PC32 2 /* PC relative 32 bit */ -#define R_386_GOT32 3 /* 32 bit GOT entry */ -#define R_386_PLT32 4 /* 32 bit PLT address */ -#define R_386_COPY 5 /* Copy symbol at runtime */ -#define R_386_GLOB_DAT 6 /* Create GOT entry */ -#define R_386_JMP_SLOT 7 /* Create PLT entry */ -#define R_386_RELATIVE 8 /* Adjust by program base */ -#define R_386_GOTOFF 9 /* 32 bit offset to GOT */ -#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ -#define R_386_32PLT 11 -#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ -#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS - block offset */ -#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block - offset */ -#define R_386_TLS_LE 17 /* Offset relative to static TLS - block */ -#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of - general dynamic thread local data */ -#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of - local dynamic thread local data - in LE code */ -#define R_386_16 20 -#define R_386_PC16 21 -#define R_386_8 22 -#define R_386_PC8 23 -#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic - thread local data */ -#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */ -#define R_386_TLS_GD_CALL 26 /* Relocation for call to - __tls_get_addr() */ -#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */ -#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic - thread local data in LE code */ -#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */ -#define R_386_TLS_LDM_CALL 30 /* Relocation for call to - __tls_get_addr() in LDM code */ -#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */ -#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */ -#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS - block offset */ -#define R_386_TLS_LE_32 34 /* Negated offset relative to static - TLS block */ -#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ -#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ -#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ -/* 38? */ -#define R_386_TLS_GOTDESC 39 /* GOT offset for TLS descriptor. */ -#define R_386_TLS_DESC_CALL 40 /* Marker of call through TLS - descriptor for - relaxation. */ -#define R_386_TLS_DESC 41 /* TLS descriptor containing - pointer to code and to - argument, returning the TLS - offset for the symbol. */ -#define R_386_IRELATIVE 42 /* Adjust indirectly by program base */ -#define R_386_GOT32X 43 /* 32 bit GOT entry, relaxable */ -/* Keep this the last entry. */ -#define R_386_NUM 44 - -/* SUN SPARC specific definitions. */ - -/* Legal values for ST_TYPE subfield of st_info (symbol type). */ - -#define STT_SPARC_REGISTER 13 /* Global register reserved to app. */ - -/* Values for Elf64_Ehdr.e_flags. */ - -#define EF_SPARCV9_MM 3 -#define EF_SPARCV9_TSO 0 -#define EF_SPARCV9_PSO 1 -#define EF_SPARCV9_RMO 2 -#define EF_SPARC_LEDATA 0x800000 /* little endian data */ -#define EF_SPARC_EXT_MASK 0xFFFF00 -#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */ -#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */ -#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */ -#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */ - -/* SPARC relocs. */ - -#define R_SPARC_NONE 0 /* No reloc */ -#define R_SPARC_8 1 /* Direct 8 bit */ -#define R_SPARC_16 2 /* Direct 16 bit */ -#define R_SPARC_32 3 /* Direct 32 bit */ -#define R_SPARC_DISP8 4 /* PC relative 8 bit */ -#define R_SPARC_DISP16 5 /* PC relative 16 bit */ -#define R_SPARC_DISP32 6 /* PC relative 32 bit */ -#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */ -#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */ -#define R_SPARC_HI22 9 /* High 22 bit */ -#define R_SPARC_22 10 /* Direct 22 bit */ -#define R_SPARC_13 11 /* Direct 13 bit */ -#define R_SPARC_LO10 12 /* Truncated 10 bit */ -#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */ -#define R_SPARC_GOT13 14 /* 13 bit GOT entry */ -#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */ -#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */ -#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */ -#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */ -#define R_SPARC_COPY 19 /* Copy symbol at runtime */ -#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */ -#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */ -#define R_SPARC_RELATIVE 22 /* Adjust by program base */ -#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */ - -/* Additional Sparc64 relocs. */ - -#define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */ -#define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */ -#define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */ -#define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */ -#define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */ -#define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */ -#define R_SPARC_10 30 /* Direct 10 bit */ -#define R_SPARC_11 31 /* Direct 11 bit */ -#define R_SPARC_64 32 /* Direct 64 bit */ -#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */ -#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */ -#define R_SPARC_HM10 35 /* High middle 10 bits of ... */ -#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */ -#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */ -#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */ -#define R_SPARC_PC_LM22 39 /* Low middle 22 bits of ... */ -#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */ -#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */ -#define R_SPARC_GLOB_JMP 42 /* was part of v9 ABI but was removed */ -#define R_SPARC_7 43 /* Direct 7 bit */ -#define R_SPARC_5 44 /* Direct 5 bit */ -#define R_SPARC_6 45 /* Direct 6 bit */ -#define R_SPARC_DISP64 46 /* PC relative 64 bit */ -#define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */ -#define R_SPARC_HIX22 48 /* High 22 bit complemented */ -#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */ -#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */ -#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */ -#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */ -#define R_SPARC_REGISTER 53 /* Global register usage */ -#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */ -#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */ -#define R_SPARC_TLS_GD_HI22 56 -#define R_SPARC_TLS_GD_LO10 57 -#define R_SPARC_TLS_GD_ADD 58 -#define R_SPARC_TLS_GD_CALL 59 -#define R_SPARC_TLS_LDM_HI22 60 -#define R_SPARC_TLS_LDM_LO10 61 -#define R_SPARC_TLS_LDM_ADD 62 -#define R_SPARC_TLS_LDM_CALL 63 -#define R_SPARC_TLS_LDO_HIX22 64 -#define R_SPARC_TLS_LDO_LOX10 65 -#define R_SPARC_TLS_LDO_ADD 66 -#define R_SPARC_TLS_IE_HI22 67 -#define R_SPARC_TLS_IE_LO10 68 -#define R_SPARC_TLS_IE_LD 69 -#define R_SPARC_TLS_IE_LDX 70 -#define R_SPARC_TLS_IE_ADD 71 -#define R_SPARC_TLS_LE_HIX22 72 -#define R_SPARC_TLS_LE_LOX10 73 -#define R_SPARC_TLS_DTPMOD32 74 -#define R_SPARC_TLS_DTPMOD64 75 -#define R_SPARC_TLS_DTPOFF32 76 -#define R_SPARC_TLS_DTPOFF64 77 -#define R_SPARC_TLS_TPOFF32 78 -#define R_SPARC_TLS_TPOFF64 79 -#define R_SPARC_GOTDATA_HIX22 80 -#define R_SPARC_GOTDATA_LOX10 81 -#define R_SPARC_GOTDATA_OP_HIX22 82 -#define R_SPARC_GOTDATA_OP_LOX10 83 -#define R_SPARC_GOTDATA_OP 84 -#define R_SPARC_H34 85 -#define R_SPARC_SIZE32 86 -#define R_SPARC_SIZE64 87 -#define R_SPARC_WDISP10 88 -#define R_SPARC_JMP_IREL 248 -#define R_SPARC_IRELATIVE 249 -#define R_SPARC_GNU_VTINHERIT 250 -#define R_SPARC_GNU_VTENTRY 251 -#define R_SPARC_REV32 252 -/* Keep this the last entry. */ -#define R_SPARC_NUM 253 - -/* For Sparc64, legal values for d_tag of Elf64_Dyn. */ - -#define DT_SPARC_REGISTER 0x70000001 -#define DT_SPARC_NUM 2 - -/* MIPS R3000 specific definitions. */ - -/* Legal values for e_flags field of Elf32_Ehdr. */ - -#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */ -#define EF_MIPS_PIC 2 /* Contains PIC code */ -#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */ -#define EF_MIPS_XGOT 8 -#define EF_MIPS_64BIT_WHIRL 16 -#define EF_MIPS_ABI2 32 -#define EF_MIPS_ABI_ON32 64 -#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */ - -/* Legal values for MIPS architecture level. */ - -#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ -#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ -#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ -#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ -#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ -#define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ -#define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ - -/* The following are non-official names and should not be used. */ - -#define E_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ -#define E_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ -#define E_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ -#define E_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ -#define E_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ -#define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ -#define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ - -/* Special section indices. */ - -#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */ -#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */ -#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */ -#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */ -#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */ - -/* Legal values for sh_type field of Elf32_Shdr. */ - -#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */ -#define SHT_MIPS_MSYM 0x70000001 -#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */ -#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */ -#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ -#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information*/ -#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */ -#define SHT_MIPS_PACKAGE 0x70000007 -#define SHT_MIPS_PACKSYM 0x70000008 -#define SHT_MIPS_RELD 0x70000009 -#define SHT_MIPS_IFACE 0x7000000b -#define SHT_MIPS_CONTENT 0x7000000c -#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */ -#define SHT_MIPS_SHDR 0x70000010 -#define SHT_MIPS_FDESC 0x70000011 -#define SHT_MIPS_EXTSYM 0x70000012 -#define SHT_MIPS_DENSE 0x70000013 -#define SHT_MIPS_PDESC 0x70000014 -#define SHT_MIPS_LOCSYM 0x70000015 -#define SHT_MIPS_AUXSYM 0x70000016 -#define SHT_MIPS_OPTSYM 0x70000017 -#define SHT_MIPS_LOCSTR 0x70000018 -#define SHT_MIPS_LINE 0x70000019 -#define SHT_MIPS_RFDESC 0x7000001a -#define SHT_MIPS_DELTASYM 0x7000001b -#define SHT_MIPS_DELTAINST 0x7000001c -#define SHT_MIPS_DELTACLASS 0x7000001d -#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */ -#define SHT_MIPS_DELTADECL 0x7000001f -#define SHT_MIPS_SYMBOL_LIB 0x70000020 -#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */ -#define SHT_MIPS_TRANSLATE 0x70000022 -#define SHT_MIPS_PIXIE 0x70000023 -#define SHT_MIPS_XLATE 0x70000024 -#define SHT_MIPS_XLATE_DEBUG 0x70000025 -#define SHT_MIPS_WHIRL 0x70000026 -#define SHT_MIPS_EH_REGION 0x70000027 -#define SHT_MIPS_XLATE_OLD 0x70000028 -#define SHT_MIPS_PDR_EXCEPTION 0x70000029 - -/* Legal values for sh_flags field of Elf32_Shdr. */ - -#define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */ -#define SHF_MIPS_MERGE 0x20000000 -#define SHF_MIPS_ADDR 0x40000000 -#define SHF_MIPS_STRINGS 0x80000000 -#define SHF_MIPS_NOSTRIP 0x08000000 -#define SHF_MIPS_LOCAL 0x04000000 -#define SHF_MIPS_NAMES 0x02000000 -#define SHF_MIPS_NODUPE 0x01000000 - - -/* Symbol tables. */ - -/* MIPS specific values for `st_other'. */ -#define STO_MIPS_DEFAULT 0x0 -#define STO_MIPS_INTERNAL 0x1 -#define STO_MIPS_HIDDEN 0x2 -#define STO_MIPS_PROTECTED 0x3 -#define STO_MIPS_PLT 0x8 -#define STO_MIPS_SC_ALIGN_UNUSED 0xff - -/* MIPS specific values for `st_info'. */ -#define STB_MIPS_SPLIT_COMMON 13 - -/* Entries found in sections of type SHT_MIPS_GPTAB. */ - -typedef union -{ - struct - { - Elf32_Word gt_current_g_value; /* -G value used for compilation */ - Elf32_Word gt_unused; /* Not used */ - } gt_header; /* First entry in section */ - struct - { - Elf32_Word gt_g_value; /* If this value were used for -G */ - Elf32_Word gt_bytes; /* This many bytes would be used */ - } gt_entry; /* Subsequent entries in section */ -} Elf32_gptab; - -/* Entry found in sections of type SHT_MIPS_REGINFO. */ - -typedef struct -{ - Elf32_Word ri_gprmask; /* General registers used */ - Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */ - Elf32_Sword ri_gp_value; /* $gp register value */ -} Elf32_RegInfo; - -/* Entries found in sections of type SHT_MIPS_OPTIONS. */ - -typedef struct -{ - unsigned char kind; /* Determines interpretation of the - variable part of descriptor. */ - unsigned char size; /* Size of descriptor, including header. */ - Elf32_Section section; /* Section header index of section affected, - 0 for global options. */ - Elf32_Word info; /* Kind-specific information. */ -} Elf_Options; - -/* Values for `kind' field in Elf_Options. */ - -#define ODK_NULL 0 /* Undefined. */ -#define ODK_REGINFO 1 /* Register usage information. */ -#define ODK_EXCEPTIONS 2 /* Exception processing options. */ -#define ODK_PAD 3 /* Section padding options. */ -#define ODK_HWPATCH 4 /* Hardware workarounds performed */ -#define ODK_FILL 5 /* record the fill value used by the linker. */ -#define ODK_TAGS 6 /* reserve space for desktop tools to write. */ -#define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */ -#define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */ - -/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */ - -#define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */ -#define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */ -#define OEX_PAGE0 0x10000 /* page zero must be mapped. */ -#define OEX_SMM 0x20000 /* Force sequential memory mode? */ -#define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */ -#define OEX_PRECISEFP OEX_FPDBUG -#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */ - -#define OEX_FPU_INVAL 0x10 -#define OEX_FPU_DIV0 0x08 -#define OEX_FPU_OFLO 0x04 -#define OEX_FPU_UFLO 0x02 -#define OEX_FPU_INEX 0x01 - -/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */ - -#define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */ -#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */ -#define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */ -#define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */ - -#define OPAD_PREFIX 0x1 -#define OPAD_POSTFIX 0x2 -#define OPAD_SYMBOL 0x4 - -/* Entry found in `.options' section. */ - -typedef struct -{ - Elf32_Word hwp_flags1; /* Extra flags. */ - Elf32_Word hwp_flags2; /* Extra flags. */ -} Elf_Options_Hw; - -/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */ - -#define OHWA0_R4KEOP_CHECKED 0x00000001 -#define OHWA1_R4KEOP_CLEAN 0x00000002 - -/* MIPS relocs. */ - -#define R_MIPS_NONE 0 /* No reloc */ -#define R_MIPS_16 1 /* Direct 16 bit */ -#define R_MIPS_32 2 /* Direct 32 bit */ -#define R_MIPS_REL32 3 /* PC relative 32 bit */ -#define R_MIPS_26 4 /* Direct 26 bit shifted */ -#define R_MIPS_HI16 5 /* High 16 bit */ -#define R_MIPS_LO16 6 /* Low 16 bit */ -#define R_MIPS_GPREL16 7 /* GP relative 16 bit */ -#define R_MIPS_LITERAL 8 /* 16 bit literal entry */ -#define R_MIPS_GOT16 9 /* 16 bit GOT entry */ -#define R_MIPS_PC16 10 /* PC relative 16 bit */ -#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ -#define R_MIPS_GPREL32 12 /* GP relative 32 bit */ - -#define R_MIPS_SHIFT5 16 -#define R_MIPS_SHIFT6 17 -#define R_MIPS_64 18 -#define R_MIPS_GOT_DISP 19 -#define R_MIPS_GOT_PAGE 20 -#define R_MIPS_GOT_OFST 21 -#define R_MIPS_GOT_HI16 22 -#define R_MIPS_GOT_LO16 23 -#define R_MIPS_SUB 24 -#define R_MIPS_INSERT_A 25 -#define R_MIPS_INSERT_B 26 -#define R_MIPS_DELETE 27 -#define R_MIPS_HIGHER 28 -#define R_MIPS_HIGHEST 29 -#define R_MIPS_CALL_HI16 30 -#define R_MIPS_CALL_LO16 31 -#define R_MIPS_SCN_DISP 32 -#define R_MIPS_REL16 33 -#define R_MIPS_ADD_IMMEDIATE 34 -#define R_MIPS_PJUMP 35 -#define R_MIPS_RELGOT 36 -#define R_MIPS_JALR 37 -#define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */ -#define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */ -#define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */ -#define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */ -#define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */ -#define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */ -#define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */ -#define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */ -#define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */ -#define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */ -#define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */ -#define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */ -#define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */ -#define R_MIPS_GLOB_DAT 51 -#define R_MIPS_COPY 126 -#define R_MIPS_JUMP_SLOT 127 -/* Keep this the last entry. */ -#define R_MIPS_NUM 128 - -/* Legal values for p_type field of Elf32_Phdr. */ - -#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ -#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ -#define PT_MIPS_OPTIONS 0x70000002 - -/* Special program header types. */ - -#define PF_MIPS_LOCAL 0x10000000 - -/* Legal values for d_tag field of Elf32_Dyn. */ - -#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */ -#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */ -#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */ -#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */ -#define DT_MIPS_FLAGS 0x70000005 /* Flags */ -#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */ -#define DT_MIPS_MSYM 0x70000007 -#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */ -#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */ -#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */ -#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */ -#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */ -#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */ -#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */ -#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */ -#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */ -#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */ -#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */ -#define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in - DT_MIPS_DELTA_CLASS. */ -#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */ -#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in - DT_MIPS_DELTA_INSTANCE. */ -#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */ -#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in - DT_MIPS_DELTA_RELOC. */ -#define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta - relocations refer to. */ -#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in - DT_MIPS_DELTA_SYM. */ -#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the - class declaration. */ -#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in - DT_MIPS_DELTA_CLASSSYM. */ -#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */ -#define DT_MIPS_PIXIE_INIT 0x70000023 -#define DT_MIPS_SYMBOL_LIB 0x70000024 -#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 -#define DT_MIPS_LOCAL_GOTIDX 0x70000026 -#define DT_MIPS_HIDDEN_GOTIDX 0x70000027 -#define DT_MIPS_PROTECTED_GOTIDX 0x70000028 -#define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */ -#define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */ -#define DT_MIPS_DYNSTR_ALIGN 0x7000002b -#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */ -#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve - function stored in GOT. */ -#define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added - by rld on dlopen() calls. */ -#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */ -#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */ -#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */ -/* The address of .got.plt in an executable using the new non-PIC ABI. */ -#define DT_MIPS_PLTGOT 0x70000032 -/* The base of the PLT in an executable using the new non-PIC ABI if that - PLT is writable. For a non-writable PLT, this is omitted or has a zero - value. */ -#define DT_MIPS_RWPLT 0x70000034 -#define DT_MIPS_NUM 0x35 - -/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ - -#define RHF_NONE 0 /* No flags */ -#define RHF_QUICKSTART (1 << 0) /* Use quickstart */ -#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */ -#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */ -#define RHF_NO_MOVE (1 << 3) -#define RHF_SGI_ONLY (1 << 4) -#define RHF_GUARANTEE_INIT (1 << 5) -#define RHF_DELTA_C_PLUS_PLUS (1 << 6) -#define RHF_GUARANTEE_START_INIT (1 << 7) -#define RHF_PIXIE (1 << 8) -#define RHF_DEFAULT_DELAY_LOAD (1 << 9) -#define RHF_REQUICKSTART (1 << 10) -#define RHF_REQUICKSTARTED (1 << 11) -#define RHF_CORD (1 << 12) -#define RHF_NO_UNRES_UNDEF (1 << 13) -#define RHF_RLD_ORDER_SAFE (1 << 14) - -/* Entries found in sections of type SHT_MIPS_LIBLIST. */ - -typedef struct -{ - Elf32_Word l_name; /* Name (string table index) */ - Elf32_Word l_time_stamp; /* Timestamp */ - Elf32_Word l_checksum; /* Checksum */ - Elf32_Word l_version; /* Interface version */ - Elf32_Word l_flags; /* Flags */ -} Elf32_Lib; - -typedef struct -{ - Elf64_Word l_name; /* Name (string table index) */ - Elf64_Word l_time_stamp; /* Timestamp */ - Elf64_Word l_checksum; /* Checksum */ - Elf64_Word l_version; /* Interface version */ - Elf64_Word l_flags; /* Flags */ -} Elf64_Lib; - - -/* Legal values for l_flags. */ - -#define LL_NONE 0 -#define LL_EXACT_MATCH (1 << 0) /* Require exact match */ -#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */ -#define LL_REQUIRE_MINOR (1 << 2) -#define LL_EXPORTS (1 << 3) -#define LL_DELAY_LOAD (1 << 4) -#define LL_DELTA (1 << 5) - -/* Entries found in sections of type SHT_MIPS_CONFLICT. */ - -typedef Elf32_Addr Elf32_Conflict; - - -/* HPPA specific definitions. */ - -/* Legal values for e_flags field of Elf32_Ehdr. */ - -#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ -#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ -#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ -#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ -#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch - prediction. */ -#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ -#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ - -/* Defined values for `e_flags & EF_PARISC_ARCH' are: */ - -#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ -#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ -#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ - -/* Additional section indices. */ - -#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tentatively declared - symbols in ANSI C. */ -#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ - -/* Legal values for sh_type field of Elf32_Shdr. */ - -#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ -#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ -#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ - -/* Legal values for sh_flags field of Elf32_Shdr. */ - -#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ -#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ -#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ - -/* Legal values for ST_TYPE subfield of st_info (symbol type). */ - -#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ - -#define STT_HP_OPAQUE (STT_LOOS + 0x1) -#define STT_HP_STUB (STT_LOOS + 0x2) - -/* HPPA relocs. */ - -#define R_PARISC_NONE 0 /* No reloc. */ -#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ -#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ -#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ -#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ -#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ -#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ -#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ -#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ -#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ -#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ -#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ -#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ -#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ -#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ -#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ -#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ -#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ -#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ -#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ -#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ -#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ -#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ -#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ -#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ -#define R_PARISC_FPTR64 64 /* 64 bits function address. */ -#define R_PARISC_PLABEL32 65 /* 32 bits function address. */ -#define R_PARISC_PLABEL21L 66 /* Left 21 bits of fdesc address. */ -#define R_PARISC_PLABEL14R 70 /* Right 14 bits of fdesc address. */ -#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ -#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ -#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ -#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ -#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ -#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ -#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ -#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ -#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ -#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ -#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ -#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ -#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ -#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ -#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ -#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ -#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ -#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ -#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ -#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ -#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ -#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ -#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ -#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ -#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ -#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ -#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ -#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ -#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ -#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ -#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ -#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ -#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ -#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ -#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ -#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ -#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ -#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ -#define R_PARISC_LORESERVE 128 -#define R_PARISC_COPY 128 /* Copy relocation. */ -#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ -#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ -#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ -#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ -#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ -#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ -#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ -#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ -#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ -#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ -#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ -#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ -#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ -#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ -#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ -#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ -#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ -#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ -#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ -#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ -#define R_PARISC_GNU_VTENTRY 232 -#define R_PARISC_GNU_VTINHERIT 233 -#define R_PARISC_TLS_GD21L 234 /* GD 21-bit left. */ -#define R_PARISC_TLS_GD14R 235 /* GD 14-bit right. */ -#define R_PARISC_TLS_GDCALL 236 /* GD call to __t_g_a. */ -#define R_PARISC_TLS_LDM21L 237 /* LD module 21-bit left. */ -#define R_PARISC_TLS_LDM14R 238 /* LD module 14-bit right. */ -#define R_PARISC_TLS_LDMCALL 239 /* LD module call to __t_g_a. */ -#define R_PARISC_TLS_LDO21L 240 /* LD offset 21-bit left. */ -#define R_PARISC_TLS_LDO14R 241 /* LD offset 14-bit right. */ -#define R_PARISC_TLS_DTPMOD32 242 /* DTP module 32-bit. */ -#define R_PARISC_TLS_DTPMOD64 243 /* DTP module 64-bit. */ -#define R_PARISC_TLS_DTPOFF32 244 /* DTP offset 32-bit. */ -#define R_PARISC_TLS_DTPOFF64 245 /* DTP offset 32-bit. */ -#define R_PARISC_TLS_LE21L R_PARISC_TPREL21L -#define R_PARISC_TLS_LE14R R_PARISC_TPREL14R -#define R_PARISC_TLS_IE21L R_PARISC_LTOFF_TP21L -#define R_PARISC_TLS_IE14R R_PARISC_LTOFF_TP14R -#define R_PARISC_TLS_TPREL32 R_PARISC_TPREL32 -#define R_PARISC_TLS_TPREL64 R_PARISC_TPREL64 -#define R_PARISC_HIRESERVE 255 - -/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ - -#define PT_HP_TLS (PT_LOOS + 0x0) -#define PT_HP_CORE_NONE (PT_LOOS + 0x1) -#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) -#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) -#define PT_HP_CORE_COMM (PT_LOOS + 0x4) -#define PT_HP_CORE_PROC (PT_LOOS + 0x5) -#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) -#define PT_HP_CORE_STACK (PT_LOOS + 0x7) -#define PT_HP_CORE_SHM (PT_LOOS + 0x8) -#define PT_HP_CORE_MMF (PT_LOOS + 0x9) -#define PT_HP_PARALLEL (PT_LOOS + 0x10) -#define PT_HP_FASTBIND (PT_LOOS + 0x11) -#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) -#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) -#define PT_HP_STACK (PT_LOOS + 0x14) - -#define PT_PARISC_ARCHEXT 0x70000000 -#define PT_PARISC_UNWIND 0x70000001 - -/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ - -#define PF_PARISC_SBP 0x08000000 - -#define PF_HP_PAGE_SIZE 0x00100000 -#define PF_HP_FAR_SHARED 0x00200000 -#define PF_HP_NEAR_SHARED 0x00400000 -#define PF_HP_CODE 0x01000000 -#define PF_HP_MODIFY 0x02000000 -#define PF_HP_LAZYSWAP 0x04000000 -#define PF_HP_SBP 0x08000000 - - -/* Alpha specific definitions. */ - -/* Legal values for e_flags field of Elf64_Ehdr. */ - -#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */ -#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */ - -/* Legal values for sh_type field of Elf64_Shdr. */ - -/* These two are primarily concerned with ECOFF debugging info. */ -#define SHT_ALPHA_DEBUG 0x70000001 -#define SHT_ALPHA_REGINFO 0x70000002 - -/* Legal values for sh_flags field of Elf64_Shdr. */ - -#define SHF_ALPHA_GPREL 0x10000000 - -/* Legal values for st_other field of Elf64_Sym. */ -#define STO_ALPHA_NOPV 0x80 /* No PV required. */ -#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */ - -/* Alpha relocs. */ - -#define R_ALPHA_NONE 0 /* No reloc */ -#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ -#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ -#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ -#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ -#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ -#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ -#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ -#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ -#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ -#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ -#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ -#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ -#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ -#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ -#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ -#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ -#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ -#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ -#define R_ALPHA_TLS_GD_HI 28 -#define R_ALPHA_TLSGD 29 -#define R_ALPHA_TLS_LDM 30 -#define R_ALPHA_DTPMOD64 31 -#define R_ALPHA_GOTDTPREL 32 -#define R_ALPHA_DTPREL64 33 -#define R_ALPHA_DTPRELHI 34 -#define R_ALPHA_DTPRELLO 35 -#define R_ALPHA_DTPREL16 36 -#define R_ALPHA_GOTTPREL 37 -#define R_ALPHA_TPREL64 38 -#define R_ALPHA_TPRELHI 39 -#define R_ALPHA_TPRELLO 40 -#define R_ALPHA_TPREL16 41 -/* Keep this the last entry. */ -#define R_ALPHA_NUM 46 - -/* Magic values of the LITUSE relocation addend. */ -#define LITUSE_ALPHA_ADDR 0 -#define LITUSE_ALPHA_BASE 1 -#define LITUSE_ALPHA_BYTOFF 2 -#define LITUSE_ALPHA_JSR 3 -#define LITUSE_ALPHA_TLS_GD 4 -#define LITUSE_ALPHA_TLS_LDM 5 - -/* Legal values for d_tag of Elf64_Dyn. */ -#define DT_ALPHA_PLTRO (DT_LOPROC + 0) -#define DT_ALPHA_NUM 1 - -/* PowerPC specific declarations */ - -/* Values for Elf32/64_Ehdr.e_flags. */ -#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ - -/* Cygnus local bits below */ -#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ -#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib - flag */ - -/* PowerPC relocations defined by the ABIs */ -#define R_PPC_NONE 0 -#define R_PPC_ADDR32 1 /* 32bit absolute address */ -#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ -#define R_PPC_ADDR16 3 /* 16bit absolute address */ -#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ -#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ -#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ -#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ -#define R_PPC_ADDR14_BRTAKEN 8 -#define R_PPC_ADDR14_BRNTAKEN 9 -#define R_PPC_REL24 10 /* PC relative 26 bit */ -#define R_PPC_REL14 11 /* PC relative 16 bit */ -#define R_PPC_REL14_BRTAKEN 12 -#define R_PPC_REL14_BRNTAKEN 13 -#define R_PPC_GOT16 14 -#define R_PPC_GOT16_LO 15 -#define R_PPC_GOT16_HI 16 -#define R_PPC_GOT16_HA 17 -#define R_PPC_PLTREL24 18 -#define R_PPC_COPY 19 -#define R_PPC_GLOB_DAT 20 -#define R_PPC_JMP_SLOT 21 -#define R_PPC_RELATIVE 22 -#define R_PPC_LOCAL24PC 23 -#define R_PPC_UADDR32 24 -#define R_PPC_UADDR16 25 -#define R_PPC_REL32 26 -#define R_PPC_PLT32 27 -#define R_PPC_PLTREL32 28 -#define R_PPC_PLT16_LO 29 -#define R_PPC_PLT16_HI 30 -#define R_PPC_PLT16_HA 31 -#define R_PPC_SDAREL16 32 -#define R_PPC_SECTOFF 33 -#define R_PPC_SECTOFF_LO 34 -#define R_PPC_SECTOFF_HI 35 -#define R_PPC_SECTOFF_HA 36 - -/* PowerPC relocations defined for the TLS access ABI. */ -#define R_PPC_TLS 67 /* none (sym+add)@tls */ -#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */ -#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */ -#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ -#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ -#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ -#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */ -#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */ -#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ -#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ -#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ -#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */ -#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ -#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ -#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ -#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ -#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ -#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ -#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ -#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ -#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */ -#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */ -#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ -#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ -#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */ -#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */ -#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */ -#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */ - -/* The remaining relocs are from the Embedded ELF ABI, and are not - in the SVR4 ELF ABI. */ -#define R_PPC_EMB_NADDR32 101 -#define R_PPC_EMB_NADDR16 102 -#define R_PPC_EMB_NADDR16_LO 103 -#define R_PPC_EMB_NADDR16_HI 104 -#define R_PPC_EMB_NADDR16_HA 105 -#define R_PPC_EMB_SDAI16 106 -#define R_PPC_EMB_SDA2I16 107 -#define R_PPC_EMB_SDA2REL 108 -#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ -#define R_PPC_EMB_MRKREF 110 -#define R_PPC_EMB_RELSEC16 111 -#define R_PPC_EMB_RELST_LO 112 -#define R_PPC_EMB_RELST_HI 113 -#define R_PPC_EMB_RELST_HA 114 -#define R_PPC_EMB_BIT_FLD 115 -#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ - -/* Diab tool relocations. */ -#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ -#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ -#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ -#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ -#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ -#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ - -/* GNU extension to support local ifunc. */ -#define R_PPC_IRELATIVE 248 - -/* GNU relocs used in PIC code sequences. */ -#define R_PPC_REL16 249 /* half16 (sym+add-.) */ -#define R_PPC_REL16_LO 250 /* half16 (sym+add-.)@l */ -#define R_PPC_REL16_HI 251 /* half16 (sym+add-.)@h */ -#define R_PPC_REL16_HA 252 /* half16 (sym+add-.)@ha */ - -/* This is a phony reloc to handle any old fashioned TOC16 references - that may still be in object files. */ -#define R_PPC_TOC16 255 - -/* PowerPC specific values for the Dyn d_tag field. */ -#define DT_PPC_GOT (DT_LOPROC + 0) -#define DT_PPC_NUM 1 - -/* PowerPC64 relocations defined by the ABIs */ -#define R_PPC64_NONE R_PPC_NONE -#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */ -#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */ -#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */ -#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */ -#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */ -#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */ -#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */ -#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN -#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN -#define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */ -#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */ -#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN -#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN -#define R_PPC64_GOT16 R_PPC_GOT16 -#define R_PPC64_GOT16_LO R_PPC_GOT16_LO -#define R_PPC64_GOT16_HI R_PPC_GOT16_HI -#define R_PPC64_GOT16_HA R_PPC_GOT16_HA - -#define R_PPC64_COPY R_PPC_COPY -#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT -#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT -#define R_PPC64_RELATIVE R_PPC_RELATIVE - -#define R_PPC64_UADDR32 R_PPC_UADDR32 -#define R_PPC64_UADDR16 R_PPC_UADDR16 -#define R_PPC64_REL32 R_PPC_REL32 -#define R_PPC64_PLT32 R_PPC_PLT32 -#define R_PPC64_PLTREL32 R_PPC_PLTREL32 -#define R_PPC64_PLT16_LO R_PPC_PLT16_LO -#define R_PPC64_PLT16_HI R_PPC_PLT16_HI -#define R_PPC64_PLT16_HA R_PPC_PLT16_HA - -#define R_PPC64_SECTOFF R_PPC_SECTOFF -#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO -#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI -#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA -#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */ -#define R_PPC64_ADDR64 38 /* doubleword64 S + A */ -#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */ -#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */ -#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */ -#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */ -#define R_PPC64_UADDR64 43 /* doubleword64 S + A */ -#define R_PPC64_REL64 44 /* doubleword64 S + A - P */ -#define R_PPC64_PLT64 45 /* doubleword64 L + A */ -#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */ -#define R_PPC64_TOC16 47 /* half16* S + A - .TOC */ -#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */ -#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */ -#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */ -#define R_PPC64_TOC 51 /* doubleword64 .TOC */ -#define R_PPC64_PLTGOT16 52 /* half16* M + A */ -#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */ -#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */ -#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */ - -#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */ -#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */ -#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */ -#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */ -#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */ -#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */ -#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */ -#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */ -#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */ -#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */ -#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */ - -/* PowerPC64 relocations defined for the TLS access ABI. */ -#define R_PPC64_TLS 67 /* none (sym+add)@tls */ -#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */ -#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */ -#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ -#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ -#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ -#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */ -#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */ -#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ -#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ -#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ -#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */ -#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ -#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ -#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ -#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ -#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ -#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ -#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ -#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ -#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */ -#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */ -#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ -#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ -#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */ -#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */ -#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */ -#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */ -#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */ -#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */ -#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */ -#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */ -#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */ -#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */ -#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */ -#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */ -#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */ -#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */ -#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */ -#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */ - -/* GNU extension to support local ifunc. */ -#define R_PPC64_JMP_IREL 247 -#define R_PPC64_IRELATIVE 248 -#define R_PPC64_REL16 249 /* half16 (sym+add-.) */ -#define R_PPC64_REL16_LO 250 /* half16 (sym+add-.)@l */ -#define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */ -#define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */ - -/* PowerPC64 specific values for the Dyn d_tag field. */ -#define DT_PPC64_GLINK (DT_LOPROC + 0) -#define DT_PPC64_OPD (DT_LOPROC + 1) -#define DT_PPC64_OPDSZ (DT_LOPROC + 2) -#define DT_PPC64_NUM 3 - - -/* ARM specific declarations */ - -/* Processor specific flags for the ELF header e_flags field. */ -#define EF_ARM_RELEXEC 0x01 -#define EF_ARM_HASENTRY 0x02 -#define EF_ARM_INTERWORK 0x04 -#define EF_ARM_APCS_26 0x08 -#define EF_ARM_APCS_FLOAT 0x10 -#define EF_ARM_PIC 0x20 -#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */ -#define EF_ARM_NEW_ABI 0x80 -#define EF_ARM_OLD_ABI 0x100 -#define EF_ARM_SOFT_FLOAT 0x200 -#define EF_ARM_VFP_FLOAT 0x400 -#define EF_ARM_MAVERICK_FLOAT 0x800 - -#define EF_ARM_ABI_FLOAT_SOFT 0x200 /* NB conflicts with EF_ARM_SOFT_FLOAT */ -#define EF_ARM_ABI_FLOAT_HARD 0x400 /* NB conflicts with EF_ARM_VFP_FLOAT */ - - -/* Other constants defined in the ARM ELF spec. version B-01. */ -/* NB. These conflict with values defined above. */ -#define EF_ARM_SYMSARESORTED 0x04 -#define EF_ARM_DYNSYMSUSESEGIDX 0x08 -#define EF_ARM_MAPSYMSFIRST 0x10 -#define EF_ARM_EABIMASK 0XFF000000 - -/* Constants defined in AAELF. */ -#define EF_ARM_BE8 0x00800000 -#define EF_ARM_LE8 0x00400000 - -#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK) -#define EF_ARM_EABI_UNKNOWN 0x00000000 -#define EF_ARM_EABI_VER1 0x01000000 -#define EF_ARM_EABI_VER2 0x02000000 -#define EF_ARM_EABI_VER3 0x03000000 -#define EF_ARM_EABI_VER4 0x04000000 -#define EF_ARM_EABI_VER5 0x05000000 - -/* Additional symbol types for Thumb. */ -#define STT_ARM_TFUNC STT_LOPROC /* A Thumb function. */ -#define STT_ARM_16BIT STT_HIPROC /* A Thumb label. */ - -/* ARM-specific values for sh_flags */ -#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ -#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined - in the input to a link step. */ - -/* ARM-specific program header flags */ -#define PF_ARM_SB 0x10000000 /* Segment contains the location - addressed by the static base. */ -#define PF_ARM_PI 0x20000000 /* Position-independent segment. */ -#define PF_ARM_ABS 0x40000000 /* Absolute segment. */ - -/* Processor specific values for the Phdr p_type field. */ -#define PT_ARM_EXIDX (PT_LOPROC + 1) /* ARM unwind segment. */ - -/* Processor specific values for the Shdr sh_type field. */ -#define SHT_ARM_EXIDX (SHT_LOPROC + 1) /* ARM unwind section. */ -#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) /* Preemption details. */ -#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */ - - -/* AArch64 relocs. */ - -#define R_AARCH64_NONE 0 /* No relocation. */ -#define R_AARCH64_ABS64 257 /* Direct 64 bit. */ -#define R_AARCH64_ABS32 258 /* Direct 32 bit. */ -#define R_AARCH64_ABS16 259 /* Direct 16-bit. */ -#define R_AARCH64_PREL64 260 /* PC-relative 64-bit. */ -#define R_AARCH64_PREL32 261 /* PC-relative 32-bit. */ -#define R_AARCH64_PREL16 262 /* PC-relative 16-bit. */ -#define R_AARCH64_MOVW_UABS_G0 263 /* Dir. MOVZ imm. from bits 15:0. */ -#define R_AARCH64_MOVW_UABS_G0_NC 264 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_UABS_G1 265 /* Dir. MOVZ imm. from bits 31:16. */ -#define R_AARCH64_MOVW_UABS_G1_NC 266 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_UABS_G2 267 /* Dir. MOVZ imm. from bits 47:32. */ -#define R_AARCH64_MOVW_UABS_G2_NC 268 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_UABS_G3 269 /* Dir. MOV{K,Z} imm. from 63:48. */ -#define R_AARCH64_MOVW_SABS_G0 270 /* Dir. MOV{N,Z} imm. from 15:0. */ -#define R_AARCH64_MOVW_SABS_G1 271 /* Dir. MOV{N,Z} imm. from 31:16. */ -#define R_AARCH64_MOVW_SABS_G2 272 /* Dir. MOV{N,Z} imm. from 47:32. */ -#define R_AARCH64_LD_PREL_LO19 273 /* PC-rel. LD imm. from bits 20:2. */ -#define R_AARCH64_ADR_PREL_LO21 274 /* PC-rel. ADR imm. from bits 20:0. */ -#define R_AARCH64_ADR_PREL_PG_HI21 275 /* Page-rel. ADRP imm. from 32:12. */ -#define R_AARCH64_ADR_PREL_PG_HI21_NC 276 /* Likewise; no overflow check. */ -#define R_AARCH64_ADD_ABS_LO12_NC 277 /* Dir. ADD imm. from bits 11:0. */ -#define R_AARCH64_LDST8_ABS_LO12_NC 278 /* Likewise for LD/ST; no check. */ -#define R_AARCH64_TSTBR14 279 /* PC-rel. TBZ/TBNZ imm. from 15:2. */ -#define R_AARCH64_CONDBR19 280 /* PC-rel. cond. br. imm. from 20:2. */ -#define R_AARCH64_JUMP26 282 /* PC-rel. B imm. from bits 27:2. */ -#define R_AARCH64_CALL26 283 /* Likewise for CALL. */ -#define R_AARCH64_LDST16_ABS_LO12_NC 284 /* Dir. ADD imm. from bits 11:1. */ -#define R_AARCH64_LDST32_ABS_LO12_NC 285 /* Likewise for bits 11:2. */ -#define R_AARCH64_LDST64_ABS_LO12_NC 286 /* Likewise for bits 11:3. */ -#define R_AARCH64_MOVW_PREL_G0 287 /* PC-rel. MOV{N,Z} imm. from 15:0. */ -#define R_AARCH64_MOVW_PREL_G0_NC 288 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_PREL_G1 289 /* PC-rel. MOV{N,Z} imm. from 31:16. */ -#define R_AARCH64_MOVW_PREL_G1_NC 290 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_PREL_G2 291 /* PC-rel. MOV{N,Z} imm. from 47:32. */ -#define R_AARCH64_MOVW_PREL_G2_NC 292 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_PREL_G3 293 /* PC-rel. MOV{N,Z} imm. from 63:48. */ -#define R_AARCH64_LDST128_ABS_LO12_NC 299 /* Dir. ADD imm. from bits 11:4. */ -#define R_AARCH64_MOVW_GOTOFF_G0 300 /* GOT-rel. off. MOV{N,Z} imm. 15:0. */ -#define R_AARCH64_MOVW_GOTOFF_G0_NC 301 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_GOTOFF_G1 302 /* GOT-rel. o. MOV{N,Z} imm. 31:16. */ -#define R_AARCH64_MOVW_GOTOFF_G1_NC 303 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_GOTOFF_G2 304 /* GOT-rel. o. MOV{N,Z} imm. 47:32. */ -#define R_AARCH64_MOVW_GOTOFF_G2_NC 305 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_GOTOFF_G3 306 /* GOT-rel. o. MOV{N,Z} imm. 63:48. */ -#define R_AARCH64_GOTREL64 307 /* GOT-relative 64-bit. */ -#define R_AARCH64_GOTREL32 308 /* GOT-relative 32-bit. */ -#define R_AARCH64_GOT_LD_PREL19 309 /* PC-rel. GOT off. load imm. 20:2. */ -#define R_AARCH64_LD64_GOTOFF_LO15 310 /* GOT-rel. off. LD/ST imm. 14:3. */ -#define R_AARCH64_ADR_GOT_PAGE 311 /* P-page-rel. GOT off. ADRP 32:12. */ -#define R_AARCH64_LD64_GOT_LO12_NC 312 /* Dir. GOT off. LD/ST imm. 11:3. */ -#define R_AARCH64_LD64_GOTPAGE_LO15 313 /* GOT-page-rel. GOT off. LD/ST 14:3 */ -#define R_AARCH64_TLSGD_ADR_PREL21 512 /* PC-relative ADR imm. 20:0. */ -#define R_AARCH64_TLSGD_ADR_PAGE21 513 /* page-rel. ADRP imm. 32:12. */ -#define R_AARCH64_TLSGD_ADD_LO12_NC 514 /* direct ADD imm. from 11:0. */ -#define R_AARCH64_TLSGD_MOVW_G1 515 /* GOT-rel. MOV{N,Z} 31:16. */ -#define R_AARCH64_TLSGD_MOVW_G0_NC 516 /* GOT-rel. MOVK imm. 15:0. */ -#define R_AARCH64_TLSLD_ADR_PREL21 517 /* Like 512; local dynamic model. */ -#define R_AARCH64_TLSLD_ADR_PAGE21 518 /* Like 513; local dynamic model. */ -#define R_AARCH64_TLSLD_ADD_LO12_NC 519 /* Like 514; local dynamic model. */ -#define R_AARCH64_TLSLD_MOVW_G1 520 /* Like 515; local dynamic model. */ -#define R_AARCH64_TLSLD_MOVW_G0_NC 521 /* Like 516; local dynamic model. */ -#define R_AARCH64_TLSLD_LD_PREL19 522 /* TLS PC-rel. load imm. 20:2. */ -#define R_AARCH64_TLSLD_MOVW_DTPREL_G2 523 /* TLS DTP-rel. MOV{N,Z} 47:32. */ -#define R_AARCH64_TLSLD_MOVW_DTPREL_G1 524 /* TLS DTP-rel. MOV{N,Z} 31:16. */ -#define R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC 525 /* Likewise; MOVK; no check. */ -#define R_AARCH64_TLSLD_MOVW_DTPREL_G0 526 /* TLS DTP-rel. MOV{N,Z} 15:0. */ -#define R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC 527 /* Likewise; MOVK; no check. */ -#define R_AARCH64_TLSLD_ADD_DTPREL_HI12 528 /* DTP-rel. ADD imm. from 23:12. */ -#define R_AARCH64_TLSLD_ADD_DTPREL_LO12 529 /* DTP-rel. ADD imm. from 11:0. */ -#define R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC 530 /* Likewise; no ovfl. check. */ -#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12 531 /* DTP-rel. LD/ST imm. 11:0. */ -#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC 532 /* Likewise; no check. */ -#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12 533 /* DTP-rel. LD/ST imm. 11:1. */ -#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC 534 /* Likewise; no check. */ -#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12 535 /* DTP-rel. LD/ST imm. 11:2. */ -#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC 536 /* Likewise; no check. */ -#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12 537 /* DTP-rel. LD/ST imm. 11:3. */ -#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC 538 /* Likewise; no check. */ -#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 539 /* GOT-rel. MOV{N,Z} 31:16. */ -#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC 540 /* GOT-rel. MOVK 15:0. */ -#define R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 541 /* Page-rel. ADRP 32:12. */ -#define R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC 542 /* Direct LD off. 11:3. */ -#define R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 543 /* PC-rel. load imm. 20:2. */ -#define R_AARCH64_TLSLE_MOVW_TPREL_G2 544 /* TLS TP-rel. MOV{N,Z} 47:32. */ -#define R_AARCH64_TLSLE_MOVW_TPREL_G1 545 /* TLS TP-rel. MOV{N,Z} 31:16. */ -#define R_AARCH64_TLSLE_MOVW_TPREL_G1_NC 546 /* Likewise; MOVK; no check. */ -#define R_AARCH64_TLSLE_MOVW_TPREL_G0 547 /* TLS TP-rel. MOV{N,Z} 15:0. */ -#define R_AARCH64_TLSLE_MOVW_TPREL_G0_NC 548 /* Likewise; MOVK; no check. */ -#define R_AARCH64_TLSLE_ADD_TPREL_HI12 549 /* TP-rel. ADD imm. 23:12. */ -#define R_AARCH64_TLSLE_ADD_TPREL_LO12 550 /* TP-rel. ADD imm. 11:0. */ -#define R_AARCH64_TLSLE_ADD_TPREL_LO12_NC 551 /* Likewise; no ovfl. check. */ -#define R_AARCH64_TLSLE_LDST8_TPREL_LO12 552 /* TP-rel. LD/ST off. 11:0. */ -#define R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC 553 /* Likewise; no ovfl. check. */ -#define R_AARCH64_TLSLE_LDST16_TPREL_LO12 554 /* TP-rel. LD/ST off. 11:1. */ -#define R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC 555 /* Likewise; no check. */ -#define R_AARCH64_TLSLE_LDST32_TPREL_LO12 556 /* TP-rel. LD/ST off. 11:2. */ -#define R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC 557 /* Likewise; no check. */ -#define R_AARCH64_TLSLE_LDST64_TPREL_LO12 558 /* TP-rel. LD/ST off. 11:3. */ -#define R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC 559 /* Likewise; no check. */ -#define R_AARCH64_TLSDESC_LD_PREL19 560 /* PC-rel. load immediate 20:2. */ -#define R_AARCH64_TLSDESC_ADR_PREL21 561 /* PC-rel. ADR immediate 20:0. */ -#define R_AARCH64_TLSDESC_ADR_PAGE21 562 /* Page-rel. ADRP imm. 32:12. */ -#define R_AARCH64_TLSDESC_LD64_LO12 563 /* Direct LD off. from 11:3. */ -#define R_AARCH64_TLSDESC_ADD_LO12 564 /* Direct ADD imm. from 11:0. */ -#define R_AARCH64_TLSDESC_OFF_G1 565 /* GOT-rel. MOV{N,Z} imm. 31:16. */ -#define R_AARCH64_TLSDESC_OFF_G0_NC 566 /* GOT-rel. MOVK imm. 15:0; no ck. */ -#define R_AARCH64_TLSDESC_LDR 567 /* Relax LDR. */ -#define R_AARCH64_TLSDESC_ADD 568 /* Relax ADD. */ -#define R_AARCH64_TLSDESC_CALL 569 /* Relax BLR. */ -#define R_AARCH64_TLSLE_LDST128_TPREL_LO12 570 /* TP-rel. LD/ST off. 11:4. */ -#define R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC 571 /* Likewise; no check. */ -#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12 572 /* DTP-rel. LD/ST imm. 11:4. */ -#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC 573 /* Likewise; no check. */ -#define R_AARCH64_COPY 1024 /* Copy symbol at runtime. */ -#define R_AARCH64_GLOB_DAT 1025 /* Create GOT entry. */ -#define R_AARCH64_JUMP_SLOT 1026 /* Create PLT entry. */ -#define R_AARCH64_RELATIVE 1027 /* Adjust by program base. */ -#define R_AARCH64_TLS_DTPMOD64 1028 /* Module number, 64 bit. */ -#define R_AARCH64_TLS_DTPREL64 1029 /* Module-relative offset, 64 bit. */ -#define R_AARCH64_TLS_TPREL64 1030 /* TP-relative offset, 64 bit. */ -#define R_AARCH64_TLSDESC 1031 /* TLS Descriptor. */ -#define R_AARCH64_IRELATIVE 1032 /* STT_GNU_IFUNC relocation. */ -/* Keep this the last entry. */ -#define R_AARCH64_NUM 1033 - -/* ARM relocs. */ - -#define R_ARM_NONE 0 /* No reloc */ -#define R_ARM_PC24 1 /* PC relative 26 bit branch */ -#define R_ARM_ABS32 2 /* Direct 32 bit */ -#define R_ARM_REL32 3 /* PC relative 32 bit */ -#define R_ARM_PC13 4 -#define R_ARM_ABS16 5 /* Direct 16 bit */ -#define R_ARM_ABS12 6 /* Direct 12 bit */ -#define R_ARM_THM_ABS5 7 -#define R_ARM_ABS8 8 /* Direct 8 bit */ -#define R_ARM_SBREL32 9 -#define R_ARM_THM_PC22 10 -#define R_ARM_THM_PC8 11 -#define R_ARM_AMP_VCALL9 12 -#define R_ARM_SWI24 13 /* Obsolete static relocation. */ -#define R_ARM_TLS_DESC 13 /* Dynamic relocation. */ -#define R_ARM_THM_SWI8 14 -#define R_ARM_XPC25 15 -#define R_ARM_THM_XPC22 16 -#define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */ -#define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */ -#define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */ -#define R_ARM_COPY 20 /* Copy symbol at runtime */ -#define R_ARM_GLOB_DAT 21 /* Create GOT entry */ -#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ -#define R_ARM_RELATIVE 23 /* Adjust by program base */ -#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ -#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ -#define R_ARM_GOT32 26 /* 32 bit GOT entry */ -#define R_ARM_PLT32 27 /* 32 bit PLT address */ -#define R_ARM_CALL 28 -#define R_ARM_JUMP24 29 -#define R_ARM_THM_JUMP24 30 -#define R_ARM_BASE_ABS 31 /* Adjust by program base. */ -#define R_ARM_ALU_PCREL_7_0 32 -#define R_ARM_ALU_PCREL_15_8 33 -#define R_ARM_ALU_PCREL_23_15 34 -#define R_ARM_LDR_SBREL_11_0 35 -#define R_ARM_ALU_SBREL_19_12 36 -#define R_ARM_ALU_SBREL_27_20 37 -#define R_ARM_TARGET1 38 -#define R_ARM_SBREL31 39 /* Program base relative. */ -#define R_ARM_V4BX 40 -#define R_ARM_TARGET2 41 -#define R_ARM_PREL31 42 -#define R_ARM_MOVW_ABS_NC 43 -#define R_ARM_MOVT_ABS 44 -#define R_ARM_MOVW_PREL_NC 45 /* PC relative 16-bit (MOVW). */ -#define R_ARM_MOVT_PREL 46 /* PC relative (MOVT). */ -#define R_ARM_THM_MOVW_ABS_NC 47 -#define R_ARM_THM_MOVT_ABS 48 -/* Values from 49 to 89 are not yet used/handled by tcc. */ -#define R_ARM_TLS_GOTDESC 90 -#define R_ARM_TLS_CALL 91 -#define R_ARM_TLS_DESCSEQ 92 -#define R_ARM_THM_TLS_CALL 93 -#define R_ARM_GOT_PREL 96 -#define R_ARM_GNU_VTENTRY 100 -#define R_ARM_GNU_VTINHERIT 101 -#define R_ARM_THM_PC11 102 /* thumb unconditional branch */ -#define R_ARM_THM_PC9 103 /* thumb conditional branch */ -#define R_ARM_TLS_GD32 104 /* PC-rel 32 bit for global dynamic - thread local data */ -#define R_ARM_TLS_LDM32 105 /* PC-rel 32 bit for local dynamic - thread local data */ -#define R_ARM_TLS_LDO32 106 /* 32 bit offset relative to TLS - block */ -#define R_ARM_TLS_IE32 107 /* PC-rel 32 bit for GOT entry of - static TLS block offset */ -#define R_ARM_TLS_LE32 108 /* 32 bit offset relative to static - TLS block */ -#define R_ARM_THM_TLS_DESCSEQ 129 -#define R_ARM_IRELATIVE 160 -#define R_ARM_RXPC25 249 -#define R_ARM_RSBREL32 250 -#define R_ARM_THM_RPC22 251 -#define R_ARM_RREL32 252 -#define R_ARM_RABS22 253 -#define R_ARM_RPC24 254 -#define R_ARM_RBASE 255 -/* Keep this the last entry. */ -#define R_ARM_NUM 256 - -/* TMS320C67xx specific declarations */ - -/* XXX: no ELF standard yet*/ - -/* TMS320C67xx relocs. */ -#define R_C60_32 1 -#define R_C60_GOT32 3 /* 32 bit GOT entry */ -#define R_C60_PLT32 4 /* 32 bit PLT address */ -#define R_C60_COPY 5 /* Copy symbol at runtime */ -#define R_C60_GLOB_DAT 6 /* Create GOT entry */ -#define R_C60_JMP_SLOT 7 /* Create PLT entry */ -#define R_C60_RELATIVE 8 /* Adjust by program base */ -#define R_C60_GOTOFF 9 /* 32 bit offset to GOT */ -#define R_C60_GOTPC 10 /* 32 bit PC relative offset to GOT */ - -#define R_C60LO16 0x54 /* low 16 bit MVKL embedded */ -#define R_C60HI16 0x55 /* high 16 bit MVKH embedded */ -/* Keep this the last entry. */ -#define R_C60_NUM 0x56 - -/* IA-64 specific declarations. */ - -/* Processor specific flags for the Ehdr e_flags field. */ -#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ -#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ -#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ - -/* Processor specific values for the Phdr p_type field. */ -#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ -#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ -#define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12) -#define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13) -#define PT_IA_64_HP_STACK (PT_LOOS + 0x14) - -/* Processor specific flags for the Phdr p_flags field. */ -#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ - -/* Processor specific values for the Shdr sh_type field. */ -#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ -#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ - -/* Processor specific flags for the Shdr sh_flags field. */ -#define SHF_IA_64_SHORT 0x10000000 /* section near gp */ -#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ - -/* Processor specific values for the Dyn d_tag field. */ -#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) -#define DT_IA_64_NUM 1 - -/* IA-64 relocations. */ -#define R_IA64_NONE 0x00 /* none */ -#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ -#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ -#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ -#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ -#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ -#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ -#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ -#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ -#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ -#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ -#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ -#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ -#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ -#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ -#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ -#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ -#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ -#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ -#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ -#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ -#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ -#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ -#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ -#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ -#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ -#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ -#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ -#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ -#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ -#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ -#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ -#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ -#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ -#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ -#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ -#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ -#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ -#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ -#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ -#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ -#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ -#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ -#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ -#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ -#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ -#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ -#define R_IA64_REL32MSB 0x6c /* data 4 + REL */ -#define R_IA64_REL32LSB 0x6d /* data 4 + REL */ -#define R_IA64_REL64MSB 0x6e /* data 8 + REL */ -#define R_IA64_REL64LSB 0x6f /* data 8 + REL */ -#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ -#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ -#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ -#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ -#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ -#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ -#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ -#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ -#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ -#define R_IA64_COPY 0x84 /* copy relocation */ -#define R_IA64_SUB 0x85 /* Addend and symbol difference */ -#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ -#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ -#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ -#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ -#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ -#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ -#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ -#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ -#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ -#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ -#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ -#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ -#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ -#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ -#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ -#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ -#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ -#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ -#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ - -/* SH specific declarations */ - -/* Processor specific flags for the ELF header e_flags field. */ -#define EF_SH_MACH_MASK 0x1f -#define EF_SH_UNKNOWN 0x0 -#define EF_SH1 0x1 -#define EF_SH2 0x2 -#define EF_SH3 0x3 -#define EF_SH_DSP 0x4 -#define EF_SH3_DSP 0x5 -#define EF_SH4AL_DSP 0x6 -#define EF_SH3E 0x8 -#define EF_SH4 0x9 -#define EF_SH2E 0xb -#define EF_SH4A 0xc -#define EF_SH2A 0xd -#define EF_SH4_NOFPU 0x10 -#define EF_SH4A_NOFPU 0x11 -#define EF_SH4_NOMMU_NOFPU 0x12 -#define EF_SH2A_NOFPU 0x13 -#define EF_SH3_NOMMU 0x14 -#define EF_SH2A_SH4_NOFPU 0x15 -#define EF_SH2A_SH3_NOFPU 0x16 -#define EF_SH2A_SH4 0x17 -#define EF_SH2A_SH3E 0x18 - -/* SH relocs. */ -#define R_SH_NONE 0 -#define R_SH_DIR32 1 -#define R_SH_REL32 2 -#define R_SH_DIR8WPN 3 -#define R_SH_IND12W 4 -#define R_SH_DIR8WPL 5 -#define R_SH_DIR8WPZ 6 -#define R_SH_DIR8BP 7 -#define R_SH_DIR8W 8 -#define R_SH_DIR8L 9 -#define R_SH_SWITCH16 25 -#define R_SH_SWITCH32 26 -#define R_SH_USES 27 -#define R_SH_COUNT 28 -#define R_SH_ALIGN 29 -#define R_SH_CODE 30 -#define R_SH_DATA 31 -#define R_SH_LABEL 32 -#define R_SH_SWITCH8 33 -#define R_SH_GNU_VTINHERIT 34 -#define R_SH_GNU_VTENTRY 35 -#define R_SH_TLS_GD_32 144 -#define R_SH_TLS_LD_32 145 -#define R_SH_TLS_LDO_32 146 -#define R_SH_TLS_IE_32 147 -#define R_SH_TLS_LE_32 148 -#define R_SH_TLS_DTPMOD32 149 -#define R_SH_TLS_DTPOFF32 150 -#define R_SH_TLS_TPOFF32 151 -#define R_SH_GOT32 160 -#define R_SH_PLT32 161 -#define R_SH_COPY 162 -#define R_SH_GLOB_DAT 163 -#define R_SH_JMP_SLOT 164 -#define R_SH_RELATIVE 165 -#define R_SH_GOTOFF 166 -#define R_SH_GOTPC 167 -/* Keep this the last entry. */ -#define R_SH_NUM 256 - -/* S/390 specific definitions. */ - -/* Valid values for the e_flags field. */ - -#define EF_S390_HIGH_GPRS 0x00000001 /* High GPRs kernel facility needed. */ - -/* Additional s390 relocs */ - -#define R_390_NONE 0 /* No reloc. */ -#define R_390_8 1 /* Direct 8 bit. */ -#define R_390_12 2 /* Direct 12 bit. */ -#define R_390_16 3 /* Direct 16 bit. */ -#define R_390_32 4 /* Direct 32 bit. */ -#define R_390_PC32 5 /* PC relative 32 bit. */ -#define R_390_GOT12 6 /* 12 bit GOT offset. */ -#define R_390_GOT32 7 /* 32 bit GOT offset. */ -#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ -#define R_390_COPY 9 /* Copy symbol at runtime. */ -#define R_390_GLOB_DAT 10 /* Create GOT entry. */ -#define R_390_JMP_SLOT 11 /* Create PLT entry. */ -#define R_390_RELATIVE 12 /* Adjust by program base. */ -#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ -#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */ -#define R_390_GOT16 15 /* 16 bit GOT offset. */ -#define R_390_PC16 16 /* PC relative 16 bit. */ -#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ -#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ -#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ -#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ -#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ -#define R_390_64 22 /* Direct 64 bit. */ -#define R_390_PC64 23 /* PC relative 64 bit. */ -#define R_390_GOT64 24 /* 64 bit GOT offset. */ -#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ -#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ -#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ -#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ -#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ -#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ -#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ -#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ -#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ -#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ -#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ -#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ -#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ -#define R_390_TLS_GDCALL 38 /* Tag for function call in general - dynamic TLS code. */ -#define R_390_TLS_LDCALL 39 /* Tag for function call in local - dynamic TLS code. */ -#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic - thread local data. */ -#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic - thread local data. */ -#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS - block offset. */ -#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS - block offset. */ -#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS - block offset. */ -#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic - thread local data in LE code. */ -#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic - thread local data in LE code. */ -#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for - negated static TLS block offset. */ -#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for - negated static TLS block offset. */ -#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for - negated static TLS block offset. */ -#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to - static TLS block. */ -#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to - static TLS block. */ -#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS - block. */ -#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS - block. */ -#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ -#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ -#define R_390_TLS_TPOFF 56 /* Negated offset in static TLS - block. */ -#define R_390_20 57 /* Direct 20 bit. */ -#define R_390_GOT20 58 /* 20 bit GOT offset. */ -#define R_390_GOTPLT20 59 /* 20 bit offset to jump slot. */ -#define R_390_TLS_GOTIE20 60 /* 20 bit GOT offset for static TLS - block offset. */ -#define R_390_IRELATIVE 61 /* STT_GNU_IFUNC relocation. */ -/* Keep this the last entry. */ -#define R_390_NUM 62 - - -/* CRIS relocations. */ -#define R_CRIS_NONE 0 -#define R_CRIS_8 1 -#define R_CRIS_16 2 -#define R_CRIS_32 3 -#define R_CRIS_8_PCREL 4 -#define R_CRIS_16_PCREL 5 -#define R_CRIS_32_PCREL 6 -#define R_CRIS_GNU_VTINHERIT 7 -#define R_CRIS_GNU_VTENTRY 8 -#define R_CRIS_COPY 9 -#define R_CRIS_GLOB_DAT 10 -#define R_CRIS_JUMP_SLOT 11 -#define R_CRIS_RELATIVE 12 -#define R_CRIS_16_GOT 13 -#define R_CRIS_32_GOT 14 -#define R_CRIS_16_GOTPLT 15 -#define R_CRIS_32_GOTPLT 16 -#define R_CRIS_32_GOTREL 17 -#define R_CRIS_32_PLT_GOTREL 18 -#define R_CRIS_32_PLT_PCREL 19 - -#define R_CRIS_NUM 20 - - -/* AMD x86-64 relocations. */ -#define R_X86_64_NONE 0 /* No reloc */ -#define R_X86_64_64 1 /* Direct 64 bit */ -#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ -#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ -#define R_X86_64_PLT32 4 /* 32 bit PLT address */ -#define R_X86_64_COPY 5 /* Copy symbol at runtime */ -#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ -#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ -#define R_X86_64_RELATIVE 8 /* Adjust by program base */ -#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative - offset to GOT */ -#define R_X86_64_32 10 /* Direct 32 bit zero extended */ -#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ -#define R_X86_64_16 12 /* Direct 16 bit zero extended */ -#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ -#define R_X86_64_8 14 /* Direct 8 bit sign extended */ -#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ -#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ -#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */ -#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */ -#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset - to two GOT entries for GD symbol */ -#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset - to two GOT entries for LD symbol */ -#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ -#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset - to GOT entry for IE symbol */ -#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */ -#define R_X86_64_PC64 24 /* PC relative 64 bit */ -#define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */ -#define R_X86_64_GOTPC32 26 /* 32 bit signed pc relative - offset to GOT */ -#define R_X86_64_GOT64 27 /* 64-bit GOT entry offset */ -#define R_X86_64_GOTPCREL64 28 /* 64-bit PC relative offset - to GOT entry */ -#define R_X86_64_GOTPC64 29 /* 64-bit PC relative offset to GOT */ -#define R_X86_64_GOTPLT64 30 /* like GOT64, says PLT entry needed */ -#define R_X86_64_PLTOFF64 31 /* 64-bit GOT relative offset - to PLT entry */ -#define R_X86_64_SIZE32 32 /* Size of symbol plus 32-bit addend */ -#define R_X86_64_SIZE64 33 /* Size of symbol plus 64-bit addend */ -#define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor. */ -#define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS - descriptor. */ -#define R_X86_64_TLSDESC 36 /* TLS descriptor. */ -#define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */ -#define R_X86_64_RELATIVE64 38 /* 64-bit adjust by program base */ -#define R_X86_64_GOTPCRELX 41 /* like GOTPCREL, but optionally with - linker optimizations */ -#define R_X86_64_REX_GOTPCRELX 42 /* like GOTPCRELX, but a REX prefix - is present */ - -#define R_X86_64_NUM 43 - -/* x86-64 sh_type values. */ -#define SHT_X86_64_UNWIND 0x70000001 /* Unwind information. */ - -/* AM33 relocations. */ -#define R_MN10300_NONE 0 /* No reloc. */ -#define R_MN10300_32 1 /* Direct 32 bit. */ -#define R_MN10300_16 2 /* Direct 16 bit. */ -#define R_MN10300_8 3 /* Direct 8 bit. */ -#define R_MN10300_PCREL32 4 /* PC-relative 32-bit. */ -#define R_MN10300_PCREL16 5 /* PC-relative 16-bit signed. */ -#define R_MN10300_PCREL8 6 /* PC-relative 8-bit signed. */ -#define R_MN10300_GNU_VTINHERIT 7 /* Ancient C++ vtable garbage... */ -#define R_MN10300_GNU_VTENTRY 8 /* ... collection annotation. */ -#define R_MN10300_24 9 /* Direct 24 bit. */ -#define R_MN10300_GOTPC32 10 /* 32-bit PCrel offset to GOT. */ -#define R_MN10300_GOTPC16 11 /* 16-bit PCrel offset to GOT. */ -#define R_MN10300_GOTOFF32 12 /* 32-bit offset from GOT. */ -#define R_MN10300_GOTOFF24 13 /* 24-bit offset from GOT. */ -#define R_MN10300_GOTOFF16 14 /* 16-bit offset from GOT. */ -#define R_MN10300_PLT32 15 /* 32-bit PCrel to PLT entry. */ -#define R_MN10300_PLT16 16 /* 16-bit PCrel to PLT entry. */ -#define R_MN10300_GOT32 17 /* 32-bit offset to GOT entry. */ -#define R_MN10300_GOT24 18 /* 24-bit offset to GOT entry. */ -#define R_MN10300_GOT16 19 /* 16-bit offset to GOT entry. */ -#define R_MN10300_COPY 20 /* Copy symbol at runtime. */ -#define R_MN10300_GLOB_DAT 21 /* Create GOT entry. */ -#define R_MN10300_JMP_SLOT 22 /* Create PLT entry. */ -#define R_MN10300_RELATIVE 23 /* Adjust by program base. */ -#define R_MN10300_TLS_GD 24 /* 32-bit offset for global dynamic. */ -#define R_MN10300_TLS_LD 25 /* 32-bit offset for local dynamic. */ -#define R_MN10300_TLS_LDO 26 /* Module-relative offset. */ -#define R_MN10300_TLS_GOTIE 27 /* GOT offset for static TLS block - offset. */ -#define R_MN10300_TLS_IE 28 /* GOT address for static TLS block - offset. */ -#define R_MN10300_TLS_LE 29 /* Offset relative to static TLS - block. */ -#define R_MN10300_TLS_DTPMOD 30 /* ID of module containing symbol. */ -#define R_MN10300_TLS_DTPOFF 31 /* Offset in module TLS block. */ -#define R_MN10300_TLS_TPOFF 32 /* Offset in static TLS block. */ -#define R_MN10300_SYM_DIFF 33 /* Adjustment for next reloc as needed - by linker relaxation. */ -#define R_MN10300_ALIGN 34 /* Alignment requirement for linker - relaxation. */ -#define R_MN10300_NUM 35 - - -/* M32R relocs. */ -#define R_M32R_NONE 0 /* No reloc. */ -#define R_M32R_16 1 /* Direct 16 bit. */ -#define R_M32R_32 2 /* Direct 32 bit. */ -#define R_M32R_24 3 /* Direct 24 bit. */ -#define R_M32R_10_PCREL 4 /* PC relative 10 bit shifted. */ -#define R_M32R_18_PCREL 5 /* PC relative 18 bit shifted. */ -#define R_M32R_26_PCREL 6 /* PC relative 26 bit shifted. */ -#define R_M32R_HI16_ULO 7 /* High 16 bit with unsigned low. */ -#define R_M32R_HI16_SLO 8 /* High 16 bit with signed low. */ -#define R_M32R_LO16 9 /* Low 16 bit. */ -#define R_M32R_SDA16 10 /* 16 bit offset in SDA. */ -#define R_M32R_GNU_VTINHERIT 11 -#define R_M32R_GNU_VTENTRY 12 -/* M32R relocs use SHT_RELA. */ -#define R_M32R_16_RELA 33 /* Direct 16 bit. */ -#define R_M32R_32_RELA 34 /* Direct 32 bit. */ -#define R_M32R_24_RELA 35 /* Direct 24 bit. */ -#define R_M32R_10_PCREL_RELA 36 /* PC relative 10 bit shifted. */ -#define R_M32R_18_PCREL_RELA 37 /* PC relative 18 bit shifted. */ -#define R_M32R_26_PCREL_RELA 38 /* PC relative 26 bit shifted. */ -#define R_M32R_HI16_ULO_RELA 39 /* High 16 bit with unsigned low */ -#define R_M32R_HI16_SLO_RELA 40 /* High 16 bit with signed low */ -#define R_M32R_LO16_RELA 41 /* Low 16 bit */ -#define R_M32R_SDA16_RELA 42 /* 16 bit offset in SDA */ -#define R_M32R_RELA_GNU_VTINHERIT 43 -#define R_M32R_RELA_GNU_VTENTRY 44 -#define R_M32R_REL32 45 /* PC relative 32 bit. */ - -#define R_M32R_GOT24 48 /* 24 bit GOT entry */ -#define R_M32R_26_PLTREL 49 /* 26 bit PC relative to PLT shifted */ -#define R_M32R_COPY 50 /* Copy symbol at runtime */ -#define R_M32R_GLOB_DAT 51 /* Create GOT entry */ -#define R_M32R_JMP_SLOT 52 /* Create PLT entry */ -#define R_M32R_RELATIVE 53 /* Adjust by program base */ -#define R_M32R_GOTOFF 54 /* 24 bit offset to GOT */ -#define R_M32R_GOTPC24 55 /* 24 bit PC relative offset to GOT */ -#define R_M32R_GOT16_HI_ULO 56 /* High 16 bit GOT entry with unsigned - low */ -#define R_M32R_GOT16_HI_SLO 57 /* High 16 bit GOT entry with signed - low */ -#define R_M32R_GOT16_LO 58 /* Low 16 bit GOT entry */ -#define R_M32R_GOTPC_HI_ULO 59 /* High 16 bit PC relative offset to - GOT with unsigned low */ -#define R_M32R_GOTPC_HI_SLO 60 /* High 16 bit PC relative offset to - GOT with signed low */ -#define R_M32R_GOTPC_LO 61 /* Low 16 bit PC relative offset to - GOT */ -#define R_M32R_GOTOFF_HI_ULO 62 /* High 16 bit offset to GOT - with unsigned low */ -#define R_M32R_GOTOFF_HI_SLO 63 /* High 16 bit offset to GOT - with signed low */ -#define R_M32R_GOTOFF_LO 64 /* Low 16 bit offset to GOT */ -#define R_M32R_NUM 256 /* Keep this the last entry. */ - - -/* TILEPro relocations. */ -#define R_TILEPRO_NONE 0 /* No reloc */ -#define R_TILEPRO_32 1 /* Direct 32 bit */ -#define R_TILEPRO_16 2 /* Direct 16 bit */ -#define R_TILEPRO_8 3 /* Direct 8 bit */ -#define R_TILEPRO_32_PCREL 4 /* PC relative 32 bit */ -#define R_TILEPRO_16_PCREL 5 /* PC relative 16 bit */ -#define R_TILEPRO_8_PCREL 6 /* PC relative 8 bit */ -#define R_TILEPRO_LO16 7 /* Low 16 bit */ -#define R_TILEPRO_HI16 8 /* High 16 bit */ -#define R_TILEPRO_HA16 9 /* High 16 bit, adjusted */ -#define R_TILEPRO_COPY 10 /* Copy relocation */ -#define R_TILEPRO_GLOB_DAT 11 /* Create GOT entry */ -#define R_TILEPRO_JMP_SLOT 12 /* Create PLT entry */ -#define R_TILEPRO_RELATIVE 13 /* Adjust by program base */ -#define R_TILEPRO_BROFF_X1 14 /* X1 pipe branch offset */ -#define R_TILEPRO_JOFFLONG_X1 15 /* X1 pipe jump offset */ -#define R_TILEPRO_JOFFLONG_X1_PLT 16 /* X1 pipe jump offset to PLT */ -#define R_TILEPRO_IMM8_X0 17 /* X0 pipe 8-bit */ -#define R_TILEPRO_IMM8_Y0 18 /* Y0 pipe 8-bit */ -#define R_TILEPRO_IMM8_X1 19 /* X1 pipe 8-bit */ -#define R_TILEPRO_IMM8_Y1 20 /* Y1 pipe 8-bit */ -#define R_TILEPRO_MT_IMM15_X1 21 /* X1 pipe mtspr */ -#define R_TILEPRO_MF_IMM15_X1 22 /* X1 pipe mfspr */ -#define R_TILEPRO_IMM16_X0 23 /* X0 pipe 16-bit */ -#define R_TILEPRO_IMM16_X1 24 /* X1 pipe 16-bit */ -#define R_TILEPRO_IMM16_X0_LO 25 /* X0 pipe low 16-bit */ -#define R_TILEPRO_IMM16_X1_LO 26 /* X1 pipe low 16-bit */ -#define R_TILEPRO_IMM16_X0_HI 27 /* X0 pipe high 16-bit */ -#define R_TILEPRO_IMM16_X1_HI 28 /* X1 pipe high 16-bit */ -#define R_TILEPRO_IMM16_X0_HA 29 /* X0 pipe high 16-bit, adjusted */ -#define R_TILEPRO_IMM16_X1_HA 30 /* X1 pipe high 16-bit, adjusted */ -#define R_TILEPRO_IMM16_X0_PCREL 31 /* X0 pipe PC relative 16 bit */ -#define R_TILEPRO_IMM16_X1_PCREL 32 /* X1 pipe PC relative 16 bit */ -#define R_TILEPRO_IMM16_X0_LO_PCREL 33 /* X0 pipe PC relative low 16 bit */ -#define R_TILEPRO_IMM16_X1_LO_PCREL 34 /* X1 pipe PC relative low 16 bit */ -#define R_TILEPRO_IMM16_X0_HI_PCREL 35 /* X0 pipe PC relative high 16 bit */ -#define R_TILEPRO_IMM16_X1_HI_PCREL 36 /* X1 pipe PC relative high 16 bit */ -#define R_TILEPRO_IMM16_X0_HA_PCREL 37 /* X0 pipe PC relative ha() 16 bit */ -#define R_TILEPRO_IMM16_X1_HA_PCREL 38 /* X1 pipe PC relative ha() 16 bit */ -#define R_TILEPRO_IMM16_X0_GOT 39 /* X0 pipe 16-bit GOT offset */ -#define R_TILEPRO_IMM16_X1_GOT 40 /* X1 pipe 16-bit GOT offset */ -#define R_TILEPRO_IMM16_X0_GOT_LO 41 /* X0 pipe low 16-bit GOT offset */ -#define R_TILEPRO_IMM16_X1_GOT_LO 42 /* X1 pipe low 16-bit GOT offset */ -#define R_TILEPRO_IMM16_X0_GOT_HI 43 /* X0 pipe high 16-bit GOT offset */ -#define R_TILEPRO_IMM16_X1_GOT_HI 44 /* X1 pipe high 16-bit GOT offset */ -#define R_TILEPRO_IMM16_X0_GOT_HA 45 /* X0 pipe ha() 16-bit GOT offset */ -#define R_TILEPRO_IMM16_X1_GOT_HA 46 /* X1 pipe ha() 16-bit GOT offset */ -#define R_TILEPRO_MMSTART_X0 47 /* X0 pipe mm "start" */ -#define R_TILEPRO_MMEND_X0 48 /* X0 pipe mm "end" */ -#define R_TILEPRO_MMSTART_X1 49 /* X1 pipe mm "start" */ -#define R_TILEPRO_MMEND_X1 50 /* X1 pipe mm "end" */ -#define R_TILEPRO_SHAMT_X0 51 /* X0 pipe shift amount */ -#define R_TILEPRO_SHAMT_X1 52 /* X1 pipe shift amount */ -#define R_TILEPRO_SHAMT_Y0 53 /* Y0 pipe shift amount */ -#define R_TILEPRO_SHAMT_Y1 54 /* Y1 pipe shift amount */ -#define R_TILEPRO_DEST_IMM8_X1 55 /* X1 pipe destination 8-bit */ -/* Relocs 56-59 are currently not defined. */ -#define R_TILEPRO_TLS_GD_CALL 60 /* "jal" for TLS GD */ -#define R_TILEPRO_IMM8_X0_TLS_GD_ADD 61 /* X0 pipe "addi" for TLS GD */ -#define R_TILEPRO_IMM8_X1_TLS_GD_ADD 62 /* X1 pipe "addi" for TLS GD */ -#define R_TILEPRO_IMM8_Y0_TLS_GD_ADD 63 /* Y0 pipe "addi" for TLS GD */ -#define R_TILEPRO_IMM8_Y1_TLS_GD_ADD 64 /* Y1 pipe "addi" for TLS GD */ -#define R_TILEPRO_TLS_IE_LOAD 65 /* "lw_tls" for TLS IE */ -#define R_TILEPRO_IMM16_X0_TLS_GD 66 /* X0 pipe 16-bit TLS GD offset */ -#define R_TILEPRO_IMM16_X1_TLS_GD 67 /* X1 pipe 16-bit TLS GD offset */ -#define R_TILEPRO_IMM16_X0_TLS_GD_LO 68 /* X0 pipe low 16-bit TLS GD offset */ -#define R_TILEPRO_IMM16_X1_TLS_GD_LO 69 /* X1 pipe low 16-bit TLS GD offset */ -#define R_TILEPRO_IMM16_X0_TLS_GD_HI 70 /* X0 pipe high 16-bit TLS GD offset */ -#define R_TILEPRO_IMM16_X1_TLS_GD_HI 71 /* X1 pipe high 16-bit TLS GD offset */ -#define R_TILEPRO_IMM16_X0_TLS_GD_HA 72 /* X0 pipe ha() 16-bit TLS GD offset */ -#define R_TILEPRO_IMM16_X1_TLS_GD_HA 73 /* X1 pipe ha() 16-bit TLS GD offset */ -#define R_TILEPRO_IMM16_X0_TLS_IE 74 /* X0 pipe 16-bit TLS IE offset */ -#define R_TILEPRO_IMM16_X1_TLS_IE 75 /* X1 pipe 16-bit TLS IE offset */ -#define R_TILEPRO_IMM16_X0_TLS_IE_LO 76 /* X0 pipe low 16-bit TLS IE offset */ -#define R_TILEPRO_IMM16_X1_TLS_IE_LO 77 /* X1 pipe low 16-bit TLS IE offset */ -#define R_TILEPRO_IMM16_X0_TLS_IE_HI 78 /* X0 pipe high 16-bit TLS IE offset */ -#define R_TILEPRO_IMM16_X1_TLS_IE_HI 79 /* X1 pipe high 16-bit TLS IE offset */ -#define R_TILEPRO_IMM16_X0_TLS_IE_HA 80 /* X0 pipe ha() 16-bit TLS IE offset */ -#define R_TILEPRO_IMM16_X1_TLS_IE_HA 81 /* X1 pipe ha() 16-bit TLS IE offset */ -#define R_TILEPRO_TLS_DTPMOD32 82 /* ID of module containing symbol */ -#define R_TILEPRO_TLS_DTPOFF32 83 /* Offset in TLS block */ -#define R_TILEPRO_TLS_TPOFF32 84 /* Offset in static TLS block */ -#define R_TILEPRO_IMM16_X0_TLS_LE 85 /* X0 pipe 16-bit TLS LE offset */ -#define R_TILEPRO_IMM16_X1_TLS_LE 86 /* X1 pipe 16-bit TLS LE offset */ -#define R_TILEPRO_IMM16_X0_TLS_LE_LO 87 /* X0 pipe low 16-bit TLS LE offset */ -#define R_TILEPRO_IMM16_X1_TLS_LE_LO 88 /* X1 pipe low 16-bit TLS LE offset */ -#define R_TILEPRO_IMM16_X0_TLS_LE_HI 89 /* X0 pipe high 16-bit TLS LE offset */ -#define R_TILEPRO_IMM16_X1_TLS_LE_HI 90 /* X1 pipe high 16-bit TLS LE offset */ -#define R_TILEPRO_IMM16_X0_TLS_LE_HA 91 /* X0 pipe ha() 16-bit TLS LE offset */ -#define R_TILEPRO_IMM16_X1_TLS_LE_HA 92 /* X1 pipe ha() 16-bit TLS LE offset */ - -#define R_TILEPRO_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ -#define R_TILEPRO_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ - -#define R_TILEPRO_NUM 130 - - -/* TILE-Gx relocations. */ -#define R_TILEGX_NONE 0 /* No reloc */ -#define R_TILEGX_64 1 /* Direct 64 bit */ -#define R_TILEGX_32 2 /* Direct 32 bit */ -#define R_TILEGX_16 3 /* Direct 16 bit */ -#define R_TILEGX_8 4 /* Direct 8 bit */ -#define R_TILEGX_64_PCREL 5 /* PC relative 64 bit */ -#define R_TILEGX_32_PCREL 6 /* PC relative 32 bit */ -#define R_TILEGX_16_PCREL 7 /* PC relative 16 bit */ -#define R_TILEGX_8_PCREL 8 /* PC relative 8 bit */ -#define R_TILEGX_HW0 9 /* hword 0 16-bit */ -#define R_TILEGX_HW1 10 /* hword 1 16-bit */ -#define R_TILEGX_HW2 11 /* hword 2 16-bit */ -#define R_TILEGX_HW3 12 /* hword 3 16-bit */ -#define R_TILEGX_HW0_LAST 13 /* last hword 0 16-bit */ -#define R_TILEGX_HW1_LAST 14 /* last hword 1 16-bit */ -#define R_TILEGX_HW2_LAST 15 /* last hword 2 16-bit */ -#define R_TILEGX_COPY 16 /* Copy relocation */ -#define R_TILEGX_GLOB_DAT 17 /* Create GOT entry */ -#define R_TILEGX_JMP_SLOT 18 /* Create PLT entry */ -#define R_TILEGX_RELATIVE 19 /* Adjust by program base */ -#define R_TILEGX_BROFF_X1 20 /* X1 pipe branch offset */ -#define R_TILEGX_JUMPOFF_X1 21 /* X1 pipe jump offset */ -#define R_TILEGX_JUMPOFF_X1_PLT 22 /* X1 pipe jump offset to PLT */ -#define R_TILEGX_IMM8_X0 23 /* X0 pipe 8-bit */ -#define R_TILEGX_IMM8_Y0 24 /* Y0 pipe 8-bit */ -#define R_TILEGX_IMM8_X1 25 /* X1 pipe 8-bit */ -#define R_TILEGX_IMM8_Y1 26 /* Y1 pipe 8-bit */ -#define R_TILEGX_DEST_IMM8_X1 27 /* X1 pipe destination 8-bit */ -#define R_TILEGX_MT_IMM14_X1 28 /* X1 pipe mtspr */ -#define R_TILEGX_MF_IMM14_X1 29 /* X1 pipe mfspr */ -#define R_TILEGX_MMSTART_X0 30 /* X0 pipe mm "start" */ -#define R_TILEGX_MMEND_X0 31 /* X0 pipe mm "end" */ -#define R_TILEGX_SHAMT_X0 32 /* X0 pipe shift amount */ -#define R_TILEGX_SHAMT_X1 33 /* X1 pipe shift amount */ -#define R_TILEGX_SHAMT_Y0 34 /* Y0 pipe shift amount */ -#define R_TILEGX_SHAMT_Y1 35 /* Y1 pipe shift amount */ -#define R_TILEGX_IMM16_X0_HW0 36 /* X0 pipe hword 0 */ -#define R_TILEGX_IMM16_X1_HW0 37 /* X1 pipe hword 0 */ -#define R_TILEGX_IMM16_X0_HW1 38 /* X0 pipe hword 1 */ -#define R_TILEGX_IMM16_X1_HW1 39 /* X1 pipe hword 1 */ -#define R_TILEGX_IMM16_X0_HW2 40 /* X0 pipe hword 2 */ -#define R_TILEGX_IMM16_X1_HW2 41 /* X1 pipe hword 2 */ -#define R_TILEGX_IMM16_X0_HW3 42 /* X0 pipe hword 3 */ -#define R_TILEGX_IMM16_X1_HW3 43 /* X1 pipe hword 3 */ -#define R_TILEGX_IMM16_X0_HW0_LAST 44 /* X0 pipe last hword 0 */ -#define R_TILEGX_IMM16_X1_HW0_LAST 45 /* X1 pipe last hword 0 */ -#define R_TILEGX_IMM16_X0_HW1_LAST 46 /* X0 pipe last hword 1 */ -#define R_TILEGX_IMM16_X1_HW1_LAST 47 /* X1 pipe last hword 1 */ -#define R_TILEGX_IMM16_X0_HW2_LAST 48 /* X0 pipe last hword 2 */ -#define R_TILEGX_IMM16_X1_HW2_LAST 49 /* X1 pipe last hword 2 */ -#define R_TILEGX_IMM16_X0_HW0_PCREL 50 /* X0 pipe PC relative hword 0 */ -#define R_TILEGX_IMM16_X1_HW0_PCREL 51 /* X1 pipe PC relative hword 0 */ -#define R_TILEGX_IMM16_X0_HW1_PCREL 52 /* X0 pipe PC relative hword 1 */ -#define R_TILEGX_IMM16_X1_HW1_PCREL 53 /* X1 pipe PC relative hword 1 */ -#define R_TILEGX_IMM16_X0_HW2_PCREL 54 /* X0 pipe PC relative hword 2 */ -#define R_TILEGX_IMM16_X1_HW2_PCREL 55 /* X1 pipe PC relative hword 2 */ -#define R_TILEGX_IMM16_X0_HW3_PCREL 56 /* X0 pipe PC relative hword 3 */ -#define R_TILEGX_IMM16_X1_HW3_PCREL 57 /* X1 pipe PC relative hword 3 */ -#define R_TILEGX_IMM16_X0_HW0_LAST_PCREL 58 /* X0 pipe PC-rel last hword 0 */ -#define R_TILEGX_IMM16_X1_HW0_LAST_PCREL 59 /* X1 pipe PC-rel last hword 0 */ -#define R_TILEGX_IMM16_X0_HW1_LAST_PCREL 60 /* X0 pipe PC-rel last hword 1 */ -#define R_TILEGX_IMM16_X1_HW1_LAST_PCREL 61 /* X1 pipe PC-rel last hword 1 */ -#define R_TILEGX_IMM16_X0_HW2_LAST_PCREL 62 /* X0 pipe PC-rel last hword 2 */ -#define R_TILEGX_IMM16_X1_HW2_LAST_PCREL 63 /* X1 pipe PC-rel last hword 2 */ -#define R_TILEGX_IMM16_X0_HW0_GOT 64 /* X0 pipe hword 0 GOT offset */ -#define R_TILEGX_IMM16_X1_HW0_GOT 65 /* X1 pipe hword 0 GOT offset */ -#define R_TILEGX_IMM16_X0_HW0_PLT_PCREL 66 /* X0 pipe PC-rel PLT hword 0 */ -#define R_TILEGX_IMM16_X1_HW0_PLT_PCREL 67 /* X1 pipe PC-rel PLT hword 0 */ -#define R_TILEGX_IMM16_X0_HW1_PLT_PCREL 68 /* X0 pipe PC-rel PLT hword 1 */ -#define R_TILEGX_IMM16_X1_HW1_PLT_PCREL 69 /* X1 pipe PC-rel PLT hword 1 */ -#define R_TILEGX_IMM16_X0_HW2_PLT_PCREL 70 /* X0 pipe PC-rel PLT hword 2 */ -#define R_TILEGX_IMM16_X1_HW2_PLT_PCREL 71 /* X1 pipe PC-rel PLT hword 2 */ -#define R_TILEGX_IMM16_X0_HW0_LAST_GOT 72 /* X0 pipe last hword 0 GOT offset */ -#define R_TILEGX_IMM16_X1_HW0_LAST_GOT 73 /* X1 pipe last hword 0 GOT offset */ -#define R_TILEGX_IMM16_X0_HW1_LAST_GOT 74 /* X0 pipe last hword 1 GOT offset */ -#define R_TILEGX_IMM16_X1_HW1_LAST_GOT 75 /* X1 pipe last hword 1 GOT offset */ -#define R_TILEGX_IMM16_X0_HW3_PLT_PCREL 76 /* X0 pipe PC-rel PLT hword 3 */ -#define R_TILEGX_IMM16_X1_HW3_PLT_PCREL 77 /* X1 pipe PC-rel PLT hword 3 */ -#define R_TILEGX_IMM16_X0_HW0_TLS_GD 78 /* X0 pipe hword 0 TLS GD offset */ -#define R_TILEGX_IMM16_X1_HW0_TLS_GD 79 /* X1 pipe hword 0 TLS GD offset */ -#define R_TILEGX_IMM16_X0_HW0_TLS_LE 80 /* X0 pipe hword 0 TLS LE offset */ -#define R_TILEGX_IMM16_X1_HW0_TLS_LE 81 /* X1 pipe hword 0 TLS LE offset */ -#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE 82 /* X0 pipe last hword 0 LE off */ -#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE 83 /* X1 pipe last hword 0 LE off */ -#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE 84 /* X0 pipe last hword 1 LE off */ -#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE 85 /* X1 pipe last hword 1 LE off */ -#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD 86 /* X0 pipe last hword 0 GD off */ -#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD 87 /* X1 pipe last hword 0 GD off */ -#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD 88 /* X0 pipe last hword 1 GD off */ -#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD 89 /* X1 pipe last hword 1 GD off */ -/* Relocs 90-91 are currently not defined. */ -#define R_TILEGX_IMM16_X0_HW0_TLS_IE 92 /* X0 pipe hword 0 TLS IE offset */ -#define R_TILEGX_IMM16_X1_HW0_TLS_IE 93 /* X1 pipe hword 0 TLS IE offset */ -#define R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL 94 /* X0 pipe PC-rel PLT last hword 0 */ -#define R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL 95 /* X1 pipe PC-rel PLT last hword 0 */ -#define R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL 96 /* X0 pipe PC-rel PLT last hword 1 */ -#define R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL 97 /* X1 pipe PC-rel PLT last hword 1 */ -#define R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL 98 /* X0 pipe PC-rel PLT last hword 2 */ -#define R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL 99 /* X1 pipe PC-rel PLT last hword 2 */ -#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE 100 /* X0 pipe last hword 0 IE off */ -#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE 101 /* X1 pipe last hword 0 IE off */ -#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE 102 /* X0 pipe last hword 1 IE off */ -#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE 103 /* X1 pipe last hword 1 IE off */ -/* Relocs 104-105 are currently not defined. */ -#define R_TILEGX_TLS_DTPMOD64 106 /* 64-bit ID of symbol's module */ -#define R_TILEGX_TLS_DTPOFF64 107 /* 64-bit offset in TLS block */ -#define R_TILEGX_TLS_TPOFF64 108 /* 64-bit offset in static TLS block */ -#define R_TILEGX_TLS_DTPMOD32 109 /* 32-bit ID of symbol's module */ -#define R_TILEGX_TLS_DTPOFF32 110 /* 32-bit offset in TLS block */ -#define R_TILEGX_TLS_TPOFF32 111 /* 32-bit offset in static TLS block */ -#define R_TILEGX_TLS_GD_CALL 112 /* "jal" for TLS GD */ -#define R_TILEGX_IMM8_X0_TLS_GD_ADD 113 /* X0 pipe "addi" for TLS GD */ -#define R_TILEGX_IMM8_X1_TLS_GD_ADD 114 /* X1 pipe "addi" for TLS GD */ -#define R_TILEGX_IMM8_Y0_TLS_GD_ADD 115 /* Y0 pipe "addi" for TLS GD */ -#define R_TILEGX_IMM8_Y1_TLS_GD_ADD 116 /* Y1 pipe "addi" for TLS GD */ -#define R_TILEGX_TLS_IE_LOAD 117 /* "ld_tls" for TLS IE */ -#define R_TILEGX_IMM8_X0_TLS_ADD 118 /* X0 pipe "addi" for TLS GD/IE */ -#define R_TILEGX_IMM8_X1_TLS_ADD 119 /* X1 pipe "addi" for TLS GD/IE */ -#define R_TILEGX_IMM8_Y0_TLS_ADD 120 /* Y0 pipe "addi" for TLS GD/IE */ -#define R_TILEGX_IMM8_Y1_TLS_ADD 121 /* Y1 pipe "addi" for TLS GD/IE */ - -#define R_TILEGX_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ -#define R_TILEGX_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ - -#define R_TILEGX_NUM 130 - -/* RISC-V ELF Flags */ -#define EF_RISCV_RVC 0x0001 -#define EF_RISCV_FLOAT_ABI 0x0006 -#define EF_RISCV_FLOAT_ABI_SOFT 0x0000 -#define EF_RISCV_FLOAT_ABI_SINGLE 0x0002 -#define EF_RISCV_FLOAT_ABI_DOUBLE 0x0004 -#define EF_RISCV_FLOAT_ABI_QUAD 0x0006 - -/* RISC-V relocations. */ -#define R_RISCV_NONE 0 -#define R_RISCV_32 1 -#define R_RISCV_64 2 -#define R_RISCV_RELATIVE 3 -#define R_RISCV_COPY 4 -#define R_RISCV_JUMP_SLOT 5 -#define R_RISCV_TLS_DTPMOD32 6 -#define R_RISCV_TLS_DTPMOD64 7 -#define R_RISCV_TLS_DTPREL32 8 -#define R_RISCV_TLS_DTPREL64 9 -#define R_RISCV_TLS_TPREL32 10 -#define R_RISCV_TLS_TPREL64 11 -#define R_RISCV_BRANCH 16 -#define R_RISCV_JAL 17 -#define R_RISCV_CALL 18 -#define R_RISCV_CALL_PLT 19 -#define R_RISCV_GOT_HI20 20 -#define R_RISCV_TLS_GOT_HI20 21 -#define R_RISCV_TLS_GD_HI20 22 -#define R_RISCV_PCREL_HI20 23 -#define R_RISCV_PCREL_LO12_I 24 -#define R_RISCV_PCREL_LO12_S 25 -#define R_RISCV_HI20 26 -#define R_RISCV_LO12_I 27 -#define R_RISCV_LO12_S 28 -#define R_RISCV_TPREL_HI20 29 -#define R_RISCV_TPREL_LO12_I 30 -#define R_RISCV_TPREL_LO12_S 31 -#define R_RISCV_TPREL_ADD 32 -#define R_RISCV_ADD8 33 -#define R_RISCV_ADD16 34 -#define R_RISCV_ADD32 35 -#define R_RISCV_ADD64 36 -#define R_RISCV_SUB8 37 -#define R_RISCV_SUB16 38 -#define R_RISCV_SUB32 39 -#define R_RISCV_SUB64 40 -#define R_RISCV_GNU_VTINHERIT 41 -#define R_RISCV_GNU_VTENTRY 42 -#define R_RISCV_ALIGN 43 -#define R_RISCV_RVC_BRANCH 44 -#define R_RISCV_RVC_JUMP 45 -#define R_RISCV_RVC_LUI 46 -#define R_RISCV_GPREL_I 47 -#define R_RISCV_GPREL_S 48 -#define R_RISCV_TPREL_I 49 -#define R_RISCV_TPREL_S 50 -#define R_RISCV_RELAX 51 -#define R_RISCV_SUB6 52 -#define R_RISCV_SET6 53 -#define R_RISCV_SET8 54 -#define R_RISCV_SET16 55 -#define R_RISCV_SET32 56 -#define R_RISCV_32_PCREL 57 - -#define R_RISCV_NUM 58 - - -#endif /* elf.h */ diff --git a/tinycc/i386-asm.c b/tinycc/i386-asm.c deleted file mode 100644 index 3cc8d18..0000000 --- a/tinycc/i386-asm.c +++ /dev/null @@ -1,1744 +0,0 @@ -/* - * i386 specific functions for TCC assembler - * - * Copyright (c) 2001, 2002 Fabrice Bellard - * Copyright (c) 2009 Frédéric Feret (x86_64 support) - * - * 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 - */ - -#define USING_GLOBALS -#include "tcc.h" - -#define MAX_OPERANDS 3 - -#define TOK_ASM_first TOK_ASM_clc -#define TOK_ASM_last TOK_ASM_emms -#define TOK_ASM_alllast TOK_ASM_subps - -#define OPC_B 0x01 /* only used with OPC_WL */ -#define OPC_WL 0x02 /* accepts w, l or no suffix */ -#define OPC_BWL (OPC_B | OPC_WL) /* accepts b, w, l or no suffix */ -#define OPC_REG 0x04 /* register is added to opcode */ -#define OPC_MODRM 0x08 /* modrm encoding */ - -#define OPCT_MASK 0x70 -#define OPC_FWAIT 0x10 /* add fwait opcode */ -#define OPC_SHIFT 0x20 /* shift opcodes */ -#define OPC_ARITH 0x30 /* arithmetic opcodes */ -#define OPC_FARITH 0x40 /* FPU arithmetic opcodes */ -#define OPC_TEST 0x50 /* test opcodes */ -#define OPC_0F01 0x60 /* 0x0f01XX (group 7, XX is 2nd opcode, - no operands and unstructured mod/rm) */ -#define OPCT_IS(v,i) (((v) & OPCT_MASK) == (i)) - -#define OPC_0F 0x100 /* Is secondary map (0x0f prefix) */ -#define OPC_48 0x200 /* Always has REX prefix */ -#ifdef TCC_TARGET_X86_64 -# define OPC_WLQ 0x1000 /* accepts w, l, q or no suffix */ -# define OPC_BWLQ (OPC_B | OPC_WLQ) /* accepts b, w, l, q or no suffix */ -# define OPC_WLX OPC_WLQ -# define OPC_BWLX OPC_BWLQ -#else -# define OPC_WLX OPC_WL -# define OPC_BWLX OPC_BWL -#endif - -#define OPC_GROUP_SHIFT 13 - -/* in order to compress the operand type, we use specific operands and - we or only with EA */ -enum { - OPT_REG8=0, /* warning: value is hardcoded from TOK_ASM_xxx */ - OPT_REG16, /* warning: value is hardcoded from TOK_ASM_xxx */ - OPT_REG32, /* warning: value is hardcoded from TOK_ASM_xxx */ -#ifdef TCC_TARGET_X86_64 - OPT_REG64, /* warning: value is hardcoded from TOK_ASM_xxx */ -#endif - OPT_MMX, /* warning: value is hardcoded from TOK_ASM_xxx */ - OPT_SSE, /* warning: value is hardcoded from TOK_ASM_xxx */ - OPT_CR, /* warning: value is hardcoded from TOK_ASM_xxx */ - OPT_TR, /* warning: value is hardcoded from TOK_ASM_xxx */ - OPT_DB, /* warning: value is hardcoded from TOK_ASM_xxx */ - OPT_SEG, - OPT_ST, -#ifdef TCC_TARGET_X86_64 - OPT_REG8_LOW, /* %spl,%bpl,%sil,%dil, encoded like ah,ch,dh,bh, but - with REX prefix, not used in insn templates */ -#endif - OPT_IM8, - OPT_IM8S, - OPT_IM16, - OPT_IM32, -#ifdef TCC_TARGET_X86_64 - OPT_IM64, -#endif - OPT_EAX, /* %al, %ax, %eax or %rax register */ - OPT_ST0, /* %st(0) register */ - OPT_CL, /* %cl register */ - OPT_DX, /* %dx register */ - OPT_ADDR, /* OP_EA with only offset */ - OPT_INDIR, /* *(expr) */ - /* composite types */ - OPT_COMPOSITE_FIRST, - OPT_IM, /* IM8 | IM16 | IM32 */ - OPT_REG, /* REG8 | REG16 | REG32 | REG64 */ - OPT_REGW, /* REG16 | REG32 | REG64 */ - OPT_IMW, /* IM16 | IM32 */ - OPT_MMXSSE, /* MMX | SSE */ - OPT_DISP, /* Like OPT_ADDR, but emitted as displacement (for jumps) */ - OPT_DISP8, /* Like OPT_ADDR, but only 8bit (short jumps) */ - /* can be ored with any OPT_xxx */ - OPT_EA = 0x80 -}; - -#define OP_REG8 (1 << OPT_REG8) -#define OP_REG16 (1 << OPT_REG16) -#define OP_REG32 (1 << OPT_REG32) -#define OP_MMX (1 << OPT_MMX) -#define OP_SSE (1 << OPT_SSE) -#define OP_CR (1 << OPT_CR) -#define OP_TR (1 << OPT_TR) -#define OP_DB (1 << OPT_DB) -#define OP_SEG (1 << OPT_SEG) -#define OP_ST (1 << OPT_ST) -#define OP_IM8 (1 << OPT_IM8) -#define OP_IM8S (1 << OPT_IM8S) -#define OP_IM16 (1 << OPT_IM16) -#define OP_IM32 (1 << OPT_IM32) -#define OP_EAX (1 << OPT_EAX) -#define OP_ST0 (1 << OPT_ST0) -#define OP_CL (1 << OPT_CL) -#define OP_DX (1 << OPT_DX) -#define OP_ADDR (1 << OPT_ADDR) -#define OP_INDIR (1 << OPT_INDIR) -#ifdef TCC_TARGET_X86_64 -# define OP_REG64 (1 << OPT_REG64) -# define OP_REG8_LOW (1 << OPT_REG8_LOW) -# define OP_IM64 (1 << OPT_IM64) -# define OP_EA32 (OP_EA << 1) -#else -# define OP_REG64 0 -# define OP_REG8_LOW 0 -# define OP_IM64 0 -# define OP_EA32 0 -#endif - -#define OP_EA 0x40000000 -#define OP_REG (OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64) - -#ifdef TCC_TARGET_X86_64 -# define TREG_XAX TREG_RAX -# define TREG_XCX TREG_RCX -# define TREG_XDX TREG_RDX -#else -# define TREG_XAX TREG_EAX -# define TREG_XCX TREG_ECX -# define TREG_XDX TREG_EDX -#endif - -typedef struct ASMInstr { - uint16_t sym; - uint16_t opcode; - uint16_t instr_type; - uint8_t nb_ops; - uint8_t op_type[MAX_OPERANDS]; /* see OP_xxx */ -} ASMInstr; - -typedef struct Operand { - uint32_t type; - int8_t reg; /* register, -1 if none */ - int8_t reg2; /* second register, -1 if none */ - uint8_t shift; - ExprValue e; -} Operand; - -static const uint8_t reg_to_size[9] = { -/* - [OP_REG8] = 0, - [OP_REG16] = 1, - [OP_REG32] = 2, -#ifdef TCC_TARGET_X86_64 - [OP_REG64] = 3, -#endif -*/ - 0, 0, 1, 0, 2, 0, 0, 0, 3 -}; - -#define NB_TEST_OPCODES 30 - -static const uint8_t test_bits[NB_TEST_OPCODES] = { - 0x00, /* o */ - 0x01, /* no */ - 0x02, /* b */ - 0x02, /* c */ - 0x02, /* nae */ - 0x03, /* nb */ - 0x03, /* nc */ - 0x03, /* ae */ - 0x04, /* e */ - 0x04, /* z */ - 0x05, /* ne */ - 0x05, /* nz */ - 0x06, /* be */ - 0x06, /* na */ - 0x07, /* nbe */ - 0x07, /* a */ - 0x08, /* s */ - 0x09, /* ns */ - 0x0a, /* p */ - 0x0a, /* pe */ - 0x0b, /* np */ - 0x0b, /* po */ - 0x0c, /* l */ - 0x0c, /* nge */ - 0x0d, /* nl */ - 0x0d, /* ge */ - 0x0e, /* le */ - 0x0e, /* ng */ - 0x0f, /* nle */ - 0x0f, /* g */ -}; - -static const uint8_t segment_prefixes[] = { - 0x26, /* es */ - 0x2e, /* cs */ - 0x36, /* ss */ - 0x3e, /* ds */ - 0x64, /* fs */ - 0x65 /* gs */ -}; - -static const ASMInstr asm_instrs[] = { -#define ALT(x) x -/* This removes a 0x0f in the second byte */ -#define O(o) ((uint64_t) ((((o) & 0xff00) == 0x0f00) ? ((((o) >> 8) & ~0xff) | ((o) & 0xff)) : (o))) -/* This constructs instr_type from opcode, type and group. */ -#define T(o,i,g) ((i) | ((g) << OPC_GROUP_SHIFT) | ((((o) & 0xff00) == 0x0f00) ? OPC_0F : 0)) -#define DEF_ASM_OP0(name, opcode) -#define DEF_ASM_OP0L(name, opcode, group, instr_type) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 0, { 0 } }, -#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 1, { op0 }}, -#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 2, { op0, op1 }}, -#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 3, { op0, op1, op2 }}, -#ifdef TCC_TARGET_X86_64 -# include "x86_64-asm.h" -#else -# include "i386-asm.h" -#endif - /* last operation */ - { 0, }, -}; - -static const uint16_t op0_codes[] = { -#define ALT(x) -#define DEF_ASM_OP0(x, opcode) opcode, -#define DEF_ASM_OP0L(name, opcode, group, instr_type) -#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) -#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) -#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) -#ifdef TCC_TARGET_X86_64 -# include "x86_64-asm.h" -#else -# include "i386-asm.h" -#endif -}; - -static inline int get_reg_shift(TCCState *s1) -{ - int shift, v; - v = asm_int_expr(s1); - switch(v) { - case 1: - shift = 0; - break; - case 2: - shift = 1; - break; - case 4: - shift = 2; - break; - case 8: - shift = 3; - break; - default: - expect("1, 2, 4 or 8 constant"); - shift = 0; - break; - } - return shift; -} - -#ifdef TCC_TARGET_X86_64 -static int asm_parse_numeric_reg(int t, unsigned int *type) -{ - int reg = -1; - if (t >= TOK_IDENT && t < tok_ident) { - const char *s = table_ident[t - TOK_IDENT]->str; - char c; - *type = OP_REG64; - if (*s == 'c') { - s++; - *type = OP_CR; - } - if (*s++ != 'r') - return -1; - /* Don't allow leading '0'. */ - if ((c = *s++) >= '1' && c <= '9') - reg = c - '0'; - else - return -1; - if ((c = *s) >= '0' && c <= '5') - s++, reg = reg * 10 + c - '0'; - if (reg > 15) - return -1; - if ((c = *s) == 0) - ; - else if (*type != OP_REG64) - return -1; - else if (c == 'b' && !s[1]) - *type = OP_REG8; - else if (c == 'w' && !s[1]) - *type = OP_REG16; - else if (c == 'd' && !s[1]) - *type = OP_REG32; - else - return -1; - } - return reg; -} -#endif - -static int asm_parse_reg(unsigned int *type) -{ - int reg = 0; - *type = 0; - if (tok != '%') - goto error_32; - next(); - if (tok >= TOK_ASM_eax && tok <= TOK_ASM_edi) { - reg = tok - TOK_ASM_eax; - *type = OP_REG32; -#ifdef TCC_TARGET_X86_64 - } else if (tok >= TOK_ASM_rax && tok <= TOK_ASM_rdi) { - reg = tok - TOK_ASM_rax; - *type = OP_REG64; - } else if (tok == TOK_ASM_rip) { - reg = -2; /* Probably should use different escape code. */ - *type = OP_REG64; - } else if ((reg = asm_parse_numeric_reg(tok, type)) >= 0 - && (*type == OP_REG32 || *type == OP_REG64)) { - ; -#endif - } else { - error_32: - expect("register"); - } - next(); - return reg; -} - -static void parse_operand(TCCState *s1, Operand *op) -{ - ExprValue e; - int reg, indir; - const char *p; - - indir = 0; - if (tok == '*') { - next(); - indir = OP_INDIR; - } - - if (tok == '%') { - next(); - if (tok >= TOK_ASM_al && tok <= TOK_ASM_db7) { - reg = tok - TOK_ASM_al; - op->type = 1 << (reg >> 3); /* WARNING: do not change constant order */ - op->reg = reg & 7; - if ((op->type & OP_REG) && op->reg == TREG_XAX) - op->type |= OP_EAX; - else if (op->type == OP_REG8 && op->reg == TREG_XCX) - op->type |= OP_CL; - else if (op->type == OP_REG16 && op->reg == TREG_XDX) - op->type |= OP_DX; - } else if (tok >= TOK_ASM_dr0 && tok <= TOK_ASM_dr7) { - op->type = OP_DB; - op->reg = tok - TOK_ASM_dr0; - } else if (tok >= TOK_ASM_es && tok <= TOK_ASM_gs) { - op->type = OP_SEG; - op->reg = tok - TOK_ASM_es; - } else if (tok == TOK_ASM_st) { - op->type = OP_ST; - op->reg = 0; - next(); - if (tok == '(') { - next(); - if (tok != TOK_PPNUM) - goto reg_error; - p = tokc.str.data; - reg = p[0] - '0'; - if ((unsigned)reg >= 8 || p[1] != '\0') - goto reg_error; - op->reg = reg; - next(); - skip(')'); - } - if (op->reg == 0) - op->type |= OP_ST0; - goto no_skip; -#ifdef TCC_TARGET_X86_64 - } else if (tok >= TOK_ASM_spl && tok <= TOK_ASM_dil) { - op->type = OP_REG8 | OP_REG8_LOW; - op->reg = 4 + tok - TOK_ASM_spl; - } else if ((op->reg = asm_parse_numeric_reg(tok, &op->type)) >= 0) { - ; -#endif - } else { - reg_error: - tcc_error("unknown register %%%s", get_tok_str(tok, &tokc)); - } - next(); - no_skip: ; - } else if (tok == '$') { - /* constant value */ - next(); - asm_expr(s1, &e); - op->type = OP_IM32; - op->e = e; - if (!op->e.sym) { - if (op->e.v == (uint8_t)op->e.v) - op->type |= OP_IM8; - if (op->e.v == (int8_t)op->e.v) - op->type |= OP_IM8S; - if (op->e.v == (uint16_t)op->e.v) - op->type |= OP_IM16; -#ifdef TCC_TARGET_X86_64 - if (op->e.v != (int32_t)op->e.v && op->e.v != (uint32_t)op->e.v) - op->type = OP_IM64; -#endif - } - } else { - /* address(reg,reg2,shift) with all variants */ - op->type = OP_EA; - op->reg = -1; - op->reg2 = -1; - op->shift = 0; - if (tok != '(') { - asm_expr(s1, &e); - op->e = e; - } else { - next(); - if (tok == '%') { - unget_tok('('); - op->e.v = 0; - op->e.sym = NULL; - } else { - /* bracketed offset expression */ - asm_expr(s1, &e); - if (tok != ')') - expect(")"); - next(); - op->e.v = e.v; - op->e.sym = e.sym; - } - op->e.pcrel = 0; - } - if (tok == '(') { - unsigned int type = 0; - next(); - if (tok != ',') { - op->reg = asm_parse_reg(&type); - } - if (tok == ',') { - next(); - if (tok != ',') { - op->reg2 = asm_parse_reg(&type); - } - if (tok == ',') { - next(); - op->shift = get_reg_shift(s1); - } - } - if (type & OP_REG32) - op->type |= OP_EA32; - skip(')'); - } - if (op->reg == -1 && op->reg2 == -1) - op->type |= OP_ADDR; - } - op->type |= indir; -} - -/* XXX: unify with C code output ? */ -ST_FUNC void gen_expr32(ExprValue *pe) -{ - if (pe->pcrel) - /* If PC-relative, always set VT_SYM, even without symbol, - so as to force a relocation to be emitted. */ - gen_addrpc32(VT_SYM, pe->sym, pe->v); - else - gen_addr32(pe->sym ? VT_SYM : 0, pe->sym, pe->v); -} - -#ifdef TCC_TARGET_X86_64 -ST_FUNC void gen_expr64(ExprValue *pe) -{ - gen_addr64(pe->sym ? VT_SYM : 0, pe->sym, pe->v); -} -#endif - -/* XXX: unify with C code output ? */ -static void gen_disp32(ExprValue *pe) -{ - Sym *sym = pe->sym; - ElfSym *esym = elfsym(sym); - if (esym && esym->st_shndx == cur_text_section->sh_num) { - /* same section: we can output an absolute value. Note - that the TCC compiler behaves differently here because - it always outputs a relocation to ease (future) code - elimination in the linker */ - gen_le32(pe->v + esym->st_value - ind - 4); - } else { - if (sym && sym->type.t == VT_VOID) { - sym->type.t = VT_FUNC; - sym->type.ref = NULL; - } - gen_addrpc32(VT_SYM, sym, pe->v); - } -} - -/* generate the modrm operand */ -static inline int asm_modrm(int reg, Operand *op) -{ - int mod, reg1, reg2, sib_reg1; - - if (op->type & (OP_REG | OP_MMX | OP_SSE)) { - g(0xc0 + (reg << 3) + op->reg); - } else if (op->reg == -1 && op->reg2 == -1) { - /* displacement only */ -#ifdef TCC_TARGET_X86_64 - g(0x04 + (reg << 3)); - g(0x25); -#else - g(0x05 + (reg << 3)); -#endif - gen_expr32(&op->e); -#ifdef TCC_TARGET_X86_64 - } else if (op->reg == -2) { - ExprValue *pe = &op->e; - g(0x05 + (reg << 3)); - gen_addrpc32(pe->sym ? VT_SYM : 0, pe->sym, pe->v); - return ind; -#endif - } else { - sib_reg1 = op->reg; - /* fist compute displacement encoding */ - if (sib_reg1 == -1) { - sib_reg1 = 5; - mod = 0x00; - } else if (op->e.v == 0 && !op->e.sym && op->reg != 5) { - mod = 0x00; - } else if (op->e.v == (int8_t)op->e.v && !op->e.sym) { - mod = 0x40; - } else { - mod = 0x80; - } - /* compute if sib byte needed */ - reg1 = op->reg; - if (op->reg2 != -1) - reg1 = 4; - g(mod + (reg << 3) + reg1); - if (reg1 == 4) { - /* add sib byte */ - reg2 = op->reg2; - if (reg2 == -1) - reg2 = 4; /* indicate no index */ - g((op->shift << 6) + (reg2 << 3) + sib_reg1); - } - /* add offset */ - if (mod == 0x40) { - g(op->e.v); - } else if (mod == 0x80 || op->reg == -1) { - gen_expr32(&op->e); - } - } - return 0; -} - -#ifdef TCC_TARGET_X86_64 -#define REX_W 0x48 -#define REX_R 0x44 -#define REX_X 0x42 -#define REX_B 0x41 - -static void asm_rex(int width64, Operand *ops, int nb_ops, int *op_type, - int regi, int rmi) -{ - unsigned char rex = width64 ? 0x48 : 0; - int saw_high_8bit = 0; - int i; - if (rmi == -1) { - /* No mod/rm byte, but we might have a register op nevertheless - (we will add it to the opcode later). */ - for(i = 0; i < nb_ops; i++) { - if (op_type[i] & (OP_REG | OP_ST)) { - if (ops[i].reg >= 8) { - rex |= REX_B; - ops[i].reg -= 8; - } else if (ops[i].type & OP_REG8_LOW) - rex |= 0x40; - else if (ops[i].type & OP_REG8 && ops[i].reg >= 4) - /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */ - saw_high_8bit = ops[i].reg; - break; - } - } - } else { - if (regi != -1) { - if (ops[regi].reg >= 8) { - rex |= REX_R; - ops[regi].reg -= 8; - } else if (ops[regi].type & OP_REG8_LOW) - rex |= 0x40; - else if (ops[regi].type & OP_REG8 && ops[regi].reg >= 4) - /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */ - saw_high_8bit = ops[regi].reg; - } - if (ops[rmi].type & (OP_REG | OP_MMX | OP_SSE | OP_CR | OP_EA)) { - if (ops[rmi].reg >= 8) { - rex |= REX_B; - ops[rmi].reg -= 8; - } else if (ops[rmi].type & OP_REG8_LOW) - rex |= 0x40; - else if (ops[rmi].type & OP_REG8 && ops[rmi].reg >= 4) - /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */ - saw_high_8bit = ops[rmi].reg; - } - if (ops[rmi].type & OP_EA && ops[rmi].reg2 >= 8) { - rex |= REX_X; - ops[rmi].reg2 -= 8; - } - } - if (rex) { - if (saw_high_8bit) - tcc_error("can't encode register %%%ch when REX prefix is required", - "acdb"[saw_high_8bit-4]); - g(rex); - } -} -#endif - - -static void maybe_print_stats (void) -{ - static int already; - - if (0 && !already) - /* print stats about opcodes */ - { - const struct ASMInstr *pa; - int freq[4]; - int op_vals[500]; - int nb_op_vals, i, j; - - already = 1; - 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]) - if (pa->instr_type == op_vals[j]) - goto found; - } - //op_vals[nb_op_vals++] = pa->op_type[i]; - op_vals[nb_op_vals++] = pa->instr_type; - 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", - (int)sizeof(asm_instrs), - (int)sizeof(asm_instrs) / (int)sizeof(ASMInstr), - freq[0], freq[1], freq[2], freq[3]); - } -} - -ST_FUNC void asm_opcode(TCCState *s1, int opcode) -{ - const ASMInstr *pa; - int i, modrm_index, modreg_index, reg, v, op1, seg_prefix, pc, p; - int nb_ops, s; - Operand ops[MAX_OPERANDS], *pop; - int op_type[3]; /* decoded op type */ - int alltypes; /* OR of all operand types */ - int autosize; - int p66; -#ifdef TCC_TARGET_X86_64 - int rex64; -#endif - - maybe_print_stats(); - /* force synthetic ';' after prefix instruction, so we can handle */ - /* one-line things like "rep stosb" instead of only "rep\nstosb" */ - if (opcode >= TOK_ASM_wait && opcode <= TOK_ASM_repnz) - unget_tok(';'); - - /* get operands */ - pop = ops; - nb_ops = 0; - seg_prefix = 0; - alltypes = 0; - for(;;) { - if (tok == ';' || tok == TOK_LINEFEED) - break; - if (nb_ops >= MAX_OPERANDS) { - tcc_error("incorrect number of operands"); - } - parse_operand(s1, pop); - if (tok == ':') { - if (pop->type != OP_SEG || seg_prefix) - tcc_error("incorrect prefix"); - seg_prefix = segment_prefixes[pop->reg]; - next(); - parse_operand(s1, pop); - if (!(pop->type & OP_EA)) { - tcc_error("segment prefix must be followed by memory reference"); - } - } - pop++; - nb_ops++; - if (tok != ',') - break; - next(); - } - - s = 0; /* avoid warning */ - -again: - /* optimize matching by using a lookup table (no hashing is needed - !) */ - for(pa = asm_instrs; pa->sym != 0; pa++) { - int it = pa->instr_type & OPCT_MASK; - s = 0; - if (it == OPC_FARITH) { - v = opcode - pa->sym; - if (!((unsigned)v < 8 * 6 && (v % 6) == 0)) - continue; - } else if (it == OPC_ARITH) { - if (!(opcode >= pa->sym && opcode < pa->sym + 8*NBWLX)) - continue; - s = (opcode - pa->sym) % NBWLX; - if ((pa->instr_type & OPC_BWLX) == OPC_WLX) - { - /* We need to reject the xxxb opcodes that we accepted above. - Note that pa->sym for WLX opcodes is the 'w' token, - to get the 'b' token subtract one. */ - if (((opcode - pa->sym + 1) % NBWLX) == 0) - continue; - s++; - } - } else if (it == OPC_SHIFT) { - if (!(opcode >= pa->sym && opcode < pa->sym + 7*NBWLX)) - continue; - s = (opcode - pa->sym) % NBWLX; - } else if (it == OPC_TEST) { - if (!(opcode >= pa->sym && opcode < pa->sym + NB_TEST_OPCODES)) - continue; - /* cmovxx is a test opcode but accepts multiple sizes. - The suffixes aren't encoded in the table, instead we - simply force size autodetection always and deal with suffixed - variants below when we don't find e.g. "cmovzl". */ - if (pa->instr_type & OPC_WLX) - s = NBWLX - 1; - } else if (pa->instr_type & OPC_B) { -#ifdef TCC_TARGET_X86_64 - /* Some instructions don't have the full size but only - bwl form. insb e.g. */ - if ((pa->instr_type & OPC_WLQ) != OPC_WLQ - && !(opcode >= pa->sym && opcode < pa->sym + NBWLX-1)) - continue; -#endif - if (!(opcode >= pa->sym && opcode < pa->sym + NBWLX)) - continue; - s = opcode - pa->sym; - } else if (pa->instr_type & OPC_WLX) { - if (!(opcode >= pa->sym && opcode < pa->sym + NBWLX-1)) - continue; - s = opcode - pa->sym + 1; - } else { - if (pa->sym != opcode) - continue; - } - if (pa->nb_ops != nb_ops) - continue; -#ifdef TCC_TARGET_X86_64 - /* Special case for moves. Selecting the IM64->REG64 form - should only be done if we really have an >32bit imm64, and that - is hardcoded. Ignore it here. */ - if (pa->opcode == 0xb0 && ops[0].type != OP_IM64 - && (ops[1].type & OP_REG) == OP_REG64 - && !(pa->instr_type & OPC_0F)) - continue; -#endif - /* now decode and check each operand */ - alltypes = 0; - for(i = 0; i < nb_ops; i++) { - int op1, op2; - op1 = pa->op_type[i]; - op2 = op1 & 0x1f; - switch(op2) { - case OPT_IM: - v = OP_IM8 | OP_IM16 | OP_IM32; - break; - case OPT_REG: - v = OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64; - break; - case OPT_REGW: - v = OP_REG16 | OP_REG32 | OP_REG64; - break; - case OPT_IMW: - v = OP_IM16 | OP_IM32; - break; - case OPT_MMXSSE: - v = OP_MMX | OP_SSE; - break; - case OPT_DISP: - case OPT_DISP8: - v = OP_ADDR; - break; - default: - v = 1 << op2; - break; - } - if (op1 & OPT_EA) - v |= OP_EA; - op_type[i] = v; - if ((ops[i].type & v) == 0) - goto next; - alltypes |= ops[i].type; - } - (void)alltypes; /* maybe unused */ - /* all is matching ! */ - break; - next: ; - } - if (pa->sym == 0) { - if (opcode >= TOK_ASM_first && opcode <= TOK_ASM_last) { - int b; - b = op0_codes[opcode - TOK_ASM_first]; - if (b & 0xff00) - g(b >> 8); - g(b); - return; - } else if (opcode <= TOK_ASM_alllast) { - tcc_error("bad operand with opcode '%s'", - get_tok_str(opcode, NULL)); - } else { - /* Special case for cmovcc, we accept size suffixes but ignore - them, but we don't want them to blow up our tables. */ - TokenSym *ts = table_ident[opcode - TOK_IDENT]; - if (ts->len >= 6 - && strchr("wlq", ts->str[ts->len-1]) - && !memcmp(ts->str, "cmov", 4)) { - opcode = tok_alloc(ts->str, ts->len-1)->tok; - goto again; - } - tcc_error("unknown opcode '%s'", ts->str); - } - } - /* if the size is unknown, then evaluate it (OPC_B or OPC_WL case) */ - autosize = NBWLX-1; -#ifdef TCC_TARGET_X86_64 - /* XXX the autosize should rather be zero, to not have to adjust this - all the time. */ - if ((pa->instr_type & OPC_BWLQ) == OPC_B) - autosize = NBWLX-2; -#endif - if (s == autosize) { - /* Check for register operands providing hints about the size. - Start from the end, i.e. destination operands. This matters - only for opcodes accepting different sized registers, lar and lsl - are such opcodes. */ - for(i = nb_ops - 1; s == autosize && i >= 0; i--) { - if ((ops[i].type & OP_REG) && !(op_type[i] & (OP_CL | OP_DX))) - s = reg_to_size[ops[i].type & OP_REG]; - } - if (s == autosize) { - if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) && - (ops[0].type & (OP_SEG | OP_IM8S | OP_IM32))) - s = 2; - else if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) && - (ops[0].type & OP_EA)) - s = NBWLX - 2; - else - tcc_error("cannot infer opcode suffix"); - } - } - -#ifdef TCC_TARGET_X86_64 - rex64 = 0; - if (pa->instr_type & OPC_48) - rex64 = 1; - else if (s == 3 || (alltypes & OP_REG64)) { - /* generate REX prefix */ - int default64 = 0; - for(i = 0; i < nb_ops; i++) { - if (op_type[i] == OP_REG64 && pa->opcode != 0xb8) { - /* If only 64bit regs are accepted in one operand - this is a default64 instruction without need for - REX prefixes, except for movabs(0xb8). */ - default64 = 1; - break; - } - } - /* XXX find better encoding for the default64 instructions. */ - if (((opcode != TOK_ASM_push && opcode != TOK_ASM_pop - && opcode != TOK_ASM_pushw && opcode != TOK_ASM_pushl - && opcode != TOK_ASM_pushq && opcode != TOK_ASM_popw - && opcode != TOK_ASM_popl && opcode != TOK_ASM_popq - && opcode != TOK_ASM_call && opcode != TOK_ASM_jmp)) - && !default64) - rex64 = 1; - } -#endif - - /* now generates the operation */ - if (OPCT_IS(pa->instr_type, OPC_FWAIT)) - g(0x9b); - if (seg_prefix) - g(seg_prefix); -#ifdef TCC_TARGET_X86_64 - /* Generate addr32 prefix if needed */ - for(i = 0; i < nb_ops; i++) { - if (ops[i].type & OP_EA32) { - g(0x67); - break; - } - } -#endif - /* generate data16 prefix if needed */ - p66 = 0; - if (s == 1) - p66 = 1; - else { - /* accepting mmx+sse in all operands --> needs 0x66 to - switch to sse mode. Accepting only sse in an operand --> is - already SSE insn and needs 0x66/f2/f3 handling. */ - for (i = 0; i < nb_ops; i++) - if ((op_type[i] & (OP_MMX | OP_SSE)) == (OP_MMX | OP_SSE) - && ops[i].type & OP_SSE) - p66 = 1; - } - if (p66) - g(0x66); - - v = pa->opcode; - p = v >> 8; /* possibly prefix byte(s) */ - switch (p) { - case 0: break; /* no prefix */ - case 0x48: break; /* REX, handled elsewhere */ - case 0x66: - case 0x67: - case 0xf2: - case 0xf3: v = v & 0xff; g(p); break; - case 0xd4: case 0xd5: break; /* aam and aad, not prefix, but hardcoded immediate argument "10" */ - case 0xd8: case 0xd9: case 0xda: case 0xdb: /* x87, no normal prefix */ - case 0xdc: case 0xdd: case 0xde: case 0xdf: break; - default: tcc_error("bad prefix 0x%2x in opcode table", p); break; - } - if (pa->instr_type & OPC_0F) - v = ((v & ~0xff) << 8) | 0x0f00 | (v & 0xff); - if ((v == 0x69 || v == 0x6b) && nb_ops == 2) { - /* kludge for imul $im, %reg */ - nb_ops = 3; - ops[2] = ops[1]; - op_type[2] = op_type[1]; - } else if (v == 0xcd && ops[0].e.v == 3 && !ops[0].e.sym) { - v--; /* int $3 case */ - nb_ops = 0; - } else if ((v == 0x06 || v == 0x07)) { - if (ops[0].reg >= 4) { - /* push/pop %fs or %gs */ - v = 0x0fa0 + (v - 0x06) + ((ops[0].reg - 4) << 3); - } else { - v += ops[0].reg << 3; - } - nb_ops = 0; - } else if (v <= 0x05) { - /* arith case */ - v += ((opcode - TOK_ASM_addb) / NBWLX) << 3; - } else if ((pa->instr_type & (OPCT_MASK | OPC_MODRM)) == OPC_FARITH) { - /* fpu arith case */ - v += ((opcode - pa->sym) / 6) << 3; - } - - /* search which operand will be used for modrm */ - modrm_index = -1; - modreg_index = -1; - if (pa->instr_type & OPC_MODRM) { - if (!nb_ops) { - /* A modrm opcode without operands is a special case (e.g. mfence). - It has a group and acts as if there's an register operand 0 - (ax). */ - i = 0; - ops[i].type = OP_REG; - ops[i].reg = 0; - goto modrm_found; - } - /* first look for an ea operand */ - for(i = 0;i < nb_ops; i++) { - if (op_type[i] & OP_EA) - goto modrm_found; - } - /* then if not found, a register or indirection (shift instructions) */ - for(i = 0;i < nb_ops; i++) { - if (op_type[i] & (OP_REG | OP_MMX | OP_SSE | OP_INDIR)) - goto modrm_found; - } -#ifdef ASM_DEBUG - tcc_error("bad op table"); -#endif - modrm_found: - modrm_index = i; - /* if a register is used in another operand then it is - used instead of group */ - for(i = 0;i < nb_ops; i++) { - int t = op_type[i]; - if (i != modrm_index && - (t & (OP_REG | OP_MMX | OP_SSE | OP_CR | OP_TR | OP_DB | OP_SEG))) { - modreg_index = i; - break; - } - } - } -#ifdef TCC_TARGET_X86_64 - asm_rex (rex64, ops, nb_ops, op_type, modreg_index, modrm_index); -#endif - - if (pa->instr_type & OPC_REG) { - /* mov $im, %reg case */ - if (v == 0xb0 && s >= 1) - v += 7; - for(i = 0; i < nb_ops; i++) { - if (op_type[i] & (OP_REG | OP_ST)) { - v += ops[i].reg; - break; - } - } - } - if (pa->instr_type & OPC_B) - v += s >= 1; - if (nb_ops == 1 && pa->op_type[0] == OPT_DISP8) { - ElfSym *esym; - int jmp_disp; - - /* see if we can really generate the jump with a byte offset */ - esym = elfsym(ops[0].e.sym); - if (!esym || esym->st_shndx != cur_text_section->sh_num) - goto no_short_jump; - jmp_disp = ops[0].e.v + esym->st_value - ind - 2 - (v >= 0xff); - if (jmp_disp == (int8_t)jmp_disp) { - /* OK to generate jump */ - ops[0].e.sym = 0; - ops[0].e.v = jmp_disp; - op_type[0] = OP_IM8S; - } else { - no_short_jump: - /* long jump will be allowed. need to modify the - opcode slightly */ - if (v == 0xeb) /* jmp */ - v = 0xe9; - else if (v == 0x70) /* jcc */ - v += 0x0f10; - else - tcc_error("invalid displacement"); - } - } - if (OPCT_IS(pa->instr_type, OPC_TEST)) - v += test_bits[opcode - pa->sym]; - else if (OPCT_IS(pa->instr_type, OPC_0F01)) - v |= 0x0f0100; - op1 = v >> 16; - if (op1) - g(op1); - op1 = (v >> 8) & 0xff; - if (op1) - g(op1); - g(v); - - if (OPCT_IS(pa->instr_type, OPC_SHIFT)) { - reg = (opcode - pa->sym) / NBWLX; - if (reg == 6) - reg = 7; - } else if (OPCT_IS(pa->instr_type, OPC_ARITH)) { - reg = (opcode - pa->sym) / NBWLX; - } else if (OPCT_IS(pa->instr_type, OPC_FARITH)) { - reg = (opcode - pa->sym) / 6; - } else { - reg = (pa->instr_type >> OPC_GROUP_SHIFT) & 7; - } - - pc = 0; - if (pa->instr_type & OPC_MODRM) { - /* if a register is used in another operand then it is - used instead of group */ - if (modreg_index >= 0) - reg = ops[modreg_index].reg; - pc = asm_modrm(reg, &ops[modrm_index]); - } - - /* emit constants */ -#ifndef TCC_TARGET_X86_64 - if (!(pa->instr_type & OPC_0F) - && (pa->opcode == 0x9a || pa->opcode == 0xea)) { - /* ljmp or lcall kludge */ - gen_expr32(&ops[1].e); - if (ops[0].e.sym) - tcc_error("cannot relocate"); - gen_le16(ops[0].e.v); - return; - } -#endif - for(i = 0;i < nb_ops; i++) { - v = op_type[i]; - if (v & (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64 | OP_IM8S | OP_ADDR)) { - /* if multiple sizes are given it means we must look - at the op size */ - if ((v | OP_IM8 | OP_IM64) == (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64)) { - if (s == 0) - v = OP_IM8; - else if (s == 1) - v = OP_IM16; - else if (s == 2 || (v & OP_IM64) == 0) - v = OP_IM32; - else - v = OP_IM64; - } - - if ((v & (OP_IM8 | OP_IM8S | OP_IM16)) && ops[i].e.sym) - tcc_error("cannot relocate"); - - if (v & (OP_IM8 | OP_IM8S)) { - g(ops[i].e.v); - } else if (v & OP_IM16) { - gen_le16(ops[i].e.v); -#ifdef TCC_TARGET_X86_64 - } else if (v & OP_IM64) { - gen_expr64(&ops[i].e); -#endif - } else if (pa->op_type[i] == OPT_DISP || pa->op_type[i] == OPT_DISP8) { - gen_disp32(&ops[i].e); - } else { - gen_expr32(&ops[i].e); - } - } - } - - /* after immediate operands, adjust pc-relative address */ - if (pc) - add32le(cur_text_section->data + pc - 4, pc - ind); -} - -/* return the constraint priority (we allocate first the lowest - numbered constraints) */ -static inline int constraint_priority(const char *str) -{ - int priority, c, pr; - - /* we take the lowest priority */ - priority = 0; - for(;;) { - c = *str; - if (c == '\0') - break; - str++; - switch(c) { - case 'A': - pr = 0; - break; - case 'a': - case 'b': - case 'c': - case 'd': - case 'S': - case 'D': - pr = 1; - break; - case 'q': - pr = 2; - break; - case 'r': - case 'R': - case 'p': - pr = 3; - break; - case 'N': - case 'M': - case 'I': - case 'e': - case 'i': - case 'm': - case 'g': - pr = 4; - break; - default: - tcc_error("unknown constraint '%c'", c); - pr = 0; - } - if (pr > priority) - priority = pr; - } - return priority; -} - -static const char *skip_constraint_modifiers(const char *p) -{ - while (*p == '=' || *p == '&' || *p == '+' || *p == '%') - p++; - return p; -} - -/* If T (a token) is of the form "%reg" returns the register - number and type, otherwise return -1. */ -ST_FUNC int asm_parse_regvar (int t) -{ - const char *s; - Operand op; - if (t < TOK_IDENT || (t & SYM_FIELD)) - return -1; - s = table_ident[t - TOK_IDENT]->str; - if (s[0] != '%') - return -1; - t = tok_alloc_const(s + 1); - unget_tok(t); - unget_tok('%'); - parse_operand(tcc_state, &op); - /* Accept only integer regs for now. */ - if (op.type & OP_REG) - return op.reg; - else - return -1; -} - -#define REG_OUT_MASK 0x01 -#define REG_IN_MASK 0x02 - -#define is_reg_allocated(reg) (regs_allocated[reg] & reg_mask) - -ST_FUNC void asm_compute_constraints(ASMOperand *operands, - int nb_operands, int nb_outputs, - const uint8_t *clobber_regs, - int *pout_reg) -{ - ASMOperand *op; - int sorted_op[MAX_ASM_OPERANDS]; - int i, j, k, p1, p2, tmp, reg, c, reg_mask; - const char *str; - uint8_t regs_allocated[NB_ASM_REGS]; - - /* init fields */ - for(i=0;i<nb_operands;i++) { - op = &operands[i]; - op->input_index = -1; - op->ref_index = -1; - op->reg = -1; - op->is_memory = 0; - op->is_rw = 0; - } - /* compute constraint priority and evaluate references to output - constraints if input constraints */ - for(i=0;i<nb_operands;i++) { - op = &operands[i]; - str = op->constraint; - str = skip_constraint_modifiers(str); - if (isnum(*str) || *str == '[') { - /* this is a reference to another constraint */ - k = find_constraint(operands, nb_operands, str, NULL); - if ((unsigned)k >= i || i < nb_outputs) - tcc_error("invalid reference in constraint %d ('%s')", - i, str); - op->ref_index = k; - if (operands[k].input_index >= 0) - tcc_error("cannot reference twice the same operand"); - operands[k].input_index = i; - op->priority = 5; - } else if ((op->vt->r & VT_VALMASK) == VT_LOCAL - && op->vt->sym - && (reg = op->vt->sym->r & VT_VALMASK) < VT_CONST) { - op->priority = 1; - op->reg = reg; - } else { - op->priority = constraint_priority(str); - } - } - - /* sort operands according to their priority */ - for(i=0;i<nb_operands;i++) - sorted_op[i] = i; - for(i=0;i<nb_operands - 1;i++) { - for(j=i+1;j<nb_operands;j++) { - p1 = operands[sorted_op[i]].priority; - p2 = operands[sorted_op[j]].priority; - if (p2 < p1) { - tmp = sorted_op[i]; - sorted_op[i] = sorted_op[j]; - sorted_op[j] = tmp; - } - } - } - - for(i = 0;i < NB_ASM_REGS; i++) { - if (clobber_regs[i]) - regs_allocated[i] = REG_IN_MASK | REG_OUT_MASK; - else - regs_allocated[i] = 0; - } - /* esp cannot be used */ - regs_allocated[4] = REG_IN_MASK | REG_OUT_MASK; - /* ebp cannot be used yet */ - regs_allocated[5] = REG_IN_MASK | REG_OUT_MASK; - - /* allocate registers and generate corresponding asm moves */ - for(i=0;i<nb_operands;i++) { - j = sorted_op[i]; - op = &operands[j]; - str = op->constraint; - /* no need to allocate references */ - if (op->ref_index >= 0) - continue; - /* select if register is used for output, input or both */ - if (op->input_index >= 0) { - reg_mask = REG_IN_MASK | REG_OUT_MASK; - } else if (j < nb_outputs) { - reg_mask = REG_OUT_MASK; - } else { - reg_mask = REG_IN_MASK; - } - if (op->reg >= 0) { - if (is_reg_allocated(op->reg)) - tcc_error("asm regvar requests register that's taken already"); - reg = op->reg; - goto reg_found; - } - try_next: - c = *str++; - switch(c) { - case '=': - goto try_next; - case '+': - op->is_rw = 1; - /* FALL THRU */ - case '&': - if (j >= nb_outputs) - tcc_error("'%c' modifier can only be applied to outputs", c); - reg_mask = REG_IN_MASK | REG_OUT_MASK; - goto try_next; - case 'A': - /* allocate both eax and edx */ - if (is_reg_allocated(TREG_XAX) || - is_reg_allocated(TREG_XDX)) - goto try_next; - op->is_llong = 1; - op->reg = TREG_XAX; - regs_allocated[TREG_XAX] |= reg_mask; - regs_allocated[TREG_XDX] |= reg_mask; - break; - case 'a': - reg = TREG_XAX; - goto alloc_reg; - case 'b': - reg = 3; - goto alloc_reg; - case 'c': - reg = TREG_XCX; - goto alloc_reg; - case 'd': - reg = TREG_XDX; - goto alloc_reg; - case 'S': - reg = 6; - goto alloc_reg; - case 'D': - reg = 7; - alloc_reg: - if (is_reg_allocated(reg)) - goto try_next; - goto reg_found; - case 'q': - /* eax, ebx, ecx or edx */ - for(reg = 0; reg < 4; reg++) { - if (!is_reg_allocated(reg)) - goto reg_found; - } - goto try_next; - case 'r': - case 'R': - case 'p': /* A general address, for x86(64) any register is acceptable*/ - /* any general register */ - for(reg = 0; reg < 8; reg++) { - if (!is_reg_allocated(reg)) - goto reg_found; - } - goto try_next; - reg_found: - /* now we can reload in the register */ - op->is_llong = 0; - op->reg = reg; - regs_allocated[reg] |= reg_mask; - break; - case 'e': - case 'i': - if (!((op->vt->r & (VT_VALMASK | VT_LVAL)) == VT_CONST)) - goto try_next; - break; - case 'I': - case 'N': - case 'M': - if (!((op->vt->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST)) - goto try_next; - break; - case 'm': - case 'g': - /* nothing special to do because the operand is already in - memory, except if the pointer itself is stored in a - memory variable (VT_LLOCAL case) */ - /* XXX: fix constant case */ - /* if it is a reference to a memory zone, it must lie - in a register, so we reserve the register in the - input registers and a load will be generated - later */ - if (j < nb_outputs || c == 'm') { - if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) { - /* any general register */ - for(reg = 0; reg < 8; reg++) { - if (!(regs_allocated[reg] & REG_IN_MASK)) - goto reg_found1; - } - goto try_next; - reg_found1: - /* now we can reload in the register */ - regs_allocated[reg] |= REG_IN_MASK; - op->reg = reg; - op->is_memory = 1; - } - } - break; - default: - tcc_error("asm constraint %d ('%s') could not be satisfied", - j, op->constraint); - break; - } - /* if a reference is present for that operand, we assign it too */ - if (op->input_index >= 0) { - operands[op->input_index].reg = op->reg; - operands[op->input_index].is_llong = op->is_llong; - } - } - - /* compute out_reg. It is used to store outputs registers to memory - locations references by pointers (VT_LLOCAL case) */ - *pout_reg = -1; - for(i=0;i<nb_operands;i++) { - op = &operands[i]; - if (op->reg >= 0 && - (op->vt->r & VT_VALMASK) == VT_LLOCAL && - !op->is_memory) { - for(reg = 0; reg < 8; reg++) { - if (!(regs_allocated[reg] & REG_OUT_MASK)) - goto reg_found2; - } - tcc_error("could not find free output register for reloading"); - reg_found2: - *pout_reg = reg; - break; - } - } - - /* print sorted constraints */ -#ifdef ASM_DEBUG - for(i=0;i<nb_operands;i++) { - j = sorted_op[i]; - op = &operands[j]; - printf("%%%d [%s]: \"%s\" r=0x%04x reg=%d\n", - j, - op->id ? get_tok_str(op->id, NULL) : "", - op->constraint, - op->vt->r, - op->reg); - } - if (*pout_reg >= 0) - printf("out_reg=%d\n", *pout_reg); -#endif -} - -ST_FUNC void subst_asm_operand(CString *add_str, - SValue *sv, int modifier) -{ - int r, reg, size, val; - char buf[64]; - - r = sv->r; - if ((r & VT_VALMASK) == VT_CONST) { - if (!(r & VT_LVAL) && modifier != 'c' && modifier != 'n' && - modifier != 'P') - cstr_ccat(add_str, '$'); - if (r & VT_SYM) { - const char *name = get_tok_str(sv->sym->v, NULL); - if (sv->sym->v >= SYM_FIRST_ANOM) { - /* In case of anonymous symbols ("L.42", used - for static data labels) we can't find them - in the C symbol table when later looking up - this name. So enter them now into the asm label - list when we still know the symbol. */ - get_asm_sym(tok_alloc_const(name), sv->sym); - } - if (tcc_state->leading_underscore) - cstr_ccat(add_str, '_'); - cstr_cat(add_str, name, -1); - if ((uint32_t)sv->c.i == 0) - goto no_offset; - cstr_ccat(add_str, '+'); - } - val = sv->c.i; - if (modifier == 'n') - val = -val; - snprintf(buf, sizeof(buf), "%d", (int)sv->c.i); - cstr_cat(add_str, buf, -1); - no_offset:; -#ifdef TCC_TARGET_X86_64 - if (r & VT_LVAL) - cstr_cat(add_str, "(%rip)", -1); -#endif - } else if ((r & VT_VALMASK) == VT_LOCAL) { -#ifdef TCC_TARGET_X86_64 - snprintf(buf, sizeof(buf), "%d(%%rbp)", (int)sv->c.i); -#else - snprintf(buf, sizeof(buf), "%d(%%ebp)", (int)sv->c.i); -#endif - cstr_cat(add_str, buf, -1); - } else if (r & VT_LVAL) { - reg = r & VT_VALMASK; - if (reg >= VT_CONST) - tcc_internal_error(""); - snprintf(buf, sizeof(buf), "(%%%s)", -#ifdef TCC_TARGET_X86_64 - get_tok_str(TOK_ASM_rax + reg, NULL) -#else - get_tok_str(TOK_ASM_eax + reg, NULL) -#endif - ); - cstr_cat(add_str, buf, -1); - } else { - /* register case */ - reg = r & VT_VALMASK; - if (reg >= VT_CONST) - tcc_internal_error(""); - - /* choose register operand size */ - if ((sv->type.t & VT_BTYPE) == VT_BYTE || - (sv->type.t & VT_BTYPE) == VT_BOOL) - size = 1; - else if ((sv->type.t & VT_BTYPE) == VT_SHORT) - size = 2; -#ifdef TCC_TARGET_X86_64 - else if ((sv->type.t & VT_BTYPE) == VT_LLONG || - (sv->type.t & VT_BTYPE) == VT_PTR) - size = 8; -#endif - else - size = 4; - if (size == 1 && reg >= 4) - size = 4; - - if (modifier == 'b') { - if (reg >= 4) - tcc_error("cannot use byte register"); - size = 1; - } else if (modifier == 'h') { - if (reg >= 4) - tcc_error("cannot use byte register"); - size = -1; - } else if (modifier == 'w') { - size = 2; - } else if (modifier == 'k') { - size = 4; -#ifdef TCC_TARGET_X86_64 - } else if (modifier == 'q') { - size = 8; -#endif - } - - switch(size) { - case -1: - reg = TOK_ASM_ah + reg; - break; - case 1: - reg = TOK_ASM_al + reg; - break; - case 2: - reg = TOK_ASM_ax + reg; - break; - default: - reg = TOK_ASM_eax + reg; - break; -#ifdef TCC_TARGET_X86_64 - case 8: - reg = TOK_ASM_rax + reg; - break; -#endif - } - snprintf(buf, sizeof(buf), "%%%s", get_tok_str(reg, NULL)); - cstr_cat(add_str, buf, -1); - } -} - -/* 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) -{ - uint8_t regs_allocated[NB_ASM_REGS]; - ASMOperand *op; - int i, reg; - - /* Strictly speaking %Xbp and %Xsp should be included in the - call-preserved registers, but currently it doesn't matter. */ -#ifdef TCC_TARGET_X86_64 -#ifdef TCC_TARGET_PE - static const uint8_t reg_saved[] = { 3, 6, 7, 12, 13, 14, 15 }; -#else - static const uint8_t reg_saved[] = { 3, 12, 13, 14, 15 }; -#endif -#else - static const uint8_t reg_saved[] = { 3, 6, 7 }; -#endif - - /* mark all used registers */ - memcpy(regs_allocated, clobber_regs, sizeof(regs_allocated)); - for(i = 0; i < nb_operands;i++) { - op = &operands[i]; - if (op->reg >= 0) - regs_allocated[op->reg] = 1; - } - if (!is_output) { - /* generate reg save code */ - for(i = 0; i < sizeof(reg_saved)/sizeof(reg_saved[0]); i++) { - reg = reg_saved[i]; - if (regs_allocated[reg]) { - if (reg >= 8) - g(0x41), reg-=8; - g(0x50 + reg); - } - } - - /* generate load code */ - for(i = 0; i < nb_operands; i++) { - op = &operands[i]; - if (op->reg >= 0) { - if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && - op->is_memory) { - /* memory reference case (for both input and - output cases) */ - SValue sv; - sv = *op->vt; - sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL | VT_LVAL; - sv.type.t = VT_PTR; - load(op->reg, &sv); - } else if (i >= nb_outputs || op->is_rw) { - /* load value in register */ - load(op->reg, op->vt); - if (op->is_llong) { - SValue sv; - sv = *op->vt; - sv.c.i += 4; - load(TREG_XDX, &sv); - } - } - } - } - } else { - /* generate save code */ - for(i = 0 ; i < nb_outputs; i++) { - op = &operands[i]; - if (op->reg >= 0) { - if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) { - if (!op->is_memory) { - SValue sv; - sv = *op->vt; - sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL; - sv.type.t = VT_PTR; - load(out_reg, &sv); - - sv = *op->vt; - sv.r = (sv.r & ~VT_VALMASK) | out_reg; - store(op->reg, &sv); - } - } else { - store(op->reg, op->vt); - if (op->is_llong) { - SValue sv; - sv = *op->vt; - sv.c.i += 4; - store(TREG_XDX, &sv); - } - } - } - } - /* generate reg restore code */ - for(i = sizeof(reg_saved)/sizeof(reg_saved[0]) - 1; i >= 0; i--) { - reg = reg_saved[i]; - if (regs_allocated[reg]) { - if (reg >= 8) - g(0x41), reg-=8; - g(0x58 + reg); - } - } - } -} - -ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str) -{ - int reg; -#ifdef TCC_TARGET_X86_64 - unsigned int type; -#endif - - if (!strcmp(str, "memory") || - !strcmp(str, "cc") || - !strcmp(str, "flags")) - return; - reg = tok_alloc_const(str); - if (reg >= TOK_ASM_eax && reg <= TOK_ASM_edi) { - reg -= TOK_ASM_eax; - } else if (reg >= TOK_ASM_ax && reg <= TOK_ASM_di) { - reg -= TOK_ASM_ax; -#ifdef TCC_TARGET_X86_64 - } else if (reg >= TOK_ASM_rax && reg <= TOK_ASM_rdi) { - reg -= TOK_ASM_rax; - } else if ((reg = asm_parse_numeric_reg(reg, &type)) >= 0) { - ; -#endif - } else { - tcc_error("invalid clobber register '%s'", str); - } - clobber_regs[reg] = 1; -} diff --git a/tinycc/i386-asm.h b/tinycc/i386-asm.h deleted file mode 100644 index 0f99b28..0000000 --- a/tinycc/i386-asm.h +++ /dev/null @@ -1,487 +0,0 @@ - DEF_ASM_OP0(clc, 0xf8) /* must be first OP0 */ - DEF_ASM_OP0(cld, 0xfc) - DEF_ASM_OP0(cli, 0xfa) - DEF_ASM_OP0(clts, 0x0f06) - DEF_ASM_OP0(cmc, 0xf5) - DEF_ASM_OP0(lahf, 0x9f) - DEF_ASM_OP0(sahf, 0x9e) - DEF_ASM_OP0(pusha, 0x60) - DEF_ASM_OP0(popa, 0x61) - DEF_ASM_OP0(pushfl, 0x9c) - DEF_ASM_OP0(popfl, 0x9d) - DEF_ASM_OP0(pushf, 0x9c) - DEF_ASM_OP0(popf, 0x9d) - DEF_ASM_OP0(stc, 0xf9) - DEF_ASM_OP0(std, 0xfd) - DEF_ASM_OP0(sti, 0xfb) - DEF_ASM_OP0(aaa, 0x37) - DEF_ASM_OP0(aas, 0x3f) - DEF_ASM_OP0(daa, 0x27) - DEF_ASM_OP0(das, 0x2f) - DEF_ASM_OP0(aad, 0xd50a) - DEF_ASM_OP0(aam, 0xd40a) - DEF_ASM_OP0(cbw, 0x6698) - DEF_ASM_OP0(cwd, 0x6699) - DEF_ASM_OP0(cwde, 0x98) - DEF_ASM_OP0(cdq, 0x99) - DEF_ASM_OP0(cbtw, 0x6698) - DEF_ASM_OP0(cwtl, 0x98) - DEF_ASM_OP0(cwtd, 0x6699) - DEF_ASM_OP0(cltd, 0x99) - DEF_ASM_OP0(int3, 0xcc) - DEF_ASM_OP0(into, 0xce) - DEF_ASM_OP0(iret, 0xcf) - DEF_ASM_OP0(rsm, 0x0faa) - DEF_ASM_OP0(hlt, 0xf4) - DEF_ASM_OP0(nop, 0x90) - DEF_ASM_OP0(pause, 0xf390) - DEF_ASM_OP0(xlat, 0xd7) - - /* strings */ -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_BWLX)) -ALT(DEF_ASM_OP0L(slodb, 0xac, 0, OPC_BWLX)) - -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_BWLX)) -ALT(DEF_ASM_OP0L(sscab, 0xae, 0, OPC_BWLX)) - -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_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_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_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_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_WLX, OPT_REGW, OPT_REGW | OPT_EA)) -ALT(DEF_ASM_OP2(btcw, 0x0fba, 7, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA)) - -ALT(DEF_ASM_OP2(popcntw, 0xf30fb8, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW)) - -ALT(DEF_ASM_OP2(tzcntw, 0xf30fbc, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW)) -ALT(DEF_ASM_OP2(lzcntw, 0xf30fbd, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW)) - - /* prefixes */ - DEF_ASM_OP0(wait, 0x9b) - DEF_ASM_OP0(fwait, 0x9b) - DEF_ASM_OP0(aword, 0x67) - DEF_ASM_OP0(addr16, 0x67) - ALT(DEF_ASM_OP0(word, 0x66)) - DEF_ASM_OP0(data16, 0x66) - DEF_ASM_OP0(lock, 0xf0) - DEF_ASM_OP0(rep, 0xf3) - DEF_ASM_OP0(repe, 0xf3) - DEF_ASM_OP0(repz, 0xf3) - DEF_ASM_OP0(repne, 0xf2) - DEF_ASM_OP0(repnz, 0xf2) - - DEF_ASM_OP0(invd, 0x0f08) - DEF_ASM_OP0(wbinvd, 0x0f09) - DEF_ASM_OP0(cpuid, 0x0fa2) - DEF_ASM_OP0(wrmsr, 0x0f30) - DEF_ASM_OP0(rdtsc, 0x0f31) - DEF_ASM_OP0(rdmsr, 0x0f32) - DEF_ASM_OP0(rdpmc, 0x0f33) - DEF_ASM_OP0(ud2, 0x0f0b) - - /* NOTE: we took the same order as gas opcode definition order */ -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_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_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, 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_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_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_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_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)) -ALT(DEF_ASM_OP2(inb, 0xec, 0, OPC_BWL, OPT_DX, OPT_EAX)) -ALT(DEF_ASM_OP1(inb, 0xec, 0, OPC_BWL, OPT_DX)) - -ALT(DEF_ASM_OP2(outb, 0xe6, 0, OPC_BWL, OPT_EAX, OPT_IM8)) -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_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)) -ALT(DEF_ASM_OP2(lss, 0x0fb2, 0, OPC_MODRM, OPT_EA, OPT_REG32)) -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_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_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_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_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_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_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_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_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_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, 0, OPT_DISP)) -ALT(DEF_ASM_OP1(jmp, 0xff, 4, OPC_MODRM, OPT_INDIR)) -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, OPC_MODRM, OPT_EA)) -ALT(DEF_ASM_OP2(ljmp, 0xea, 0, 0, OPT_IM16, OPT_IM32)) -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) - DEF_ASM_OP0(retl,0xc3) -ALT(DEF_ASM_OP1(retl,0xc2, 0, 0, OPT_IM16)) -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_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 */ -ALT(DEF_ASM_OP0L(fcomp, 0xd8d9, 0, 0)) - -ALT(DEF_ASM_OP1(fadd, 0xd8c0, 0, OPC_FARITH | OPC_REG, OPT_ST)) -ALT(DEF_ASM_OP2(fadd, 0xd8c0, 0, OPC_FARITH | OPC_REG, OPT_ST, OPT_ST0)) -ALT(DEF_ASM_OP2(fadd, 0xdcc0, 0, OPC_FARITH | OPC_REG, OPT_ST0, OPT_ST)) -ALT(DEF_ASM_OP2(fmul, 0xdcc8, 0, OPC_FARITH | OPC_REG, OPT_ST0, OPT_ST)) -ALT(DEF_ASM_OP0L(fadd, 0xdec1, 0, OPC_FARITH)) -ALT(DEF_ASM_OP1(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST)) -ALT(DEF_ASM_OP2(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST, OPT_ST0)) -ALT(DEF_ASM_OP2(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST0, OPT_ST)) -ALT(DEF_ASM_OP0L(faddp, 0xdec1, 0, OPC_FARITH)) -ALT(DEF_ASM_OP1(fadds, 0xd8, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) -ALT(DEF_ASM_OP1(fiaddl, 0xda, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) -ALT(DEF_ASM_OP1(faddl, 0xdc, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) -ALT(DEF_ASM_OP1(fiadds, 0xde, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) - - DEF_ASM_OP0(fucompp, 0xdae9) - DEF_ASM_OP0(ftst, 0xd9e4) - DEF_ASM_OP0(fxam, 0xd9e5) - DEF_ASM_OP0(fld1, 0xd9e8) - DEF_ASM_OP0(fldl2t, 0xd9e9) - DEF_ASM_OP0(fldl2e, 0xd9ea) - DEF_ASM_OP0(fldpi, 0xd9eb) - DEF_ASM_OP0(fldlg2, 0xd9ec) - DEF_ASM_OP0(fldln2, 0xd9ed) - DEF_ASM_OP0(fldz, 0xd9ee) - - DEF_ASM_OP0(f2xm1, 0xd9f0) - DEF_ASM_OP0(fyl2x, 0xd9f1) - DEF_ASM_OP0(fptan, 0xd9f2) - DEF_ASM_OP0(fpatan, 0xd9f3) - DEF_ASM_OP0(fxtract, 0xd9f4) - DEF_ASM_OP0(fprem1, 0xd9f5) - DEF_ASM_OP0(fdecstp, 0xd9f6) - DEF_ASM_OP0(fincstp, 0xd9f7) - DEF_ASM_OP0(fprem, 0xd9f8) - DEF_ASM_OP0(fyl2xp1, 0xd9f9) - DEF_ASM_OP0(fsqrt, 0xd9fa) - DEF_ASM_OP0(fsincos, 0xd9fb) - DEF_ASM_OP0(frndint, 0xd9fc) - DEF_ASM_OP0(fscale, 0xd9fd) - DEF_ASM_OP0(fsin, 0xd9fe) - DEF_ASM_OP0(fcos, 0xd9ff) - DEF_ASM_OP0(fchs, 0xd9e0) - DEF_ASM_OP0(fabs, 0xd9e1) - DEF_ASM_OP0(fninit, 0xdbe3) - DEF_ASM_OP0(fnclex, 0xdbe2) - DEF_ASM_OP0(fnop, 0xd9d0) - - /* fp load */ - DEF_ASM_OP1(fld, 0xd9c0, 0, OPC_REG, OPT_ST) - DEF_ASM_OP1(fldl, 0xd9c0, 0, OPC_REG, OPT_ST) - DEF_ASM_OP1(flds, 0xd9, 0, OPC_MODRM, OPT_EA) -ALT(DEF_ASM_OP1(fldl, 0xdd, 0, OPC_MODRM, OPT_EA)) - DEF_ASM_OP1(fildl, 0xdb, 0, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fildq, 0xdf, 5, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fildll, 0xdf, 5, OPC_MODRM,OPT_EA) - DEF_ASM_OP1(fldt, 0xdb, 5, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fbld, 0xdf, 4, OPC_MODRM, OPT_EA) - - /* fp store */ - DEF_ASM_OP1(fst, 0xddd0, 0, OPC_REG, OPT_ST) - DEF_ASM_OP1(fstl, 0xddd0, 0, OPC_REG, OPT_ST) - DEF_ASM_OP1(fsts, 0xd9, 2, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fstps, 0xd9, 3, OPC_MODRM, OPT_EA) -ALT(DEF_ASM_OP1(fstl, 0xdd, 2, OPC_MODRM, OPT_EA)) - DEF_ASM_OP1(fstpl, 0xdd, 3, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fist, 0xdf, 2, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fistp, 0xdf, 3, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fistl, 0xdb, 2, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fistpl, 0xdb, 3, OPC_MODRM, OPT_EA) - - DEF_ASM_OP1(fstp, 0xddd8, 0, OPC_REG, OPT_ST) - DEF_ASM_OP1(fistpq, 0xdf, 7, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fistpll, 0xdf, 7, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fstpt, 0xdb, 7, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fbstp, 0xdf, 6, OPC_MODRM, OPT_EA) - - /* exchange */ - DEF_ASM_OP0(fxch, 0xd9c9) -ALT(DEF_ASM_OP1(fxch, 0xd9c8, 0, OPC_REG, OPT_ST)) - - /* misc FPU */ - DEF_ASM_OP1(fucom, 0xdde0, 0, OPC_REG, OPT_ST ) - DEF_ASM_OP1(fucomp, 0xdde8, 0, OPC_REG, OPT_ST ) - - DEF_ASM_OP0L(finit, 0xdbe3, 0, OPC_FWAIT) - DEF_ASM_OP1(fldcw, 0xd9, 5, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(fnstcw, 0xd9, 7, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(fstcw, 0xd9, 7, OPC_MODRM | OPC_FWAIT, OPT_EA ) - DEF_ASM_OP0(fnstsw, 0xdfe0) -ALT(DEF_ASM_OP1(fnstsw, 0xdfe0, 0, 0, OPT_EAX )) -ALT(DEF_ASM_OP1(fnstsw, 0xdd, 7, OPC_MODRM, OPT_EA )) - DEF_ASM_OP1(fstsw, 0xdfe0, 0, OPC_FWAIT, OPT_EAX ) -ALT(DEF_ASM_OP0L(fstsw, 0xdfe0, 0, OPC_FWAIT)) -ALT(DEF_ASM_OP1(fstsw, 0xdd, 7, OPC_MODRM | OPC_FWAIT, OPT_EA )) - DEF_ASM_OP0L(fclex, 0xdbe2, 0, OPC_FWAIT) - DEF_ASM_OP1(fnstenv, 0xd9, 6, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(fstenv, 0xd9, 6, OPC_MODRM | OPC_FWAIT, OPT_EA ) - DEF_ASM_OP1(fldenv, 0xd9, 4, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(fnsave, 0xdd, 6, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(fsave, 0xdd, 6, OPC_MODRM | OPC_FWAIT, OPT_EA ) - DEF_ASM_OP1(frstor, 0xdd, 4, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(ffree, 0xddc0, 4, OPC_REG, OPT_ST ) - DEF_ASM_OP1(ffreep, 0xdfc0, 4, OPC_REG, OPT_ST ) - DEF_ASM_OP1(fxsave, 0x0fae, 0, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(fxrstor, 0x0fae, 1, OPC_MODRM, OPT_EA ) - - /* segments */ - DEF_ASM_OP2(arpl, 0x63, 0, OPC_MODRM, OPT_REG16, OPT_REG16 | OPT_EA) -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_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) - DEF_ASM_OP1(sldt, 0x0f00, 0, OPC_MODRM, OPT_REG | OPT_EA) - DEF_ASM_OP1(smsw, 0x0f01, 4, OPC_MODRM, OPT_REG | OPT_EA) - DEF_ASM_OP1(str, 0x0f00, 1, OPC_MODRM, OPT_REG16| OPT_EA) - DEF_ASM_OP1(verr, 0x0f00, 4, OPC_MODRM, OPT_REG | OPT_EA) - DEF_ASM_OP1(verw, 0x0f00, 5, OPC_MODRM, OPT_REG | OPT_EA) - - /* 486 */ - DEF_ASM_OP1(bswap, 0x0fc8, 0, OPC_REG, OPT_REG32 ) -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, 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 | 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 ) - DEF_ASM_OP2(fcmovu, 0xdad8, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcmovnb, 0xdbc0, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcmovne, 0xdbc8, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcmovnbe, 0xdbd0, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcmovnu, 0xdbd8, 0, OPC_REG, OPT_ST, OPT_ST0 ) - - DEF_ASM_OP2(fucomi, 0xdbe8, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcomi, 0xdbf0, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fucomip, 0xdfe8, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcomip, 0xdff0, 0, OPC_REG, OPT_ST, OPT_ST0 ) - - /* mmx */ - DEF_ASM_OP0(emms, 0x0f77) /* must be last OP0 */ - 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 )) -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_OP1(ldmxcsr, 0x0fae, 2, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(stmxcsr, 0x0fae, 3, OPC_MODRM, OPT_EA) - 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 -#undef DEF_ASM_OP0L -#undef DEF_ASM_OP1 -#undef DEF_ASM_OP2 -#undef DEF_ASM_OP3 diff --git a/tinycc/i386-gen.c b/tinycc/i386-gen.c deleted file mode 100644 index 62bc2ad..0000000 --- a/tinycc/i386-gen.c +++ /dev/null @@ -1,1140 +0,0 @@ -/* - * X86 code generator for TCC - * - * 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 - */ - -#ifdef TARGET_DEFS_ONLY - -/* number of available registers */ -#define NB_REGS 5 -#define NB_ASM_REGS 8 -#define CONFIG_TCC_ASM - -/* a register can belong to several classes. The classes must be - sorted from more general to more precise (see gv2() code which does - assumptions on it). */ -#define RC_INT 0x0001 /* generic integer register */ -#define RC_FLOAT 0x0002 /* generic float register */ -#define RC_EAX 0x0004 -#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_IRE2 RC_EDX /* function return: second integer register */ -#define RC_FRET RC_ST0 /* function return: float register */ - -/* pretty names for the registers */ -enum { - TREG_EAX = 0, - TREG_ECX, - TREG_EDX, - TREG_EBX, - TREG_ST0, - TREG_ESP = 4 -}; - -/* return registers for function */ -#define REG_IRET TREG_EAX /* single word int return register */ -#define REG_IRE2 TREG_EDX /* second word return register (for long long) */ -#define REG_FRET TREG_ST0 /* float return register */ - -/* defined if function parameters must be evaluated in reverse order */ -#define INVERT_FUNC_PARAMS - -/* defined if structures are passed as pointers. Otherwise structures - are directly pushed on stack. */ -/* #define FUNC_STRUCT_PARAM_AS_PTR */ - -/* pointer size, in bytes */ -#define PTR_SIZE 4 - -/* long double size and alignment, in bytes */ -#define LDOUBLE_SIZE 12 -#define LDOUBLE_ALIGN 4 -/* maximum alignment (for aligned attribute support) */ -#define MAX_ALIGN 8 - -/* define if return values need to be extended explicitely - at caller side (for interfacing with non-TCC compilers) */ -#define PROMOTE_RET - -/******************************************************/ -#else /* ! TARGET_DEFS_ONLY */ -/******************************************************/ -#define USING_GLOBALS -#include "tcc.h" - -ST_DATA const char * const target_machine_defs = - "__i386__\0" - "__i386\0" - ; - -/* 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 addr_t func_bound_offset; -static unsigned long func_bound_ind; -ST_DATA int func_bound_add_epilog; -static void gen_bounds_prolog(void); -static void gen_bounds_epilog(void); -#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); - cur_text_section->data[ind] = c; - ind = ind1; -} - -ST_FUNC void o(unsigned int c) -{ - while (c) { - g(c); - c = c >> 8; - } -} - -ST_FUNC void gen_le16(int v) -{ - g(v); - g(v >> 8); -} - -ST_FUNC void gen_le32(int c) -{ - g(c); - g(c >> 8); - g(c >> 16); - g(c >> 24); -} - -/* output a symbol and patch all calls to it */ -ST_FUNC void gsym_addr(int t, int a) -{ - while (t) { - unsigned char *ptr = cur_text_section->data + t; - uint32_t n = read32le(ptr); /* next value */ - write32le(ptr, a - t - 4); - t = n; - } -} - -/* instruction + 4 bytes data. Return the address of the data */ -static int oad(int c, int s) -{ - int t; - if (nocode_wanted) - return s; - o(c); - t = ind; - gen_le32(s); - return t; -} - -ST_FUNC void gen_fill_nops(int bytes) -{ - while (bytes--) - g(0x90); -} - -/* 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) -{ - 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) -{ - if (r & VT_SYM) - greloc(cur_text_section, sym, ind, R_386_PC32); - gen_le32(c - 4); -} - -/* generate a modrm reference. 'op_reg' contains the additional 3 - opcode bits */ -static void gen_modrm(int op_reg, int r, Sym *sym, int c) -{ - op_reg = op_reg << 3; - if ((r & VT_VALMASK) == VT_CONST) { - /* constant memory reference */ - o(0x05 | op_reg); - gen_addr32(r, sym, c); - } else if ((r & VT_VALMASK) == VT_LOCAL) { - /* currently, we use only ebp as base */ - if (c == (char)c) { - /* short reference */ - o(0x45 | op_reg); - g(c); - } else { - oad(0x85 | op_reg, c); - } - } else { - g(0x00 | op_reg | (r & VT_VALMASK)); - } -} - -/* load 'r' from value 'sv' */ -ST_FUNC void load(int r, SValue *sv) -{ - int v, t, ft, fc, fr; - SValue v1; - -#ifdef TCC_TARGET_PE - SValue v2; - sv = pe_getimport(sv, &v2); -#endif - - fr = sv->r; - ft = sv->type.t & ~VT_DEFSIGN; - 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.i = fc; - v1.sym = NULL; - fr = r; - if (!(reg_classes[fr] & RC_INT)) - fr = get_reg(RC_INT); - load(fr, &v1); - } - if ((ft & VT_BTYPE) == VT_FLOAT) { - o(0xd9); /* flds */ - r = 0; - } else if ((ft & VT_BTYPE) == VT_DOUBLE) { - o(0xdd); /* fldl */ - r = 0; - } else if ((ft & VT_BTYPE) == VT_LDOUBLE) { - o(0xdb); /* fldt */ - r = 5; - } 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 */ - } else if ((ft & VT_TYPE) == VT_SHORT) { - o(0xbf0f); /* movswl */ - } else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) { - o(0xb70f); /* movzwl */ - } else { - o(0x8b); /* movl */ - } - gen_modrm(r, fr, sv->sym, fc); - } else { - if (v == VT_CONST) { - o(0xb8 + r); /* mov $xx, r */ - gen_addr32(fr, sv->sym, fc); - } else if (v == VT_LOCAL) { - if (fc) { - o(0x8d); /* lea xxx(%ebp), r */ - gen_modrm(r, VT_LOCAL, sv->sym, fc); - } else { - o(0x89); - o(0xe8 + r); /* mov %ebp, r */ - } - } else if (v == VT_CMP) { - o(0x0f); /* setxx %br */ - o(fc); - o(0xc0 + r); - o(0xc0b60f + r * 0x90000); /* movzbl %al, %eax */ - } else if (v == VT_JMP || v == VT_JMPI) { - t = v & 1; - oad(0xb8 + r, t); /* mov $1, r */ - o(0x05eb); /* jmp after */ - gsym(fc); - oad(0xb8 + r, t ^ 1); /* mov $0, r */ - } else if (v != r) { - o(0x89); - o(0xc0 + r + v * 8); /* mov v, r */ - } - } -} - -/* store register 'r' in lvalue 'v' */ -ST_FUNC void store(int r, SValue *v) -{ - int fr, bt, ft, fc; - -#ifdef TCC_TARGET_PE - SValue v2; - v = pe_getimport(v, &v2); -#endif - - ft = v->type.t; - 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) { - o(0xd9); /* fsts */ - r = 2; - } else if (bt == VT_DOUBLE) { - o(0xdd); /* fstpl */ - r = 2; - } else if (bt == VT_LDOUBLE) { - o(0xc0d9); /* fld %st(0) */ - o(0xdb); /* fstpt */ - r = 7; - } else { - if (bt == VT_SHORT) - o(0x66); - if (bt == VT_BYTE || bt == VT_BOOL) - o(0x88); - else - o(0x89); - } - if (fr == VT_CONST || - fr == VT_LOCAL || - (v->r & VT_LVAL)) { - gen_modrm(r, v->r, v->sym, fc); - } else if (fr != r) { - o(0xc0 + fr + r * 8); /* mov r, fr */ - } -} - -static void gadd_sp(int val) -{ - if (val == (char)val) { - o(0xc483); - g(val); - } else { - oad(0xc481, val); /* add $xxx, %esp */ - } -} - -#if defined CONFIG_TCC_BCHECK || defined TCC_TARGET_PE -static void gen_static_call(int v) -{ - Sym *sym; - - sym = external_helper_sym(v); - oad(0xe8, -4); - greloc(cur_text_section, sym, ind-4, R_386_PC32); -} -#endif - -/* '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 && (vtop->r & VT_SYM)) { - /* constant and relocation case */ - greloc(cur_text_section, vtop->sym, ind + 1, R_386_PC32); - oad(0xe8 + is_jmp, vtop->c.i - 4); /* call/jmp im */ - } else { - /* otherwise, indirect call */ - r = gv(RC_INT); - o(0xff); /* call/jmp *r */ - o(0xd0 + r + (is_jmp << 4)); - } -} - -static const uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX }; -static const 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) -{ -#if defined(TCC_TARGET_PE) || TARGETOS_FreeBSD || TARGETOS_OpenBSD - 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. */ -ST_FUNC void gfunc_call(int nb_args) -{ - int size, align, r, args_size, i, func_call; - Sym *func_sym; - -#ifdef CONFIG_TCC_BCHECK - if (tcc_state->do_bounds_check) - gbound_args(nb_args); -#endif - - args_size = 0; - for(i = 0;i < nb_args; i++) { - if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { - size = type_size(&vtop->type, &align); - /* align to stack align size */ - size = (size + 3) & ~3; - /* allocate the necessary size on stack */ -#ifdef TCC_TARGET_PE - if (size >= 4096) { - r = get_reg(RC_EAX); - oad(0x68, size); // push size - /* cannot call normal 'alloca' with bound checking */ - gen_static_call(tok_alloc_const("__alloca")); - gadd_sp(4); - } else -#endif - { - oad(0xec81, size); /* sub $xxx, %esp */ - /* generate structure store */ - r = get_reg(RC_INT); - o(0xe089 + (r << 8)); /* mov %esp, r */ - } - vset(&vtop->type, r | VT_LVAL, 0); - vswap(); - vstore(); - args_size += size; - } else if (is_float(vtop->type.t)) { - gv(RC_FLOAT); /* only one float register */ - if ((vtop->type.t & VT_BTYPE) == VT_FLOAT) - size = 4; - else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) - size = 8; - else - size = 12; - oad(0xec81, size); /* sub $xxx, %esp */ - if (size == 12) - o(0x7cdb); - else - o(0x5cd9 + size - 4); /* fstp[s|l] 0(%esp) */ - g(0x24); - g(0x00); - args_size += size; - } else { - /* simple type (currently always same size) */ - /* XXX: implicit cast ? */ - r = gv(RC_INT); - if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { - size = 8; - o(0x50 + vtop->r2); /* push r */ - } else { - size = 4; - } - o(0x50 + r); /* push r */ - args_size += size; - } - vtop--; - } - save_regs(0); /* save used temporary registers */ - func_sym = vtop->type.ref; - func_call = func_sym->f.func_call; - /* fast call case */ - if ((func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) || - func_call == FUNC_FASTCALLW) { - int fastcall_nb_regs; - const uint8_t *fastcall_regs_ptr; - if (func_call == FUNC_FASTCALLW) { - fastcall_regs_ptr = fastcallw_regs; - fastcall_nb_regs = 2; - } else { - fastcall_regs_ptr = fastcall_regs; - fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1; - } - for(i = 0;i < fastcall_nb_regs; i++) { - if (args_size <= 0) - break; - o(0x58 + fastcall_regs_ptr[i]); /* pop r */ - /* XXX: incorrect for struct/floats */ - args_size -= 4; - } - } -#if !defined(TCC_TARGET_PE) && !TARGETOS_FreeBSD || TARGETOS_OpenBSD - 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 && func_call != FUNC_FASTCALLW) - gadd_sp(args_size); - vtop--; -} - -#ifdef TCC_TARGET_PE -#define FUNC_PROLOG_SIZE (10 + USE_EBX) -#else -#define FUNC_PROLOG_SIZE (9 + USE_EBX) -#endif - -/* generate function prolog of type 't' */ -ST_FUNC void gfunc_prolog(Sym *func_sym) -{ - CType *func_type = &func_sym->type; - int addr, align, size, func_call, fastcall_nb_regs; - int param_index, param_addr; - const uint8_t *fastcall_regs_ptr; - Sym *sym; - CType *type; - - sym = func_type->ref; - func_call = sym->f.func_call; - addr = 8; - loc = 0; - func_vc = 0; - - if (func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) { - fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1; - fastcall_regs_ptr = fastcall_regs; - } else if (func_call == FUNC_FASTCALLW) { - fastcall_nb_regs = 2; - fastcall_regs_ptr = fastcallw_regs; - } else { - fastcall_nb_regs = 0; - fastcall_regs_ptr = NULL; - } - param_index = 0; - - ind += FUNC_PROLOG_SIZE; - func_sub_sp_offset = ind; - /* if the function returns a structure, then add an - implicit pointer parameter */ -#if defined(TCC_TARGET_PE) || TARGETOS_FreeBSD || TARGETOS_OpenBSD - 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; - param_index++; - } - /* define parameters */ - while ((sym = sym->next) != NULL) { - type = &sym->type; - size = type_size(type, &align); - size = (size + 3) & ~3; -#ifdef FUNC_STRUCT_PARAM_AS_PTR - /* structs are passed as pointer */ - if ((type->t & VT_BTYPE) == VT_STRUCT) { - size = 4; - } -#endif - if (param_index < fastcall_nb_regs) { - /* save FASTCALL register */ - loc -= 4; - o(0x89); /* movl */ - gen_modrm(fastcall_regs_ptr[param_index], VT_LOCAL, NULL, loc); - param_addr = loc; - } else { - param_addr = addr; - addr += size; - } - sym_push(sym->v & ~SYM_FIELD, type, - VT_LOCAL | VT_LVAL, param_addr); - param_index++; - } - func_ret_sub = 0; - /* pascal type call or fastcall ? */ - if (func_call == FUNC_STDCALL || func_call == FUNC_FASTCALLW) - func_ret_sub = addr - 8; -#if !defined(TCC_TARGET_PE) && !TARGETOS_FreeBSD || TARGETOS_OpenBSD - else if (func_vc) - func_ret_sub = 4; -#endif - -#ifdef CONFIG_TCC_BCHECK - if (tcc_state->do_bounds_check) - gen_bounds_prolog(); -#endif -} - -/* generate function epilog */ -ST_FUNC void gfunc_epilog(void) -{ - addr_t v, saved_ind; - -#ifdef CONFIG_TCC_BCHECK - if (tcc_state->do_bounds_check) - gen_bounds_epilog(); -#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 */ - } else { - o(0xc2); /* ret n */ - g(func_ret_sub); - g(func_ret_sub >> 8); - } - saved_ind = ind; - ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; -#ifdef TCC_TARGET_PE - if (v >= 4096) { - oad(0xb8, v); /* mov stacksize, %eax */ - 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); -#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 gjmp2(0xe9, t); -} - -/* generate a jump to a fixed address */ -ST_FUNC void gjmp_addr(int a) -{ - int r; - r = a - ind - 2; - if (r == (char)r) { - g(0xeb); - g(r); - } else { - oad(0xe9, a - ind - 5); - } -} - -#if 0 -/* generate a jump to a fixed address */ -ST_FUNC void gjmp_cond_addr(int a, int op) -{ - int r = a - ind - 2; - if (r == (char)r) - g(op - 32), g(r); - else - g(0x0f), gjmp2(op - 16, r - 4); -} -#endif - -ST_FUNC int gjmp_append(int n, int t) -{ - void *p; - /* insert vtop->c jump list in t */ - if (n) { - uint32_t n1 = n, n2; - while ((n2 = read32le(p = cur_text_section->data + n1))) - n1 = n2; - write32le(p, t); - t = n; - } - return t; -} - -ST_FUNC int gjmp_cond(int op, int t) -{ - g(0x0f); - t = gjmp2(op - 16, t); - return t; -} - -ST_FUNC void gen_opi(int op) -{ - int r, fr, opc, c; - - switch(op) { - case '+': - case TOK_ADDC1: /* add with carry generation */ - opc = 0; - gen_op8: - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { - /* constant case */ - vswap(); - r = gv(RC_INT); - vswap(); - c = vtop->c.i; - if (c == (char)c) { - /* generate inc and dec for smaller code */ - if ((c == 1 || c == -1) && (op == '+' || op == '-')) { - opc = (c == 1) ^ (op == '+'); - o (0x40 | (opc << 3) | r); // inc,dec - } else { - o(0x83); - o(0xc0 | (opc << 3) | r); - g(c); - } - } else { - o(0x81); - oad(0xc0 | (opc << 3) | r, c); - } - } else { - gv2(RC_INT, RC_INT); - r = vtop[-1].r; - fr = vtop[0].r; - o((opc << 3) | 0x01); - o(0xc0 + r + fr * 8); - } - vtop--; - if (op >= TOK_ULT && op <= TOK_GT) - vset_VT_CMP(op); - break; - case '-': - case TOK_SUBC1: /* sub with carry generation */ - opc = 5; - goto gen_op8; - case TOK_ADDC2: /* add with carry use */ - opc = 2; - goto gen_op8; - case TOK_SUBC2: /* sub with carry use */ - opc = 3; - goto gen_op8; - case '&': - opc = 4; - goto gen_op8; - case '^': - opc = 6; - goto gen_op8; - case '|': - opc = 1; - goto gen_op8; - case '*': - gv2(RC_INT, RC_INT); - r = vtop[-1].r; - fr = vtop[0].r; - vtop--; - o(0xaf0f); /* imul fr, r */ - o(0xc0 + fr + r * 8); - break; - case TOK_SHL: - opc = 4; - goto gen_shift; - case TOK_SHR: - opc = 5; - goto gen_shift; - case TOK_SAR: - opc = 7; - gen_shift: - opc = 0xc0 | (opc << 3); - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { - /* constant case */ - vswap(); - r = gv(RC_INT); - vswap(); - c = vtop->c.i & 0x1f; - o(0xc1); /* shl/shr/sar $xxx, r */ - o(opc | r); - g(c); - } else { - /* we generate the shift in ecx */ - gv2(RC_INT, RC_ECX); - r = vtop[-1].r; - o(0xd3); /* shl/shr/sar %cl, r */ - o(opc | r); - } - vtop--; - break; - case '/': - case TOK_UDIV: - case TOK_PDIV: - case '%': - case TOK_UMOD: - case TOK_UMULL: - /* first operand must be in eax */ - /* XXX: need better constraint for second operand */ - gv2(RC_EAX, RC_ECX); - r = vtop[-1].r; - 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); - vtop->r2 = TREG_EDX; - r = TREG_EAX; - } else { - if (op == TOK_UDIV || op == TOK_UMOD) { - o(0xf7d231); /* xor %edx, %edx, div fr, %eax */ - o(0xf0 + fr); - } else { - o(0xf799); /* cltd, idiv fr, %eax */ - o(0xf8 + fr); - } - if (op == '%' || op == TOK_UMOD) - r = TREG_EDX; - else - r = TREG_EAX; - } - vtop->r = r; - break; - default: - opc = 7; - goto gen_op8; - } -} - -/* generate a floating point operation 'v = t1 op t2' instruction. The - two operands are guaranteed to have the same floating point type */ -/* XXX: need to use ST1 too */ -ST_FUNC void gen_opf(int op) -{ - int a, ft, fc, swapped, r; - - if (op == TOK_NEG) { /* unary minus */ - gv(RC_FLOAT); - o(0xe0d9); /* fchs */ - return; - } - - /* convert constants to memory references */ - if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { - vswap(); - gv(RC_FLOAT); - vswap(); - } - if ((vtop[0].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) - gv(RC_FLOAT); - - /* must put at least one value in the floating point register */ - if ((vtop[-1].r & VT_LVAL) && - (vtop[0].r & VT_LVAL)) { - vswap(); - gv(RC_FLOAT); - vswap(); - } - swapped = 0; - /* swap the stack if needed so that t1 is the register and t2 is - the memory reference */ - if (vtop[-1].r & VT_LVAL) { - vswap(); - swapped = 1; - } - if (op >= TOK_ULT && op <= TOK_GT) { - /* load on stack second operand */ - load(TREG_ST0, vtop); - save_reg(TREG_EAX); /* eax is used by FP comparison code */ - if (op == TOK_GE || op == TOK_GT) - swapped = !swapped; - else if (op == TOK_EQ || op == TOK_NE) - swapped = 0; - if (swapped) - o(0xc9d9); /* fxch %st(1) */ - 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 */ - o(0x40fC80); /* cmp $0x40, %ah */ - } else if (op == TOK_NE) { - o(0x45e480); /* and $0x45, %ah */ - o(0x40f480); /* xor $0x40, %ah */ - op = TOK_NE; - } else if (op == TOK_GE || op == TOK_LE) { - o(0x05c4f6); /* test $0x05, %ah */ - op = TOK_EQ; - } else { - o(0x45c4f6); /* test $0x45, %ah */ - op = TOK_EQ; - } - vtop--; - vset_VT_CMP(op); - } else { - /* no memory reference possible for long double operations */ - if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { - load(TREG_ST0, vtop); - swapped = !swapped; - } - - switch(op) { - default: - case '+': - a = 0; - break; - case '-': - a = 4; - if (swapped) - a++; - break; - case '*': - a = 1; - break; - case '/': - a = 6; - if (swapped) - a++; - break; - } - ft = vtop->type.t; - fc = vtop->c.i; - if ((ft & VT_BTYPE) == VT_LDOUBLE) { - o(0xde); /* fxxxp %st, %st(1) */ - o(0xc1 + (a << 3)); - } else { - /* if saved lvalue, then we must reload it */ - r = vtop->r; - if ((r & VT_VALMASK) == VT_LLOCAL) { - SValue v1; - r = get_reg(RC_INT); - v1.type.t = VT_INT; - v1.r = VT_LOCAL | VT_LVAL; - v1.c.i = fc; - v1.sym = NULL; - load(r, &v1); - fc = 0; - } - - if ((ft & VT_BTYPE) == VT_DOUBLE) - o(0xdc); - else - o(0xd8); - gen_modrm(a, r, vtop->sym, fc); - } - vtop--; - } -} - -/* convert integers to fp 't' type. Must handle 'int', 'unsigned int' - and 'long long' cases. */ -ST_FUNC void gen_cvt_itof(int t) -{ - save_reg(TREG_ST0); - gv(RC_INT); - if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { - /* signed long long to float/double/long double (unsigned case - is handled generically) */ - o(0x50 + vtop->r2); /* push r2 */ - o(0x50 + (vtop->r & VT_VALMASK)); /* push r */ - o(0x242cdf); /* fildll (%esp) */ - o(0x08c483); /* add $8, %esp */ - vtop->r2 = VT_CONST; - } else if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == - (VT_INT | VT_UNSIGNED)) { - /* unsigned int to float/double/long double */ - o(0x6a); /* push $0 */ - g(0x00); - o(0x50 + (vtop->r & VT_VALMASK)); /* push r */ - o(0x242cdf); /* fildll (%esp) */ - o(0x08c483); /* add $8, %esp */ - } else { - /* int to float/double/long double */ - o(0x50 + (vtop->r & VT_VALMASK)); /* push r */ - o(0x2404db); /* fildl (%esp) */ - o(0x04c483); /* add $4, %esp */ - } - vtop->r2 = VT_CONST; - vtop->r = TREG_ST0; -} - -/* convert fp to int 't' type */ -ST_FUNC void gen_cvt_ftoi(int t) -{ - int bt = vtop->type.t & VT_BTYPE; - if (bt == VT_FLOAT) - vpush_helper_func(TOK___fixsfdi); - else if (bt == VT_LDOUBLE) - vpush_helper_func(TOK___fixxfdi); - else - vpush_helper_func(TOK___fixdfdi); - vswap(); - gfunc_call(1); - vpushi(0); - vtop->r = REG_IRET; - if ((t & VT_BTYPE) == VT_LLONG) - vtop->r2 = REG_IRE2; -} - -/* convert from one floating point type to another */ -ST_FUNC void gen_cvt_ftof(int t) -{ - /* all we have to do on i386 is to put the float in a register */ - gv(RC_FLOAT); -} - -/* char/short to int conversion */ -ST_FUNC void gen_cvt_csti(int t) -{ - int r, sz, xl; - r = gv(RC_INT); - sz = !(t & VT_UNSIGNED); - xl = (t & VT_BTYPE) == VT_SHORT; - o(0xc0b60f /* mov[sz] %a[xl], %eax */ - | (sz << 3 | xl) << 8 - | (r << 3 | r) << 16 - ); -} - -/* increment tcov counter */ -ST_FUNC void gen_increment_tcov (SValue *sv) -{ - o(0x0583); /* addl $1, xxx */ - greloc(cur_text_section, sv->sym, ind, R_386_32); - gen_le32(0); - o(1); - o(0x1583); /* addcl $0, xxx */ - greloc(cur_text_section, sv->sym, ind, R_386_32); - gen_le32(4); - g(0); -} - -/* computed goto support */ -ST_FUNC void ggoto(void) -{ - gcall_or_jmp(1); - vtop--; -} - -/* bound check support functions */ -#ifdef CONFIG_TCC_BCHECK - -static void gen_bounds_prolog(void) -{ - /* leave some room for bound checking code */ - func_bound_offset = lbounds_section->data_offset; - func_bound_ind = ind; - func_bound_add_epilog = 0; - oad(0xb8, 0); /* lbound section pointer */ - oad(0xb8, 0); /* call to function */ -} - -static void gen_bounds_epilog(void) -{ - addr_t saved_ind; - addr_t *bounds_ptr; - Sym *sym_data; - int offset_modified = func_bound_offset != lbounds_section->data_offset; - - if (!offset_modified && !func_bound_add_epilog) - return; - - /* add end of table info */ - bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t)); - *bounds_ptr = 0; - - sym_data = get_sym_ref(&char_pointer_type, lbounds_section, - func_bound_offset, PTR_SIZE); - - /* generate bound local allocation */ - if (offset_modified) { - saved_ind = ind; - ind = func_bound_ind; - greloc(cur_text_section, sym_data, ind + 1, R_386_32); - ind = ind + 5; - 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); - oad(0xb8, 0); /* mov %eax, xxx */ - gen_static_call(TOK___bound_local_delete); - o(0x585a); /* restore returned value, if any */ -} -#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) { - int use_call = 0; - -#if defined(CONFIG_TCC_BCHECK) - use_call = tcc_state->do_bounds_check; -#endif -#ifdef TCC_TARGET_PE /* alloca does more than just adjust %rsp on Windows */ - use_call = 1; -#endif - if (use_call) - { - vpush_helper_func(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(); - } -} - -/* end of X86 code generator */ -/*************************************************************/ -#endif -/*************************************************************/ diff --git a/tinycc/i386-link.c b/tinycc/i386-link.c deleted file mode 100644 index 2fb1463..0000000 --- a/tinycc/i386-link.c +++ /dev/null @@ -1,325 +0,0 @@ -#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_RELATIVE R_386_RELATIVE - -#define R_NUM R_386_NUM - -#define ELF_START_ADDR 0x08048000 -#define ELF_PAGE_SIZE 0x1000 - -#define PCRELATIVE_DLLPLT 0 -#define RELOCATE_DLLPLT 1 - -#else /* !TARGET_DEFS_ONLY */ - -#include "tcc.h" - -#ifdef NEED_RELOC_TYPE -/* 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: - case R_386_TLS_GD: - case R_386_TLS_LDM: - case R_386_TLS_LDO_32: - case R_386_TLS_LE: - return 0; - - case R_386_PC16: - case R_386_PC32: - case R_386_PLT32: - case R_386_JMP_SLOT: - return 1; - } - return -1; -} - -/* Returns an enumerator to describe whether 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: - case R_386_TLS_GD: - case R_386_TLS_LDM: - case R_386_TLS_LDO_32: - case R_386_TLS_LE: - return ALWAYS_GOTPLT_ENTRY; - } - return -1; -} - -#ifdef NEED_BUILD_GOT -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_DYN) - modrm = 0xa3; - else - modrm = 0x25; - - /* empty PLT: create PLT0 entry that pushes the library identifier - (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->plt->reloc ? s1->plt->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 - sizeof (ElfW_Rel)); - 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 (!(s1->output_type & TCC_OUTPUT_DYN) && 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; - } - } - - if (s1->plt->reloc) { - ElfW_Rel *rel; - int x = s1->plt->sh_addr + 16 + 6; - p = s1->got->data; - for_each_elem(s1->plt->reloc, 0, rel, ElfW_Rel) { - write32le(p + rel->r_offset, x); - x += 16; - } - } -} -#endif -#endif - -void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned 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_DYN) { - esym_index = get_sym_attr(s1, sym_index, 0)->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 = get_sym_attr(s1, sym_index, 0)->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, get_sym_attr(s1, sym_index, 0)->got_offset); - return; - case R_386_16: - if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) { - output_file: - tcc_error_noabort("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: -#ifdef TCC_TARGET_PE - add32le(ptr, val - s1->pe_imagebase); -#endif - /* do nothing */ - return; - case R_386_COPY: - /* This relocation must copy initialized data from the library - to the program .bss segment. Currently made like for ARM - (to remove noise of default case). Is this true? - */ - return; - case R_386_TLS_GD: - { - static const unsigned char expect[] = { - /* lea 0(,%ebx,1),%eax */ - 0x8d, 0x04, 0x1d, 0x00, 0x00, 0x00, 0x00, - /* call __tls_get_addr@PLT */ - 0xe8, 0xfc, 0xff, 0xff, 0xff }; - static const unsigned char replace[] = { - /* mov %gs:0,%eax */ - 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, - /* sub 0,%eax */ - 0x81, 0xe8, 0x00, 0x00, 0x00, 0x00 }; - - if (memcmp (ptr-3, expect, sizeof(expect)) == 0) { - ElfW(Sym) *sym; - Section *sec; - int32_t x; - - memcpy(ptr-3, replace, sizeof(replace)); - rel[1].r_info = ELFW(R_INFO)(0, R_386_NONE); - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - sec = s1->sections[sym->st_shndx]; - x = sym->st_value - sec->sh_addr - sec->data_offset; - add32le(ptr + 5, -x); - } - else - tcc_error_noabort("unexpected R_386_TLS_GD pattern"); - } - return; - case R_386_TLS_LDM: - { - static const unsigned char expect[] = { - /* lea 0(%ebx),%eax */ - 0x8d, 0x83, 0x00, 0x00, 0x00, 0x00, - /* call __tls_get_addr@PLT */ - 0xe8, 0xfc, 0xff, 0xff, 0xff }; - static const unsigned char replace[] = { - /* mov %gs:0,%eax */ - 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, - /* nop */ - 0x90, - /* lea 0(%esi,%eiz,1),%esi */ - 0x8d, 0x74, 0x26, 0x00 }; - - if (memcmp (ptr-2, expect, sizeof(expect)) == 0) { - memcpy(ptr-2, replace, sizeof(replace)); - rel[1].r_info = ELFW(R_INFO)(0, R_386_NONE); - } - else - tcc_error_noabort("unexpected R_386_TLS_LDM pattern"); - } - return; - case R_386_TLS_LDO_32: - case R_386_TLS_LE: - { - ElfW(Sym) *sym; - Section *sec; - int32_t x; - - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - sec = s1->sections[sym->st_shndx]; - x = val - sec->sh_addr - sec->data_offset; - add32le(ptr, x); - } - return; - case R_386_NONE: - 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 */ diff --git a/tinycc/i386-tok.h b/tinycc/i386-tok.h deleted file mode 100644 index 2907105..0000000 --- a/tinycc/i386-tok.h +++ /dev/null @@ -1,332 +0,0 @@ -/* ------------------------------------------------------------------ */ -/* WARNING: relative order of tokens is important. */ - -#define DEF_BWL(x) \ - DEF(TOK_ASM_ ## x ## b, #x "b") \ - DEF(TOK_ASM_ ## x ## w, #x "w") \ - DEF(TOK_ASM_ ## x ## l, #x "l") \ - DEF(TOK_ASM_ ## x, #x) -#define DEF_WL(x) \ - DEF(TOK_ASM_ ## x ## w, #x "w") \ - DEF(TOK_ASM_ ## x ## l, #x "l") \ - DEF(TOK_ASM_ ## x, #x) -#ifdef TCC_TARGET_X86_64 -# define DEF_BWLQ(x) \ - DEF(TOK_ASM_ ## x ## b, #x "b") \ - DEF(TOK_ASM_ ## x ## w, #x "w") \ - DEF(TOK_ASM_ ## x ## l, #x "l") \ - DEF(TOK_ASM_ ## x ## q, #x "q") \ - DEF(TOK_ASM_ ## x, #x) -# define DEF_WLQ(x) \ - DEF(TOK_ASM_ ## x ## w, #x "w") \ - DEF(TOK_ASM_ ## x ## l, #x "l") \ - DEF(TOK_ASM_ ## x ## q, #x "q") \ - DEF(TOK_ASM_ ## x, #x) -# define DEF_BWLX DEF_BWLQ -# define DEF_WLX DEF_WLQ -/* number of sizes + 1 */ -# define NBWLX 5 -#else -# define DEF_BWLX DEF_BWL -# define DEF_WLX DEF_WL -/* number of sizes + 1 */ -# define NBWLX 4 -#endif - -#define DEF_FP1(x) \ - DEF(TOK_ASM_ ## f ## x ## s, "f" #x "s") \ - DEF(TOK_ASM_ ## fi ## x ## l, "fi" #x "l") \ - DEF(TOK_ASM_ ## f ## x ## l, "f" #x "l") \ - DEF(TOK_ASM_ ## fi ## x ## s, "fi" #x "s") - -#define DEF_FP(x) \ - DEF(TOK_ASM_ ## f ## x, "f" #x ) \ - DEF(TOK_ASM_ ## f ## x ## p, "f" #x "p") \ - DEF_FP1(x) - -#define DEF_ASMTEST(x,suffix) \ - DEF_ASM(x ## o ## suffix) \ - DEF_ASM(x ## no ## suffix) \ - DEF_ASM(x ## b ## suffix) \ - DEF_ASM(x ## c ## suffix) \ - DEF_ASM(x ## nae ## suffix) \ - DEF_ASM(x ## nb ## suffix) \ - DEF_ASM(x ## nc ## suffix) \ - DEF_ASM(x ## ae ## suffix) \ - DEF_ASM(x ## e ## suffix) \ - DEF_ASM(x ## z ## suffix) \ - DEF_ASM(x ## ne ## suffix) \ - DEF_ASM(x ## nz ## suffix) \ - DEF_ASM(x ## be ## suffix) \ - DEF_ASM(x ## na ## suffix) \ - DEF_ASM(x ## nbe ## suffix) \ - DEF_ASM(x ## a ## suffix) \ - DEF_ASM(x ## s ## suffix) \ - DEF_ASM(x ## ns ## suffix) \ - DEF_ASM(x ## p ## suffix) \ - DEF_ASM(x ## pe ## suffix) \ - DEF_ASM(x ## np ## suffix) \ - DEF_ASM(x ## po ## suffix) \ - DEF_ASM(x ## l ## suffix) \ - DEF_ASM(x ## nge ## suffix) \ - DEF_ASM(x ## nl ## suffix) \ - DEF_ASM(x ## ge ## suffix) \ - DEF_ASM(x ## le ## suffix) \ - DEF_ASM(x ## ng ## suffix) \ - DEF_ASM(x ## nle ## suffix) \ - DEF_ASM(x ## g ## suffix) - -/* ------------------------------------------------------------------ */ -/* register */ - DEF_ASM(al) - DEF_ASM(cl) - DEF_ASM(dl) - DEF_ASM(bl) - DEF_ASM(ah) - DEF_ASM(ch) - DEF_ASM(dh) - DEF_ASM(bh) - DEF_ASM(ax) - DEF_ASM(cx) - DEF_ASM(dx) - DEF_ASM(bx) - DEF_ASM(sp) - DEF_ASM(bp) - DEF_ASM(si) - DEF_ASM(di) - DEF_ASM(eax) - DEF_ASM(ecx) - DEF_ASM(edx) - DEF_ASM(ebx) - DEF_ASM(esp) - DEF_ASM(ebp) - DEF_ASM(esi) - DEF_ASM(edi) -#ifdef TCC_TARGET_X86_64 - DEF_ASM(rax) - DEF_ASM(rcx) - DEF_ASM(rdx) - DEF_ASM(rbx) - DEF_ASM(rsp) - DEF_ASM(rbp) - DEF_ASM(rsi) - DEF_ASM(rdi) -#endif - DEF_ASM(mm0) - DEF_ASM(mm1) - DEF_ASM(mm2) - DEF_ASM(mm3) - DEF_ASM(mm4) - DEF_ASM(mm5) - DEF_ASM(mm6) - DEF_ASM(mm7) - DEF_ASM(xmm0) - DEF_ASM(xmm1) - DEF_ASM(xmm2) - DEF_ASM(xmm3) - DEF_ASM(xmm4) - DEF_ASM(xmm5) - DEF_ASM(xmm6) - DEF_ASM(xmm7) - DEF_ASM(cr0) - DEF_ASM(cr1) - DEF_ASM(cr2) - DEF_ASM(cr3) - DEF_ASM(cr4) - DEF_ASM(cr5) - DEF_ASM(cr6) - DEF_ASM(cr7) - DEF_ASM(tr0) - DEF_ASM(tr1) - DEF_ASM(tr2) - DEF_ASM(tr3) - DEF_ASM(tr4) - DEF_ASM(tr5) - DEF_ASM(tr6) - DEF_ASM(tr7) - DEF_ASM(db0) - DEF_ASM(db1) - DEF_ASM(db2) - DEF_ASM(db3) - DEF_ASM(db4) - DEF_ASM(db5) - DEF_ASM(db6) - DEF_ASM(db7) - DEF_ASM(dr0) - DEF_ASM(dr1) - DEF_ASM(dr2) - DEF_ASM(dr3) - DEF_ASM(dr4) - DEF_ASM(dr5) - DEF_ASM(dr6) - DEF_ASM(dr7) - DEF_ASM(es) - DEF_ASM(cs) - DEF_ASM(ss) - DEF_ASM(ds) - 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) - - DEF_BWLX(add) - DEF_BWLX(or) - DEF_BWLX(adc) - DEF_BWLX(sbb) - DEF_BWLX(and) - DEF_BWLX(sub) - DEF_BWLX(xor) - DEF_BWLX(cmp) - - /* unary ops */ - DEF_BWLX(inc) - DEF_BWLX(dec) - DEF_BWLX(not) - DEF_BWLX(neg) - DEF_BWLX(mul) - DEF_BWLX(imul) - DEF_BWLX(div) - DEF_BWLX(idiv) - - DEF_BWLX(xchg) - DEF_BWLX(test) - - /* shifts */ - DEF_BWLX(rol) - DEF_BWLX(ror) - DEF_BWLX(rcl) - DEF_BWLX(rcr) - DEF_BWLX(shl) - DEF_BWLX(shr) - DEF_BWLX(sar) - - DEF_WLX(shld) - DEF_WLX(shrd) - - DEF_ASM(pushw) - DEF_ASM(pushl) -#ifdef TCC_TARGET_X86_64 - DEF_ASM(pushq) -#endif - DEF_ASM(push) - - DEF_ASM(popw) - DEF_ASM(popl) -#ifdef TCC_TARGET_X86_64 - DEF_ASM(popq) -#endif - DEF_ASM(pop) - - DEF_BWL(in) - DEF_BWL(out) - - 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 - - DEF_WLX(lea) - - DEF_ASM(les) - DEF_ASM(lds) - DEF_ASM(lss) - DEF_ASM(lfs) - DEF_ASM(lgs) - - DEF_ASM(call) - DEF_ASM(jmp) - DEF_ASM(lcall) - DEF_ASM(ljmp) - - DEF_ASMTEST(j,) - - DEF_ASMTEST(set,) - DEF_ASMTEST(set,b) - DEF_ASMTEST(cmov,) - - DEF_WLX(bsf) - DEF_WLX(bsr) - DEF_WLX(bt) - DEF_WLX(bts) - DEF_WLX(btr) - DEF_WLX(btc) - DEF_WLX(popcnt) - DEF_WLX(tzcnt) - DEF_WLX(lzcnt) - - DEF_WLX(lar) - DEF_WLX(lsl) - - /* generic FP ops */ - DEF_FP(add) - DEF_FP(mul) - - DEF_ASM(fcom) - DEF_ASM(fcom_1) /* non existent op, just to have a regular table */ - DEF_FP1(com) - - DEF_FP(comp) - DEF_FP(sub) - DEF_FP(subr) - DEF_FP(div) - DEF_FP(divr) - - DEF_BWLX(xadd) - DEF_BWLX(cmpxchg) - - /* string ops */ - DEF_BWLX(cmps) - DEF_BWLX(scmp) - DEF_BWL(ins) - DEF_BWL(outs) - DEF_BWLX(lods) - DEF_BWLX(slod) - DEF_BWLX(movs) - DEF_BWLX(smov) - DEF_BWLX(scas) - DEF_BWLX(ssca) - DEF_BWLX(stos) - DEF_BWLX(ssto) - - /* generic asm ops */ -#define ALT(x) -#define DEF_ASM_OP0(name, opcode) DEF_ASM(name) -#define DEF_ASM_OP0L(name, opcode, group, instr_type) -#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) -#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) -#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) -#ifdef TCC_TARGET_X86_64 -# include "x86_64-asm.h" -#else -# include "i386-asm.h" -#endif - -#define ALT(x) -#define DEF_ASM_OP0(name, opcode) -#define DEF_ASM_OP0L(name, opcode, group, instr_type) DEF_ASM(name) -#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) DEF_ASM(name) -#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) DEF_ASM(name) -#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) DEF_ASM(name) -#ifdef TCC_TARGET_X86_64 -# include "x86_64-asm.h" -#else -# include "i386-asm.h" -#endif diff --git a/tinycc/il-gen.c b/tinycc/il-gen.c deleted file mode 100644 index bb670cc..0000000 --- a/tinycc/il-gen.c +++ /dev/null @@ -1,657 +0,0 @@ -/* - * CIL code generator for TCC - * - * Copyright (c) 2002 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 - */ - -#error this code has bit-rotted since 2003 - -/* number of available registers */ -#define NB_REGS 3 - -/* a register can belong to several classes. The classes must be - sorted from more general to more precise (see gv2() code which does - assumptions on it). */ -#define RC_ST 0x0001 /* any stack entry */ -#define RC_ST0 0x0002 /* top of stack */ -#define RC_ST1 0x0004 /* top - 1 */ - -#define RC_INT RC_ST -#define RC_FLOAT RC_ST -#define RC_IRET RC_ST0 /* function return: integer register */ -#define RC_LRET RC_ST0 /* function return: second integer register */ -#define RC_FRET RC_ST0 /* function return: float register */ - -/* pretty names for the registers */ -enum { - REG_ST0 = 0, - REG_ST1, - REG_ST2, -}; - -const int reg_classes[NB_REGS] = { - /* ST0 */ RC_ST | RC_ST0, - /* ST1 */ RC_ST | RC_ST1, - /* ST2 */ RC_ST, -}; - -/* return registers for function */ -#define REG_IRET REG_ST0 /* single word int return register */ -#define REG_LRET REG_ST0 /* second word return register (for long long) */ -#define REG_FRET REG_ST0 /* float return register */ - -/* defined if function parameters must be evaluated in reverse order */ -/* #define INVERT_FUNC_PARAMS */ - -/* defined if structures are passed as pointers. Otherwise structures - are directly pushed on stack. */ -/* #define FUNC_STRUCT_PARAM_AS_PTR */ - -/* pointer size, in bytes */ -#define PTR_SIZE 4 - -/* long double size and alignment, in bytes */ -#define LDOUBLE_SIZE 8 -#define LDOUBLE_ALIGN 8 - -/* function call context */ -typedef struct GFuncContext { - int func_call; /* func call type (FUNC_STDCALL or FUNC_CDECL) */ -} GFuncContext; - -/******************************************************/ -/* opcode definitions */ - -#define IL_OP_PREFIX 0xFE - -enum ILOPCodes { -#define OP(name, str, n) IL_OP_ ## name = n, -#include "il-opcodes.h" -#undef OP -}; - -char *il_opcodes_str[] = { -#define OP(name, str, n) [n] = str, -#include "il-opcodes.h" -#undef OP -}; - -/******************************************************/ - -/* arguments variable numbers start from there */ -#define ARG_BASE 0x70000000 - -static FILE *il_outfile; - -static void out_byte(int c) -{ - *(char *)ind++ = c; -} - -static void out_le32(int c) -{ - out_byte(c); - out_byte(c >> 8); - out_byte(c >> 16); - out_byte(c >> 24); -} - -static void init_outfile(void) -{ - if (!il_outfile) { - il_outfile = stdout; - fprintf(il_outfile, - ".assembly extern mscorlib\n" - "{\n" - ".ver 1:0:2411:0\n" - "}\n\n"); - } -} - -static void out_op1(int op) -{ - if (op & 0x100) - out_byte(IL_OP_PREFIX); - out_byte(op & 0xff); -} - -/* output an opcode with prefix */ -static void out_op(int op) -{ - out_op1(op); - fprintf(il_outfile, " %s\n", il_opcodes_str[op]); -} - -static void out_opb(int op, int c) -{ - out_op1(op); - out_byte(c); - fprintf(il_outfile, " %s %d\n", il_opcodes_str[op], c); -} - -static void out_opi(int op, int c) -{ - out_op1(op); - out_le32(c); - fprintf(il_outfile, " %s 0x%x\n", il_opcodes_str[op], c); -} - -/* XXX: not complete */ -static void il_type_to_str(char *buf, int buf_size, - int t, const char *varstr) -{ - int bt; - Sym *s, *sa; - char buf1[256]; - const char *tstr; - - t = t & VT_TYPE; - bt = t & VT_BTYPE; - buf[0] = '\0'; - if (t & VT_UNSIGNED) - pstrcat(buf, buf_size, "unsigned "); - switch(bt) { - case VT_VOID: - tstr = "void"; - goto add_tstr; - case VT_BOOL: - tstr = "bool"; - goto add_tstr; - case VT_BYTE: - tstr = "int8"; - goto add_tstr; - case VT_SHORT: - tstr = "int16"; - goto add_tstr; - case VT_ENUM: - case VT_INT: - case VT_LONG: - tstr = "int32"; - goto add_tstr; - case VT_LLONG: - tstr = "int64"; - goto add_tstr; - case VT_FLOAT: - tstr = "float32"; - goto add_tstr; - case VT_DOUBLE: - case VT_LDOUBLE: - tstr = "float64"; - add_tstr: - pstrcat(buf, buf_size, tstr); - break; - case VT_STRUCT: - tcc_error("structures not handled yet"); - break; - case VT_FUNC: - s = sym_find((unsigned)t >> VT_STRUCT_SHIFT); - il_type_to_str(buf, buf_size, s->t, varstr); - pstrcat(buf, buf_size, "("); - sa = s->next; - while (sa != NULL) { - il_type_to_str(buf1, sizeof(buf1), sa->t, NULL); - pstrcat(buf, buf_size, buf1); - sa = sa->next; - if (sa) - pstrcat(buf, buf_size, ", "); - } - pstrcat(buf, buf_size, ")"); - goto no_var; - case VT_PTR: - s = sym_find((unsigned)t >> VT_STRUCT_SHIFT); - pstrcpy(buf1, sizeof(buf1), "*"); - if (varstr) - pstrcat(buf1, sizeof(buf1), varstr); - il_type_to_str(buf, buf_size, s->t, buf1); - goto no_var; - } - if (varstr) { - pstrcat(buf, buf_size, " "); - pstrcat(buf, buf_size, varstr); - } - no_var: ; -} - - -/* patch relocation entry with value 'val' */ -void greloc_patch1(Reloc *p, int val) -{ -} - -/* output a symbol and patch all calls to it */ -void gsym_addr(t, a) -{ -} - -/* output jump and return symbol */ -static int out_opj(int op, int c) -{ - out_op1(op); - out_le32(0); - if (c == 0) { - c = ind - (int)cur_text_section->data; - } - fprintf(il_outfile, " %s L%d\n", il_opcodes_str[op], c); - return c; -} - -void gsym(int t) -{ - fprintf(il_outfile, "L%d:\n", t); -} - -/* load 'r' from value 'sv' */ -void load(int r, SValue *sv) -{ - int v, fc, ft; - - v = sv->r & VT_VALMASK; - fc = sv->c.i; - ft = sv->t; - - if (sv->r & VT_LVAL) { - if (v == VT_LOCAL) { - if (fc >= ARG_BASE) { - fc -= ARG_BASE; - if (fc >= 0 && fc <= 4) { - out_op(IL_OP_LDARG_0 + fc); - } else if (fc <= 0xff) { - out_opb(IL_OP_LDARG_S, fc); - } else { - out_opi(IL_OP_LDARG, fc); - } - } else { - if (fc >= 0 && fc <= 4) { - out_op(IL_OP_LDLOC_0 + fc); - } else if (fc <= 0xff) { - out_opb(IL_OP_LDLOC_S, fc); - } else { - out_opi(IL_OP_LDLOC, fc); - } - } - } else if (v == VT_CONST) { - /* XXX: handle globals */ - out_opi(IL_OP_LDSFLD, 0); - } else { - if ((ft & VT_BTYPE) == VT_FLOAT) { - out_op(IL_OP_LDIND_R4); - } else if ((ft & VT_BTYPE) == VT_DOUBLE) { - out_op(IL_OP_LDIND_R8); - } else if ((ft & VT_BTYPE) == VT_LDOUBLE) { - out_op(IL_OP_LDIND_R8); - } else if ((ft & VT_TYPE) == VT_BYTE) - out_op(IL_OP_LDIND_I1); - else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) - out_op(IL_OP_LDIND_U1); - else if ((ft & VT_TYPE) == VT_SHORT) - out_op(IL_OP_LDIND_I2); - else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) - out_op(IL_OP_LDIND_U2); - else - out_op(IL_OP_LDIND_I4); - } - } else { - if (v == VT_CONST) { - /* XXX: handle globals */ - if (fc >= -1 && fc <= 8) { - out_op(IL_OP_LDC_I4_M1 + fc + 1); - } else { - out_opi(IL_OP_LDC_I4, fc); - } - } else if (v == VT_LOCAL) { - if (fc >= ARG_BASE) { - fc -= ARG_BASE; - if (fc <= 0xff) { - out_opb(IL_OP_LDARGA_S, fc); - } else { - out_opi(IL_OP_LDARGA, fc); - } - } else { - if (fc <= 0xff) { - out_opb(IL_OP_LDLOCA_S, fc); - } else { - out_opi(IL_OP_LDLOCA, fc); - } - } - } else { - /* XXX: do it */ - } - } -} - -/* store register 'r' in lvalue 'v' */ -void store(int r, SValue *sv) -{ - int v, fc, ft; - - v = sv->r & VT_VALMASK; - fc = sv->c.i; - ft = sv->t; - if (v == VT_LOCAL) { - if (fc >= ARG_BASE) { - fc -= ARG_BASE; - /* XXX: check IL arg store semantics */ - if (fc <= 0xff) { - out_opb(IL_OP_STARG_S, fc); - } else { - out_opi(IL_OP_STARG, fc); - } - } else { - if (fc >= 0 && fc <= 4) { - out_op(IL_OP_STLOC_0 + fc); - } else if (fc <= 0xff) { - out_opb(IL_OP_STLOC_S, fc); - } else { - out_opi(IL_OP_STLOC, fc); - } - } - } else if (v == VT_CONST) { - /* XXX: handle globals */ - out_opi(IL_OP_STSFLD, 0); - } else { - if ((ft & VT_BTYPE) == VT_FLOAT) - out_op(IL_OP_STIND_R4); - else if ((ft & VT_BTYPE) == VT_DOUBLE) - out_op(IL_OP_STIND_R8); - else if ((ft & VT_BTYPE) == VT_LDOUBLE) - out_op(IL_OP_STIND_R8); - else if ((ft & VT_BTYPE) == VT_BYTE) - out_op(IL_OP_STIND_I1); - else if ((ft & VT_BTYPE) == VT_SHORT) - out_op(IL_OP_STIND_I2); - else - out_op(IL_OP_STIND_I4); - } -} - -/* start function call and return function call context */ -void gfunc_start(GFuncContext *c, int func_call) -{ - c->func_call = func_call; -} - -/* push function parameter which is in (vtop->t, vtop->c). Stack entry - is then popped. */ -void gfunc_param(GFuncContext *c) -{ - if ((vtop->t & VT_BTYPE) == VT_STRUCT) { - tcc_error("structures passed as value not handled yet"); - } else { - /* simply push on stack */ - gv(RC_ST0); - } - vtop--; -} - -/* generate function call with address in (vtop->t, vtop->c) and free function - context. Stack entry is popped */ -void gfunc_call(GFuncContext *c) -{ - char buf[1024]; - - if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { - /* XXX: more info needed from tcc */ - il_type_to_str(buf, sizeof(buf), vtop->t, "xxx"); - fprintf(il_outfile, " call %s\n", buf); - } else { - /* indirect call */ - gv(RC_INT); - il_type_to_str(buf, sizeof(buf), vtop->t, NULL); - fprintf(il_outfile, " calli %s\n", buf); - } - vtop--; -} - -/* generate function prolog of type 't' */ -void gfunc_prolog(int t) -{ - int addr, u, func_call; - Sym *sym; - char buf[1024]; - - init_outfile(); - - /* XXX: pass function name to gfunc_prolog */ - il_type_to_str(buf, sizeof(buf), t, funcname); - fprintf(il_outfile, ".method static %s il managed\n", buf); - fprintf(il_outfile, "{\n"); - /* XXX: cannot do better now */ - fprintf(il_outfile, " .maxstack %d\n", NB_REGS); - fprintf(il_outfile, " .locals (int32, int32, int32, int32, int32, int32, int32, int32)\n"); - - if (!strcmp(funcname, "main")) - fprintf(il_outfile, " .entrypoint\n"); - - sym = sym_find((unsigned)t >> VT_STRUCT_SHIFT); - func_call = sym->r; - - addr = ARG_BASE; - /* 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++; - } - /* define parameters */ - while ((sym = sym->next) != NULL) { - u = sym->t; - sym_push(sym->v & ~SYM_FIELD, u, - VT_LOCAL | lvalue_type(sym->type.t), addr); - addr++; - } -} - -/* generate function epilog */ -void gfunc_epilog(void) -{ - out_op(IL_OP_RET); - fprintf(il_outfile, "}\n\n"); -} - -/* generate a jump to a label */ -int gjmp(int t) -{ - return out_opj(IL_OP_BR, t); -} - -/* generate a jump to a fixed address */ -void gjmp_addr(int a) -{ - /* XXX: handle syms */ - out_opi(IL_OP_BR, a); -} - -/* generate a test. set 'inv' to invert test. Stack entry is popped */ -int gtst(int inv, int t) -{ - int v, *p, c; - - v = vtop->r & VT_VALMASK; - if (v == VT_CMP) { - c = vtop->c.i ^ inv; - switch(c) { - case TOK_EQ: - c = IL_OP_BEQ; - break; - case TOK_NE: - c = IL_OP_BNE_UN; - break; - case TOK_LT: - c = IL_OP_BLT; - break; - case TOK_LE: - c = IL_OP_BLE; - break; - case TOK_GT: - c = IL_OP_BGT; - break; - case TOK_GE: - c = IL_OP_BGE; - break; - case TOK_ULT: - c = IL_OP_BLT_UN; - break; - case TOK_ULE: - c = IL_OP_BLE_UN; - break; - case TOK_UGT: - c = IL_OP_BGT_UN; - break; - case TOK_UGE: - c = IL_OP_BGE_UN; - break; - } - t = out_opj(c, 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 *)*p; - *p = t; - t = vtop->c.i; - } else { - t = gjmp(t); - gsym(vtop->c.i); - } - } - vtop--; - return t; -} - -/* generate an integer binary operation */ -void gen_opi(int op) -{ - gv2(RC_ST1, RC_ST0); - switch(op) { - case '+': - out_op(IL_OP_ADD); - goto std_op; - case '-': - out_op(IL_OP_SUB); - goto std_op; - case '&': - out_op(IL_OP_AND); - goto std_op; - case '^': - out_op(IL_OP_XOR); - goto std_op; - case '|': - out_op(IL_OP_OR); - goto std_op; - case '*': - out_op(IL_OP_MUL); - goto std_op; - case TOK_SHL: - out_op(IL_OP_SHL); - goto std_op; - case TOK_SHR: - out_op(IL_OP_SHR_UN); - goto std_op; - case TOK_SAR: - out_op(IL_OP_SHR); - goto std_op; - case '/': - case TOK_PDIV: - out_op(IL_OP_DIV); - goto std_op; - case TOK_UDIV: - out_op(IL_OP_DIV_UN); - goto std_op; - case '%': - out_op(IL_OP_REM); - goto std_op; - case TOK_UMOD: - out_op(IL_OP_REM_UN); - std_op: - vtop--; - vtop[0].r = REG_ST0; - break; - case TOK_EQ: - case TOK_NE: - case TOK_LT: - case TOK_LE: - case TOK_GT: - case TOK_GE: - case TOK_ULT: - case TOK_ULE: - case TOK_UGT: - case TOK_UGE: - vtop--; - vtop[0].r = VT_CMP; - vtop[0].c.i = op; - break; - } -} - -/* generate a floating point operation 'v = t1 op t2' instruction. The - two operands are guaranteed to have the same floating point type */ -void gen_opf(int op) -{ - /* same as integer */ - gen_opi(op); -} - -/* convert integers to fp 't' type. Must handle 'int', 'unsigned int' - and 'long long' cases. */ -void gen_cvt_itof(int t) -{ - gv(RC_ST0); - if (t == VT_FLOAT) - out_op(IL_OP_CONV_R4); - else - out_op(IL_OP_CONV_R8); -} - -/* convert fp to int 't' type */ -/* XXX: handle long long case */ -void gen_cvt_ftoi(int t) -{ - gv(RC_ST0); - switch(t) { - case VT_INT | VT_UNSIGNED: - out_op(IL_OP_CONV_U4); - break; - case VT_LLONG: - out_op(IL_OP_CONV_I8); - break; - case VT_LLONG | VT_UNSIGNED: - out_op(IL_OP_CONV_U8); - break; - default: - out_op(IL_OP_CONV_I4); - break; - } -} - -/* convert from one floating point type to another */ -void gen_cvt_ftof(int t) -{ - gv(RC_ST0); - if (t == VT_FLOAT) { - out_op(IL_OP_CONV_R4); - } else { - out_op(IL_OP_CONV_R8); - } -} - -/* end of CIL code generator */ -/*************************************************************/ - diff --git a/tinycc/il-opcodes.h b/tinycc/il-opcodes.h deleted file mode 100644 index d53ffb2..0000000 --- a/tinycc/il-opcodes.h +++ /dev/null @@ -1,251 +0,0 @@ -/* - * CIL opcode definition - * - * Copyright (c) 2002 Fabrice Bellard - * - * 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. - */ -OP(NOP, "nop", 0x00) -OP(BREAK, "break", 0x01) -OP(LDARG_0, "ldarg.0", 0x02) -OP(LDARG_1, "ldarg.1", 0x03) -OP(LDARG_2, "ldarg.2", 0x04) -OP(LDARG_3, "ldarg.3", 0x05) -OP(LDLOC_0, "ldloc.0", 0x06) -OP(LDLOC_1, "ldloc.1", 0x07) -OP(LDLOC_2, "ldloc.2", 0x08) -OP(LDLOC_3, "ldloc.3", 0x09) -OP(STLOC_0, "stloc.0", 0x0a) -OP(STLOC_1, "stloc.1", 0x0b) -OP(STLOC_2, "stloc.2", 0x0c) -OP(STLOC_3, "stloc.3", 0x0d) -OP(LDARG_S, "ldarg.s", 0x0e) -OP(LDARGA_S, "ldarga.s", 0x0f) -OP(STARG_S, "starg.s", 0x10) -OP(LDLOC_S, "ldloc.s", 0x11) -OP(LDLOCA_S, "ldloca.s", 0x12) -OP(STLOC_S, "stloc.s", 0x13) -OP(LDNULL, "ldnull", 0x14) -OP(LDC_I4_M1, "ldc.i4.m1", 0x15) -OP(LDC_I4_0, "ldc.i4.0", 0x16) -OP(LDC_I4_1, "ldc.i4.1", 0x17) -OP(LDC_I4_2, "ldc.i4.2", 0x18) -OP(LDC_I4_3, "ldc.i4.3", 0x19) -OP(LDC_I4_4, "ldc.i4.4", 0x1a) -OP(LDC_I4_5, "ldc.i4.5", 0x1b) -OP(LDC_I4_6, "ldc.i4.6", 0x1c) -OP(LDC_I4_7, "ldc.i4.7", 0x1d) -OP(LDC_I4_8, "ldc.i4.8", 0x1e) -OP(LDC_I4_S, "ldc.i4.s", 0x1f) -OP(LDC_I4, "ldc.i4", 0x20) -OP(LDC_I8, "ldc.i8", 0x21) -OP(LDC_R4, "ldc.r4", 0x22) -OP(LDC_R8, "ldc.r8", 0x23) -OP(LDPTR, "ldptr", 0x24) -OP(DUP, "dup", 0x25) -OP(POP, "pop", 0x26) -OP(JMP, "jmp", 0x27) -OP(CALL, "call", 0x28) -OP(CALLI, "calli", 0x29) -OP(RET, "ret", 0x2a) -OP(BR_S, "br.s", 0x2b) -OP(BRFALSE_S, "brfalse.s", 0x2c) -OP(BRTRUE_S, "brtrue.s", 0x2d) -OP(BEQ_S, "beq.s", 0x2e) -OP(BGE_S, "bge.s", 0x2f) -OP(BGT_S, "bgt.s", 0x30) -OP(BLE_S, "ble.s", 0x31) -OP(BLT_S, "blt.s", 0x32) -OP(BNE_UN_S, "bne.un.s", 0x33) -OP(BGE_UN_S, "bge.un.s", 0x34) -OP(BGT_UN_S, "bgt.un.s", 0x35) -OP(BLE_UN_S, "ble.un.s", 0x36) -OP(BLT_UN_S, "blt.un.s", 0x37) -OP(BR, "br", 0x38) -OP(BRFALSE, "brfalse", 0x39) -OP(BRTRUE, "brtrue", 0x3a) -OP(BEQ, "beq", 0x3b) -OP(BGE, "bge", 0x3c) -OP(BGT, "bgt", 0x3d) -OP(BLE, "ble", 0x3e) -OP(BLT, "blt", 0x3f) -OP(BNE_UN, "bne.un", 0x40) -OP(BGE_UN, "bge.un", 0x41) -OP(BGT_UN, "bgt.un", 0x42) -OP(BLE_UN, "ble.un", 0x43) -OP(BLT_UN, "blt.un", 0x44) -OP(SWITCH, "switch", 0x45) -OP(LDIND_I1, "ldind.i1", 0x46) -OP(LDIND_U1, "ldind.u1", 0x47) -OP(LDIND_I2, "ldind.i2", 0x48) -OP(LDIND_U2, "ldind.u2", 0x49) -OP(LDIND_I4, "ldind.i4", 0x4a) -OP(LDIND_U4, "ldind.u4", 0x4b) -OP(LDIND_I8, "ldind.i8", 0x4c) -OP(LDIND_I, "ldind.i", 0x4d) -OP(LDIND_R4, "ldind.r4", 0x4e) -OP(LDIND_R8, "ldind.r8", 0x4f) -OP(LDIND_REF, "ldind.ref", 0x50) -OP(STIND_REF, "stind.ref", 0x51) -OP(STIND_I1, "stind.i1", 0x52) -OP(STIND_I2, "stind.i2", 0x53) -OP(STIND_I4, "stind.i4", 0x54) -OP(STIND_I8, "stind.i8", 0x55) -OP(STIND_R4, "stind.r4", 0x56) -OP(STIND_R8, "stind.r8", 0x57) -OP(ADD, "add", 0x58) -OP(SUB, "sub", 0x59) -OP(MUL, "mul", 0x5a) -OP(DIV, "div", 0x5b) -OP(DIV_UN, "div.un", 0x5c) -OP(REM, "rem", 0x5d) -OP(REM_UN, "rem.un", 0x5e) -OP(AND, "and", 0x5f) -OP(OR, "or", 0x60) -OP(XOR, "xor", 0x61) -OP(SHL, "shl", 0x62) -OP(SHR, "shr", 0x63) -OP(SHR_UN, "shr.un", 0x64) -OP(NEG, "neg", 0x65) -OP(NOT, "not", 0x66) -OP(CONV_I1, "conv.i1", 0x67) -OP(CONV_I2, "conv.i2", 0x68) -OP(CONV_I4, "conv.i4", 0x69) -OP(CONV_I8, "conv.i8", 0x6a) -OP(CONV_R4, "conv.r4", 0x6b) -OP(CONV_R8, "conv.r8", 0x6c) -OP(CONV_U4, "conv.u4", 0x6d) -OP(CONV_U8, "conv.u8", 0x6e) -OP(CALLVIRT, "callvirt", 0x6f) -OP(CPOBJ, "cpobj", 0x70) -OP(LDOBJ, "ldobj", 0x71) -OP(LDSTR, "ldstr", 0x72) -OP(NEWOBJ, "newobj", 0x73) -OP(CASTCLASS, "castclass", 0x74) -OP(ISINST, "isinst", 0x75) -OP(CONV_R_UN, "conv.r.un", 0x76) -OP(ANN_DATA_S, "ann.data.s", 0x77) -OP(UNBOX, "unbox", 0x79) -OP(THROW, "throw", 0x7a) -OP(LDFLD, "ldfld", 0x7b) -OP(LDFLDA, "ldflda", 0x7c) -OP(STFLD, "stfld", 0x7d) -OP(LDSFLD, "ldsfld", 0x7e) -OP(LDSFLDA, "ldsflda", 0x7f) -OP(STSFLD, "stsfld", 0x80) -OP(STOBJ, "stobj", 0x81) -OP(CONV_OVF_I1_UN, "conv.ovf.i1.un", 0x82) -OP(CONV_OVF_I2_UN, "conv.ovf.i2.un", 0x83) -OP(CONV_OVF_I4_UN, "conv.ovf.i4.un", 0x84) -OP(CONV_OVF_I8_UN, "conv.ovf.i8.un", 0x85) -OP(CONV_OVF_U1_UN, "conv.ovf.u1.un", 0x86) -OP(CONV_OVF_U2_UN, "conv.ovf.u2.un", 0x87) -OP(CONV_OVF_U4_UN, "conv.ovf.u4.un", 0x88) -OP(CONV_OVF_U8_UN, "conv.ovf.u8.un", 0x89) -OP(CONV_OVF_I_UN, "conv.ovf.i.un", 0x8a) -OP(CONV_OVF_U_UN, "conv.ovf.u.un", 0x8b) -OP(BOX, "box", 0x8c) -OP(NEWARR, "newarr", 0x8d) -OP(LDLEN, "ldlen", 0x8e) -OP(LDELEMA, "ldelema", 0x8f) -OP(LDELEM_I1, "ldelem.i1", 0x90) -OP(LDELEM_U1, "ldelem.u1", 0x91) -OP(LDELEM_I2, "ldelem.i2", 0x92) -OP(LDELEM_U2, "ldelem.u2", 0x93) -OP(LDELEM_I4, "ldelem.i4", 0x94) -OP(LDELEM_U4, "ldelem.u4", 0x95) -OP(LDELEM_I8, "ldelem.i8", 0x96) -OP(LDELEM_I, "ldelem.i", 0x97) -OP(LDELEM_R4, "ldelem.r4", 0x98) -OP(LDELEM_R8, "ldelem.r8", 0x99) -OP(LDELEM_REF, "ldelem.ref", 0x9a) -OP(STELEM_I, "stelem.i", 0x9b) -OP(STELEM_I1, "stelem.i1", 0x9c) -OP(STELEM_I2, "stelem.i2", 0x9d) -OP(STELEM_I4, "stelem.i4", 0x9e) -OP(STELEM_I8, "stelem.i8", 0x9f) -OP(STELEM_R4, "stelem.r4", 0xa0) -OP(STELEM_R8, "stelem.r8", 0xa1) -OP(STELEM_REF, "stelem.ref", 0xa2) -OP(CONV_OVF_I1, "conv.ovf.i1", 0xb3) -OP(CONV_OVF_U1, "conv.ovf.u1", 0xb4) -OP(CONV_OVF_I2, "conv.ovf.i2", 0xb5) -OP(CONV_OVF_U2, "conv.ovf.u2", 0xb6) -OP(CONV_OVF_I4, "conv.ovf.i4", 0xb7) -OP(CONV_OVF_U4, "conv.ovf.u4", 0xb8) -OP(CONV_OVF_I8, "conv.ovf.i8", 0xb9) -OP(CONV_OVF_U8, "conv.ovf.u8", 0xba) -OP(REFANYVAL, "refanyval", 0xc2) -OP(CKFINITE, "ckfinite", 0xc3) -OP(MKREFANY, "mkrefany", 0xc6) -OP(ANN_CALL, "ann.call", 0xc7) -OP(ANN_CATCH, "ann.catch", 0xc8) -OP(ANN_DEAD, "ann.dead", 0xc9) -OP(ANN_HOISTED, "ann.hoisted", 0xca) -OP(ANN_HOISTED_CALL, "ann.hoisted.call", 0xcb) -OP(ANN_LAB, "ann.lab", 0xcc) -OP(ANN_DEF, "ann.def", 0xcd) -OP(ANN_REF_S, "ann.ref.s", 0xce) -OP(ANN_PHI, "ann.phi", 0xcf) -OP(LDTOKEN, "ldtoken", 0xd0) -OP(CONV_U2, "conv.u2", 0xd1) -OP(CONV_U1, "conv.u1", 0xd2) -OP(CONV_I, "conv.i", 0xd3) -OP(CONV_OVF_I, "conv.ovf.i", 0xd4) -OP(CONV_OVF_U, "conv.ovf.u", 0xd5) -OP(ADD_OVF, "add.ovf", 0xd6) -OP(ADD_OVF_UN, "add.ovf.un", 0xd7) -OP(MUL_OVF, "mul.ovf", 0xd8) -OP(MUL_OVF_UN, "mul.ovf.un", 0xd9) -OP(SUB_OVF, "sub.ovf", 0xda) -OP(SUB_OVF_UN, "sub.ovf.un", 0xdb) -OP(ENDFINALLY, "endfinally", 0xdc) -OP(LEAVE, "leave", 0xdd) -OP(LEAVE_S, "leave.s", 0xde) -OP(STIND_I, "stind.i", 0xdf) -OP(CONV_U, "conv.u", 0xe0) - -/* prefix instructions. we use an opcode >= 256 to ease coding */ - -OP(ARGLIST, "arglist", 0x100) -OP(CEQ, "ceq", 0x101) -OP(CGT, "cgt", 0x102) -OP(CGT_UN, "cgt.un", 0x103) -OP(CLT, "clt", 0x104) -OP(CLT_UN, "clt.un", 0x105) -OP(LDFTN, "ldftn", 0x106) -OP(LDVIRTFTN, "ldvirtftn", 0x107) -OP(JMPI, "jmpi", 0x108) -OP(LDARG, "ldarg", 0x109) -OP(LDARGA, "ldarga", 0x10a) -OP(STARG, "starg", 0x10b) -OP(LDLOC, "ldloc", 0x10c) -OP(LDLOCA, "ldloca", 0x10d) -OP(STLOC, "stloc", 0x10e) -OP(LOCALLOC, "localloc", 0x10f) -OP(ENDFILTER, "endfilter", 0x111) -OP(UNALIGNED, "unaligned", 0x112) -OP(VOLATILE, "volatile", 0x113) -OP(TAIL, "tail", 0x114) -OP(INITOBJ, "initobj", 0x115) -OP(ANN_LIVE, "ann.live", 0x116) -OP(CPBLK, "cpblk", 0x117) -OP(INITBLK, "initblk", 0x118) -OP(ANN_REF, "ann.ref", 0x119) -OP(RETHROW, "rethrow", 0x11a) -OP(SIZEOF, "sizeof", 0x11c) -OP(REFANYTYPE, "refanytype", 0x11d) -OP(ANN_DATA, "ann.data", 0x122) -OP(ANN_ARG, "ann.arg", 0x123) diff --git a/tinycc/include/float.h b/tinycc/include/float.h deleted file mode 100644 index 24b7410..0000000 --- a/tinycc/include/float.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef _FLOAT_H_ -#define _FLOAT_H_ - -#define FLT_RADIX 2 - -/* IEEE float */ -#define FLT_MANT_DIG 24 -#define FLT_DIG 6 -#define FLT_ROUNDS 1 -#define FLT_EPSILON 1.19209290e-07F -#define FLT_MIN_EXP (-125) -#define FLT_MIN 1.17549435e-38F -#define FLT_MIN_10_EXP (-37) -#define FLT_MAX_EXP 128 -#define FLT_MAX 3.40282347e+38F -#define FLT_MAX_10_EXP 38 - -/* IEEE double */ -#define DBL_MANT_DIG 53 -#define DBL_DIG 15 -#define DBL_EPSILON 2.2204460492503131e-16 -#define DBL_MIN_EXP (-1021) -#define DBL_MIN 2.2250738585072014e-308 -#define DBL_MIN_10_EXP (-307) -#define DBL_MAX_EXP 1024 -#define DBL_MAX 1.7976931348623157e+308 -#define DBL_MAX_10_EXP 308 - -/* horrible intel long double */ -#if defined __i386__ || defined __x86_64__ - -#define LDBL_MANT_DIG 64 -#define LDBL_DIG 18 -#define LDBL_EPSILON 1.08420217248550443401e-19L -#define LDBL_MIN_EXP (-16381) -#define LDBL_MIN 3.36210314311209350626e-4932L -#define LDBL_MIN_10_EXP (-4931) -#define LDBL_MAX_EXP 16384 -#define LDBL_MAX 1.18973149535723176502e+4932L -#define LDBL_MAX_10_EXP 4932 -#define DECIMAL_DIG 21 - -#elif defined __aarch64__ || defined __riscv -/* - * Use values from: - * gcc -dM -E -xc /dev/null | grep LDBL | sed -e "s/__//g" - */ -#define LDBL_MANT_DIG 113 -#define LDBL_DIG 33 -#define LDBL_EPSILON 1.92592994438723585305597794258492732e-34L -#define LDBL_MIN_EXP (-16381) -#define LDBL_MIN 3.36210314311209350626267781732175260e-4932L -#define LDBL_MIN_10_EXP (-4931) -#define LDBL_MAX_EXP 16384 -#define LDBL_MAX 1.18973149535723176508575932662800702e+4932L -#define LDBL_MAX_EXP 16384 -#define DECIMAL_DIG 36 - -#else - -/* same as IEEE double */ -#define LDBL_MANT_DIG 53 -#define LDBL_DIG 15 -#define LDBL_EPSILON 2.2204460492503131e-16L -#define LDBL_MIN_EXP (-1021) -#define LDBL_MIN 2.2250738585072014e-308L -#define LDBL_MIN_10_EXP (-307) -#define LDBL_MAX_EXP 1024 -#define LDBL_MAX 1.7976931348623157e+308L -#define LDBL_MAX_10_EXP 308 -#define DECIMAL_DIG 17 - -#endif - -#endif /* _FLOAT_H_ */ diff --git a/tinycc/include/stdalign.h b/tinycc/include/stdalign.h deleted file mode 100644 index ae46c34..0000000 --- a/tinycc/include/stdalign.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _STDALIGN_H -#define _STDALIGN_H - -#if __STDC_VERSION__ < 201112L && (defined(__GNUC__) || defined(__TINYC__)) -# define _Alignas(t) __attribute__((__aligned__(t))) -# define _Alignof(t) __alignof__(t) -#endif - -#define alignas _Alignas -#define alignof _Alignof - -#define __alignas_is_defined 1 -#define __alignof_is_defined 1 - -#endif /* _STDALIGN_H */ - diff --git a/tinycc/include/stdarg.h b/tinycc/include/stdarg.h deleted file mode 100644 index aa784da..0000000 --- a/tinycc/include/stdarg.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _STDARG_H -#define _STDARG_H - -typedef __builtin_va_list va_list; -#define va_start __builtin_va_start -#define va_arg __builtin_va_arg -#define va_copy __builtin_va_copy -#define va_end __builtin_va_end - -/* fix a buggy dependency on GCC in libio.h */ -typedef va_list __gnuc_va_list; -#define _VA_LIST_DEFINED - -#endif /* _STDARG_H */ diff --git a/tinycc/include/stdatomic.h b/tinycc/include/stdatomic.h deleted file mode 100644 index a8372ee..0000000 --- a/tinycc/include/stdatomic.h +++ /dev/null @@ -1,172 +0,0 @@ -/* This file is derived from clang's stdatomic.h */ - -/*===---- stdatomic.h - Standard header for atomic types and operations -----=== - * - * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. - * See https://llvm.org/LICENSE.txt for license information. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - * - *===-----------------------------------------------------------------------=== - */ - -#ifndef _STDATOMIC_H -#define _STDATOMIC_H - -#include <stddef.h> -#include <stdint.h> -#include <stdbool.h> - -#define __ATOMIC_RELAXED 0 -#define __ATOMIC_CONSUME 1 -#define __ATOMIC_ACQUIRE 2 -#define __ATOMIC_RELEASE 3 -#define __ATOMIC_ACQ_REL 4 -#define __ATOMIC_SEQ_CST 5 - -/* Memory ordering */ -typedef enum { - memory_order_relaxed = __ATOMIC_RELAXED, - memory_order_consume = __ATOMIC_CONSUME, - memory_order_acquire = __ATOMIC_ACQUIRE, - memory_order_release = __ATOMIC_RELEASE, - memory_order_acq_rel = __ATOMIC_ACQ_REL, - memory_order_seq_cst = __ATOMIC_SEQ_CST, -} memory_order; - -/* Atomic typedefs */ -typedef _Atomic(_Bool) atomic_bool; -typedef _Atomic(char) atomic_char; -typedef _Atomic(signed char) atomic_schar; -typedef _Atomic(unsigned char) atomic_uchar; -typedef _Atomic(short) atomic_short; -typedef _Atomic(unsigned short) atomic_ushort; -typedef _Atomic(int) atomic_int; -typedef _Atomic(unsigned int) atomic_uint; -typedef _Atomic(long) atomic_long; -typedef _Atomic(unsigned long) atomic_ulong; -typedef _Atomic(long long) atomic_llong; -typedef _Atomic(unsigned long long) atomic_ullong; -typedef _Atomic(uint_least16_t) atomic_char16_t; -typedef _Atomic(uint_least32_t) atomic_char32_t; -typedef _Atomic(wchar_t) atomic_wchar_t; -typedef _Atomic(int_least8_t) atomic_int_least8_t; -typedef _Atomic(uint_least8_t) atomic_uint_least8_t; -typedef _Atomic(int_least16_t) atomic_int_least16_t; -typedef _Atomic(uint_least16_t) atomic_uint_least16_t; -typedef _Atomic(int_least32_t) atomic_int_least32_t; -typedef _Atomic(uint_least32_t) atomic_uint_least32_t; -typedef _Atomic(int_least64_t) atomic_int_least64_t; -typedef _Atomic(uint_least64_t) atomic_uint_least64_t; -typedef _Atomic(int_fast8_t) atomic_int_fast8_t; -typedef _Atomic(uint_fast8_t) atomic_uint_fast8_t; -typedef _Atomic(int_fast16_t) atomic_int_fast16_t; -typedef _Atomic(uint_fast16_t) atomic_uint_fast16_t; -typedef _Atomic(int_fast32_t) atomic_int_fast32_t; -typedef _Atomic(uint_fast32_t) atomic_uint_fast32_t; -typedef _Atomic(int_fast64_t) atomic_int_fast64_t; -typedef _Atomic(uint_fast64_t) atomic_uint_fast64_t; -typedef _Atomic(intptr_t) atomic_intptr_t; -typedef _Atomic(uintptr_t) atomic_uintptr_t; -typedef _Atomic(size_t) atomic_size_t; -typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t; -typedef _Atomic(intmax_t) atomic_intmax_t; -typedef _Atomic(uintmax_t) atomic_uintmax_t; - -/* Atomic flag */ -typedef struct { - atomic_bool value; -} atomic_flag; - -#define ATOMIC_FLAG_INIT {0} - -#define atomic_flag_test_and_set_explicit(object, order) \ - __atomic_test_and_set((void *)(&((object)->value)), order) -#define atomic_flag_test_and_set(object) \ - atomic_flag_test_and_set_explicit(object, __ATOMIC_SEQ_CST) - -#define atomic_flag_clear_explicit(object, order) \ - __atomic_clear((bool *)(&((object)->value)), order) -#define atomic_flag_clear(object) \ - atomic_flag_clear_explicit(object, __ATOMIC_SEQ_CST) - -/* Generic routines */ -#define atomic_init(object, desired) \ - atomic_store_explicit(object, desired, __ATOMIC_RELAXED) - -#define atomic_store_explicit(object, desired, order) \ - ({ __typeof__ (object) ptr = (object); \ - __typeof__ (*ptr) tmp = (desired); \ - __atomic_store (ptr, &tmp, (order)); \ - }) -#define atomic_store(object, desired) \ - atomic_store_explicit (object, desired, __ATOMIC_SEQ_CST) - -#define atomic_load_explicit(object, order) \ - ({ __typeof__ (object) ptr = (object); \ - __typeof__ (*ptr) tmp; \ - __atomic_load (ptr, &tmp, (order)); \ - tmp; \ - }) -#define atomic_load(object) atomic_load_explicit (object, __ATOMIC_SEQ_CST) - -#define atomic_exchange_explicit(object, desired, order) \ - ({ __typeof__ (object) ptr = (object); \ - __typeof__ (*ptr) val = (desired); \ - __typeof__ (*ptr) tmp; \ - __atomic_exchange (ptr, &val, &tmp, (order)); \ - tmp; \ - }) -#define atomic_exchange(object, desired) \ - atomic_exchange_explicit (object, desired, __ATOMIC_SEQ_CST) - -#define atomic_compare_exchange_strong_explicit(object, expected, desired, success, failure) \ - ({ __typeof__ (object) ptr = (object); \ - __typeof__ (*ptr) tmp = desired; \ - __atomic_compare_exchange(ptr, expected, &tmp, 0, success, failure); \ - }) -#define atomic_compare_exchange_strong(object, expected, desired) \ - atomic_compare_exchange_strong_explicit (object, expected, desired, \ - __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) - -#define atomic_compare_exchange_weak_explicit(object, expected, desired, success, failure) \ - ({ __typeof__ (object) ptr = (object); \ - __typeof__ (*ptr) tmp = desired; \ - __atomic_compare_exchange(ptr, expected, &tmp, 1, success, failure); \ - }) -#define atomic_compare_exchange_weak(object, expected, desired) \ - atomic_compare_exchange_weak_explicit (PTR, VAL, DES, \ - __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) - -#define atomic_fetch_add(object, operand) \ - __atomic_fetch_add(object, operand, __ATOMIC_SEQ_CST) -#define atomic_fetch_add_explicit __atomic_fetch_add - -#define atomic_fetch_sub(object, operand) \ - __atomic_fetch_sub(object, operand, __ATOMIC_SEQ_CST) -#define atomic_fetch_sub_explicit __atomic_fetch_sub - -#define atomic_fetch_or(object, operand) \ - __atomic_fetch_or(object, operand, __ATOMIC_SEQ_CST) -#define atomic_fetch_or_explicit __atomic_fetch_or - -#define atomic_fetch_xor(object, operand) \ - __atomic_fetch_xor(object, operand, __ATOMIC_SEQ_CST) -#define atomic_fetch_xor_explicit __atomic_fetch_xor - -#define atomic_fetch_and(object, operand) \ - __atomic_fetch_and(object, operand, __ATOMIC_SEQ_CST) -#define atomic_fetch_and_explicit __atomic_fetch_and - -extern void atomic_thread_fence (memory_order); -extern void __atomic_thread_fence (memory_order); -#define atomic_thread_fence(order) __atomic_thread_fence (order) -extern void atomic_signal_fence (memory_order); -extern void __atomic_signal_fence (memory_order); -#define atomic_signal_fence(order) __atomic_signal_fence (order) -extern bool __atomic_is_lock_free(size_t size, void *ptr); -#define atomic_is_lock_free(OBJ) __atomic_is_lock_free (sizeof (*(OBJ)), (OBJ)) - -extern bool __atomic_test_and_set (void *, memory_order); -extern void __atomic_clear (bool *, memory_order); - -#endif /* _STDATOMIC_H */ diff --git a/tinycc/include/stdbool.h b/tinycc/include/stdbool.h deleted file mode 100644 index d2ee446..0000000 --- a/tinycc/include/stdbool.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _STDBOOL_H -#define _STDBOOL_H - -/* ISOC99 boolean */ - -#define bool _Bool -#define true 1 -#define false 0 -#define __bool_true_false_are_defined 1 - -#endif /* _STDBOOL_H */ diff --git a/tinycc/include/stddef.h b/tinycc/include/stddef.h deleted file mode 100644 index da9b9e0..0000000 --- a/tinycc/include/stddef.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _STDDEF_H -#define _STDDEF_H - -typedef __SIZE_TYPE__ size_t; -typedef __PTRDIFF_TYPE__ ssize_t; -typedef __WCHAR_TYPE__ wchar_t; -typedef __PTRDIFF_TYPE__ ptrdiff_t; -typedef __PTRDIFF_TYPE__ intptr_t; -typedef __SIZE_TYPE__ uintptr_t; - -#if __STDC_VERSION__ >= 201112L -typedef union { long long __ll; long double __ld; } max_align_t; -#endif - -#ifndef NULL -#define NULL ((void*)0) -#endif - -#undef offsetof -#define offsetof(type, field) ((size_t)&((type *)0)->field) - -#if defined __i386__ || defined __x86_64__ -void *alloca(size_t size); -#endif - -#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 diff --git a/tinycc/include/stdnoreturn.h b/tinycc/include/stdnoreturn.h deleted file mode 100644 index 4d580ea..0000000 --- a/tinycc/include/stdnoreturn.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _STDNORETURN_H -#define _STDNORETURN_H - -/* ISOC11 noreturn */ -#define noreturn _Noreturn - -#endif /* _STDNORETURN_H */ diff --git a/tinycc/include/tccdefs.h b/tinycc/include/tccdefs.h deleted file mode 100644 index 4e03cb9..0000000 --- a/tinycc/include/tccdefs.h +++ /dev/null @@ -1,325 +0,0 @@ -/* tccdefs.h - - Nothing is defined before this file except target machine, target os - and the few things related to option settings in tccpp.c:tcc_predefs(). - - This file is either included at runtime as is, or converted and - included as C-strings at compile-time (depending on CONFIG_TCC_PREDEFS). - - Note that line indent matters: - - - in lines starting at column 1, platform macros are replaced by - corresponding TCC target compile-time macros. See conftest.c for - the list of platform macros supported in lines starting at column 1. - - - only lines indented >= 4 are actually included into the executable, - check tccdefs_.h. -*/ - -#if __SIZEOF_POINTER__ == 4 - /* 32bit systems. */ -#if defined __OpenBSD__ - #define __SIZE_TYPE__ unsigned long - #define __PTRDIFF_TYPE__ long -#else - #define __SIZE_TYPE__ unsigned int - #define __PTRDIFF_TYPE__ int -#endif - #define __ILP32__ 1 - #define __INT64_TYPE__ long long -#elif __SIZEOF_LONG__ == 4 - /* 64bit Windows. */ - #define __SIZE_TYPE__ unsigned long long - #define __PTRDIFF_TYPE__ long long - #define __LLP64__ 1 - #define __INT64_TYPE__ long long -#else - /* Other 64bit systems. */ - #define __SIZE_TYPE__ unsigned long - #define __PTRDIFF_TYPE__ long - #define __LP64__ 1 -# if defined __linux__ - #define __INT64_TYPE__ long -# else /* APPLE, BSD */ - #define __INT64_TYPE__ long long -# endif -#endif - #define __SIZEOF_INT__ 4 - #define __INT_MAX__ 0x7fffffff -#if __SIZEOF_LONG__ == 4 - #define __LONG_MAX__ 0x7fffffffL -#else - #define __LONG_MAX__ 0x7fffffffffffffffL -#endif - #define __SIZEOF_LONG_LONG__ 8 - #define __LONG_LONG_MAX__ 0x7fffffffffffffffLL - #define __CHAR_BIT__ 8 - #define __ORDER_LITTLE_ENDIAN__ 1234 - #define __ORDER_BIG_ENDIAN__ 4321 - #define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ -#if defined _WIN32 - #define __WCHAR_TYPE__ unsigned short - #define __WINT_TYPE__ unsigned short -#elif defined __linux__ - #define __WCHAR_TYPE__ int - #define __WINT_TYPE__ unsigned int -#else - #define __WCHAR_TYPE__ int - #define __WINT_TYPE__ int -#endif - - #if __STDC_VERSION__ >= 201112L - # define __STDC_NO_ATOMICS__ 1 - # define __STDC_NO_COMPLEX__ 1 - # define __STDC_NO_THREADS__ 1 -#if !defined _WIN32 - # define __STDC_UTF_16__ 1 - # define __STDC_UTF_32__ 1 -#endif - #endif - -#if defined _WIN32 - #define __declspec(x) __attribute__((x)) - #define __cdecl - -#elif defined __FreeBSD__ - #define __GNUC__ 9 - #define __GNUC_MINOR__ 3 - #define __GNUC_PATCHLEVEL__ 0 - #define __GNUC_STDC_INLINE__ 1 - #define __NO_TLS 1 - #define __RUNETYPE_INTERNAL 1 -# if __SIZEOF_POINTER__ == 8 - /* FIXME, __int128_t is used by setjump */ - #define __int128_t struct { unsigned char _dummy[16] __attribute((aligned(16))); } - #define __SIZEOF_SIZE_T__ 8 - #define __SIZEOF_PTRDIFF_T__ 8 -#else - #define __SIZEOF_SIZE_T__ 4 - #define __SIZEOF_PTRDIFF_T__ 4 -# endif - -#elif defined __FreeBSD_kernel__ - -#elif defined __NetBSD__ - #define __GNUC__ 4 - #define __GNUC_MINOR__ 1 - #define __GNUC_PATCHLEVEL__ 0 - #define _Pragma(x) - #define __ELF__ 1 -#if defined __aarch64__ - #define _LOCORE /* avoids usage of __asm */ -#endif - -#elif defined __OpenBSD__ - #define __GNUC__ 4 - #define _ANSI_LIBRARY 1 - -#elif defined __APPLE__ - /* emulate APPLE-GCC to make libc's headerfiles compile: */ - #define __GNUC__ 4 /* darwin emits warning on GCC<4 */ - #define __APPLE_CC__ 1 /* for <TargetConditionals.h> */ - #define __LITTLE_ENDIAN__ 1 - #define _DONT_USE_CTYPE_INLINE_ 1 - /* avoids usage of GCC/clang specific builtins in libc-headerfiles: */ - #define __FINITE_MATH_ONLY__ 1 - #define _FORTIFY_SOURCE 0 - -#elif defined __ANDROID__ - #define BIONIC_IOCTL_NO_SIGNEDNESS_OVERLOAD - #define __PRETTY_FUNCTION__ __FUNCTION__ - #define __has_builtin(x) 0 - #define __has_feature(x) 0 - #define _Nonnull - #define _Nullable - -#else - /* Linux */ - -#endif - /* Some derived integer types needed to get stdint.h to compile correctly on some platforms */ -#ifndef __NetBSD__ - #define __UINTPTR_TYPE__ unsigned __PTRDIFF_TYPE__ - #define __INTPTR_TYPE__ __PTRDIFF_TYPE__ -#endif - #define __INT32_TYPE__ int - -#if !defined _WIN32 - /* glibc defines */ - #define __REDIRECT(name, proto, alias) name proto __asm__ (#alias) - #define __REDIRECT_NTH(name, proto, alias) name proto __asm__ (#alias) __THROW -#endif - - /* skip __builtin... with -E */ - #ifndef __TCC_PP__ - - #define __builtin_offsetof(type, field) ((__SIZE_TYPE__)&((type*)0)->field) - #define __builtin_extract_return_addr(x) x -#if !defined __linux__ && !defined _WIN32 - /* used by math.h */ - #define __builtin_huge_val() 1e500 - #define __builtin_huge_valf() 1e50f - #define __builtin_huge_vall() 1e5000L -# if defined __APPLE__ - #define __builtin_nanf(ignored_string) (0.0F/0.0F) - /* used by floats.h to implement FLT_ROUNDS C99 macro. 1 == to nearest */ - #define __builtin_flt_rounds() 1 - /* used by _fd_def.h */ - #define __builtin_bzero(p, ignored_size) bzero(p, sizeof(*(p))) -# else - #define __builtin_nanf(ignored_string) (0.0F/0.0F) -# endif -#endif - - /* __builtin_va_list */ -#if defined __x86_64__ -#if !defined _WIN32 - /* GCC compatible definition of va_list. */ - /* This should be in sync with the declaration in our lib/libtcc1.c */ - typedef struct { - unsigned gp_offset, fp_offset; - union { - unsigned overflow_offset; - char *overflow_arg_area; - }; - char *reg_save_area; - } __builtin_va_list[1]; - - void *__va_arg(__builtin_va_list ap, int arg_type, int size, int align); - #define __builtin_va_start(ap, last) \ - (*(ap) = *(__builtin_va_list)((char*)__builtin_frame_address(0) - 24)) - #define __builtin_va_arg(ap, t) \ - (*(t *)(__va_arg(ap, __builtin_va_arg_types(t), sizeof(t), __alignof__(t)))) - #define __builtin_va_copy(dest, src) (*(dest) = *(src)) - -#else /* _WIN64 */ - typedef char* __builtin_va_list; - #define __builtin_va_arg(ap, t) ((sizeof(t) > 8 || (sizeof(t) & (sizeof(t) - 1))) \ - ? **(t **)((ap += 8) - 8) : *(t *)((ap += 8) - 8)) -#endif - -#elif defined __arm__ - typedef char *__builtin_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 __builtin_va_start(ap,last) (ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)) - #define __builtin_va_arg(ap,type) (ap = (void *) ((_tcc_align(ap,type)+sizeof(type)+3) \ - &~3), *(type *)(ap - ((sizeof(type)+3)&~3))) - -#elif defined __aarch64__ -#if defined __APPLE__ - typedef struct { - void *__stack; - } __builtin_va_list; - -#else - typedef struct { - void *__stack, *__gr_top, *__vr_top; - int __gr_offs, __vr_offs; - } __builtin_va_list; - -#endif -#elif defined __riscv - typedef char *__builtin_va_list; - #define __va_reg_size (__riscv_xlen >> 3) - #define _tcc_align(addr,type) (((unsigned long)addr + __alignof__(type) - 1) \ - & -(__alignof__(type))) - #define __builtin_va_arg(ap,type) (*(sizeof(type) > (2*__va_reg_size) ? *(type **)((ap += __va_reg_size) - __va_reg_size) : (ap = (va_list)(_tcc_align(ap,type) + (sizeof(type)+__va_reg_size - 1)& -__va_reg_size), (type *)(ap - ((sizeof(type)+ __va_reg_size - 1)& -__va_reg_size))))) - -#else /* __i386__ */ - typedef char *__builtin_va_list; - #define __builtin_va_start(ap,last) (ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)) - #define __builtin_va_arg(ap,t) (*(t*)((ap+=(sizeof(t)+3)&~3)-((sizeof(t)+3)&~3))) - -#endif - #define __builtin_va_end(ap) (void)(ap) - #ifndef __builtin_va_copy - # define __builtin_va_copy(dest, src) (dest) = (src) - #endif - - /* TCC BBUILTIN AND BOUNDS ALIASES */ - #ifdef __leading_underscore - # define __RENAME(X) __asm__("_"X) - #else - # define __RENAME(X) __asm__(X) - #endif - - #ifdef __TCC_BCHECK__ - # define __BUILTINBC(ret,name,params) ret __builtin_##name params __RENAME("__bound_"#name); - # define __BOUND(ret,name,params) ret name params __RENAME("__bound_"#name); - #else - # define __BUILTINBC(ret,name,params) ret __builtin_##name params __RENAME(#name); - # define __BOUND(ret,name,params) - #endif -#ifdef _WIN32 - #define __BOTH __BOUND - #define __BUILTIN(ret,name,params) -#else - #define __BOTH(ret,name,params) __BUILTINBC(ret,name,params)__BOUND(ret,name,params) - #define __BUILTIN(ret,name,params) ret __builtin_##name params __RENAME(#name); -#endif - - __BOTH(void*, memcpy, (void *, const void*, __SIZE_TYPE__)) - __BOTH(void*, memmove, (void *, const void*, __SIZE_TYPE__)) - __BOTH(void*, memset, (void *, int, __SIZE_TYPE__)) - __BOTH(int, memcmp, (const void *, const void*, __SIZE_TYPE__)) - __BOTH(__SIZE_TYPE__, strlen, (const char *)) - __BOTH(char*, strcpy, (char *, const char *)) - __BOTH(char*, strncpy, (char *, const char*, __SIZE_TYPE__)) - __BOTH(int, strcmp, (const char*, const char*)) - __BOTH(int, strncmp, (const char*, const char*, __SIZE_TYPE__)) - __BOTH(char*, strcat, (char*, const char*)) - __BOTH(char*, strncat, (char*, const char*, __SIZE_TYPE__)) - __BOTH(char*, strchr, (const char*, int)) - __BOTH(char*, strrchr, (const char*, int)) - __BOTH(char*, strdup, (const char*)) -#if defined __ARM_EABI__ - __BOUND(void*,__aeabi_memcpy,(void*,const void*,__SIZE_TYPE__)) - __BOUND(void*,__aeabi_memmove,(void*,const void*,__SIZE_TYPE__)) - __BOUND(void*,__aeabi_memmove4,(void*,const void*,__SIZE_TYPE__)) - __BOUND(void*,__aeabi_memmove8,(void*,const void*,__SIZE_TYPE__)) - __BOUND(void*,__aeabi_memset,(void*,int,__SIZE_TYPE__)) -#endif - -#if defined __linux__ || defined __APPLE__ // HAVE MALLOC_REDIR - #define __MAYBE_REDIR __BUILTIN -#else - #define __MAYBE_REDIR __BOTH -#endif - __MAYBE_REDIR(void*, malloc, (__SIZE_TYPE__)) - __MAYBE_REDIR(void*, realloc, (void *, __SIZE_TYPE__)) - __MAYBE_REDIR(void*, calloc, (__SIZE_TYPE__, __SIZE_TYPE__)) - __MAYBE_REDIR(void*, memalign, (__SIZE_TYPE__, __SIZE_TYPE__)) - __MAYBE_REDIR(void, free, (void*)) -#if defined __i386__ || defined __x86_64__ - __BOTH(void*, alloca, (__SIZE_TYPE__)) -#else - __BUILTIN(void*, alloca, (__SIZE_TYPE__)) -#endif - __BUILTIN(void, abort, (void)) - __BOUND(void, longjmp, ()) -#if !defined _WIN32 - __BOUND(void*, mmap, ()) - __BOUND(int, munmap, ()) -#endif - #undef __BUILTINBC - #undef __BUILTIN - #undef __BOUND - #undef __BOTH - #undef __MAYBE_REDIR - #undef __RENAME - - #define __BUILTIN_EXTERN(name,u) \ - int __builtin_##name(u int); \ - int __builtin_##name##l(u long); \ - int __builtin_##name##ll(u long long); - __BUILTIN_EXTERN(ffs,) - __BUILTIN_EXTERN(clz, unsigned) - __BUILTIN_EXTERN(ctz, unsigned) - __BUILTIN_EXTERN(clrsb,) - __BUILTIN_EXTERN(popcount, unsigned) - __BUILTIN_EXTERN(parity, unsigned) - #undef __BUILTIN_EXTERN - - #endif /* ndef __TCC_PP__ */
\ No newline at end of file diff --git a/tinycc/include/tgmath.h b/tinycc/include/tgmath.h deleted file mode 100644 index 5d3e357..0000000 --- a/tinycc/include/tgmath.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * ISO C Standard: 7.22 Type-generic math <tgmath.h> - */ - -#ifndef _TGMATH_H -#define _TGMATH_H - -#include <math.h> - -#ifndef __cplusplus -#define __tgmath_real(x, F) \ - _Generic ((x), float: F##f, long double: F##l, default: F)(x) -#define __tgmath_real_2_1(x, y, F) \ - _Generic ((x), float: F##f, long double: F##l, default: F)(x, y) -#define __tgmath_real_2(x, y, F) \ - _Generic ((x)+(y), float: F##f, long double: F##l, default: F)(x, y) -#define __tgmath_real_3_2(x, y, z, F) \ - _Generic ((x)+(y), float: F##f, long double: F##l, default: F)(x, y, z) -#define __tgmath_real_3(x, y, z, F) \ - _Generic ((x)+(y)+(z), float: F##f, long double: F##l, default: F)(x, y, z) - -/* Functions defined in both <math.h> and <complex.h> (7.22p4) */ -#define acos(z) __tgmath_real(z, acos) -#define asin(z) __tgmath_real(z, asin) -#define atan(z) __tgmath_real(z, atan) -#define acosh(z) __tgmath_real(z, acosh) -#define asinh(z) __tgmath_real(z, asinh) -#define atanh(z) __tgmath_real(z, atanh) -#define cos(z) __tgmath_real(z, cos) -#define sin(z) __tgmath_real(z, sin) -#define tan(z) __tgmath_real(z, tan) -#define cosh(z) __tgmath_real(z, cosh) -#define sinh(z) __tgmath_real(z, sinh) -#define tanh(z) __tgmath_real(z, tanh) -#define exp(z) __tgmath_real(z, exp) -#define log(z) __tgmath_real(z, log) -#define pow(z1,z2) __tgmath_real_2(z1, z2, pow) -#define sqrt(z) __tgmath_real(z, sqrt) -#define fabs(z) __tgmath_real(z, fabs) - -/* Functions defined in <math.h> only (7.22p5) */ -#define atan2(x,y) __tgmath_real_2(x, y, atan2) -#define cbrt(x) __tgmath_real(x, cbrt) -#define ceil(x) __tgmath_real(x, ceil) -#define copysign(x,y) __tgmath_real_2(x, y, copysign) -#define erf(x) __tgmath_real(x, erf) -#define erfc(x) __tgmath_real(x, erfc) -#define exp2(x) __tgmath_real(x, exp2) -#define expm1(x) __tgmath_real(x, expm1) -#define fdim(x,y) __tgmath_real_2(x, y, fdim) -#define floor(x) __tgmath_real(x, floor) -#define fma(x,y,z) __tgmath_real_3(x, y, z, fma) -#define fmax(x,y) __tgmath_real_2(x, y, fmax) -#define fmin(x,y) __tgmath_real_2(x, y, fmin) -#define fmod(x,y) __tgmath_real_2(x, y, fmod) -#define frexp(x,y) __tgmath_real_2_1(x, y, frexp) -#define hypot(x,y) __tgmath_real_2(x, y, hypot) -#define ilogb(x) __tgmath_real(x, ilogb) -#define ldexp(x,y) __tgmath_real_2_1(x, y, ldexp) -#define lgamma(x) __tgmath_real(x, lgamma) -#define llrint(x) __tgmath_real(x, llrint) -#define llround(x) __tgmath_real(x, llround) -#define log10(x) __tgmath_real(x, log10) -#define log1p(x) __tgmath_real(x, log1p) -#define log2(x) __tgmath_real(x, log2) -#define logb(x) __tgmath_real(x, logb) -#define lrint(x) __tgmath_real(x, lrint) -#define lround(x) __tgmath_real(x, lround) -#define nearbyint(x) __tgmath_real(x, nearbyint) -#define nextafter(x,y) __tgmath_real_2(x, y, nextafter) -#define nexttoward(x,y) __tgmath_real_2(x, y, nexttoward) -#define remainder(x,y) __tgmath_real_2(x, y, remainder) -#define remquo(x,y,z) __tgmath_real_3_2(x, y, z, remquo) -#define rint(x) __tgmath_real(x, rint) -#define round(x) __tgmath_real(x, round) -#define scalbln(x,y) __tgmath_real_2_1(x, y, scalbln) -#define scalbn(x,y) __tgmath_real_2_1(x, y, scalbn) -#define tgamma(x) __tgmath_real(x, tgamma) -#define trunc(x) __tgmath_real(x, trunc) - -/* Functions defined in <complex.h> only (7.22p6) -#define carg(z) __tgmath_cplx_only(z, carg) -#define cimag(z) __tgmath_cplx_only(z, cimag) -#define conj(z) __tgmath_cplx_only(z, conj) -#define cproj(z) __tgmath_cplx_only(z, cproj) -#define creal(z) __tgmath_cplx_only(z, creal) -*/ -#endif /* __cplusplus */ -#endif /* _TGMATH_H */ diff --git a/tinycc/include/varargs.h b/tinycc/include/varargs.h deleted file mode 100644 index d614366..0000000 --- a/tinycc/include/varargs.h +++ /dev/null @@ -1,12 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _VARARGS_H -#define _VARARGS_H - -#error "TinyCC no longer implements <varargs.h>." -#error "Revise your code to use <stdarg.h>." - -#endif diff --git a/tinycc/lib/Makefile b/tinycc/lib/Makefile deleted file mode 100644 index 6f08376..0000000 --- a/tinycc/lib/Makefile +++ /dev/null @@ -1,94 +0,0 @@ -# -# Tiny C Compiler Makefile for libtcc1.a -# - -TOP = .. -include $(TOP)/Makefile -VPATH = $(TOPSRC)/lib $(TOPSRC)/win32/lib -T = $(or $(CROSS_TARGET),$(NATIVE_TARGET),unknown) -X = $(if $(CROSS_TARGET),$(CROSS_TARGET)-) - -XTCC ?= $(TOP)/$(X)tcc$(EXESUF) -XCC = $(XTCC) -XAR = $(XTCC) -ar -XFLAGS-unx = -B$(TOPSRC) -XFLAGS-win = -B$(TOPSRC)/win32 -I$(TOPSRC)/include -XFLAGS = $(XFLAGS$(XCFG)) -I$(TOP) -XCFG = $(or $(findstring -win,$T),-unx) -S = $(if $(findstring yes,$(SILENT)),@$(info * $@)) - -# in order to use gcc, type: make <target>-libtcc1-usegcc=yes -arm-libtcc1-usegcc ?= no - -# This makes bounds checking 40%..60% faster. -x86_64-libtcc1-usegcc=yes -#i386-libtcc1-usegcc=yes - -ifeq "$($(T)-libtcc1-usegcc)" "yes" - XCC = $(CC) - XAR = $(AR) - XFLAGS = $(CFLAGS) -fPIC -gdwarf -fno-omit-frame-pointer -Wno-unused-function -Wno-unused-variable -endif - -ifneq ($(CONFIG_backtrace),no) -# only for native compiler -ifneq ($(CONFIG_bcheck),no) -$(X)BCHECK_O = bcheck.o -endif -$(X)BT_O = bt-exe.o bt-log.o -$(X)B_O = $(BCHECK_O) bt-exe.o bt-log.o bt-dll.o -endif -$(X)BT_O += tcov.o - -DSO_O = dsohandle.o - -I386_O = libtcc1.o alloca.o alloca-bt.o stdatomic.o atomic.o builtin.o $(BT_O) -X86_64_O = libtcc1.o alloca.o alloca-bt.o stdatomic.o atomic.o builtin.o $(BT_O) -ARM_O = libtcc1.o armeabi.o alloca.o armflush.o stdatomic.o atomic.o builtin.o $(BT_O) -ARM64_O = lib-arm64.o stdatomic.o atomic.o builtin.o $(BT_O) -RISCV64_O = lib-arm64.o stdatomic.o atomic.o builtin.o $(BT_O) -WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o - -OBJ-i386 = $(I386_O) $(BCHECK_O) $(DSO_O) -OBJ-x86_64 = $(X86_64_O) va_list.o $(BCHECK_O) $(DSO_O) -OBJ-x86_64-osx = $(X86_64_O) va_list.o $(BCHECK_O) -OBJ-i386-win32 = $(I386_O) chkstk.o $(B_O) $(WIN_O) -OBJ-x86_64-win32 = $(X86_64_O) chkstk.o $(B_O) $(WIN_O) -OBJ-arm64 = $(ARM64_O) $(BCHECK_O) $(DSO_O) -OBJ-arm64-osx = $(ARM64_O) $(BCHECK_O) -OBJ-arm = $(ARM_O) $(BCHECK_O) $(DSO_O) -OBJ-arm-fpa = $(ARM_O) $(DSO_O) -OBJ-arm-fpa-ld = $(ARM_O) $(DSO_O) -OBJ-arm-vfp = $(ARM_O) $(DSO_O) -OBJ-arm-eabi = $(ARM_O) $(DSO_O) -OBJ-arm-eabihf = $(ARM_O) $(DSO_O) -OBJ-arm-wince = $(ARM_O) $(WIN_O) -OBJ-riscv64 = $(RISCV64_O) $(BCHECK_O) $(DSO_O) - -OBJ-extra = $(filter $(B_O),$(OBJ-$T)) -OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T))) - -ALL = $(addprefix $(TOP)/,$(X)libtcc1.a $(OBJ-extra)) - -all: $(ALL) - -$(TOP)/$(X)libtcc1.a : $(OBJ-libtcc1) - $S$(XAR) rcs $@ $^ - -$(X)%.o : %.c - $S$(XCC) -c $< -o $@ $(XFLAGS) - -$(X)%.o : %.S - $S$(XCC) -c $< -o $@ $(XFLAGS) - -$(TOP)/%.o : %.c - $S$(XCC) -c $< -o $@ $(XFLAGS) - -$(TOP)/bcheck.o : XFLAGS += -g $(if $(CONFIG_musl),-DTCC_MUSL) -$(TOP)/bt-exe.o : $(TOP)/tccrun.c - -$(X)crt1w.o : crt1.c -$(X)wincrt1w.o : wincrt1.c - -clean : - rm -f *.a *.o $(ALL) diff --git a/tinycc/lib/alloca-bt.S b/tinycc/lib/alloca-bt.S deleted file mode 100644 index c161488..0000000 --- a/tinycc/lib/alloca-bt.S +++ /dev/null @@ -1,96 +0,0 @@ -/* ---------------------------------------------- */ -/* alloca-bt.S */ - -#ifdef __leading_underscore -# define _(s) _##s -#else -# define _(s) s -#endif - -/* ---------------------------------------------- */ -#if defined __i386__ - -.globl _(__bound_alloca) -_(__bound_alloca): - pop %edx - pop %eax - mov %eax, %ecx - add $3+1,%eax - and $-4,%eax - jz p6 - -#ifdef _WIN32 -p4: - cmp $4096,%eax - jbe p5 - test %eax,-4096(%esp) - sub $4096,%esp - sub $4096,%eax - jmp p4 - -p5: -#endif - - sub %eax,%esp - mov %esp,%eax - - push %edx - push %eax - push %ecx - push %eax - call _(__bound_new_region) - add $8, %esp - pop %eax - pop %edx - -p6: - push %edx - push %edx - ret - -/* ---------------------------------------------- */ -#elif defined __x86_64__ - -.globl _(__bound_alloca) -_(__bound_alloca): -#ifdef _WIN32 - inc %rcx # add one extra to separate regions - jmp _(alloca) -.globl _(__bound_alloca_nr) -_(__bound_alloca_nr): - dec %rcx - push %rax - mov %rcx,%rdx - mov %rax,%rcx - sub $32,%rsp - call _(__bound_new_region) - add $32,%rsp - pop %rax - ret -#else - pop %rdx - mov %rdi,%rax - mov %rax,%rsi # size, a second parm to the __bound_new_region - - add $15 + 1,%rax # add one extra to separate regions - 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 - -/* ---------------------------------------------- */ -#endif diff --git a/tinycc/lib/alloca.S b/tinycc/lib/alloca.S deleted file mode 100644 index 6ebafd7..0000000 --- a/tinycc/lib/alloca.S +++ /dev/null @@ -1,85 +0,0 @@ -/* ---------------------------------------------- */ -/* alloca.S */ - -#ifdef __leading_underscore -# define _(s) _##s -#else -# define _(s) s -#endif - -/* ---------------------------------------------- */ -#if defined __i386__ - -.globl _(alloca), _(__alloca) -_(alloca): -_(__alloca): - push %ebp - mov %esp,%ebp - mov 8(%ebp),%eax - add $3,%eax - and $-4,%eax -#ifdef _WIN32 - jmp .+16 #p2 -p1: - sub $4096,%esp - sub $4096,%eax - test %eax,(%esp) -p2: - cmp $4096,%eax - jae p1 -#endif - sub %eax,%esp - mov 4(%ebp),%eax - mov 0(%ebp),%ebp - add $8,%esp - push %eax - lea 8(%esp),%eax - ret - -/* ---------------------------------------------- */ -#elif defined __x86_64__ - -.globl _(alloca) -_(alloca): - pop %rdx -#ifdef _WIN32 - mov %rcx,%rax -#else - mov %rdi,%rax -#endif - add $15,%rax - and $-16,%rax - jz p3 - -#ifdef _WIN32 -p1: - cmp $4096,%rax - jbe p2 - test %rax,-4096(%rsp) - sub $4096,%rsp - sub $4096,%rax - jmp p1 -p2: -#endif - sub %rax,%rsp - mov %rsp,%rax -p3: - push %rdx - ret - -/* ---------------------------------------------- */ -#elif defined __arm__ - - .text - .align 2 - .global alloca - .type alloca, %function -alloca: - rsb sp, r0, sp - bic sp, sp, #7 - mov r0, sp - mov pc, lr - .size alloca, .-alloca - -/* ---------------------------------------------- */ -#endif diff --git a/tinycc/lib/armeabi.c b/tinycc/lib/armeabi.c deleted file mode 100644 index 6ade65e..0000000 --- a/tinycc/lib/armeabi.c +++ /dev/null @@ -1,544 +0,0 @@ -/* 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; \ - \ - if ((val.high & ~0x80000000) == 0 && val.low == 0) { \ - ret.low = ret.high = 0; \ - goto _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++; \ - } \ - \ -_ret_: \ - 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; \ - goto _ret_; \ - } \ - } \ - \ - /* fill exponent bits */ \ - ret.high |= (s + ONE_EXP(DOUBLE)) << (DOUBLE_FRAC_BITS - 32); \ - \ - /* fill sign bit */ \ - ret.high |= sign << 31; \ - \ -_ret_: \ - 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)); -} - -/* Some targets do not have all eabi calls (OpenBSD) */ -typedef __SIZE_TYPE__ size_t; -extern void *memcpy(void *dest, const void *src, size_t n); -extern void *memmove(void *dest, const void *src, size_t n); -extern void *memset(void *s, int c, size_t n); - -void * -__aeabi_memcpy (void *dest, const void *src, size_t n) -{ - return memcpy (dest, src, n); -} - -void * -__aeabi_memmove (void *dest, const void *src, size_t n) -{ - return memmove (dest, src, n); -} - -void * -__aeabi_memmove4 (void *dest, const void *src, size_t n) -{ - return memmove (dest, src, n); -} - -void * -__aeabi_memmove8 (void *dest, const void *src, size_t n) -{ - return memmove (dest, src, n); -} - -void * -__aeabi_memset (void *s, size_t n, int c) -{ - return memset (s, c, n); -} diff --git a/tinycc/lib/armflush.c b/tinycc/lib/armflush.c deleted file mode 100644 index c379e43..0000000 --- a/tinycc/lib/armflush.c +++ /dev/null @@ -1,51 +0,0 @@ -/* armflush.c - flush the instruction cache - - __clear_cache is used in tccrun.c, It is a built-in - intrinsic with gcc. However tcc in order to compile - itself needs this function */ - -#ifdef __TINYC__ - -/* syscall wrapper */ -unsigned _tccsyscall(unsigned syscall_nr, ...); - -/* arm-tcc supports only fake asm currently */ -__asm__( - ".global _tccsyscall\n" - "_tccsyscall:\n" - "push {r7, lr}\n\t" - "mov r7, r0\n\t" - "mov r0, r1\n\t" - "mov r1, r2\n\t" - "mov r2, r3\n\t" - "svc #0\n\t" - "pop {r7, pc}" - ); - -/* from unistd.h: */ -#if defined(__thumb__) || defined(__ARM_EABI__) -# define __NR_SYSCALL_BASE 0x0 -#else -# define __NR_SYSCALL_BASE 0x900000 -#endif -#define __ARM_NR_BASE (__NR_SYSCALL_BASE+0x0f0000) -#define __ARM_NR_cacheflush (__ARM_NR_BASE+2) - -#define syscall _tccsyscall - -#else - -#define _GNU_SOURCE -#include <unistd.h> -#include <sys/syscall.h> -#include <stdio.h> - -#endif - -/* 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 */ - syscall(__ARM_NR_cacheflush, beginning, end, 0); -} diff --git a/tinycc/lib/atomic.S b/tinycc/lib/atomic.S deleted file mode 100644 index 29fdbee..0000000 --- a/tinycc/lib/atomic.S +++ /dev/null @@ -1,858 +0,0 @@ -/* ---------------------------------------------- */ -/* This file implements for arm/arm64/riscv: - * __atomic_compare_exchange_1 - * __atomic_compare_exchange_2 - * __atomic_compare_exchange_4 - * __atomic_compare_exchange_8 - */ - -#ifdef __leading_underscore -# define _(s) _##s -#else -# define _(s) s -#endif - -#if defined __i386__ - .text - .align 2 - - .global _(__atomic_test_and_set) - .type _(__atomic_test_and_set), %function -_(__atomic_test_and_set): - movl 4(%esp), %edx - movl $1, %eax - xchgb (%edx), %al - ret - .size _(__atomic_test_and_set), .-_(__atomic_test_and_set) - - .global _(__atomic_clear) - .type _(__atomic_clear), %function -_(__atomic_clear): - movl 4(%esp), %edx - xorl %eax, %eax - xchgb (%edx), %al - ret - .size _(__atomic_clear), .-_(__atomic_clear) - -#elif defined __x86_64__ - .text - .align 2 - - .global _(__atomic_test_and_set) - .type _(__atomic_test_and_set), %function -_(__atomic_test_and_set): - movl $1, %eax - xchgb (%rdi), %al - ret - .size _(__atomic_test_and_set), .-_(__atomic_test_and_set) - - .global _(__atomic_clear) - .type _(__atomic_clear), %function -_(__atomic_clear): - xorl %eax, %eax - xchgb (%rdi), %al - ret - .size _(__atomic_clear), .-_(__atomic_clear) - -#elif defined __arm__ - -#ifndef __TINYC__ - .arch armv6k - .syntax unified -#endif - .text - .align 2 - - .global _(fetch_and_add_arm) - .type _(fetch_and_add_arm), %function -_(fetch_and_add_arm): - mcr p15, #0, r0, c7, c10, #5 -.L0: - ldrex r3, [r0] - add r3, r3, r1 - strex r2, r3, [r0] - cmp r2, #0 - bne .L0 - mcr p15, #0, r0, c7, c10, #5 - bx lr - .size _(fetch_and_add_arm), .-_(fetch_and_add_arm) - - .global _(__atomic_test_and_set) - .type _(__atomic_test_and_set), %function -_(__atomic_test_and_set): -#ifdef __TINYC__ - .int 0xe92d4030 - .int 0xee070fba - .int 0xe5d03000 - .int 0xe24dd014 - .int 0xe1a05000 - .int 0xe2533000 - .int 0xe1a04001 - .int 0x13a03001 - .int 0xee070fba - .int 0xe5cd300f - .int 0xe3a03001 - .int 0xe1a02003 - .int 0xe28d100f - .int 0xe1a00005 - .int 0xe58d4004 - .int 0xe58d4000 - .int 0xeb000009 - .int 0xe3500000 - .int 0x0afffff6 - .int 0xe5dd000f - .int 0xe28dd014 - .int 0xe8bd8030 -#else - push {r4, r5, lr} - mcr p15, 0, r0, c7, c10, 5 - ldrb r3, [r0] - sub sp, sp, #20 - mov r5, r0 - subs r3, r3, #0 - mov r4, r1 - movne r3, #1 - mcr p15, 0, r0, c7, c10, 5 - strb r3, [sp, #15] -.L20: - mov r3, #1 - mov r2, r3 - add r1, sp, #15 - mov r0, r5 - str r4, [sp, #4] - str r4, [sp] - bl __atomic_compare_exchange_1 - cmp r0, #0 - beq .L20 - ldrb r0, [sp, #15] - add sp, sp, #20 - pop {r4, r5, pc} -#endif - .size _(__atomic_test_and_set), .-_(__atomic_test_and_set) - - .global _(__atomic_clear) - .type _(__atomic_clear), %function -_(__atomic_clear): -#ifdef __TINYC__ - .int 0xe3a03000 - .int 0xee070fba - .int 0xe5c03000 - .int 0xee070fba - .int 0xe12fff1e -#else - mov r3, #0 - mcr p15, 0, r0, c7, c10, 5 - strb r3, [r0] - mcr p15, 0, r0, c7, c10, 5 - bx lr -#endif - .size _(__atomic_clear), .-_(__atomic_clear) - - .global _(__atomic_compare_exchange_1) - .type _(__atomic_compare_exchange_1), %function -_(__atomic_compare_exchange_1): -#ifdef __TINYC__ - .int 0xe52de004 - .int 0xe5d13000 - .int 0xf57ff05b - .int 0xe1d0cf9f - .int 0xe15c0003 - .int 0x1a000002 - .int 0xe1c0ef92 - .int 0xe35e0000 - .int 0x1afffff9 - .int 0x03a00001 - .int 0x13a00000 - .int 0xf57ff05b - .int 0x15c1c000 - .int 0xe49df004 -#else - str lr, [sp, #-4]! - ldrb r3, [r1] - mcr p15, 0, r0, c7, c10, 5 -.L1: - ldrexb ip, [r0] - cmp ip, r3 - bne .L2 - strexb lr, r2, [r0] - cmp lr, #0 - bne .L1 -.L2: - mcr p15, 0, r0, c7, c10, 5 - moveq r0, #1 - movne r0, #0 - strbne ip, [r1] - ldr pc, [sp], #4 -#endif - .size _(__atomic_compare_exchange_1), .-_(__atomic_compare_exchange_1) - - .global _(__atomic_compare_exchange_2) - .type _(__atomic_compare_exchange_2), %function -_(__atomic_compare_exchange_2): -#ifdef __TINYC__ - .int 0xe52de004 - .int 0xe1d130b0 - .int 0xf57ff05b - .int 0xe1f0cf9f - .int 0xe15c0003 - .int 0x1a000002 - .int 0xe1e0ef92 - .int 0xe35e0000 - .int 0x1afffff9 - .int 0x03a00001 - .int 0x13a00000 - .int 0xf57ff05b - .int 0x11c1c0b0 - .int 0xe49df004 -#else - str lr, [sp, #-4]! - ldrh r3, [r1] - mcr p15, 0, r0, c7, c10, 5 -.L3: - ldrexh ip, [r0] - cmp ip, r3 - bne .L4 - strexh lr, r2, [r0] - cmp lr, #0 - bne .L3 -.L4: - mcr p15, 0, r0, c7, c10, 5 - moveq r0, #1 - movne r0, #0 - strhne ip, [r1] - ldr pc, [sp], #4 -#endif - .size _(__atomic_compare_exchange_2), .-_(__atomic_compare_exchange_2) - - .global _(__atomic_compare_exchange_4) - .type _(__atomic_compare_exchange_4), %function -_(__atomic_compare_exchange_4): -#ifdef __TINYC__ - .int 0xe52de004 - .int 0xe5913000 - .int 0xf57ff05b - .int 0xe190cf9f - .int 0xe15c0003 - .int 0x1a000002 - .int 0xe180ef92 - .int 0xe35e0000 - .int 0x1afffff9 - .int 0x03a00001 - .int 0x13a00000 - .int 0xf57ff05b - .int 0x1581c000 - .int 0xe49df004 -#else - str lr, [sp, #-4]! - ldr r3, [r1] - mcr p15, 0, r0, c7, c10, 5 -.L5: - ldrex ip, [r0] - cmp ip, r3 - bne .L6 - strex lr, r2, [r0] - cmp lr, #0 - bne .L5 -.L6: - mcr p15, 0, r0, c7, c10, 5 - moveq r0, #1 - movne r0, #0 - strne ip, [r1] - ldr pc, [sp], #4 -#endif - .size _(__atomic_compare_exchange_4), .-_(__atomic_compare_exchange_4) - -/* ---------------------------------------------- */ -#elif defined __aarch64__ - - .text - .align 2 - - .global _(fetch_and_add_arm64) - .type _(fetch_and_add_arm64), %function -_(fetch_and_add_arm64): -#ifdef __TINYC__ - .int 0x885f7c02 - .int 0x0b010042 - .int 0x8803fc02 - .int 0x35ffffa3 - .int 0xd5033bbf - .int 0xd65f03c0 -#else - ldxr w2, [x0] - add w2, w2, w1 - stlxr w3, w2, [x0] - cbnz w3, _(fetch_and_add_arm64) - dmb ish - ret -#endif - .size _(fetch_and_add_arm64), .-_(fetch_and_add_arm64) - - .global _(__atomic_test_and_set) - .type _(__atomic_test_and_set), %function -_(__atomic_test_and_set): -#ifdef __TINYC__ - .int 0xa9bf7bfd - .int 0xaa0003e1 - .int 0x52800020 - .int 0x910003fd - .int 0x2a0003f0 - .int 0x085ffc20 - .int 0x0811fc30 - .int 0x35ffffd1 - .int 0xa8c17bfd - .int 0xd65f03c0 -#else - stp x29, x30, [sp, -16]! - mov x1, x0 - mov w0, 1 - mov x29, sp - mov w16, w0 -.L20: - ldaxrb w0, [x1] - stlxrb w17, w16, [x1] - cbnz w17, .L20 - ldp x29, x30, [sp], 16 - ret -#endif - .size _(__atomic_test_and_set), .-_(__atomic_test_and_set) - - .global _(__atomic_clear) - .type _(__atomic_clear), %function -_(__atomic_clear): -#ifdef __TINYC__ - .int 0x089ffc1f - .int 0xd65f03c0 -#else - stlrb wzr, [x0] - ret -#endif - .size _(__atomic_clear), .-_(__atomic_clear) - - .global _(__atomic_compare_exchange_1) - .type _(__atomic_compare_exchange_1), %function -_(__atomic_compare_exchange_1): -#ifdef __TINYC__ - .int 0xa9be7bfd - .int 0x910003fd - .int 0xa90153f3 - .int 0xaa0103f3 - .int 0x12001c41 - .int 0xaa0003e2 - .int 0x39400274 - .int 0x2a1403e0 - .int 0x53001c10 - .int 0x085ffc40 - .int 0x6b10001f - .int 0x54000061 - .int 0x0811fc41 - .int 0x35ffff91 - .int 0x6b34001f - .int 0x1a9f17e1 - .int 0x54000040 - .int 0x39000260 - .int 0x2a0103e0 - .int 0xa94153f3 - .int 0xa8c27bfd - .int 0xd65f03c0 -#else - stp x29, x30, [sp, -32]! - mov x29, sp - stp x19, x20, [sp, 16] - mov x19, x1 - and w1, w2, 255 - mov x2, x0 - ldrb w20, [x19] - mov w0, w20 - uxtb w16, w0 -.L1: - ldaxrb w0, [x2] - cmp w0, w16 - b.ne .L2 - stlxrb w17, w1, [x2] - cbnz w17, .L1 -.L2: - cmp w0, w20, uxtb - cset w1, eq - beq .L3 - strb w0, [x19] -.L3: - mov w0, w1 - ldp x19, x20, [sp, 16] - ldp x29, x30, [sp], 32 - ret -#endif - .size _(__atomic_compare_exchange_1), .-_(__atomic_compare_exchange_1) - - .global _(__atomic_compare_exchange_2) - .type _(__atomic_compare_exchange_2), %function -_(__atomic_compare_exchange_2): -#ifdef __TINYC__ - .int 0xa9be7bfd - .int 0x910003fd - .int 0xa90153f3 - .int 0xaa0103f3 - .int 0x12003c41 - .int 0xaa0003e2 - .int 0x79400274 - .int 0x2a1403e0 - .int 0x53003c10 - .int 0x485ffc40 - .int 0x6b10001f - .int 0x54000061 - .int 0x4811fc41 - .int 0x35ffff91 - .int 0x6b34201f - .int 0x1a9f17e1 - .int 0x54000040 - .int 0x79000260 - .int 0x2a0103e0 - .int 0xa94153f3 - .int 0xa8c27bfd - .int 0xd65f03c0 -#else - stp x29, x30, [sp, -32]! - mov x29, sp - stp x19, x20, [sp, 16] - mov x19, x1 - and w1, w2, 65535 - mov x2, x0 - ldrh w20, [x19] - mov w0, w20 - uxth w16, w0 -.L4: - ldaxrh w0, [x2] - cmp w0, w16 - b.ne .L5 - stlxrh w17, w1, [x2] - cbnz w17, .L4 -.L5: - cmp w0, w20, uxth - cset w1, eq - beq .L6 - strh w0, [x19] -.L6: - mov w0, w1 - ldp x19, x20, [sp, 16] - ldp x29, x30, [sp], 32 - ret -#endif - .size _(__atomic_compare_exchange_2), .-_(__atomic_compare_exchange_2) - - .global _(__atomic_compare_exchange_4) - .type _(__atomic_compare_exchange_4), %function -_(__atomic_compare_exchange_4): -#ifdef __TINYC__ - .int 0xa9be7bfd - .int 0x910003fd - .int 0xa90153f3 - .int 0xaa0103f3 - .int 0x2a0203e1 - .int 0xaa0003e2 - .int 0xb9400274 - .int 0x2a1403e0 - .int 0x2a0003f0 - .int 0x885ffc40 - .int 0x6b10001f - .int 0x54000061 - .int 0x8811fc41 - .int 0x35ffff91 - .int 0x6b14001f - .int 0x1a9f17e1 - .int 0x54000040 - .int 0xb9000260 - .int 0x2a0103e0 - .int 0xa94153f3 - .int 0xa8c27bfd - .int 0xd65f03c0 -#else - stp x29, x30, [sp, -32]! - mov x29, sp - stp x19, x20, [sp, 16] - mov x19, x1 - mov w1, w2 - mov x2, x0 - ldr w20, [x19] - mov w0, w20 - mov w16, w0 -.L7: - ldaxr w0, [x2] - cmp w0, w16 - b.ne .L8 - stlxr w17, w1, [x2] - cbnz w17, .L7 -.L8: - cmp w0, w20 - cset w1, eq - beq .L9 - str w0, [x19] -.L9: - mov w0, w1 - ldp x19, x20, [sp, 16] - ldp x29, x30, [sp], 32 - ret -#endif - .size _(__atomic_compare_exchange_4), .-_(__atomic_compare_exchange_4) - - .global _(__atomic_compare_exchange_8) - .type _(__atomic_compare_exchange_8), %function -_(__atomic_compare_exchange_8): -#ifdef __TINYC__ - .int 0xa9be7bfd - .int 0x910003fd - .int 0xa90153f3 - .int 0xaa0103f3 - .int 0xaa0203e1 - .int 0xaa0003e2 - .int 0xf9400274 - .int 0xaa1403e0 - .int 0xaa0003f0 - .int 0xc85ffc40 - .int 0xeb10001f - .int 0x54000061 - .int 0xc811fc41 - .int 0x35ffff91 - .int 0xeb14001f - .int 0x1a9f17e1 - .int 0x54000040 - .int 0xf9000260 - .int 0x2a0103e0 - .int 0xa94153f3 - .int 0xa8c27bfd - .int 0xd65f03c0 -#else - stp x29, x30, [sp, -32]! - mov x29, sp - stp x19, x20, [sp, 16] - mov x19, x1 - mov x1, x2 - mov x2, x0 - ldr x20, [x19] - mov x0, x20 - mov x16, x0 -.L10: - ldaxr x0, [x2] - cmp x0, x16 - b.ne .L11 - stlxr w17, x1, [x2] - cbnz w17, .L10 -.L11: - cmp x0, x20 - cset w1, eq - beq .L12 - str x0, [x19] -.L12: - mov w0, w1 - ldp x19, x20, [sp, 16] - ldp x29, x30, [sp], 32 - ret -#endif - .size _(__atomic_compare_exchange_8), .-_(__atomic_compare_exchange_8) - -/* ---------------------------------------------- */ -#elif defined __riscv - - .text - .align 2 - - .global _(fetch_and_add_riscv64) - .type _(fetch_and_add_riscv64), %function -_(fetch_and_add_riscv64): -#ifdef __TINYC__ - .int 0x0f50000f - .int 0x004b5202f - .short 0x8082 -#else - fence iorw,ow - amoadd.w.aq zero,a1,0(a0) - ret -#endif - .size _(fetch_and_add_riscv64), .-_(fetch_and_add_riscv64) - - .global _(__atomic_test_and_set) - .type _(__atomic_test_and_set), %function -_(__atomic_test_and_set): -#ifdef __TINYC__ - .int 0x00357793 - .int 0x0037979b - .short 0x4685 - .short 0x9971 - .int 0x00f696bb - .int 0x0f50000f - .int 0x44d5272f - .int 0x00f7553b - .int 0x0ff57513 - .short 0x8082 -#else - andi a5,a0,3 - slliw a5,a5,3 - li a3,1 - andi a0,a0,-4 - sllw a3,a3,a5 - fence iorw,ow; amoor.w.aq a4,a3,0(a0) - srlw a0,a4,a5 - andi a0,a0,0xff - ret -#endif - .size _(__atomic_test_and_set), .-_(__atomic_test_and_set) - - .global _(__atomic_clear) - .type _(__atomic_clear), %function -_(__atomic_clear): -#ifdef __TINYC__ - .int 0x0ff0000f - .int 0x00050023 - .int 0x0ff0000f - .short 0x8082 -#else - fence iorw,iorw - sb zero,0(a0) - fence iorw,iorw - ret -#endif - .size _(__atomic_clear), .-_(__atomic_clear) - - .global _(__atomic_compare_exchange_1) - .type _(__atomic_compare_exchange_1), %function -_(__atomic_compare_exchange_1): -#ifdef __TINYC__ - .short 0x1141 - .short 0x86ba - .short 0x873e - .short 0xe406 - .int 0x0ff0000f - .int 0x0005c803 - .int 0xff857893 - .int 0x0008b783 - .short 0x891d - .short 0x050e - .int 0x0ff00693 - .int 0x00a696b3 - .int 0x00a81833 - .int 0x00a61633 - .int 0xfff6c713 - .short 0x8f7d - .int 0x00f6f333 - .short 0x8f51 - .int 0x03031263 - .int 0x1008b32f - .int 0x00f31663 - .int 0x18e8be2f - .int 0xfe0e1ae3 - .int 0x40f30733 - .short 0x879a - .short 0xff69 - .int 0x0ff0000f - .short 0x4505 - .short 0xa801 - .int 0x00a7d7b3 - .int 0x00f58023 - .int 0x0ff0000f - .short 0x4501 - .short 0x60a2 - .short 0x0141 - .short 0x8082 -#else - addi sp,sp,-16 - mv a3,a4 - mv a4,a5 - sd ra,8(sp) - fence - lbu a6,0(a1) - andi a7,a0,-8 - ld a5,0(a7) - andi a0,a0,7 - slli a0,a0,0x3 - li a3,255 - sll a3,a3,a0 - sll a6,a6,a0 - sll a2,a2,a0 -.L1: - not a4,a3 - and a4,a4,a5 - and t1,a3,a5 - or a4,a4,a2 - bne t1,a6,.L4 -.L2: - lr.d t1,(a7) - bne t1,a5,.L3 - sc.d t3,a4,(a7) - bnez t3,.L2 -.L3: - sub a4,t1,a5 - mv a5,t1 - bnez a4,.L1 - fence - li a0,1 - j .L5 -.L4: - srl a5,a5,a0 - sb a5,0(a1) - fence - li a0,0 -.L5: - ld ra,8(sp) - addi sp,sp,16 - jr ra -#endif - .size _(__atomic_compare_exchange_1), .-_(__atomic_compare_exchange_1) - - .global _(__atomic_compare_exchange_2) - .type _(__atomic_compare_exchange_2), %function -_(__atomic_compare_exchange_2): -#ifdef __TINYC__ - .short 0x1141 - .short 0x86ba - .short 0x873e - .short 0xe406 - .int 0x0ff0000f - .int 0x0005d803 - .int 0xff857893 - .short 0x67c1 - .short 0x891d - .int 0x0008b703 - .short 0x050e - .short 0x17fd - .int 0x00a797b3 - .int 0x00a81833 - .int 0x00a61633 - .int 0xfff7c693 - .short 0x8ef9 - .int 0x00e7f333 - .short 0x8ed1 - .int 0x03031263 - .int 0x1008b32f - .int 0x00e31663 - .int 0x18d8be2f - .int 0xfe0e1ae3 - .int 0x40e306b3 - .short 0x871a - .short 0xfee9 - .int 0x0ff0000f - .short 0x4505 - .short 0xa801 - .int 0x00a75733 - .int 0x00e59023 - .int 0x0ff0000f - .short 0x4501 - .short 0x60a2 - .short 0x0141 - .short 0x8082 -#else - addi sp,sp,-16 - mv a3,a4 - mv a4,a5 - sd ra,8(sp) - fence - lhu a6,0(a1) - andi a7,a0,-8 - lui a5,0x10 - andi a0,a0,7 - ld a4,0(a7) - slli a0,a0,0x3 - addi a5,a5,-1 - sll a5,a5,a0 - sll a6,a6,a0 - sll a2,a2,a0 -.L6: - not a3,a5 - and a3,a3,a4 - and t1,a5,a4 - or a3,a3,a2 - bne t1,a6,.L9 -.L7: - lr.d t1,(a7) - bne t1,a4,.L8 - sc.d t3,a3,(a7) - bnez t3,.L7 -.L8: - sub a3,t1,a4 - mv a4,t1 - bnez a3,.L6 - fence - li a0,1 - j .L10 -.L9: - srl a4,a4,a0 - sh a4,0(a1) - fence - li a0,0 -.L10: - ld ra,8(sp) - addi sp,sp,16 - jr ra -#endif - .size _(__atomic_compare_exchange_2), .-_(__atomic_compare_exchange_2) - - .global _(__atomic_compare_exchange_4) - .type _(__atomic_compare_exchange_4), %function -_(__atomic_compare_exchange_4): -#ifdef __TINYC__ - .short 0x419c - .int 0x0f50000f - .int 0x1405272f - .int 0x00f71663 - .int 0x1cc5282f - .int 0xfe081ae3 - .int 0x40f707bb - .int 0x0017b513 - .short 0xc391 - .short 0xc198 - .short 0x8905 - .short 0x8082 -#else - lw a5,0(a1) - fence iorw,ow; -.L11: - lr.w.aq a4,0(a0) - bne a4,a5,.L12 - sc.w.aq a6,a2,0(a0) - bnez a6,.L11 -.L12: - subw a5,a4,a5 - seqz a0,a5 - beq a5,zero,.L13 - sw a4,0(a1) -.L13: - andi a0,a0,1 - ret -#endif - .size _(__atomic_compare_exchange_4), .-_(__atomic_compare_exchange_4) - - .global _(__atomic_compare_exchange_8) - .type _(__atomic_compare_exchange_8), %function -_(__atomic_compare_exchange_8): -#ifdef __TINYC__ - .short 0x619c - .int 0x0f50000f - .int 0x1405372f - .int 0x00f71563 - .int 0x1cc536af - .short 0xfaf5 - .int 0x40f707b3 - .int 0x0017b513 - .short 0xc391 - .short 0xe198 - .short 0x8905 - .short 0x8082 -#else - ld a5,0(a1) - fence iorw,ow; -.L14: - lr.d.aq a4,0(a0) - bne a4,a5,.L15 - sc.d.aq a3,a2,0(a0) - bnez a3,.L14 -.L15: - sub a5,a4,a5 - seqz a0,a5 - beq a5,zero,.L16 - sd a4,0(a1) -.L16: - andi a0,a0,1 - ret -#endif - .size _(__atomic_compare_exchange_8), .-_(__atomic_compare_exchange_8) - -/* ---------------------------------------------- */ -#endif diff --git a/tinycc/lib/bcheck.c b/tinycc/lib/bcheck.c deleted file mode 100644 index b8dd1c5..0000000 --- a/tinycc/lib/bcheck.c +++ /dev/null @@ -1,2270 +0,0 @@ -/* - * Tiny C Memory and bounds checker - * - * Copyright (c) 2002 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 - */ -#include <stdlib.h> -#include <stdio.h> -#include <stdarg.h> -#include <string.h> -#include <setjmp.h> - -#if !defined(__FreeBSD__) \ - && !defined(__FreeBSD_kernel__) \ - && !defined(__DragonFly__) \ - && !defined(__OpenBSD__) \ - && !defined(__APPLE__) \ - && !defined(__NetBSD__) -#include <malloc.h> -#endif - -#if !defined(_WIN32) -#include <unistd.h> -#include <sys/syscall.h> -#endif - -#define BOUND_DEBUG (1) -#define BOUND_STATISTIC (1) - -#if BOUND_DEBUG - #define dprintf(a...) if (print_calls) fprintf(a) -#else - #define dprintf(a...) -#endif - -#ifdef __attribute__ - /* an __attribute__ macro is defined in the system headers */ - #undef __attribute__ -#endif -#define FASTCALL __attribute__((regparm(3))) - -#ifdef _WIN32 -# define DLL_EXPORT __declspec(dllexport) -#else -# define DLL_EXPORT -#endif - -#if defined(__FreeBSD__) \ - || defined(__FreeBSD_kernel__) \ - || defined(__DragonFly__) \ - || defined(__OpenBSD__) \ - || defined(__NetBSD__) \ - || defined(__dietlibc__) - -#include <sys/mman.h> -#define INIT_SEM() -#define EXIT_SEM() -#define WAIT_SEM() -#define POST_SEM() -#define TRY_SEM() -#define HAVE_MEMALIGN (0) -#define MALLOC_REDIR (0) -#define HAVE_PTHREAD_CREATE (0) -#define HAVE_CTYPE (0) -#define HAVE_ERRNO (0) -#define HAVE_SIGNAL (0) -#define HAVE_SIGACTION (0) -#define HAVE_FORK (0) -#define HAVE_TLS_FUNC (0) -#define HAVE_TLS_VAR (0) - -#elif defined(_WIN32) - -#include <windows.h> -#include <signal.h> -static CRITICAL_SECTION bounds_sem; -#define INIT_SEM() InitializeCriticalSection(&bounds_sem) -#define EXIT_SEM() DeleteCriticalSection(&bounds_sem) -#define WAIT_SEM() EnterCriticalSection(&bounds_sem) -#define POST_SEM() LeaveCriticalSection(&bounds_sem) -#define TRY_SEM() TryEnterCriticalSection(&bounds_sem) -#define HAVE_MEMALIGN (0) -#define MALLOC_REDIR (0) -#define HAVE_PTHREAD_CREATE (0) -#define HAVE_CTYPE (0) -#define HAVE_ERRNO (0) -#define HAVE_SIGNAL (1) -#define HAVE_SIGACTION (0) -#define HAVE_FORK (0) -#define HAVE_TLS_FUNC (1) -#define HAVE_TLS_VAR (0) - -#else - -#define __USE_GNU /* get RTLD_NEXT */ -#include <sys/mman.h> -#include <ctype.h> -#include <pthread.h> -#include <dlfcn.h> -#include <errno.h> -#include <signal.h> -#ifdef __APPLE__ -#include <dispatch/dispatch.h> -static dispatch_semaphore_t bounds_sem; -#define INIT_SEM() bounds_sem = dispatch_semaphore_create(1) -#define EXIT_SEM() dispatch_release(*(dispatch_object_t*)&bounds_sem) -#define WAIT_SEM() if (use_sem) dispatch_semaphore_wait(bounds_sem, DISPATCH_TIME_FOREVER) -#define POST_SEM() if (use_sem) dispatch_semaphore_signal(bounds_sem) -#define TRY_SEM() if (use_sem) dispatch_semaphore_wait(bounds_sem, DISPATCH_TIME_NOW) -#elif 0 -#include <semaphore.h> -static sem_t bounds_sem; -#define INIT_SEM() sem_init (&bounds_sem, 0, 1) -#define EXIT_SEM() sem_destroy (&bounds_sem) -#define WAIT_SEM() if (use_sem) while (sem_wait (&bounds_sem) < 0 \ - && errno == EINTR) -#define POST_SEM() if (use_sem) sem_post (&bounds_sem) -#define TRY_SEM() if (use_sem) while (sem_trywait (&bounds_sem) < 0 \ - && errno == EINTR) -#elif 0 -static pthread_mutex_t bounds_mtx; -#define INIT_SEM() pthread_mutex_init (&bounds_mtx, NULL) -#define EXIT_SEM() pthread_mutex_destroy (&bounds_mtx) -#define WAIT_SEM() if (use_sem) pthread_mutex_lock (&bounds_mtx) -#define POST_SEM() if (use_sem) pthread_mutex_unlock (&bounds_mtx) -#define TRY_SEM() if (use_sem) pthread_mutex_trylock (&bounds_mtx) -#else -static pthread_spinlock_t bounds_spin; -/* about 25% faster then semaphore. */ -#define INIT_SEM() pthread_spin_init (&bounds_spin, 0) -#define EXIT_SEM() pthread_spin_destroy (&bounds_spin) -#define WAIT_SEM() if (use_sem) pthread_spin_lock (&bounds_spin) -#define POST_SEM() if (use_sem) pthread_spin_unlock (&bounds_spin) -#define TRY_SEM() if (use_sem) pthread_spin_trylock (&bounds_spin) -#endif -#define HAVE_MEMALIGN (1) -#define MALLOC_REDIR (1) -#define HAVE_PTHREAD_CREATE (1) -#define HAVE_CTYPE (1) -#define HAVE_ERRNO (1) -#define HAVE_SIGNAL (1) -#define HAVE_SIGACTION (1) -#define HAVE_FORK (1) -#if !defined(__APPLE__) && defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) -#define HAVE_TLS_FUNC (0) -#define HAVE_TLS_VAR (1) -#else -#define HAVE_TLS_FUNC (1) -#define HAVE_TLS_VAR (0) -#endif -#if defined TCC_MUSL || defined __ANDROID__ -# undef HAVE_CTYPE -#endif -#endif - -#if MALLOC_REDIR -static void *(*malloc_redir) (size_t); -static void *(*calloc_redir) (size_t, size_t); -static void (*free_redir) (void *); -static void *(*realloc_redir) (void *, size_t); -static unsigned int pool_index; -static unsigned char __attribute__((aligned(16))) initial_pool[256]; -#endif -#if HAVE_MEMALIGN -static void *(*memalign_redir) (size_t, size_t); -#endif -#if HAVE_PTHREAD_CREATE -static int (*pthread_create_redir) (pthread_t *thread, - const pthread_attr_t *attr, - void *(*start_routine)(void *), void *arg); -#endif -#if HAVE_SIGNAL -typedef void (*bound_sig)(int); -static bound_sig (*signal_redir) (int signum, bound_sig handler); -#endif -#if HAVE_SIGACTION -static int (*sigaction_redir) (int signum, const struct sigaction *act, - struct sigaction *oldact); -#endif -#if HAVE_FORK -static int (*fork_redir) (void); -#endif - -#define TCC_TYPE_NONE (0) -#define TCC_TYPE_MALLOC (1) -#define TCC_TYPE_CALLOC (2) -#define TCC_TYPE_REALLOC (3) -#define TCC_TYPE_MEMALIGN (4) -#define TCC_TYPE_STRDUP (5) - -/* this pointer is generated when bound check is incorrect */ -#define INVALID_POINTER ((void *)(-2)) - -typedef struct tree_node Tree; -struct tree_node { - Tree * left, * right; - size_t start; - size_t size; - unsigned char type; - unsigned char is_invalid; /* true if pointers outside region are invalid */ -}; - -typedef struct alloca_list_struct { - size_t fp; - void *p; - size_t size; - struct alloca_list_struct *next; -} alloca_list_type; - -#if defined(_WIN32) -#define BOUND_TID_TYPE DWORD -#define BOUND_GET_TID(id) id = GetCurrentThreadId() -#elif defined(__OpenBSD__) -#define BOUND_TID_TYPE pid_t -#define BOUND_GET_TID(id) id = getthrid() -#elif defined(__FreeBSD__) -#define BOUND_TID_TYPE pid_t -#define BOUND_GET_TID(id) syscall (SYS_thr_self, &id) -#elif defined(__NetBSD__) -#define BOUND_TID_TYPE pid_t -#define BOUND_GET_TID(id) id = syscall (SYS__lwp_self) -#elif defined(__linux__) -#define BOUND_TID_TYPE pid_t -#define BOUND_GET_TID(id) id = syscall (SYS_gettid) -#else -#define BOUND_TID_TYPE int -#define BOUND_GET_TID(id) id = 0 -#endif - -typedef struct jmp_list_struct { - void *penv; - size_t fp; - size_t end_fp; - BOUND_TID_TYPE tid; - struct jmp_list_struct *next; -} jmp_list_type; - -#define BOUND_STATISTIC_SPLAY (0) -static Tree * splay (size_t addr, Tree *t); -static Tree * splay_end (size_t addr, Tree *t); -static Tree * splay_insert(size_t addr, size_t size, Tree * t); -static Tree * splay_delete(size_t addr, Tree *t); -void splay_printtree(Tree * t, int d); - -/* external interface */ -void __bounds_checking (int no_check); -void __bound_checking_lock (void); -void __bound_checking_unlock (void); -void __bound_never_fatal (int no_check); -DLL_EXPORT void * __bound_ptr_add(void *p, size_t offset); -DLL_EXPORT void * __bound_ptr_indir1(void *p, size_t offset); -DLL_EXPORT void * __bound_ptr_indir2(void *p, size_t offset); -DLL_EXPORT void * __bound_ptr_indir4(void *p, size_t offset); -DLL_EXPORT void * __bound_ptr_indir8(void *p, size_t offset); -DLL_EXPORT void * __bound_ptr_indir12(void *p, size_t offset); -DLL_EXPORT void * __bound_ptr_indir16(void *p, size_t offset); -DLL_EXPORT void FASTCALL __bound_local_new(void *p1); -DLL_EXPORT void FASTCALL __bound_local_delete(void *p1); -void __bound_init(size_t *, int); -void __bound_main_arg(int argc, char **argv, char **envp); -void __bound_exit(void); -void __bound_exit_dll(size_t *); -#if !defined(_WIN32) -void *__bound_mmap (void *start, size_t size, int prot, int flags, int fd, - off_t offset); -int __bound_munmap (void *start, size_t size); -DLL_EXPORT void __bound_siglongjmp(jmp_buf env, int val); -#endif -DLL_EXPORT void __bound_new_region(void *p, size_t size); -DLL_EXPORT void __bound_setjmp(jmp_buf env); -DLL_EXPORT void __bound_longjmp(jmp_buf env, int val); -DLL_EXPORT void *__bound_memcpy(void *dst, const void *src, size_t size); -DLL_EXPORT int __bound_memcmp(const void *s1, const void *s2, size_t size); -DLL_EXPORT void *__bound_memmove(void *dst, const void *src, size_t size); -DLL_EXPORT void *__bound_memset(void *dst, int c, size_t size); -DLL_EXPORT int __bound_strlen(const char *s); -DLL_EXPORT char *__bound_strcpy(char *dst, const char *src); -DLL_EXPORT char *__bound_strncpy(char *dst, const char *src, size_t n); -DLL_EXPORT int __bound_strcmp(const char *s1, const char *s2); -DLL_EXPORT int __bound_strncmp(const char *s1, const char *s2, size_t n); -DLL_EXPORT char *__bound_strcat(char *dest, const char *src); -DLL_EXPORT char *__bound_strncat(char *dest, const char *src, size_t n); -DLL_EXPORT char *__bound_strchr(const char *string, int ch); -DLL_EXPORT char *__bound_strrchr(const char *string, int ch); -DLL_EXPORT char *__bound_strdup(const char *s); - -#if defined(__arm__) && defined(__ARM_EABI__) -DLL_EXPORT void *__bound___aeabi_memcpy(void *dst, const void *src, size_t size); -DLL_EXPORT void *__bound___aeabi_memmove(void *dst, const void *src, size_t size); -DLL_EXPORT void *__bound___aeabi_memmove4(void *dst, const void *src, size_t size); -DLL_EXPORT void *__bound___aeabi_memmove8(void *dst, const void *src, size_t size); -DLL_EXPORT void *__bound___aeabi_memset(void *dst, int c, size_t size); -DLL_EXPORT void *__aeabi_memcpy(void *dst, const void *src, size_t size); -DLL_EXPORT void *__aeabi_memmove(void *dst, const void *src, size_t size); -DLL_EXPORT void *__aeabi_memmove4(void *dst, const void *src, size_t size); -DLL_EXPORT void *__aeabi_memmove8(void *dst, const void *src, size_t size); -DLL_EXPORT void *__aeabi_memset(void *dst, int c, size_t size); -#endif - -#if MALLOC_REDIR -#define BOUND_MALLOC(a) malloc_redir(a) -#define BOUND_MEMALIGN(a,b) memalign_redir(a,b) -#define BOUND_FREE(a) free_redir(a) -#define BOUND_REALLOC(a,b) realloc_redir(a,b) -#define BOUND_CALLOC(a,b) calloc_redir(a,b) -#else -#define BOUND_MALLOC(a) malloc(a) -#define BOUND_MEMALIGN(a,b) memalign(a,b) -#define BOUND_FREE(a) free(a) -#define BOUND_REALLOC(a,b) realloc(a,b) -#define BOUND_CALLOC(a,b) calloc(a,b) -DLL_EXPORT void *__bound_malloc(size_t size, const void *caller); -DLL_EXPORT void *__bound_memalign(size_t size, size_t align, const void *caller); -DLL_EXPORT void __bound_free(void *ptr, const void *caller); -DLL_EXPORT void *__bound_realloc(void *ptr, size_t size, const void *caller); -DLL_EXPORT void *__bound_calloc(size_t nmemb, size_t size); -#endif - -#define FREE_REUSE_SIZE (100) -static unsigned int free_reuse_index; -static void *free_reuse_list[FREE_REUSE_SIZE]; - -static Tree *tree = NULL; -#define TREE_REUSE (1) -#if TREE_REUSE -static Tree *tree_free_list; -#endif -static alloca_list_type *alloca_list; -static jmp_list_type *jmp_list; - -static unsigned char inited; -static unsigned char print_warn_ptr_add; -static unsigned char print_calls; -static unsigned char print_heap; -static unsigned char print_statistic; -static unsigned char no_strdup; -static unsigned char use_sem; -static int never_fatal; -#if HAVE_TLS_FUNC -#if defined(_WIN32) -static int no_checking = 0; -static DWORD no_checking_key; -#define NO_CHECKING_CHECK() if (!p) { \ - p = (int *) LocalAlloc(LPTR, sizeof(int)); \ - if (!p) bound_alloc_error("tls malloc"); \ - *p = 0; \ - TlsSetValue(no_checking_key, p); \ - } -#define NO_CHECKING_GET() ({ int *p = TlsGetValue(no_checking_key); \ - NO_CHECKING_CHECK(); \ - *p; \ - }) -#define NO_CHECKING_SET(v) { int *p = TlsGetValue(no_checking_key); \ - NO_CHECKING_CHECK(); \ - *p = v; \ - } -#else -static int no_checking = 0; -static pthread_key_t no_checking_key; -#define NO_CHECKING_CHECK() if (!p) { \ - p = (int *) BOUND_MALLOC(sizeof(int)); \ - if (!p) bound_alloc_error("tls malloc"); \ - *p = 0; \ - pthread_setspecific(no_checking_key, p); \ - } -#define NO_CHECKING_GET() ({ int *p = pthread_getspecific(no_checking_key); \ - NO_CHECKING_CHECK(); \ - *p; \ - }) -#define NO_CHECKING_SET(v) { int *p = pthread_getspecific(no_checking_key); \ - NO_CHECKING_CHECK(); \ - *p = v; \ - } -#endif -#elif HAVE_TLS_VAR -static __thread int no_checking = 0; -#define NO_CHECKING_GET() no_checking -#define NO_CHECKING_SET(v) no_checking = v -#else -static int no_checking = 0; -#define NO_CHECKING_GET() no_checking -#define NO_CHECKING_SET(v) no_checking = v -#endif -static char exec[100]; - -#if BOUND_STATISTIC -static unsigned long long bound_ptr_add_count; -static unsigned long long bound_ptr_indir1_count; -static unsigned long long bound_ptr_indir2_count; -static unsigned long long bound_ptr_indir4_count; -static unsigned long long bound_ptr_indir8_count; -static unsigned long long bound_ptr_indir12_count; -static unsigned long long bound_ptr_indir16_count; -static unsigned long long bound_local_new_count; -static unsigned long long bound_local_delete_count; -static unsigned long long bound_malloc_count; -static unsigned long long bound_calloc_count; -static unsigned long long bound_realloc_count; -static unsigned long long bound_free_count; -static unsigned long long bound_memalign_count; -static unsigned long long bound_mmap_count; -static unsigned long long bound_munmap_count; -static unsigned long long bound_alloca_count; -static unsigned long long bound_setjmp_count; -static unsigned long long bound_longjmp_count; -static unsigned long long bound_mempcy_count; -static unsigned long long bound_memcmp_count; -static unsigned long long bound_memmove_count; -static unsigned long long bound_memset_count; -static unsigned long long bound_strlen_count; -static unsigned long long bound_strcpy_count; -static unsigned long long bound_strncpy_count; -static unsigned long long bound_strcmp_count; -static unsigned long long bound_strncmp_count; -static unsigned long long bound_strcat_count; -static unsigned long long bound_strncat_count; -static unsigned long long bound_strchr_count; -static unsigned long long bound_strrchr_count; -static unsigned long long bound_strdup_count; -static unsigned long long bound_not_found; -#define INCR_COUNT(x) ++x -#else -#define INCR_COUNT(x) -#endif -#if BOUND_STATISTIC_SPLAY -static unsigned long long bound_splay; -static unsigned long long bound_splay_end; -static unsigned long long bound_splay_insert; -static unsigned long long bound_splay_delete; -#define INCR_COUNT_SPLAY(x) ++x -#else -#define INCR_COUNT_SPLAY(x) -#endif - -int tcc_backtrace(const char *fmt, ...); - -/* print a bound error message */ -#define bound_warning(...) \ - do { \ - WAIT_SEM (); \ - tcc_backtrace("^bcheck.c^BCHECK: " __VA_ARGS__); \ - POST_SEM (); \ - } while (0) - -#define bound_error(...) \ - do { \ - bound_warning(__VA_ARGS__); \ - if (never_fatal == 0) \ - exit(255); \ - } while (0) - -static void bound_alloc_error(const char *s) -{ - fprintf(stderr,"FATAL: %s\n",s); - exit (1); -} - -static void bound_not_found_warning(const char *file, const char *function, - void *ptr) -{ - dprintf(stderr, "%s%s, %s(): Not found %p\n", exec, file, function, ptr); -} - -static void fetch_and_add(int* variable, int value) -{ -#if defined __i386__ || defined __x86_64__ - __asm__ volatile("lock; addl %0, %1" - : "+r" (value), "+m" (*variable) // input+output - : // No input-only - : "memory" - ); -#elif defined __arm__ - extern void fetch_and_add_arm(int* variable, int value); - fetch_and_add_arm(variable, value); -#elif defined __aarch64__ - extern void fetch_and_add_arm64(int* variable, int value); - fetch_and_add_arm64(variable, value); -#elif defined __riscv - extern void fetch_and_add_riscv64(int* variable, int value); - fetch_and_add_riscv64(variable, value); -#else - *variable += value; -#endif -} - -/* enable/disable checking. This can be used in signal handlers. */ -void __bounds_checking (int no_check) -{ -#if HAVE_TLS_FUNC || HAVE_TLS_VAR - NO_CHECKING_SET(NO_CHECKING_GET() + no_check); -#else - fetch_and_add (&no_checking, no_check); -#endif -} - -void __bound_checking_lock(void) -{ - WAIT_SEM (); -} - -void __bound_checking_unlock(void) -{ - POST_SEM (); -} - -/* enable/disable checking. This can be used in signal handlers. */ -void __bound_never_fatal (int neverfatal) -{ - fetch_and_add (&never_fatal, neverfatal); -} - -/* return '(p + offset)' for pointer arithmetic (a pointer can reach - the end of a region in this case */ -void * __bound_ptr_add(void *p, size_t offset) -{ - size_t addr = (size_t)p; - - if (NO_CHECKING_GET()) - return p + offset; - - dprintf(stderr, "%s, %s(): %p 0x%lx\n", - __FILE__, __FUNCTION__, p, (unsigned long)offset); - - WAIT_SEM (); - INCR_COUNT(bound_ptr_add_count); - if (tree) { - addr -= tree->start; - if (addr >= tree->size) { - addr = (size_t)p; - tree = splay (addr, tree); - addr -= tree->start; - } - if (addr >= tree->size) { - addr = (size_t)p; - tree = splay_end (addr, tree); - addr -= tree->start; - } - if (addr <= tree->size) { - if (tree->is_invalid || addr + offset > tree->size) { - POST_SEM (); - if (print_warn_ptr_add) - bound_warning("%p is outside of the region", p + offset); - if (never_fatal <= 0) - return INVALID_POINTER; /* return an invalid pointer */ - return p + offset; - } - } - else if (p) { /* Allow NULL + offset. offsetoff is using it. */ - INCR_COUNT(bound_not_found); - POST_SEM (); - bound_not_found_warning (__FILE__, __FUNCTION__, p); - return p + offset; - } - } - POST_SEM (); - return p + offset; -} - -/* return '(p + offset)' for pointer indirection (the resulting must - be strictly inside the region */ -#define BOUND_PTR_INDIR(dsize) \ -void * __bound_ptr_indir ## dsize (void *p, size_t offset) \ -{ \ - size_t addr = (size_t)p; \ - \ - if (NO_CHECKING_GET()) \ - return p + offset; \ - \ - dprintf(stderr, "%s, %s(): %p 0x%lx\n", \ - __FILE__, __FUNCTION__, p, (unsigned long)offset); \ - WAIT_SEM (); \ - INCR_COUNT(bound_ptr_indir ## dsize ## _count); \ - if (tree) { \ - addr -= tree->start; \ - if (addr >= tree->size) { \ - addr = (size_t)p; \ - tree = splay (addr, tree); \ - addr -= tree->start; \ - } \ - if (addr >= tree->size) { \ - addr = (size_t)p; \ - tree = splay_end (addr, tree); \ - addr -= tree->start; \ - } \ - if (addr <= tree->size) { \ - if (tree->is_invalid || addr + offset + dsize > tree->size) { \ - POST_SEM (); \ - bound_warning("%p is outside of the region", p + offset); \ - if (never_fatal <= 0) \ - return INVALID_POINTER; /* return an invalid pointer */ \ - return p + offset; \ - } \ - } \ - else { \ - INCR_COUNT(bound_not_found); \ - POST_SEM (); \ - bound_not_found_warning (__FILE__, __FUNCTION__, p); \ - return p + offset; \ - } \ - } \ - POST_SEM (); \ - return p + offset; \ -} - -BOUND_PTR_INDIR(1) -BOUND_PTR_INDIR(2) -BOUND_PTR_INDIR(4) -BOUND_PTR_INDIR(8) -BOUND_PTR_INDIR(12) -BOUND_PTR_INDIR(16) - -/* Needed when using ...libtcc1-usegcc=yes in lib/Makefile */ -#if (defined(__GNUC__) && (__GNUC__ >= 6)) || defined(__clang__) -/* - * At least gcc 6.2 complains when __builtin_frame_address is used with - * 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 = (size_t)__builtin_frame_address(1);\ -} - -/* called when entering a function to add all the local regions */ -void FASTCALL __bound_local_new(void *p1) -{ - size_t addr, fp, *p = p1; - - if (NO_CHECKING_GET()) - return; - GET_CALLER_FP(fp); - dprintf(stderr, "%s, %s(): p1=%p fp=%p\n", - __FILE__, __FUNCTION__, p, (void *)fp); - WAIT_SEM (); - while ((addr = p[0])) { - INCR_COUNT(bound_local_new_count); - tree = splay_insert(addr + fp, p[1], tree); - p += 2; - } - POST_SEM (); -#if BOUND_DEBUG - if (print_calls) { - p = p1; - while ((addr = p[0])) { - dprintf(stderr, "%s, %s(): %p 0x%lx\n", - __FILE__, __FUNCTION__, - (void *) (addr + fp), (unsigned long) p[1]); - p += 2; - } - } -#endif -} - -/* called when leaving a function to delete all the local regions */ -void FASTCALL __bound_local_delete(void *p1) -{ - size_t addr, fp, *p = p1; - - if (NO_CHECKING_GET()) - return; - GET_CALLER_FP(fp); - dprintf(stderr, "%s, %s(): p1=%p fp=%p\n", - __FILE__, __FUNCTION__, p, (void *)fp); - WAIT_SEM (); - while ((addr = p[0])) { - INCR_COUNT(bound_local_delete_count); - tree = splay_delete(addr + fp, tree); - p += 2; - } - if (alloca_list) { - alloca_list_type *last = NULL; - alloca_list_type *cur = alloca_list; - - do { - if (cur->fp == fp) { - if (last) - last->next = cur->next; - else - alloca_list = cur->next; - tree = splay_delete ((size_t) cur->p, tree); - dprintf(stderr, "%s, %s(): remove alloca/vla %p\n", - __FILE__, __FUNCTION__, cur->p); - BOUND_FREE (cur); - cur = last ? last->next : alloca_list; - } - else { - last = cur; - cur = cur->next; - } - } while (cur); - } - if (jmp_list) { - jmp_list_type *last = NULL; - jmp_list_type *cur = jmp_list; - - do { - if (cur->fp == fp) { - if (last) - last->next = cur->next; - else - jmp_list = cur->next; - dprintf(stderr, "%s, %s(): remove setjmp %p\n", - __FILE__, __FUNCTION__, cur->penv); - BOUND_FREE (cur); - cur = last ? last->next : jmp_list; - } - else { - last = cur; - cur = cur->next; - } - } while (cur); - } - - POST_SEM (); -#if BOUND_DEBUG - if (print_calls) { - p = p1; - while ((addr = p[0])) { - if (addr != 1) { - dprintf(stderr, "%s, %s(): %p 0x%lx\n", - __FILE__, __FUNCTION__, - (void *) (addr + fp), (unsigned long) p[1]); - } - p+= 2; - } - } -#endif -} - -/* used by alloca */ -void __bound_new_region(void *p, size_t size) -{ - size_t fp; - alloca_list_type *last; - alloca_list_type *cur; - alloca_list_type *new; - - if (NO_CHECKING_GET()) - return; - - dprintf(stderr, "%s, %s(): %p, 0x%lx\n", - __FILE__, __FUNCTION__, p, (unsigned long)size); - GET_CALLER_FP (fp); - new = BOUND_MALLOC (sizeof (alloca_list_type)); - WAIT_SEM (); - INCR_COUNT(bound_alloca_count); - last = NULL; - cur = alloca_list; - while (cur) { -#if defined(__i386__) || (defined(__arm__) && !defined(__ARM_EABI__)) - int align = 4; -#elif defined(__arm__) - int align = 8; -#else - int align = 16; -#endif - void *cure = (void *)((char *)cur->p + ((cur->size + align) & -align)); - void *pe = (void *)((char *)p + ((size + align) & -align)); - if (cur->fp == fp && ((cur->p <= p && cure > p) || - (p <= cur->p && pe > cur->p))) { - if (last) - last->next = cur->next; - else - alloca_list = cur->next; - tree = splay_delete((size_t)cur->p, tree); - break; - } - last = cur; - cur = cur->next; - } - tree = splay_insert((size_t)p, size, tree); - if (new) { - new->fp = fp; - new->p = p; - new->size = size; - new->next = alloca_list; - alloca_list = new; - } - POST_SEM (); - if (cur) { - dprintf(stderr, "%s, %s(): remove alloca/vla %p\n", - __FILE__, __FUNCTION__, cur->p); - BOUND_FREE (cur); - } -} - -void __bound_setjmp(jmp_buf env) -{ - jmp_list_type *jl; - void *e = (void *) env; - - if (NO_CHECKING_GET() == 0) { - dprintf(stderr, "%s, %s(): %p\n", __FILE__, __FUNCTION__, e); - WAIT_SEM (); - INCR_COUNT(bound_setjmp_count); - jl = jmp_list; - while (jl) { - if (jl->penv == e) - break; - jl = jl->next; - } - if (jl == NULL) { - jl = BOUND_MALLOC (sizeof (jmp_list_type)); - if (jl) { - jl->penv = e; - jl->next = jmp_list; - jmp_list = jl; - } - } - if (jl) { - size_t fp; - - GET_CALLER_FP (fp); - jl->fp = fp; - jl->end_fp = (size_t)__builtin_frame_address(0); - BOUND_GET_TID(jl->tid); - } - POST_SEM (); - } -} - -static void __bound_long_jump(jmp_buf env, int val, int sig, const char *func) -{ - jmp_list_type *jl; - void *e; - BOUND_TID_TYPE tid; - - if (NO_CHECKING_GET() == 0) { - e = (void *)env; - BOUND_GET_TID(tid); - dprintf(stderr, "%s, %s(): %p\n", __FILE__, func, e); - WAIT_SEM(); - INCR_COUNT(bound_longjmp_count); - jl = jmp_list; - while (jl) { - if (jl->penv == e && jl->tid == tid) { - size_t start_fp = (size_t)__builtin_frame_address(0); - size_t end_fp = jl->end_fp; - jmp_list_type *cur = jmp_list; - jmp_list_type *last = NULL; - - while (cur->penv != e || cur->tid != tid) { - if (cur->tid == tid) { - dprintf(stderr, "%s, %s(): remove setjmp %p\n", - __FILE__, func, cur->penv); - if (last) - last->next = cur->next; - else - jmp_list = cur->next; - BOUND_FREE (cur); - cur = last ? last->next : jmp_list; - } - else { - last = cur; - cur = cur->next; - } - } - for (;;) { - Tree *t = tree; - alloca_list_type *last; - alloca_list_type *cur; - - while (t && (t->start < start_fp || t->start > end_fp)) - if (t->start < start_fp) - t = t->right; - else - t = t->left; - if (t == NULL) - break; - last = NULL; - cur = alloca_list; - while (cur) { - if ((size_t) cur->p == t->start) { - dprintf(stderr, "%s, %s(): remove alloca/vla %p\n", - __FILE__, func, cur->p); - if (last) - last->next = cur->next; - else - alloca_list = cur->next; - BOUND_FREE (cur); - break; - } - last = cur; - cur = cur->next; - } - dprintf(stderr, "%s, %s(): delete %p\n", - __FILE__, func, (void *) t->start); - tree = splay_delete(t->start, tree); - } - break; - } - jl = jl->next; - } - POST_SEM(); - } -#if !defined(_WIN32) - sig ? siglongjmp(env, val) : -#endif - longjmp (env, val); -} - -void __bound_longjmp(jmp_buf env, int val) -{ - __bound_long_jump(env,val, 0, __FUNCTION__); -} - -#if !defined(_WIN32) -void __bound_siglongjmp(jmp_buf env, int val) -{ - __bound_long_jump(env,val, 1, __FUNCTION__); -} -#endif - -#if (defined(__GNUC__) && (__GNUC__ >= 6)) || defined(__clang__) -#pragma GCC diagnostic pop -#endif - -void __bound_init(size_t *p, int mode) -{ - dprintf(stderr, "%s, %s(): start %s\n", __FILE__, __FUNCTION__, - mode < 0 ? "lazy" : mode == 0 ? "normal use" : "for -run"); - - if (inited) { - WAIT_SEM(); - goto add_bounds; - } - inited = 1; - -#if HAVE_TLS_FUNC -#if defined(_WIN32) - no_checking_key = TlsAlloc(); - TlsSetValue(no_checking_key, &no_checking); -#else - pthread_key_create(&no_checking_key, NULL); - pthread_setspecific(no_checking_key, &no_checking); -#endif -#endif - NO_CHECKING_SET(1); - - print_warn_ptr_add = getenv ("TCC_BOUNDS_WARN_POINTER_ADD") != NULL; - print_calls = getenv ("TCC_BOUNDS_PRINT_CALLS") != NULL; - print_heap = getenv ("TCC_BOUNDS_PRINT_HEAP") != NULL; - print_statistic = getenv ("TCC_BOUNDS_PRINT_STATISTIC") != NULL; - never_fatal = getenv ("TCC_BOUNDS_NEVER_FATAL") != NULL; - - INIT_SEM (); - -#if MALLOC_REDIR - { - void *addr = mode > 0 ? RTLD_DEFAULT : RTLD_NEXT; - - /* tcc -run required RTLD_DEFAULT. Normal usage requires RTLD_NEXT, - but using RTLD_NEXT with -run segfaults on MacOS in dyld as the - generated code segment isn't registered with dyld and hence the - caller image of dlsym isn't known to it */ - *(void **) (&malloc_redir) = dlsym (addr, "malloc"); - if (malloc_redir == NULL) { - dprintf(stderr, "%s, %s(): use RTLD_DEFAULT\n", - __FILE__, __FUNCTION__); - addr = RTLD_DEFAULT; - *(void **) (&malloc_redir) = dlsym (addr, "malloc"); - } - *(void **) (&calloc_redir) = dlsym (addr, "calloc"); - *(void **) (&free_redir) = dlsym (addr, "free"); - *(void **) (&realloc_redir) = dlsym (addr, "realloc"); - *(void **) (&memalign_redir) = dlsym (addr, "memalign"); - dprintf(stderr, "%s, %s(): malloc_redir %p\n", - __FILE__, __FUNCTION__, malloc_redir); - dprintf(stderr, "%s, %s(): free_redir %p\n", - __FILE__, __FUNCTION__, free_redir); - dprintf(stderr, "%s, %s(): realloc_redir %p\n", - __FILE__, __FUNCTION__, realloc_redir); - dprintf(stderr, "%s, %s(): memalign_redir %p\n", - __FILE__, __FUNCTION__, memalign_redir); - if (malloc_redir == NULL || free_redir == NULL) - bound_alloc_error ("Cannot redirect malloc/free"); -#if HAVE_PTHREAD_CREATE - *(void **) (&pthread_create_redir) = dlsym (addr, "pthread_create"); - dprintf(stderr, "%s, %s(): pthread_create_redir %p\n", - __FILE__, __FUNCTION__, pthread_create_redir); - if (pthread_create_redir == NULL) - bound_alloc_error ("Cannot redirect pthread_create"); -#endif -#if HAVE_SIGNAL - *(void **) (&signal_redir) = dlsym (addr, "signal"); - dprintf(stderr, "%s, %s(): signal_redir %p\n", - __FILE__, __FUNCTION__, signal_redir); - if (signal_redir == NULL) - bound_alloc_error ("Cannot redirect signal"); -#endif -#if HAVE_SIGACTION - *(void **) (&sigaction_redir) = dlsym (addr, "sigaction"); - dprintf(stderr, "%s, %s(): sigaction_redir %p\n", - __FILE__, __FUNCTION__, sigaction_redir); - if (sigaction_redir == NULL) - bound_alloc_error ("Cannot redirect sigaction"); -#endif -#if HAVE_FORK - *(void **) (&fork_redir) = dlsym (addr, "fork"); - dprintf(stderr, "%s, %s(): fork_redir %p\n", - __FILE__, __FUNCTION__, fork_redir); - if (fork_redir == NULL) - bound_alloc_error ("Cannot redirect fork"); -#endif - } -#endif - -#ifdef __linux__ - { - FILE *fp; - unsigned char found; - unsigned long start; - unsigned long end; - unsigned long ad = - (unsigned long) __builtin_return_address(0); - char line[1000]; - - /* Display exec name. Usefull when a lot of code is compiled with tcc */ - fp = fopen ("/proc/self/comm", "r"); - if (fp) { - memset (exec, 0, sizeof(exec)); - fread (exec, 1, sizeof(exec) - 2, fp); - if (strchr(exec,'\n')) - *strchr(exec,'\n') = '\0'; - strcat (exec, ":"); - fclose (fp); - } - /* check if dlopen is used (is threre a better way?) */ - found = 0; - fp = fopen ("/proc/self/maps", "r"); - if (fp) { - while (fgets (line, sizeof(line), fp)) { - if (sscanf (line, "%lx-%lx", &start, &end) == 2 && - ad >= start && ad < end) { - found = 1; - break; - } - if (strstr (line,"[heap]")) - break; - } - fclose (fp); - } - if (found == 0) { - use_sem = 1; - no_strdup = 1; - } - } -#endif - - WAIT_SEM (); - -#if HAVE_CTYPE -#ifdef __APPLE__ - tree = splay_insert((size_t) &_DefaultRuneLocale, - sizeof (_DefaultRuneLocale), tree); -#else - /* XXX: Does not work if locale is changed */ - tree = splay_insert((size_t) __ctype_b_loc(), - sizeof (unsigned short *), tree); - tree = splay_insert((size_t) (*__ctype_b_loc() - 128), - 384 * sizeof (unsigned short), tree); - tree = splay_insert((size_t) __ctype_tolower_loc(), - sizeof (__int32_t *), tree); - tree = splay_insert((size_t) (*__ctype_tolower_loc() - 128), - 384 * sizeof (__int32_t), tree); - tree = splay_insert((size_t) __ctype_toupper_loc(), - sizeof (__int32_t *), tree); - tree = splay_insert((size_t) (*__ctype_toupper_loc() - 128), - 384 * sizeof (__int32_t), tree); -#endif -#endif -#if HAVE_ERRNO - tree = splay_insert((size_t) (&errno), sizeof (int), tree); -#endif - -add_bounds: - if (!p) - goto no_bounds; - - /* add all static bound check values */ - while (p[0] != 0) { - tree = splay_insert(p[0], p[1], tree); -#if BOUND_DEBUG - if (print_calls) { - dprintf(stderr, "%s, %s(): static var %p 0x%lx\n", - __FILE__, __FUNCTION__, - (void *) p[0], (unsigned long) p[1]); - } -#endif - p += 2; - } -no_bounds: - - POST_SEM (); - NO_CHECKING_SET(0); - dprintf(stderr, "%s, %s(): end\n\n", __FILE__, __FUNCTION__); -} - -void -#if (defined(__GLIBC__) && (__GLIBC_MINOR__ >= 4)) || defined(_WIN32) -__attribute__((constructor)) -#endif -__bound_main_arg(int argc, char **argv, char **envp) -{ - __bound_init (0, -1); - if (argc && argv) { - int i; - - WAIT_SEM (); - for (i = 0; i < argc; i++) - tree = splay_insert((size_t) argv[i], strlen (argv[i]) + 1, tree); - tree = splay_insert((size_t) argv, (argc + 1) * sizeof(char *), tree); - POST_SEM (); -#if BOUND_DEBUG - if (print_calls) { - for (i = 0; i < argc; i++) - dprintf(stderr, "%s, %s(): arg %p 0x%lx\n", - __FILE__, __FUNCTION__, - argv[i], (unsigned long)(strlen (argv[i]) + 1)); - dprintf(stderr, "%s, %s(): argv %p %d\n", - __FILE__, __FUNCTION__, argv, - (int)((argc + 1) * sizeof(char *))); - } -#endif - } - - if (envp && *envp) { - char **p = envp; - - WAIT_SEM (); - while (*p) { - tree = splay_insert((size_t) *p, strlen (*p) + 1, tree); - ++p; - } - tree = splay_insert((size_t) envp, (++p - envp) * sizeof(char *), tree); - POST_SEM (); -#if BOUND_DEBUG - if (print_calls) { - p = envp; - while (*p) { - dprintf(stderr, "%s, %s(): env %p 0x%lx\n", - __FILE__, __FUNCTION__, - *p, (unsigned long)(strlen (*p) + 1)); - ++p; - } - dprintf(stderr, "%s, %s(): environ %p %d\n", - __FILE__, __FUNCTION__, envp, - (int)((++p - envp) * sizeof(char *))); - } -#endif - } -} - -void __attribute__((destructor)) __bound_exit(void) -{ - int i; - static const char * const alloc_type[] = { - "", "malloc", "calloc", "realloc", "memalign", "strdup" - }; - - dprintf(stderr, "%s, %s():\n", __FILE__, __FUNCTION__); - - if (inited) { -#if !defined(_WIN32) && !defined(__APPLE__) && !defined TCC_MUSL && \ - !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \ - !defined(__ANDROID__) - if (print_heap) { - extern void __libc_freeres (void); - __libc_freeres (); - } -#endif - - NO_CHECKING_SET(1); - - TRY_SEM (); - while (alloca_list) { - alloca_list_type *next = alloca_list->next; - - tree = splay_delete ((size_t) alloca_list->p, tree); - BOUND_FREE (alloca_list); - alloca_list = next; - } - while (jmp_list) { - jmp_list_type *next = jmp_list->next; - - BOUND_FREE (jmp_list); - jmp_list = next; - } - for (i = 0; i < FREE_REUSE_SIZE; i++) { - if (free_reuse_list[i]) { - tree = splay_delete ((size_t) free_reuse_list[i], tree); - BOUND_FREE (free_reuse_list[i]); - } - } - while (tree) { - if (print_heap && tree->type != 0) - fprintf (stderr, "%s, %s(): %s found size %lu\n", - __FILE__, __FUNCTION__, alloc_type[tree->type], - (unsigned long) tree->size); - tree = splay_delete (tree->start, tree); - } -#if TREE_REUSE - while (tree_free_list) { - Tree *next = tree_free_list->left; - BOUND_FREE (tree_free_list); - tree_free_list = next; - } -#endif - POST_SEM (); - EXIT_SEM (); -#if HAVE_TLS_FUNC -#if defined(_WIN32) - TlsFree(no_checking_key); -#else - pthread_key_delete(no_checking_key); -#endif -#endif - inited = 0; - if (print_statistic) { -#if BOUND_STATISTIC - fprintf (stderr, "bound_ptr_add_count %llu\n", bound_ptr_add_count); - fprintf (stderr, "bound_ptr_indir1_count %llu\n", bound_ptr_indir1_count); - fprintf (stderr, "bound_ptr_indir2_count %llu\n", bound_ptr_indir2_count); - fprintf (stderr, "bound_ptr_indir4_count %llu\n", bound_ptr_indir4_count); - fprintf (stderr, "bound_ptr_indir8_count %llu\n", bound_ptr_indir8_count); - fprintf (stderr, "bound_ptr_indir12_count %llu\n", bound_ptr_indir12_count); - fprintf (stderr, "bound_ptr_indir16_count %llu\n", bound_ptr_indir16_count); - fprintf (stderr, "bound_local_new_count %llu\n", bound_local_new_count); - fprintf (stderr, "bound_local_delete_count %llu\n", bound_local_delete_count); - fprintf (stderr, "bound_malloc_count %llu\n", bound_malloc_count); - fprintf (stderr, "bound_calloc_count %llu\n", bound_calloc_count); - fprintf (stderr, "bound_realloc_count %llu\n", bound_realloc_count); - fprintf (stderr, "bound_free_count %llu\n", bound_free_count); - fprintf (stderr, "bound_memalign_count %llu\n", bound_memalign_count); - fprintf (stderr, "bound_mmap_count %llu\n", bound_mmap_count); - fprintf (stderr, "bound_munmap_count %llu\n", bound_munmap_count); - fprintf (stderr, "bound_alloca_count %llu\n", bound_alloca_count); - fprintf (stderr, "bound_setjmp_count %llu\n", bound_setjmp_count); - fprintf (stderr, "bound_longjmp_count %llu\n", bound_longjmp_count); - fprintf (stderr, "bound_mempcy_count %llu\n", bound_mempcy_count); - fprintf (stderr, "bound_memcmp_count %llu\n", bound_memcmp_count); - fprintf (stderr, "bound_memmove_count %llu\n", bound_memmove_count); - fprintf (stderr, "bound_memset_count %llu\n", bound_memset_count); - fprintf (stderr, "bound_strlen_count %llu\n", bound_strlen_count); - fprintf (stderr, "bound_strcpy_count %llu\n", bound_strcpy_count); - fprintf (stderr, "bound_strncpy_count %llu\n", bound_strncpy_count); - fprintf (stderr, "bound_strcmp_count %llu\n", bound_strcmp_count); - fprintf (stderr, "bound_strncmp_count %llu\n", bound_strncmp_count); - fprintf (stderr, "bound_strcat_count %llu\n", bound_strcat_count); - fprintf (stderr, "bound_strncat_count %llu\n", bound_strncat_count); - fprintf (stderr, "bound_strchr_count %llu\n", bound_strchr_count); - fprintf (stderr, "bound_strrchr_count %llu\n", bound_strrchr_count); - fprintf (stderr, "bound_strdup_count %llu\n", bound_strdup_count); - fprintf (stderr, "bound_not_found %llu\n", bound_not_found); -#endif -#if BOUND_STATISTIC_SPLAY - fprintf (stderr, "bound_splay %llu\n", bound_splay); - fprintf (stderr, "bound_splay_end %llu\n", bound_splay_end); - fprintf (stderr, "bound_splay_insert %llu\n", bound_splay_insert); - fprintf (stderr, "bound_splay_delete %llu\n", bound_splay_delete); -#endif - } - } -} - -void __bound_exit_dll(size_t *p) -{ - dprintf(stderr, "%s, %s()\n", __FILE__, __FUNCTION__); - - if (p) { - WAIT_SEM (); - while (p[0] != 0) { - tree = splay_delete(p[0], tree); -#if BOUND_DEBUG - if (print_calls) { - dprintf(stderr, "%s, %s(): remove static var %p 0x%lx\n", - __FILE__, __FUNCTION__, - (void *) p[0], (unsigned long) p[1]); - } -#endif - p += 2; - } - POST_SEM (); - } -} - -#if HAVE_PTHREAD_CREATE -typedef struct { - void *(*start_routine) (void *); - void *arg; - sigset_t old_mask; -} bound_thread_create_type; - -static void *bound_thread_create(void *bdata) -{ - bound_thread_create_type *data = (bound_thread_create_type *) bdata; - void *retval; -#if HAVE_TLS_FUNC - int *p = (int *) BOUND_MALLOC(sizeof(int)); - - if (!p) bound_alloc_error("bound_thread_create malloc"); - *p = 0; - pthread_setspecific(no_checking_key, p); -#endif - pthread_sigmask(SIG_SETMASK, &data->old_mask, NULL); - retval = data->start_routine(data->arg); -#if HAVE_TLS_FUNC - pthread_setspecific(no_checking_key, NULL); - BOUND_FREE (p); -#endif - BOUND_FREE (data); - return retval; -} - -int pthread_create(pthread_t *thread, const pthread_attr_t *attr, - void *(*start_routine) (void *), void *arg) -{ - int retval; - bound_thread_create_type *data; - sigset_t mask; - sigset_t old_mask; - - use_sem = 1; - dprintf (stderr, "%s, %s()\n", __FILE__, __FUNCTION__); - sigfillset(&mask); - pthread_sigmask(SIG_SETMASK, &mask, &old_mask); - data = (bound_thread_create_type *) BOUND_MALLOC(sizeof(bound_thread_create_type)); - if (!data) bound_alloc_error("bound_thread_create malloc"); - data->start_routine = start_routine; - data->arg = arg; - data->old_mask = old_mask; - retval = pthread_create_redir(thread, attr, bound_thread_create, data); - pthread_sigmask(SIG_SETMASK, &old_mask, NULL); - return retval; -} -#endif - -#if HAVE_SIGNAL || HAVE_SIGACTION -typedef union { -#if HAVE_SIGNAL - bound_sig signal_handler; -#endif -#if HAVE_SIGACTION - void (*sig_handler)(int); - void (*sig_sigaction)(int, siginfo_t *, void *); -#endif -} bound_sig_type; - -static unsigned char bound_sig_used[NSIG]; -static bound_sig_type bound_sig_data[NSIG]; -#endif - -#if HAVE_SIGNAL -static void signal_handler(int sig) -{ - __bounds_checking(1); - bound_sig_data[sig].signal_handler(sig); - __bounds_checking(-1); -} - -bound_sig signal(int signum, bound_sig handler) -{ - bound_sig retval; - - dprintf (stderr, "%s, %s() %d %p\n", __FILE__, __FUNCTION__, - signum, handler); - retval = signal_redir(signum, handler ? signal_handler : handler); - if (retval != SIG_ERR) { - if (bound_sig_used[signum]) - retval = bound_sig_data[signum].signal_handler; - if (handler) { - bound_sig_used[signum] = 1; - bound_sig_data[signum].signal_handler = handler; - } - } - return retval; -} -#endif - -#if HAVE_SIGACTION -static void sig_handler(int sig) -{ - __bounds_checking(1); - bound_sig_data[sig].sig_handler(sig); - __bounds_checking(-1); -} - -static void sig_sigaction(int sig, siginfo_t *info, void *ucontext) -{ - __bounds_checking(1); - bound_sig_data[sig].sig_sigaction(sig, info, ucontext); - __bounds_checking(-1); -} - -int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) -{ - int retval; - struct sigaction nact, oact; - - dprintf (stderr, "%s, %s() %d %p %p\n", __FILE__, __FUNCTION__, - signum, act, oldact); - - if (sigaction_redir == NULL) - __bound_init(0,-1); - - if (act) { - nact = *act; - if (nact.sa_flags & SA_SIGINFO) - nact.sa_sigaction = sig_sigaction; - else - nact.sa_handler = sig_handler; - retval = sigaction_redir(signum, &nact, &oact); - } - else - retval = sigaction_redir(signum, act, &oact); - if (retval >= 0) { - if (bound_sig_used[signum]) { - if (oact.sa_flags & SA_SIGINFO) - oact.sa_sigaction = bound_sig_data[signum].sig_sigaction; - else - oact.sa_handler = bound_sig_data[signum].sig_handler; - } - if (oldact) { - *oldact = oact; - } - if (act) { - bound_sig_used[signum] = 1; - if (act->sa_flags & SA_SIGINFO) - bound_sig_data[signum].sig_sigaction = act->sa_sigaction; - else - bound_sig_data[signum].sig_handler = act->sa_handler; - } - } - return retval; -} -#endif - -#if HAVE_FORK -pid_t fork(void) -{ - pid_t retval; - - WAIT_SEM(); - retval = (*fork_redir)(); - if (retval == 0) - INIT_SEM(); - else - POST_SEM(); - return retval; -} -#endif - -#if MALLOC_REDIR -void *malloc(size_t size) -#else -void *__bound_malloc(size_t size, const void *caller) -#endif -{ - void *ptr; - -#if MALLOC_REDIR - /* This will catch the first dlsym call from __bound_init */ - if (malloc_redir == NULL) { - __bound_init (0, -1); - if (malloc_redir == NULL) { - ptr = &initial_pool[pool_index]; - pool_index = (pool_index + size + 15) & ~15; - if (pool_index >= sizeof (initial_pool)) - bound_alloc_error ("initial memory pool too small"); - dprintf (stderr, "%s, %s(): initial %p, 0x%lx\n", - __FILE__, __FUNCTION__, ptr, (unsigned long)size); - return ptr; - } - } -#endif - /* we allocate one more byte to ensure the regions will be - separated by at least one byte. With the glibc malloc, it may - be in fact not necessary */ - ptr = BOUND_MALLOC (size + 1); - dprintf(stderr, "%s, %s(): %p, 0x%lx\n", - __FILE__, __FUNCTION__, ptr, (unsigned long)size); - - if (inited && NO_CHECKING_GET() == 0) { - WAIT_SEM (); - INCR_COUNT(bound_malloc_count); - - if (ptr) { - tree = splay_insert ((size_t) ptr, size ? size : size + 1, tree); - if (tree && tree->start == (size_t) ptr) - tree->type = TCC_TYPE_MALLOC; - } - POST_SEM (); - } - return ptr; -} - -#if MALLOC_REDIR -void *memalign(size_t size, size_t align) -#else -void *__bound_memalign(size_t size, size_t align, const void *caller) -#endif -{ - void *ptr; - -#if HAVE_MEMALIGN - /* we allocate one more byte to ensure the regions will be - separated by at least one byte. With the glibc malloc, it may - be in fact not necessary */ - ptr = BOUND_MEMALIGN(size + 1, align); -#else - if (align > 4) { - /* XXX: handle it ? */ - ptr = NULL; - } else { - /* we suppose that malloc aligns to at least four bytes */ - ptr = BOUND_MALLOC(size + 1); - } -#endif - dprintf(stderr, "%s, %s(): %p, 0x%lx\n", - __FILE__, __FUNCTION__, ptr, (unsigned long)size); - - if (NO_CHECKING_GET() == 0) { - WAIT_SEM (); - INCR_COUNT(bound_memalign_count); - - if (ptr) { - tree = splay_insert((size_t) ptr, size ? size : size + 1, tree); - if (tree && tree->start == (size_t) ptr) - tree->type = TCC_TYPE_MEMALIGN; - } - POST_SEM (); - } - return ptr; -} - -#if MALLOC_REDIR -void free(void *ptr) -#else -void __bound_free(void *ptr, const void *caller) -#endif -{ - size_t addr = (size_t) ptr; - void *p; - - if (ptr == NULL || tree == NULL -#if MALLOC_REDIR - || ((unsigned char *) ptr >= &initial_pool[0] && - (unsigned char *) ptr < &initial_pool[sizeof(initial_pool)]) -#endif - ) - return; - - dprintf(stderr, "%s, %s(): %p\n", __FILE__, __FUNCTION__, ptr); - - if (inited && NO_CHECKING_GET() == 0) { - WAIT_SEM (); - INCR_COUNT(bound_free_count); - tree = splay (addr, tree); - if (tree->start == addr) { - if (tree->is_invalid) { - POST_SEM (); - bound_error("freeing invalid region"); - return; - } - tree->is_invalid = 1; - memset (ptr, 0x5a, tree->size); - p = free_reuse_list[free_reuse_index]; - free_reuse_list[free_reuse_index] = ptr; - free_reuse_index = (free_reuse_index + 1) % FREE_REUSE_SIZE; - if (p) - tree = splay_delete((size_t)p, tree); - ptr = p; - } - POST_SEM (); - } - BOUND_FREE (ptr); -} - -#if MALLOC_REDIR -void *realloc(void *ptr, size_t size) -#else -void *__bound_realloc(void *ptr, size_t size, const void *caller) -#endif -{ - void *new_ptr; - - if (size == 0) { -#if MALLOC_REDIR - free(ptr); -#else - __bound_free(ptr, caller); -#endif - return NULL; - } - - new_ptr = BOUND_REALLOC (ptr, size + 1); - dprintf(stderr, "%s, %s(): %p, 0x%lx\n", - __FILE__, __FUNCTION__, new_ptr, (unsigned long)size); - - if (NO_CHECKING_GET() == 0) { - WAIT_SEM (); - INCR_COUNT(bound_realloc_count); - - if (ptr) - tree = splay_delete ((size_t) ptr, tree); - if (new_ptr) { - tree = splay_insert ((size_t) new_ptr, size ? size : size + 1, tree); - if (tree && tree->start == (size_t) new_ptr) - tree->type = TCC_TYPE_REALLOC; - } - POST_SEM (); - } - return new_ptr; -} - -#if MALLOC_REDIR -void *calloc(size_t nmemb, size_t size) -#else -void *__bound_calloc(size_t nmemb, size_t size) -#endif -{ - void *ptr; - - size *= nmemb; -#if MALLOC_REDIR - /* This will catch the first dlsym call from __bound_init */ - if (malloc_redir == NULL) { - __bound_init (0, -1); - if (malloc_redir == NULL) { - ptr = &initial_pool[pool_index]; - pool_index = (pool_index + size + 15) & ~15; - if (pool_index >= sizeof (initial_pool)) - bound_alloc_error ("initial memory pool too small"); - dprintf (stderr, "%s, %s(): initial %p, 0x%lx\n", - __FILE__, __FUNCTION__, ptr, (unsigned long)size); - memset (ptr, 0, size); - return ptr; - } - } -#endif - ptr = BOUND_MALLOC(size + 1); - dprintf (stderr, "%s, %s(): %p, 0x%lx\n", - __FILE__, __FUNCTION__, ptr, (unsigned long)size); - - if (ptr) { - memset (ptr, 0, size); - if (NO_CHECKING_GET() == 0) { - WAIT_SEM (); - INCR_COUNT(bound_calloc_count); - tree = splay_insert ((size_t) ptr, size ? size : size + 1, tree); - if (tree && tree->start == (size_t) ptr) - tree->type = TCC_TYPE_CALLOC; - POST_SEM (); - } - } - return ptr; -} - -#if !defined(_WIN32) -void *__bound_mmap (void *start, size_t size, int prot, - int flags, int fd, off_t offset) -{ - void *result; - - dprintf(stderr, "%s, %s(): %p, 0x%lx\n", - __FILE__, __FUNCTION__, start, (unsigned long)size); - result = mmap (start, size, prot, flags, fd, offset); - if (result && NO_CHECKING_GET() == 0) { - WAIT_SEM (); - INCR_COUNT(bound_mmap_count); - tree = splay_insert((size_t)result, size, tree); - POST_SEM (); - } - return result; -} - -int __bound_munmap (void *start, size_t size) -{ - int result; - - dprintf(stderr, "%s, %s(): %p, 0x%lx\n", - __FILE__, __FUNCTION__, start, (unsigned long)size); - if (start && NO_CHECKING_GET() == 0) { - WAIT_SEM (); - INCR_COUNT(bound_munmap_count); - tree = splay_delete ((size_t) start, tree); - POST_SEM (); - } - result = munmap (start, size); - return result; -} -#endif - -/* some useful checked functions */ - -/* check that (p ... p + size - 1) lies inside 'p' region, if any */ -static void __bound_check(const void *p, size_t size, const char *function) -{ - if (size != 0 && __bound_ptr_add((void *)p, size) == INVALID_POINTER) { - bound_error("invalid pointer %p, size 0x%lx in %s", - p, (unsigned long)size, function); - } -} - -static int check_overlap (const void *p1, size_t n1, - const void *p2, size_t n2, - const char *function) -{ - const void *p1e = (const void *) ((const char *) p1 + n1); - const void *p2e = (const void *) ((const char *) p2 + n2); - - if (NO_CHECKING_GET() == 0 && n1 != 0 && n2 !=0 && - ((p1 <= p2 && p1e > p2) || /* p1----p2====p1e----p2e */ - (p2 <= p1 && p2e > p1))) { /* p2----p1====p2e----p1e */ - bound_error("overlapping regions %p(0x%lx), %p(0x%lx) in %s", - p1, (unsigned long)n1, p2, (unsigned long)n2, function); - return never_fatal < 0; - } - return 0; -} - -void *__bound_memcpy(void *dest, const void *src, size_t n) -{ - dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n", - __FILE__, __FUNCTION__, dest, src, (unsigned long)n); - INCR_COUNT(bound_mempcy_count); - __bound_check(dest, n, "memcpy dest"); - __bound_check(src, n, "memcpy src"); - if (check_overlap(dest, n, src, n, "memcpy")) - return dest; - return memcpy(dest, src, n); -} - -int __bound_memcmp(const void *s1, const void *s2, size_t n) -{ - const unsigned char *u1 = (const unsigned char *) s1; - const unsigned char *u2 = (const unsigned char *) s2; - int retval = 0; - - dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n", - __FILE__, __FUNCTION__, s1, s2, (unsigned long)n); - INCR_COUNT(bound_memcmp_count); - for (;;) { - if ((ssize_t) --n == -1) - break; - else if (*u1 != *u2) { - retval = *u1++ - *u2++; - break; - } - ++u1; - ++u2; - } - __bound_check(s1, (const void *)u1 - s1, "memcmp s1"); - __bound_check(s2, (const void *)u2 - s2, "memcmp s2"); - return retval; -} - -void *__bound_memmove(void *dest, const void *src, size_t n) -{ - dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n", - __FILE__, __FUNCTION__, dest, src, (unsigned long)n); - INCR_COUNT(bound_memmove_count); - __bound_check(dest, n, "memmove dest"); - __bound_check(src, n, "memmove src"); - return memmove(dest, src, n); -} - -void *__bound_memset(void *s, int c, size_t n) -{ - dprintf(stderr, "%s, %s(): %p, %d, 0x%lx\n", - __FILE__, __FUNCTION__, s, c, (unsigned long)n); - INCR_COUNT(bound_memset_count); - __bound_check(s, n, "memset"); - return memset(s, c, n); -} - -#if defined(__arm__) && defined(__ARM_EABI__) -void *__bound___aeabi_memcpy(void *dest, const void *src, size_t n) -{ - dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n", - __FILE__, __FUNCTION__, dest, src, (unsigned long)n); - INCR_COUNT(bound_mempcy_count); - __bound_check(dest, n, "memcpy dest"); - __bound_check(src, n, "memcpy src"); - if (check_overlap(dest, n, src, n, "memcpy")) - return dest; - return __aeabi_memcpy(dest, src, n); -} - -void *__bound___aeabi_memmove(void *dest, const void *src, size_t n) -{ - dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n", - __FILE__, __FUNCTION__, dest, src, (unsigned long)n); - INCR_COUNT(bound_memmove_count); - __bound_check(dest, n, "memmove dest"); - __bound_check(src, n, "memmove src"); - return __aeabi_memmove(dest, src, n); -} - -void *__bound___aeabi_memmove4(void *dest, const void *src, size_t n) -{ - dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n", - __FILE__, __FUNCTION__, dest, src, (unsigned long)n); - INCR_COUNT(bound_memmove_count); - __bound_check(dest, n, "memmove dest"); - __bound_check(src, n, "memmove src"); - return __aeabi_memmove4(dest, src, n); -} - -void *__bound___aeabi_memmove8(void *dest, const void *src, size_t n) -{ - dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n", - __FILE__, __FUNCTION__, dest, src, (unsigned long)n); - INCR_COUNT(bound_memmove_count); - __bound_check(dest, n, "memmove dest"); - __bound_check(src, n, "memmove src"); - return __aeabi_memmove8(dest, src, n); -} - -void *__bound___aeabi_memset(void *s, int c, size_t n) -{ - dprintf(stderr, "%s, %s(): %p, %d, 0x%lx\n", - __FILE__, __FUNCTION__, s, c, (unsigned long)n); - INCR_COUNT(bound_memset_count); - __bound_check(s, n, "memset"); - return __aeabi_memset(s, c, n); -} -#endif - -int __bound_strlen(const char *s) -{ - const char *p = s; - - dprintf(stderr, "%s, %s(): %p\n", - __FILE__, __FUNCTION__, s); - INCR_COUNT(bound_strlen_count); - while (*p++); - __bound_check(s, p - s, "strlen"); - return (p - s) - 1; -} - -char *__bound_strcpy(char *dest, const char *src) -{ - size_t len; - const char *p = src; - - dprintf(stderr, "%s, %s(): %p, %p\n", - __FILE__, __FUNCTION__, dest, src); - INCR_COUNT(bound_strcpy_count); - while (*p++); - len = p - src; - __bound_check(dest, len, "strcpy dest"); - __bound_check(src, len, "strcpy src"); - if (check_overlap(dest, len, src, len, "strcpy")) - return dest; - return strcpy (dest, src); -} - -char *__bound_strncpy(char *dest, const char *src, size_t n) -{ - size_t len = n; - const char *p = src; - - dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n", - __FILE__, __FUNCTION__, dest, src, (unsigned long)n); - INCR_COUNT(bound_strncpy_count); - while (len-- && *p++); - len = p - src; - __bound_check(dest, len, "strncpy dest"); - __bound_check(src, len, "strncpy src"); - if (check_overlap(dest, len, src, len, "strncpy")) - return dest; - return strncpy(dest, src, n); -} - -int __bound_strcmp(const char *s1, const char *s2) -{ - const unsigned char *u1 = (const unsigned char *) s1; - const unsigned char *u2 = (const unsigned char *) s2; - - dprintf(stderr, "%s, %s(): %p, %p\n", - __FILE__, __FUNCTION__, s1, s2); - INCR_COUNT(bound_strcmp_count); - while (*u1 && *u1 == *u2) { - ++u1; - ++u2; - } - __bound_check(s1, ((const char *)u1 - s1) + 1, "strcmp s1"); - __bound_check(s2, ((const char *)u2 - s2) + 1, "strcmp s2"); - return *u1 - *u2; -} - -int __bound_strncmp(const char *s1, const char *s2, size_t n) -{ - const unsigned char *u1 = (const unsigned char *) s1; - const unsigned char *u2 = (const unsigned char *) s2; - int retval = 0; - - dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n", - __FILE__, __FUNCTION__, s1, s2, (unsigned long)n); - INCR_COUNT(bound_strncmp_count); - do { - if ((ssize_t) --n == -1) - break; - else if (*u1 != *u2) { - retval = *u1++ - *u2++; - break; - } - ++u2; - } while (*u1++); - __bound_check(s1, (const char *)u1 - s1, "strncmp s1"); - __bound_check(s2, (const char *)u2 - s2, "strncmp s2"); - return retval; -} - -char *__bound_strcat(char *dest, const char *src) -{ - char *r = dest; - const char *s = src; - - dprintf(stderr, "%s, %s(): %p, %p\n", - __FILE__, __FUNCTION__, dest, src); - INCR_COUNT(bound_strcat_count); - while (*dest++); - while (*src++); - __bound_check(r, (dest - r) + (src - s) - 1, "strcat dest"); - __bound_check(s, src - s, "strcat src"); - if (check_overlap(r, (dest - r) + (src - s) - 1, s, src - s, "strcat")) - return dest; - return strcat(r, s); -} - -char *__bound_strncat(char *dest, const char *src, size_t n) -{ - char *r = dest; - const char *s = src; - size_t len = n; - - dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n", - __FILE__, __FUNCTION__, dest, src, (unsigned long)n); - INCR_COUNT(bound_strncat_count); - while (*dest++); - while (len-- && *src++); - __bound_check(r, (dest - r) + (src - s) - 1, "strncat dest"); - __bound_check(s, src - s, "strncat src"); - if (check_overlap(r, (dest - r) + (src - s) - 1, s, src - s, "strncat")) - return dest; - return strncat(r, s, n); -} - -char *__bound_strchr(const char *s, int c) -{ - const unsigned char *str = (const unsigned char *) s; - unsigned char ch = c; - - dprintf(stderr, "%s, %s(): %p, %d\n", - __FILE__, __FUNCTION__, s, ch); - INCR_COUNT(bound_strchr_count); - while (*str) { - if (*str == ch) - break; - ++str; - } - __bound_check(s, ((const char *)str - s) + 1, "strchr"); - return *str == ch ? (char *) str : NULL; -} - -char *__bound_strrchr(const char *s, int c) -{ - const unsigned char *str = (const unsigned char *) s; - unsigned char ch = c; - - dprintf(stderr, "%s, %s(): %p, %d\n", - __FILE__, __FUNCTION__, s, ch); - INCR_COUNT(bound_strrchr_count); - while (*str++); - __bound_check(s, (const char *)str - s, "strrchr"); - while (str != (const unsigned char *)s) { - if (*--str == ch) - break; - } - __bound_check(s, (const char *)str - s, "strrchr"); - return *str == ch ? (char *) str : NULL; -} - -char *__bound_strdup(const char *s) -{ - const char *p = s; - char *new; - - INCR_COUNT(bound_strdup_count); - while (*p++); - __bound_check(s, p - s, "strdup"); - new = BOUND_MALLOC ((p - s) + 1); - dprintf(stderr, "%s, %s(): %p, 0x%lx\n", - __FILE__, __FUNCTION__, new, (unsigned long)(p -s)); - if (new) { - if (NO_CHECKING_GET() == 0 && no_strdup == 0) { - WAIT_SEM (); - tree = splay_insert((size_t)new, p - s, tree); - if (tree && tree->start == (size_t) new) - tree->type = TCC_TYPE_STRDUP; - POST_SEM (); - } - memcpy (new, s, p - s); - } - return new; -} - -/* - An implementation of top-down splaying with sizes - D. Sleator <sleator@cs.cmu.edu>, January 1994. - - This extends top-down-splay.c to maintain a size field in each node. - This is the number of nodes in the subtree rooted there. This makes - it possible to efficiently compute the rank of a key. (The rank is - the number of nodes to the left of the given key.) It it also - possible to quickly find the node of a given rank. Both of these - operations are illustrated in the code below. The remainder of this - introduction is taken from top-down-splay.c. - - "Splay trees", or "self-adjusting search trees" are a simple and - efficient data structure for storing an ordered set. The data - structure consists of a binary tree, with no additional fields. It - allows searching, insertion, deletion, deletemin, deletemax, - splitting, joining, and many other operations, all with amortized - logarithmic performance. Since the trees adapt to the sequence of - requests, their performance on real access patterns is typically even - better. Splay trees are described in a number of texts and papers - [1,2,3,4]. - - The code here is adapted from simple top-down splay, at the bottom of - page 669 of [2]. It can be obtained via anonymous ftp from - spade.pc.cs.cmu.edu in directory /usr/sleator/public. - - The chief modification here is that the splay operation works even if the - item being splayed is not in the tree, and even if the tree root of the - tree is NULL. So the line: - - t = splay(i, t); - - causes it to search for item with key i in the tree rooted at t. If it's - there, it is splayed to the root. If it isn't there, then the node put - at the root is the last one before NULL that would have been reached in a - normal binary search for i. (It's a neighbor of i in the tree.) This - allows many other operations to be easily implemented, as shown below. - - [1] "Data Structures and Their Algorithms", Lewis and Denenberg, - Harper Collins, 1991, pp 243-251. - [2] "Self-adjusting Binary Search Trees" Sleator and Tarjan, - JACM Volume 32, No 3, July 1985, pp 652-686. - [3] "Data Structure and Algorithm Analysis", Mark Weiss, - Benjamin Cummins, 1992, pp 119-130. - [4] "Data Structures, Algorithms, and Performance", Derick Wood, - Addison-Wesley, 1993, pp 367-375 -*/ - -/* Code adapted for tcc */ - -#define compare(start,tstart,tsize) (start < tstart ? -1 : \ - start >= tstart+tsize ? 1 : 0) - -static Tree * splay (size_t addr, Tree *t) -/* Splay using the key start (which may or may not be in the tree.) */ -/* The starting root is t, and the tree used is defined by rat */ -{ - Tree N, *l, *r, *y; - int comp; - - INCR_COUNT_SPLAY(bound_splay); - if (t == NULL) return t; - N.left = N.right = NULL; - l = r = &N; - - for (;;) { - comp = compare(addr, t->start, t->size); - if (comp < 0) { - y = t->left; - if (y == NULL) break; - if (compare(addr, y->start, y->size) < 0) { - t->left = y->right; /* rotate right */ - y->right = t; - t = y; - if (t->left == NULL) break; - } - r->left = t; /* link right */ - r = t; - t = t->left; - } else if (comp > 0) { - y = t->right; - if (y == NULL) break; - if (compare(addr, y->start, y->size) > 0) { - t->right = y->left; /* rotate left */ - y->left = t; - t = y; - if (t->right == NULL) break; - } - l->right = t; /* link left */ - l = t; - t = t->right; - } else { - break; - } - } - l->right = t->left; /* assemble */ - r->left = t->right; - t->left = N.right; - t->right = N.left; - - return t; -} - -#define compare_end(start,tend) (start < tend ? -1 : \ - start > tend ? 1 : 0) - -static Tree * splay_end (size_t addr, Tree *t) -/* Splay using the key start (which may or may not be in the tree.) */ -/* The starting root is t, and the tree used is defined by rat */ -{ - Tree N, *l, *r, *y; - int comp; - - INCR_COUNT_SPLAY(bound_splay_end); - if (t == NULL) return t; - N.left = N.right = NULL; - l = r = &N; - - for (;;) { - comp = compare_end(addr, t->start + t->size); - if (comp < 0) { - y = t->left; - if (y == NULL) break; - if (compare_end(addr, y->start + y->size) < 0) { - t->left = y->right; /* rotate right */ - y->right = t; - t = y; - if (t->left == NULL) break; - } - r->left = t; /* link right */ - r = t; - t = t->left; - } else if (comp > 0) { - y = t->right; - if (y == NULL) break; - if (compare_end(addr, y->start + y->size) > 0) { - t->right = y->left; /* rotate left */ - y->left = t; - t = y; - if (t->right == NULL) break; - } - l->right = t; /* link left */ - l = t; - t = t->right; - } else { - break; - } - } - l->right = t->left; /* assemble */ - r->left = t->right; - t->left = N.right; - t->right = N.left; - - return t; -} - -static Tree * splay_insert(size_t addr, size_t size, Tree * t) -/* Insert key start into the tree t, if it is not already there. */ -/* Return a pointer to the resulting tree. */ -{ - Tree * new; - - INCR_COUNT_SPLAY(bound_splay_insert); - if (t != NULL) { - t = splay(addr,t); - if (compare(addr, t->start, t->size)==0) { - return t; /* it's already there */ - } - } -#if TREE_REUSE - if (tree_free_list) { - new = tree_free_list; - tree_free_list = new->left; - } - else -#endif - { - new = (Tree *) BOUND_MALLOC (sizeof (Tree)); - } - if (new == NULL) { - bound_alloc_error("not enough memory for bound checking code"); - } - else { - if (t == NULL) { - new->left = new->right = NULL; - } else if (compare(addr, t->start, t->size) < 0) { - new->left = t->left; - new->right = t; - t->left = NULL; - } else { - new->right = t->right; - new->left = t; - t->right = NULL; - } - new->start = addr; - new->size = size; - new->type = TCC_TYPE_NONE; - new->is_invalid = 0; - } - return new; -} - -#define compare_destroy(start,tstart) (start < tstart ? -1 : \ - start > tstart ? 1 : 0) - -static Tree * splay_delete(size_t addr, Tree *t) -/* Deletes addr from the tree if it's there. */ -/* Return a pointer to the resulting tree. */ -{ - Tree * x; - - INCR_COUNT_SPLAY(bound_splay_delete); - if (t==NULL) return NULL; - t = splay(addr,t); - if (compare_destroy(addr, t->start) == 0) { /* found it */ - if (t->left == NULL) { - x = t->right; - } else { - x = splay(addr, t->left); - x->right = t->right; - } -#if TREE_REUSE - t->left = tree_free_list; - tree_free_list = t; -#else - BOUND_FREE(t); -#endif - return x; - } else { - return t; /* It wasn't there */ - } -} - -void splay_printtree(Tree * t, int d) -{ - int i; - if (t == NULL) return; - splay_printtree(t->right, d+1); - for (i=0; i<d; i++) fprintf(stderr," "); - fprintf(stderr,"%p(0x%lx:%u:%u)\n", - (void *) t->start, (unsigned long) t->size, - (unsigned)t->type, (unsigned)t->is_invalid); - splay_printtree(t->left, d+1); -} diff --git a/tinycc/lib/bt-dll.c b/tinycc/lib/bt-dll.c deleted file mode 100644 index 7c62cef..0000000 --- a/tinycc/lib/bt-dll.c +++ /dev/null @@ -1,74 +0,0 @@ -/* ------------------------------------------------------------- */ -/* stubs for calling bcheck functions from a dll. */ - -#include <windows.h> -#include <stdio.h> - -#define REDIR_ALL \ - REDIR(__bt_init) \ - REDIR(__bt_exit) \ - REDIR(tcc_backtrace) \ - \ - REDIR(__bound_ptr_add) \ - REDIR(__bound_ptr_indir1) \ - REDIR(__bound_ptr_indir2) \ - REDIR(__bound_ptr_indir4) \ - REDIR(__bound_ptr_indir8) \ - REDIR(__bound_ptr_indir12) \ - REDIR(__bound_ptr_indir16) \ - REDIR(__bound_local_new) \ - REDIR(__bound_local_delete) \ - REDIR(__bound_new_region) \ - \ - REDIR(__bound_free) \ - REDIR(__bound_malloc) \ - REDIR(__bound_realloc) \ - REDIR(__bound_memcpy) \ - REDIR(__bound_memcmp) \ - REDIR(__bound_memmove) \ - REDIR(__bound_memset) \ - REDIR(__bound_strlen) \ - REDIR(__bound_strcpy) \ - REDIR(__bound_strncpy) \ - REDIR(__bound_strcmp) \ - REDIR(__bound_strncmp) \ - REDIR(__bound_strcat) \ - REDIR(__bound_strchr) \ - REDIR(__bound_strdup) - -#ifdef __leading_underscore -#define _(s) "_"#s -#else -#define _(s) #s -#endif - -#define REDIR(s) void *s; -static struct { REDIR_ALL } all_ptrs; -#undef REDIR -#define REDIR(s) #s"\0" -static const char all_names[] = REDIR_ALL; -#undef REDIR -#define REDIR(s) __asm__(".global " _(s) ";" _(s) ": jmp *%0" : : "m" (all_ptrs.s) ); -static void all_jmps() { REDIR_ALL } -#undef REDIR - -void __bt_init_dll(int bcheck) -{ - const char *s = all_names; - void **p = (void**)&all_ptrs; - do { - *p = (void*)GetProcAddress(GetModuleHandle(NULL), (char*)s); - if (NULL == *p) { - char buf[100]; - sprintf(buf, - "Error: function '%s()' not found in executable. " - "(Need -bt or -b for linking the exe.)", s); - if (GetStdHandle(STD_ERROR_HANDLE)) - fprintf(stderr, "TCC/BCHECK: %s\n", buf), fflush(stderr); - else - MessageBox(NULL, buf, "TCC/BCHECK", MB_ICONERROR); - ExitProcess(1); - } - s = strchr(s,'\0') + 1, ++p; - } while (*s && (bcheck || p < &all_ptrs.__bound_ptr_add)); -} diff --git a/tinycc/lib/bt-exe.c b/tinycc/lib/bt-exe.c deleted file mode 100644 index 3a2d02e..0000000 --- a/tinycc/lib/bt-exe.c +++ /dev/null @@ -1,74 +0,0 @@ -/* ------------------------------------------------------------- */ -/* for linking rt_printline and the signal/exception handler - from tccrun.c into executables. */ - -#define CONFIG_TCC_BACKTRACE_ONLY -#define ONE_SOURCE 1 -#define pstrcpy tcc_pstrcpy -#include "../tccrun.c" - -int (*__rt_error)(void*, void*, const char *, va_list); -__attribute__((weak)) void __bound_checking_lock(void); -__attribute__((weak)) void __bound_checking_unlock(void); - -#ifndef _WIN32 -# define __declspec(n) -#endif - -__declspec(dllexport) -void __bt_init(rt_context *p, int num_callers) -{ - __attribute__((weak)) int main(); - __attribute__((weak)) void __bound_init(void*, int); - struct rt_context *rc = &g_rtctxt; - //fprintf(stderr, "__bt_init %d %p %p\n", num_callers, p->stab_sym, p->bounds_start), fflush(stderr); - /* call __bound_init here due to redirection of sigaction */ - /* needed to add global symbols */ - if (p->bounds_start) { - __bound_init(p->bounds_start, -1); - __bound_checking_lock(); - } - if (num_callers) { - memcpy(rc, p, offsetof(rt_context, next)); - rc->num_callers = num_callers - 1; - rc->top_func = main; - __rt_error = _rt_error; - set_exception_handler(); - } else { - p->next = rc->next, rc->next = p; - } - if (p->bounds_start) - __bound_checking_unlock(); -} - -__declspec(dllexport) -void __bt_exit(rt_context *p) -{ - __attribute__((weak)) void __bound_exit_dll(void*); - struct rt_context *rc = &g_rtctxt; - - if (p->bounds_start) { - __bound_exit_dll(p->bounds_start); - __bound_checking_lock(); - } - while (rc) { - if (rc->next == p) { - rc->next = rc->next->next; - break; - } - rc = rc->next; - } - if (p->bounds_start) - __bound_checking_unlock(); -} - -/* copy a string and truncate it. */ -ST_FUNC char *pstrcpy(char *buf, size_t buf_size, const char *s) -{ - int l = strlen(s); - if (l >= buf_size) - l = buf_size - 1; - memcpy(buf, s, l); - buf[l] = 0; - return buf; -} diff --git a/tinycc/lib/bt-log.c b/tinycc/lib/bt-log.c deleted file mode 100644 index 8f7a4db..0000000 --- a/tinycc/lib/bt-log.c +++ /dev/null @@ -1,47 +0,0 @@ -/* ------------------------------------------------------------- */ -/* function to get a stack backtrace on demand with a message */ - -#include <stdarg.h> -#include <stdio.h> -#include <string.h> - -int (*__rt_error)(void*, void*, const char *, va_list); - -#ifdef _WIN32 -# define DLL_EXPORT __declspec(dllexport) -#else -# define DLL_EXPORT -#endif - -/* Needed when using ...libtcc1-usegcc=yes in lib/Makefile */ -#if (defined(__GNUC__) && (__GNUC__ >= 6)) || defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wframe-address" -#endif - -DLL_EXPORT int tcc_backtrace(const char *fmt, ...) -{ - va_list ap; - int ret; - - if (__rt_error) { - void *fp = __builtin_frame_address(1); - void *ip = __builtin_return_address(0); - va_start(ap, fmt); - ret = __rt_error(fp, ip, fmt, ap); - va_end(ap); - } else { - const char *p; - if (fmt[0] == '^' && (p = strchr(fmt + 1, fmt[0]))) - fmt = p + 1; - va_start(ap, fmt); - ret = vfprintf(stderr, fmt, ap); - va_end(ap); - fprintf(stderr, "\n"), fflush(stderr); - } - return ret; -} - -#if (defined(__GNUC__) && (__GNUC__ >= 6)) || defined(__clang__) -#pragma GCC diagnostic pop -#endif diff --git a/tinycc/lib/builtin.c b/tinycc/lib/builtin.c deleted file mode 100644 index e40a003..0000000 --- a/tinycc/lib/builtin.c +++ /dev/null @@ -1,164 +0,0 @@ -/* uses alias to allow building with gcc/clang */ -#ifdef __TINYC__ -#define BUILTIN(x) __builtin_##x -#define BUILTINN(x) "__builtin_" # x -#else -#define BUILTIN(x) __tcc_builtin_##x -#define BUILTINN(x) "__tcc_builtin_" # x -#endif - -/* ---------------------------------------------- */ -/* This file implements: - * __builtin_ffs - * __builtin_clz - * __builtin_ctz - * __builtin_clrsb - * __builtin_popcount - * __builtin_parity - * for int, long and long long - */ - -static const unsigned char table_1_32[] = { - 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, - 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 -}; -static const unsigned char table_2_32[32] = { - 31, 22, 30, 21, 18, 10, 29, 2, 20, 17, 15, 13, 9, 6, 28, 1, - 23, 19, 11, 3, 16, 14, 7, 24, 12, 4, 8, 25, 5, 26, 27, 0 -}; -static const unsigned char table_1_64[] = { - 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, - 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, - 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, - 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12 -}; -static const unsigned char table_2_64[] = { - 63, 16, 62, 7, 15, 36, 61, 3, 6, 14, 22, 26, 35, 47, 60, 2, - 9, 5, 28, 11, 13, 21, 42, 19, 25, 31, 34, 40, 46, 52, 59, 1, - 17, 8, 37, 4, 23, 27, 48, 10, 29, 12, 43, 20, 32, 41, 53, 18, - 38, 24, 49, 30, 44, 33, 54, 39, 50, 45, 55, 51, 56, 57, 58, 0 -}; - -#define FFSI(x) \ - return table_1_32[((x & -x) * 0x077cb531u) >> 27] + (x != 0); -#define FFSL(x) \ - return table_1_64[((x & -x) * 0x022fdd63cc95386dull) >> 58] + (x != 0); -#define CTZI(x) \ - return table_1_32[((x & -x) * 0x077cb531u) >> 27]; -#define CTZL(x) \ - return table_1_64[((x & -x) * 0x022fdd63cc95386dull) >> 58]; -#define CLZI(x) \ - x |= x >> 1; \ - x |= x >> 2; \ - x |= x >> 4; \ - x |= x >> 8; \ - x |= x >> 16; \ - return table_2_32[(x * 0x07c4acddu) >> 27]; -#define CLZL(x) \ - x |= x >> 1; \ - x |= x >> 2; \ - x |= x >> 4; \ - x |= x >> 8; \ - x |= x >> 16; \ - x |= x >> 32; \ - return table_2_64[x * 0x03f79d71b4cb0a89ull >> 58]; -#define POPCOUNTI(x, m) \ - x = x - ((x >> 1) & 0x55555555); \ - x = (x & 0x33333333) + ((x >> 2) & 0x33333333); \ - x = (x + (x >> 4)) & 0xf0f0f0f; \ - return ((x * 0x01010101) >> 24) & m; -#define POPCOUNTL(x, m) \ - x = x - ((x >> 1) & 0x5555555555555555ull); \ - x = (x & 0x3333333333333333ull) + ((x >> 2) & 0x3333333333333333ull); \ - x = (x + (x >> 4)) & 0xf0f0f0f0f0f0f0full; \ - return ((x * 0x0101010101010101ull) >> 56) & m; - -/* Returns one plus the index of the least significant 1-bit of x, - or if x is zero, returns zero. */ -int BUILTIN(ffs) (int x) { FFSI(x) } -int BUILTIN(ffsll) (long long x) { FFSL(x) } -#if __SIZEOF_LONG__ == 4 -int BUILTIN(ffsl) (long x) __attribute__((alias(BUILTINN(ffs)))); -#else -int BUILTIN(ffsl) (long x) __attribute__((alias(BUILTINN(ffsll)))); -#endif - -/* Returns the number of leading 0-bits in x, starting at the most significant - bit position. If x is 0, the result is undefined. */ -int BUILTIN(clz) (unsigned int x) { CLZI(x) } -int BUILTIN(clzll) (unsigned long long x) { CLZL(x) } -#if __SIZEOF_LONG__ == 4 -int BUILTIN(clzl) (unsigned long x) __attribute__((alias(BUILTINN(clz)))); -#else -int BUILTIN(clzl) (unsigned long x) __attribute__((alias(BUILTINN(clzll)))); -#endif - -/* Returns the number of trailing 0-bits in x, starting at the least - significant bit position. If x is 0, the result is undefined. */ -int BUILTIN(ctz) (unsigned int x) { CTZI(x) } -int BUILTIN(ctzll) (unsigned long long x) { CTZL(x) } -#if __SIZEOF_LONG__ == 4 -int BUILTIN(ctzl) (unsigned long x) __attribute__((alias(BUILTINN(ctz)))); -#else -int BUILTIN(ctzl) (unsigned long x) __attribute__((alias(BUILTINN(ctzll)))); -#endif - -/* Returns the number of leading redundant sign bits in x, i.e. the number - of bits following the most significant bit that are identical to it. - There are no special cases for 0 or other values. */ -int BUILTIN(clrsb) (int x) { if (x < 0) x = ~x; x <<= 1; CLZI(x) } -int BUILTIN(clrsbll) (long long x) { if (x < 0) x = ~x; x <<= 1; CLZL(x) } -#if __SIZEOF_LONG__ == 4 -int BUILTIN(clrsbl) (long x) __attribute__((alias(BUILTINN(clrsb)))); -#else -int BUILTIN(clrsbl) (long x) __attribute__((alias(BUILTINN(clrsbll)))); -#endif - -/* Returns the number of 1-bits in x.*/ -int BUILTIN(popcount) (unsigned int x) { POPCOUNTI(x, 0x3f) } -int BUILTIN(popcountll) (unsigned long long x) { POPCOUNTL(x, 0x7f) } -#if __SIZEOF_LONG__ == 4 -int BUILTIN(popcountl) (unsigned long x) __attribute__((alias(BUILTINN(popcount)))); -#else -int BUILTIN(popcountl ) (unsigned long x) __attribute__((alias(BUILTINN(popcountll)))); -#endif - -/* Returns the parity of x, i.e. the number of 1-bits in x modulo 2. */ -int BUILTIN(parity) (unsigned int x) { POPCOUNTI(x, 0x01) } -int BUILTIN(parityll) (unsigned long long x) { POPCOUNTL(x, 0x01) } -#if __SIZEOF_LONG__ == 4 -int BUILTIN(parityl) (unsigned long x) __attribute__((alias(BUILTINN(parity)))); -#else -int BUILTIN(parityl) (unsigned long x) __attribute__((alias(BUILTINN(parityll)))); -#endif - -#ifndef __TINYC__ -#if defined(__GNUC__) && (__GNUC__ >= 6) -/* gcc overrides alias from __builtin_ffs... to ffs.. so use assembly code */ -__asm__(".globl __builtin_ffs"); -__asm__(".set __builtin_ffs,__tcc_builtin_ffs"); -__asm__(".globl __builtin_ffsl"); -__asm__(".set __builtin_ffsl,__tcc_builtin_ffsl"); -__asm__(".globl __builtin_ffsll"); -__asm__(".set __builtin_ffsll,__tcc_builtin_ffsll"); -#else -int __builtin_ffs(int x) __attribute__((alias("__tcc_builtin_ffs"))); -int __builtin_ffsl(long x) __attribute__((alias("__tcc_builtin_ffsl"))); -int __builtin_ffsll(long long x) __attribute__((alias("__tcc_builtin_ffsll"))); -#endif -int __builtin_clz(unsigned int x) __attribute__((alias("__tcc_builtin_clz"))); -int __builtin_clzl(unsigned long x) __attribute__((alias("__tcc_builtin_clzl"))); -int __builtin_clzll(unsigned long long x) __attribute__((alias("__tcc_builtin_clzll"))); -int __builtin_ctz(unsigned int x) __attribute__((alias("__tcc_builtin_ctz"))); -int __builtin_ctzl(unsigned long x) __attribute__((alias("__tcc_builtin_ctzl"))); -int __builtin_ctzll(unsigned long long x) __attribute__((alias("__tcc_builtin_ctzll"))); -int __builtin_clrsb(int x) __attribute__((alias("__tcc_builtin_clrsb"))); -int __builtin_clrsbl(long x) __attribute__((alias("__tcc_builtin_clrsbl"))); -int __builtin_clrsbll(long long x) __attribute__((alias("__tcc_builtin_clrsbll"))); -int __builtin_popcount(unsigned int x) __attribute__((alias("__tcc_builtin_popcount"))); -int __builtin_popcountl(unsigned long x) __attribute__((alias("__tcc_builtin_popcountl"))); -int __builtin_popcountll(unsigned long long x) __attribute__((alias("__tcc_builtin_popcountll"))); -int __builtin_parity(unsigned int x) __attribute__((alias("__tcc_builtin_parity"))); -int __builtin_parityl(unsigned long x) __attribute__((alias("__tcc_builtin_parityl"))); -int __builtin_parityll(unsigned long long x) __attribute__((alias("__tcc_builtin_parityll"))); -#endif diff --git a/tinycc/lib/dsohandle.c b/tinycc/lib/dsohandle.c deleted file mode 100644 index 0993dbc..0000000 --- a/tinycc/lib/dsohandle.c +++ /dev/null @@ -1 +0,0 @@ -void * __dso_handle __attribute((visibility("hidden"))) = &__dso_handle; diff --git a/tinycc/lib/lib-arm64.c b/tinycc/lib/lib-arm64.c deleted file mode 100644 index 226827e..0000000 --- a/tinycc/lib/lib-arm64.c +++ /dev/null @@ -1,677 +0,0 @@ -/* - * 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 - -#if !defined __riscv && !defined __APPLE__ -void __clear_cache(void *beg, void *end) -{ - __arm64_clear_cache(beg, end); -} -#endif - -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 if (a << 1 >> 24 == 0) { - uint64_t adj = 0; - while (!(a << 1 >> 1 >> (23 - adj))) - adj++; - x.x1 = aa >> 31 << 63 | (16256 - adj + 1) << 48 | aa << adj << 41 >> 16; - } 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 if (a << 1 >> 53 == 0) { - uint64_t adj = 0; - while (!(a << 1 >> 1 >> (52 - adj))) - adj++; - x.x0 <<= adj; - x.x1 = a >> 63 << 63 | (15360 - adj + 1) << 48 | a << adj << 12 >> 16; - } 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); -} diff --git a/tinycc/lib/libtcc1.c b/tinycc/lib/libtcc1.c deleted file mode 100644 index ae94af1..0000000 --- a/tinycc/lib/libtcc1.c +++ /dev/null @@ -1,641 +0,0 @@ -/* TCC runtime library. - Parts of this code are (c) 2002 Fabrice Bellard - - Copyright (C) 1987, 1988, 1992, 1994, 1995 Free Software Foundation, Inc. - -This file 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, or (at your option) any -later version. - -In addition to the permissions in the GNU General Public License, the -Free Software Foundation gives you unlimited permission to link the -compiled version of this file into combinations with other programs, -and to distribute those combinations without any restriction coming -from the use of this file. (The General Public License restrictions -do apply in other respects; for example, they cover modification of -the file, and distribution when not linked into a combine -executable.) - -This file 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; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. -*/ - -#define W_TYPE_SIZE 32 -#define BITS_PER_UNIT 8 - -typedef int Wtype; -typedef unsigned int UWtype; -typedef unsigned int USItype; -typedef long long DWtype; -typedef unsigned long long UDWtype; - -struct DWstruct { - Wtype low, high; -}; - -typedef union -{ - struct DWstruct s; - DWtype ll; -} DWunion; - -typedef long double XFtype; -#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT) -#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE) - -/* the following deal with IEEE single-precision numbers */ -#define EXCESS 126 -#define SIGNBIT 0x80000000 -#define HIDDEN (1 << 23) -#define SIGN(fp) ((fp) & SIGNBIT) -#define EXP(fp) (((fp) >> 23) & 0xFF) -#define MANT(fp) (((fp) & 0x7FFFFF) | HIDDEN) -#define PACK(s,e,m) ((s) | ((e) << 23) | (m)) - -/* the following deal with IEEE double-precision numbers */ -#define EXCESSD 1022 -#define HIDDEND (1 << 20) -#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF) -#define SIGND(fp) ((fp.l.upper) & SIGNBIT) -#define MANTD(fp) (((((fp.l.upper) & 0xFFFFF) | HIDDEND) << 10) | \ - (fp.l.lower >> 22)) -#define HIDDEND_LL ((long long)1 << 52) -#define MANTD_LL(fp) ((fp.ll & (HIDDEND_LL-1)) | HIDDEND_LL) -#define PACKD_LL(s,e,m) (((long long)((s)+((e)<<20))<<32)|(m)) - -/* the following deal with x86 long double-precision numbers */ -#define EXCESSLD 16382 -#define EXPLD(fp) (fp.l.upper & 0x7fff) -#define SIGNLD(fp) ((fp.l.upper) & 0x8000) - -/* only for x86 */ -union ldouble_long { - long double ld; - struct { - unsigned long long lower; - unsigned short upper; - } l; -}; - -union double_long { - double d; -#if 1 - struct { - unsigned int lower; - int upper; - } l; -#else - struct { - int upper; - unsigned int lower; - } l; -#endif - long long ll; -}; - -union float_long { - float f; - unsigned int l; -}; - -/* XXX: we don't support several builtin supports for now */ -#if !defined __x86_64__ && !defined __arm__ - -/* XXX: use gcc/tcc intrinsic ? */ -#if defined __i386__ -#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ - __asm__ ("subl %5,%1\n\tsbbl %3,%0" \ - : "=r" ((USItype) (sh)), \ - "=&r" ((USItype) (sl)) \ - : "0" ((USItype) (ah)), \ - "g" ((USItype) (bh)), \ - "1" ((USItype) (al)), \ - "g" ((USItype) (bl))) -#define umul_ppmm(w1, w0, u, v) \ - __asm__ ("mull %3" \ - : "=a" ((USItype) (w0)), \ - "=d" ((USItype) (w1)) \ - : "%0" ((USItype) (u)), \ - "rm" ((USItype) (v))) -#define udiv_qrnnd(q, r, n1, n0, dv) \ - __asm__ ("divl %4" \ - : "=a" ((USItype) (q)), \ - "=d" ((USItype) (r)) \ - : "0" ((USItype) (n0)), \ - "1" ((USItype) (n1)), \ - "rm" ((USItype) (dv))) -#define count_leading_zeros(count, x) \ - do { \ - USItype __cbtmp; \ - __asm__ ("bsrl %1,%0" \ - : "=r" (__cbtmp) : "rm" ((USItype) (x))); \ - (count) = __cbtmp ^ 31; \ - } while (0) -#else -#error unsupported CPU type -#endif - -/* most of this code is taken from libgcc2.c from gcc */ - -static UDWtype __udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp) -{ - DWunion ww; - DWunion nn, dd; - DWunion rr; - UWtype d0, d1, n0, n1, n2; - UWtype q0, q1; - UWtype b, bm; - - nn.ll = n; - dd.ll = d; - - d0 = dd.s.low; - d1 = dd.s.high; - n0 = nn.s.low; - n1 = nn.s.high; - -#if !defined(UDIV_NEEDS_NORMALIZATION) - if (d1 == 0) - { - if (d0 > n1) - { - /* 0q = nn / 0D */ - - udiv_qrnnd (q0, n0, n1, n0, d0); - q1 = 0; - - /* Remainder in n0. */ - } - else - { - /* qq = NN / 0d */ - - if (d0 == 0) - d0 = 1 / d0; /* Divide intentionally by zero. */ - - udiv_qrnnd (q1, n1, 0, n1, d0); - udiv_qrnnd (q0, n0, n1, n0, d0); - - /* Remainder in n0. */ - } - - if (rp != 0) - { - rr.s.low = n0; - rr.s.high = 0; - *rp = rr.ll; - } - } - -#else /* UDIV_NEEDS_NORMALIZATION */ - - if (d1 == 0) - { - if (d0 > n1) - { - /* 0q = nn / 0D */ - - count_leading_zeros (bm, d0); - - if (bm != 0) - { - /* Normalize, i.e. make the most significant bit of the - denominator set. */ - - d0 = d0 << bm; - n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm)); - n0 = n0 << bm; - } - - udiv_qrnnd (q0, n0, n1, n0, d0); - q1 = 0; - - /* Remainder in n0 >> bm. */ - } - else - { - /* qq = NN / 0d */ - - if (d0 == 0) - d0 = 1 / d0; /* Divide intentionally by zero. */ - - count_leading_zeros (bm, d0); - - if (bm == 0) - { - /* From (n1 >= d0) /\ (the most significant bit of d0 is set), - conclude (the most significant bit of n1 is set) /\ (the - leading quotient digit q1 = 1). - - This special case is necessary, not an optimization. - (Shifts counts of W_TYPE_SIZE are undefined.) */ - - n1 -= d0; - q1 = 1; - } - else - { - /* Normalize. */ - - b = W_TYPE_SIZE - bm; - - d0 = d0 << bm; - n2 = n1 >> b; - n1 = (n1 << bm) | (n0 >> b); - n0 = n0 << bm; - - udiv_qrnnd (q1, n1, n2, n1, d0); - } - - /* n1 != d0... */ - - udiv_qrnnd (q0, n0, n1, n0, d0); - - /* Remainder in n0 >> bm. */ - } - - if (rp != 0) - { - rr.s.low = n0 >> bm; - rr.s.high = 0; - *rp = rr.ll; - } - } -#endif /* UDIV_NEEDS_NORMALIZATION */ - - else - { - if (d1 > n1) - { - /* 00 = nn / DD */ - - q0 = 0; - q1 = 0; - - /* Remainder in n1n0. */ - if (rp != 0) - { - rr.s.low = n0; - rr.s.high = n1; - *rp = rr.ll; - } - } - else - { - /* 0q = NN / dd */ - - count_leading_zeros (bm, d1); - if (bm == 0) - { - /* From (n1 >= d1) /\ (the most significant bit of d1 is set), - conclude (the most significant bit of n1 is set) /\ (the - quotient digit q0 = 0 or 1). - - This special case is necessary, not an optimization. */ - - /* The condition on the next line takes advantage of that - n1 >= d1 (true due to program flow). */ - if (n1 > d1 || n0 >= d0) - { - q0 = 1; - sub_ddmmss (n1, n0, n1, n0, d1, d0); - } - else - q0 = 0; - - q1 = 0; - - if (rp != 0) - { - rr.s.low = n0; - rr.s.high = n1; - *rp = rr.ll; - } - } - else - { - UWtype m1, m0; - /* Normalize. */ - - b = W_TYPE_SIZE - bm; - - d1 = (d1 << bm) | (d0 >> b); - d0 = d0 << bm; - n2 = n1 >> b; - n1 = (n1 << bm) | (n0 >> b); - n0 = n0 << bm; - - udiv_qrnnd (q0, n1, n2, n1, d1); - umul_ppmm (m1, m0, q0, d0); - - if (m1 > n1 || (m1 == n1 && m0 > n0)) - { - q0--; - sub_ddmmss (m1, m0, m1, m0, d1, d0); - } - - q1 = 0; - - /* Remainder in (n1n0 - m1m0) >> bm. */ - if (rp != 0) - { - sub_ddmmss (n1, n0, n1, n0, m1, m0); - rr.s.low = (n1 << b) | (n0 >> bm); - rr.s.high = n1 >> bm; - *rp = rr.ll; - } - } - } - } - - ww.s.low = q0; - ww.s.high = q1; - return ww.ll; -} - -#define __negdi2(a) (-(a)) - -long long __divdi3(long long u, long long v) -{ - int c = 0; - DWunion uu, vv; - DWtype w; - - uu.ll = u; - vv.ll = v; - - if (uu.s.high < 0) { - c = ~c; - uu.ll = __negdi2 (uu.ll); - } - if (vv.s.high < 0) { - c = ~c; - vv.ll = __negdi2 (vv.ll); - } - w = __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) 0); - if (c) - w = __negdi2 (w); - return w; -} - -long long __moddi3(long long u, long long v) -{ - int c = 0; - DWunion uu, vv; - DWtype w; - - uu.ll = u; - vv.ll = v; - - if (uu.s.high < 0) { - c = ~c; - uu.ll = __negdi2 (uu.ll); - } - if (vv.s.high < 0) - vv.ll = __negdi2 (vv.ll); - - __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) &w); - if (c) - w = __negdi2 (w); - return w; -} - -unsigned long long __udivdi3(unsigned long long u, unsigned long long v) -{ - return __udivmoddi4 (u, v, (UDWtype *) 0); -} - -unsigned long long __umoddi3(unsigned long long u, unsigned long long v) -{ - UDWtype w; - - __udivmoddi4 (u, v, &w); - return w; -} - -/* XXX: fix tcc's code generator to do this instead */ -long long __ashrdi3(long long a, int b) -{ -#ifdef __TINYC__ - DWunion u; - u.ll = a; - if (b >= 32) { - u.s.low = u.s.high >> (b - 32); - u.s.high = u.s.high >> 31; - } else if (b != 0) { - u.s.low = ((unsigned)u.s.low >> b) | (u.s.high << (32 - b)); - u.s.high = u.s.high >> b; - } - return u.ll; -#else - return a >> b; -#endif -} - -/* XXX: fix tcc's code generator to do this instead */ -unsigned long long __lshrdi3(unsigned long long a, int b) -{ -#ifdef __TINYC__ - DWunion u; - u.ll = a; - if (b >= 32) { - u.s.low = (unsigned)u.s.high >> (b - 32); - u.s.high = 0; - } else if (b != 0) { - u.s.low = ((unsigned)u.s.low >> b) | (u.s.high << (32 - b)); - u.s.high = (unsigned)u.s.high >> b; - } - return u.ll; -#else - return a >> b; -#endif -} - -/* XXX: fix tcc's code generator to do this instead */ -long long __ashldi3(long long a, int b) -{ -#ifdef __TINYC__ - DWunion u; - u.ll = a; - if (b >= 32) { - u.s.high = (unsigned)u.s.low << (b - 32); - u.s.low = 0; - } else if (b != 0) { - u.s.high = ((unsigned)u.s.high << b) | ((unsigned)u.s.low >> (32 - b)); - u.s.low = (unsigned)u.s.low << b; - } - return u.ll; -#else - return a << b; -#endif -} - -#endif /* !__x86_64__ */ - -/* XXX: fix tcc's code generator to do this instead */ -float __floatundisf(unsigned long long a) -{ - DWunion uu; - XFtype r; - - uu.ll = a; - if (uu.s.high >= 0) { - return (float)uu.ll; - } else { - r = (XFtype)uu.ll; - r += 18446744073709551616.0; - return (float)r; - } -} - -double __floatundidf(unsigned long long a) -{ - DWunion uu; - XFtype r; - - uu.ll = a; - if (uu.s.high >= 0) { - return (double)uu.ll; - } else { - r = (XFtype)uu.ll; - r += 18446744073709551616.0; - return (double)r; - } -} - -long double __floatundixf(unsigned long long a) -{ - DWunion uu; - XFtype r; - - uu.ll = a; - if (uu.s.high >= 0) { - return (long double)uu.ll; - } else { - r = (XFtype)uu.ll; - r += 18446744073709551616.0; - return (long double)r; - } -} - -unsigned long long __fixunssfdi (float a1) -{ - register union float_long fl1; - register int exp; - register unsigned long long l; - - fl1.f = a1; - - if (fl1.l == 0) - return (0); - - exp = EXP (fl1.l) - EXCESS - 24; - l = MANT(fl1.l); - - if (exp >= 41) - return 1ULL << 63; - else if (exp >= 0) - l <<= exp; - else if (exp >= -23) - l >>= -exp; - else - return 0; - if (SIGN(fl1.l)) - l = (unsigned long long)-l; - return l; -} - -long long __fixsfdi (float a1) -{ - long long ret; int s; - ret = __fixunssfdi((s = a1 >= 0) ? a1 : -a1); - return s ? ret : -ret; -} - -unsigned long long __fixunsdfdi (double a1) -{ - register union double_long dl1; - register int exp; - register unsigned long long l; - - dl1.d = a1; - - if (dl1.ll == 0) - return (0); - - exp = EXPD (dl1) - EXCESSD - 53; - l = MANTD_LL(dl1); - - if (exp >= 12) - return 1ULL << 63; /* overflow result (like gcc, somewhat) */ - else if (exp >= 0) - l <<= exp; - else if (exp >= -52) - l >>= -exp; - else - return 0; - if (SIGND(dl1)) - l = (unsigned long long)-l; - return l; -} - -long long __fixdfdi (double a1) -{ - long long ret; int s; - ret = __fixunsdfdi((s = a1 >= 0) ? a1 : -a1); - return s ? ret : -ret; -} - -#ifndef __arm__ -unsigned long long __fixunsxfdi (long double a1) -{ - register union ldouble_long dl1; - register int exp; - register unsigned long long l; - - dl1.ld = a1; - - if (dl1.l.lower == 0 && dl1.l.upper == 0) - return (0); - - exp = EXPLD (dl1) - EXCESSLD - 64; - l = dl1.l.lower; - if (exp > 0) - return 1ULL << 63; - if (exp < -63) - return 0; - l >>= -exp; - if (SIGNLD(dl1)) - l = (unsigned long long)-l; - return l; -} - -long long __fixxfdi (long double a1) -{ - long long ret; int s; - ret = __fixunsxfdi((s = a1 >= 0) ? a1 : -a1); - return s ? ret : -ret; -} -#endif /* !ARM */ - -#if defined __x86_64__ -/* float constants used for unary minus operation */ -const float __mzerosf = -0.0; -const double __mzerodf = -0.0; -#endif - -#if defined _WIN64 -/* MSVC x64 intrinsic */ -void __faststorefence(void) -{ - __asm__("lock; orl $0,(%rsp)"); -} -#endif diff --git a/tinycc/lib/stdatomic.c b/tinycc/lib/stdatomic.c deleted file mode 100644 index bd8c0ce..0000000 --- a/tinycc/lib/stdatomic.c +++ /dev/null @@ -1,166 +0,0 @@ -// for libtcc1, avoid including files that are not part of tcc -// #include <stdint.h> -#define uint8_t unsigned char -#define uint16_t unsigned short -#define uint32_t unsigned int -#define uint64_t unsigned long long -#define bool _Bool -#define false 0 -#define true 1 -#define __ATOMIC_RELAXED 0 -#define __ATOMIC_CONSUME 1 -#define __ATOMIC_ACQUIRE 2 -#define __ATOMIC_RELEASE 3 -#define __ATOMIC_ACQ_REL 4 -#define __ATOMIC_SEQ_CST 5 -typedef __SIZE_TYPE__ size_t; - -#if defined __i386__ || defined __x86_64__ -#define ATOMIC_COMPARE_EXCHANGE(TYPE, MODE, SUFFIX) \ - bool __atomic_compare_exchange_##MODE \ - (volatile void *atom, void *ref, TYPE xchg, \ - bool weak, int success_memorder, int failure_memorder) \ - { \ - TYPE rv; \ - TYPE cmp = *(TYPE *)ref; \ - __asm__ volatile( \ - "lock cmpxchg" SUFFIX " %2,%1\n" \ - : "=a" (rv), "+m" (*(TYPE *)atom) \ - : "q" (xchg), "0" (cmp) \ - : "memory" \ - ); \ - *(TYPE *)ref = rv; \ - return (rv == cmp); \ - } -#else -#define ATOMIC_COMPARE_EXCHANGE(TYPE, MODE, SUFFIX) \ - extern bool __atomic_compare_exchange_##MODE \ - (volatile void *atom, void *ref, TYPE xchg, \ - bool weak, int success_memorder, int failure_memorder); -#endif - -#define ATOMIC_LOAD(TYPE, MODE) \ - TYPE __atomic_load_##MODE(const volatile void *atom, int memorder) \ - { \ - return *(volatile TYPE *)atom; \ - } - -#define ATOMIC_STORE(TYPE, MODE) \ - void __atomic_store_##MODE(volatile void *atom, TYPE value, int memorder) \ - { \ - *(volatile TYPE *)atom = value; \ - } - -#define ATOMIC_GEN_OP(TYPE, MODE, NAME, OP, RET) \ - TYPE __atomic_##NAME##_##MODE(volatile void *atom, TYPE value, int memorder) \ - { \ - TYPE xchg, cmp; \ - __atomic_load((TYPE *)atom, (TYPE *)&cmp, __ATOMIC_RELAXED); \ - do { \ - xchg = (OP); \ - } while (!__atomic_compare_exchange((TYPE *)atom, &cmp, &xchg, true, \ - __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)); \ - return RET; \ - } - -#define ATOMIC_EXCHANGE(TYPE, MODE) \ - ATOMIC_GEN_OP(TYPE, MODE, exchange, value, cmp) -#define ATOMIC_ADD_FETCH(TYPE, MODE) \ - ATOMIC_GEN_OP(TYPE, MODE, add_fetch, (cmp + value), xchg) -#define ATOMIC_SUB_FETCH(TYPE, MODE) \ - ATOMIC_GEN_OP(TYPE, MODE, sub_fetch, (cmp - value), xchg) -#define ATOMIC_AND_FETCH(TYPE, MODE) \ - ATOMIC_GEN_OP(TYPE, MODE, and_fetch, (cmp & value), xchg) -#define ATOMIC_OR_FETCH(TYPE, MODE) \ - ATOMIC_GEN_OP(TYPE, MODE, or_fetch, (cmp | value), xchg) -#define ATOMIC_XOR_FETCH(TYPE, MODE) \ - ATOMIC_GEN_OP(TYPE, MODE, xor_fetch, (cmp ^ value), xchg) -#define ATOMIC_NAND_FETCH(TYPE, MODE) \ - ATOMIC_GEN_OP(TYPE, MODE, nand_fetch, ~(cmp & value), xchg) -#define ATOMIC_FETCH_ADD(TYPE, MODE) \ - ATOMIC_GEN_OP(TYPE, MODE, fetch_add, (cmp + value), cmp) -#define ATOMIC_FETCH_SUB(TYPE, MODE) \ - ATOMIC_GEN_OP(TYPE, MODE, fetch_sub, (cmp - value), cmp) -#define ATOMIC_FETCH_AND(TYPE, MODE) \ - ATOMIC_GEN_OP(TYPE, MODE, fetch_and, (cmp & value), cmp) -#define ATOMIC_FETCH_OR(TYPE, MODE) \ - ATOMIC_GEN_OP(TYPE, MODE, fetch_or, (cmp | value), cmp) -#define ATOMIC_FETCH_XOR(TYPE, MODE) \ - ATOMIC_GEN_OP(TYPE, MODE, fetch_xor, (cmp ^ value), cmp) -#define ATOMIC_FETCH_NAND(TYPE, MODE) \ - ATOMIC_GEN_OP(TYPE, MODE, fetch_nand, ~(cmp & value), cmp) - -#define ATOMIC_GEN(TYPE, SIZE, SUFFIX) \ - ATOMIC_STORE(TYPE, SIZE) \ - ATOMIC_LOAD(TYPE, SIZE) \ - ATOMIC_COMPARE_EXCHANGE(TYPE, SIZE, SUFFIX) \ - ATOMIC_EXCHANGE(TYPE, SIZE) \ - ATOMIC_ADD_FETCH(TYPE, SIZE) \ - ATOMIC_SUB_FETCH(TYPE, SIZE) \ - ATOMIC_AND_FETCH(TYPE, SIZE) \ - ATOMIC_OR_FETCH(TYPE, SIZE) \ - ATOMIC_XOR_FETCH(TYPE, SIZE) \ - ATOMIC_NAND_FETCH(TYPE, SIZE) \ - ATOMIC_FETCH_ADD(TYPE, SIZE) \ - ATOMIC_FETCH_SUB(TYPE, SIZE) \ - ATOMIC_FETCH_AND(TYPE, SIZE) \ - ATOMIC_FETCH_OR(TYPE, SIZE) \ - ATOMIC_FETCH_XOR(TYPE, SIZE) \ - ATOMIC_FETCH_NAND(TYPE, SIZE) - -ATOMIC_GEN(uint8_t, 1, "b") -ATOMIC_GEN(uint16_t, 2, "w") -ATOMIC_GEN(uint32_t, 4, "l") -#if defined __x86_64__ || defined __aarch64__ || defined __riscv -ATOMIC_GEN(uint64_t, 8, "q") -#endif - -/* uses alias to allow building with gcc/clang */ -#ifdef __TINYC__ -#define ATOMIC(x) __atomic_##x -#else -#define ATOMIC(x) __tcc_atomic_##x -#endif - -void ATOMIC(signal_fence) (int memorder) -{ -} - -void ATOMIC(thread_fence) (int memorder) -{ -#if defined __i386__ - __asm__ volatile("lock orl $0, (%esp)"); -#elif defined __x86_64__ - __asm__ volatile("lock orq $0, (%rsp)"); -#elif defined __arm__ - __asm__ volatile(".int 0xee070fba"); // mcr p15, 0, r0, c7, c10, 5 -#elif defined __aarch64__ - __asm__ volatile(".int 0xd5033bbf"); // dmb ish -#elif defined __riscv - __asm__ volatile(".int 0x0ff0000f"); // fence iorw,iorw -#endif -} - -bool ATOMIC(is_lock_free) (unsigned long size, const volatile void *ptr) -{ - bool ret; - - switch (size) { - case 1: ret = true; break; - case 2: ret = true; break; - case 4: ret = true; break; -#if defined __x86_64__ || defined __aarch64__ || defined __riscv - case 8: ret = true; break; -#else - case 8: ret = false; break; -#endif - default: ret = false; break; - } - return ret; -} - -#ifndef __TINYC__ -void __atomic_signal_fence(int memorder) __attribute__((alias("__tcc_atomic_signal_fence"))); -void __atomic_thread_fence(int memorder) __attribute__((alias("__tcc_atomic_thread_fence"))); -bool __atomic_is_lock_free(unsigned long size, const volatile void *ptr) __attribute__((alias("__tcc_atomic_is_lock_free"))); -#endif diff --git a/tinycc/lib/tcov.c b/tinycc/lib/tcov.c deleted file mode 100644 index 32b7d18..0000000 --- a/tinycc/lib/tcov.c +++ /dev/null @@ -1,428 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <fcntl.h> -#ifndef _WIN32 -#include <unistd.h> -#include <errno.h> -#else -#include <windows.h> -#include <io.h> -#endif - -/* section layout (all little endian): - 32bit offset to executable/so file name - filename \0 - function name \0 - align to 64 bits - 64bit function start line - 64bits end_line(28bits) / start_line(28bits) / flag=0xff(8bits) - 64bits counter - \0 - \0 - \0 - executable/so file name \0 - */ - -typedef struct tcov_line { - unsigned int fline; - unsigned int lline; - unsigned long long count; -} tcov_line; - -typedef struct tcov_function { - char *function; - unsigned int first_line; - unsigned int n_line; - unsigned int m_line; - tcov_line *line; -} tcov_function; - -typedef struct tcov_file { - char *filename; - unsigned int n_func; - unsigned int m_func; - tcov_function *func; - struct tcov_file *next; -} tcov_file; - -static FILE *open_tcov_file (char *cov_filename) -{ - int fd; -#ifndef _WIN32 - struct flock lock; - - lock.l_type = F_WRLCK; - lock.l_whence = SEEK_SET; - lock.l_start = 0; - lock.l_len = 0; /* Until EOF. */ - lock.l_pid = getpid (); -#endif - fd = open (cov_filename, O_RDWR | O_CREAT, 0666); - if (fd < 0) - return NULL; - -#ifndef _WIN32 - while (fcntl (fd, F_SETLKW, &lock) && errno == EINTR) - continue; -#else - { - OVERLAPPED overlapped = { 0 }; - LockFileEx((HANDLE)_get_osfhandle(fd), LOCKFILE_EXCLUSIVE_LOCK, - 0, 1, 0, &overlapped); - } -#endif - - return fdopen (fd, "r+"); -} - -static unsigned long long get_value(unsigned char *p, int size) -{ - unsigned long long value = 0; - - p += size; - while (size--) - value = (value << 8) | *--p; - return value; -} - -static int sort_func (const void *p, const void *q) -{ - const tcov_function *pp = (const tcov_function *) p; - const tcov_function *pq = (const tcov_function *) q; - - return pp->first_line > pq->first_line ? 1 : - pp->first_line < pq->first_line ? -1 : 0; -} - -static int sort_line (const void *p, const void *q) -{ - const tcov_line *pp = (const tcov_line *) p; - const tcov_line *pq = (const tcov_line *) q; - - return pp->fline > pq->fline ? 1 : - pp->fline < pq->fline ? -1 : - pp->count < pq->count ? 1 : - pp->count > pq->count ? -1 : 0; -} - -/* sort to let inline functions work */ -static tcov_file *sort_test_coverage (unsigned char *p) -{ - int i, j, k; - unsigned char *start = p; - tcov_file *file = NULL; - tcov_file *nfile; - - p += 4; - while (*p) { - char *filename = (char *)p; - size_t len = strlen (filename); - - nfile = file; - while (nfile) { - if (strcmp (nfile->filename, filename) == 0) - break; - nfile = nfile->next; - } - if (nfile == NULL) { - nfile = malloc (sizeof(tcov_file)); - if (nfile == NULL) { - fprintf (stderr, "Malloc error test_coverage\n"); - return file; - } - nfile->filename = filename; - nfile->n_func = 0; - nfile->m_func = 0; - nfile->func = NULL; - nfile->next = NULL; - if (file == NULL) - file = nfile; - else { - tcov_file *lfile = file; - - while (lfile->next) - lfile = lfile->next; - lfile->next = nfile; - } - } - p += len + 1; - while (*p) { - int i; - char *function = (char *)p; - tcov_function *func; - - p += strlen (function) + 1; - p += -(p - start) & 7; - for (i = 0; i < nfile->n_func; i++) { - func = &nfile->func[i]; - if (strcmp (func->function, function) == 0) - break; - } - if (i == nfile->n_func) { - if (nfile->n_func >= nfile->m_func) { - nfile->m_func = nfile->m_func == 0 ? 4 : nfile->m_func * 2; - nfile->func = realloc (nfile->func, - nfile->m_func * - sizeof (tcov_function)); - if (nfile->func == NULL) { - fprintf (stderr, "Realloc error test_coverage\n"); - return file; - } - } - func = &nfile->func[nfile->n_func++]; - func->function = function; - func->first_line = get_value (p, 8); - func->n_line = 0; - func->m_line = 0; - func->line = NULL; - } - p += 8; - while (*p) { - tcov_line *line; - unsigned long long val; - - if (func->n_line >= func->m_line) { - func->m_line = func->m_line == 0 ? 4 : func->m_line * 2; - func->line = realloc (func->line, - func->m_line * sizeof (tcov_line)); - if (func->line == NULL) { - fprintf (stderr, "Realloc error test_coverage\n"); - return file; - } - } - line = &func->line[func->n_line++]; - val = get_value (p, 8); - line->fline = (val >> 8) & 0xfffffffULL; - line->lline = val >> 36; - line->count = get_value (p + 8, 8); - p += 16; - } - p++; - } - p++; - } - nfile = file; - while (nfile) { - qsort (nfile->func, nfile->n_func, sizeof (tcov_function), sort_func); - for (i = 0; i < nfile->n_func; i++) { - tcov_function *func = &nfile->func[i]; - qsort (func->line, func->n_line, sizeof (tcov_line), sort_line); - } - nfile = nfile->next; - } - return file; -} - -/* merge with previous tcov file */ -static void merge_test_coverage (tcov_file *file, FILE *fp, - unsigned int *pruns) -{ - unsigned int runs; - char *p; - char str[10000]; - - *pruns = 1; - if (fp == NULL) - return; - if (fgets(str, sizeof(str), fp) && - (p = strrchr (str, ':')) && - (sscanf (p + 1, "%u", &runs) == 1)) - *pruns = runs + 1; - while (file) { - int i; - size_t len = strlen (file->filename); - - while (fgets(str, sizeof(str), fp) && - (p = strstr(str, "0:File:")) == NULL) {} - if ((p = strstr(str, "0:File:")) == NULL || - strncmp (p + strlen("0:File:"), file->filename, len) != 0 || - p[strlen("0:File:") + len] != ' ') - break; - for (i = 0; i < file->n_func; i++) { - int j; - tcov_function *func = &file->func[i]; - unsigned int next_zero = 0; - unsigned int curline = 0; - - for (j = 0; j < func->n_line; j++) { - tcov_line *line = &func->line[j]; - unsigned int fline = line->fline; - unsigned long long count; - unsigned int tmp; - char c; - - while (curline < fline && - fgets(str, sizeof(str), fp)) - if ((p = strchr(str, ':')) && - sscanf (p + 1, "%u", &tmp) == 1) - curline = tmp; - if (sscanf (str, "%llu%c\n", &count, &c) == 2) { - if (next_zero == 0) - line->count += count; - next_zero = c == '*'; - } - } - } - file = file->next; - } -} - -/* store tcov data in file */ -void __store_test_coverage (unsigned char * p) -{ - int i, j; - unsigned int files; - unsigned int funcs; - unsigned int blocks; - unsigned int blocks_run; - unsigned int runs; - char *cov_filename = (char *)p + get_value (p, 4); - FILE *fp; - char *q; - tcov_file *file; - tcov_file *nfile; - tcov_function *func; - - fp = open_tcov_file (cov_filename); - if (fp == NULL) { - fprintf (stderr, "Cannot create coverage file: %s\n", cov_filename); - return; - } - file = sort_test_coverage (p); - merge_test_coverage (file, fp, &runs); - fseek (fp, 0, SEEK_SET); - fprintf (fp, " -: 0:Runs:%u\n", runs); - files = 0; - funcs = 0; - blocks = 0; - blocks_run = 0; - nfile = file; - while (nfile) { - files++; - for (i = 0; i < nfile->n_func; i++) { - func = &nfile->func[i]; - funcs++; - for (j = 0; j < func->n_line; j++) { - blocks++; - blocks_run += func->line[j].count != 0; - } - } - nfile = nfile->next; - } - if (blocks == 0) - blocks = 1; - fprintf (fp, " -: 0:All:%s Files:%u Functions:%u %.02f%%\n", - cov_filename, files, funcs, 100.0 * (double) blocks_run / blocks); - nfile = file; - while (nfile) { - FILE *src = fopen (nfile->filename, "r"); - unsigned int curline = 1; - char str[10000]; - - if (src == NULL) - goto next; - funcs = 0; - blocks = 0; - blocks_run = 0; - for (i = 0; i < nfile->n_func; i++) { - func = &nfile->func[i]; - funcs++; - for (j = 0; j < func->n_line; j++) { - blocks++; - blocks_run += func->line[j].count != 0; - } - } - if (blocks == 0) - blocks = 1; - fprintf (fp, " -: 0:File:%s Functions:%u %.02f%%\n", - nfile->filename, funcs, 100.0 * (double) blocks_run / blocks); - for (i = 0; i < nfile->n_func; i++) { - func = &nfile->func[i]; - - while (curline < func->first_line) - if (fgets(str, sizeof(str), src)) - fprintf (fp, " -:%5u:%s", curline++, str); - blocks = 0; - blocks_run = 0; - for (j = 0; j < func->n_line; j++) { - blocks++; - blocks_run += func->line[j].count != 0; - } - if (blocks == 0) - blocks = 1; - fprintf (fp, " -: 0:Function:%s %.02f%%\n", - func->function, 100.0 * (double) blocks_run / blocks); -#if 0 - for (j = 0; j < func->n_line; j++) { - unsigned int fline = func->line[j].fline; - unsigned int lline = func->line[j].lline; - unsigned long long count = func->line[j].count; - - fprintf (fp, "%u %u %llu\n", fline, lline, count); - } -#endif - for (j = 0; j < func->n_line;) { - unsigned int fline = func->line[j].fline; - unsigned int lline = func->line[j].lline; - unsigned long long count = func->line[j].count; - unsigned int has_zero = 0; - unsigned int same_line = fline == lline; - - j++; - while (j < func->n_line) { - unsigned int nfline = func->line[j].fline; - unsigned int nlline = func->line[j].lline; - unsigned long long ncount = func->line[j].count; - - if (fline == nfline) { - if (ncount == 0) - has_zero = 1; - else if (ncount > count) - count = ncount; - same_line = nfline == nlline; - lline = nlline; - j++; - } - else - break; - } - if (same_line) - lline++; - - while (curline < fline) - if (fgets(str, sizeof(str), src)) - fprintf (fp, " -:%5u:%s", curline++, str); - while (curline < lline && - fgets(str, sizeof(str), src)) { - if (count == 0) - fprintf (fp, " #####:%5u:%s", - curline, str); - else if (has_zero) - fprintf (fp, "%8llu*:%5u:%s", - count, curline, str); - else - fprintf (fp, "%9llu:%5u:%s", - count, curline, str); - curline++; - } - } - } - while (fgets(str, sizeof(str), src)) - fprintf (fp, " -:%5u:%s", curline++, str); - fclose (src); -next: - nfile = nfile->next; - } - while (file) { - for (i = 0; i < file->n_func; i++) { - func = &file->func[i]; - free (func->line); - } - free (file->func); - nfile = file; - file = file->next; - free (nfile); - } - fclose (fp); -} diff --git a/tinycc/lib/va_list.c b/tinycc/lib/va_list.c deleted file mode 100644 index 1fb5512..0000000 --- a/tinycc/lib/va_list.c +++ /dev/null @@ -1,67 +0,0 @@ -/* va_list.c - tinycc support for va_list on X86_64 */ - -#if defined __x86_64__ - -/* Avoid include files, they may not be available when cross compiling */ -extern void abort(void); - -/* 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. */ -/*predefined by TCC (tcc_predefs.h): -typedef struct { - unsigned int gp_offset; - unsigned int fp_offset; - union { - unsigned int overflow_offset; - char *overflow_arg_area; - }; - char *reg_save_area; -} __builtin_va_list[1]; -*/ - -extern void *memcpy(void *dest, const void *src, unsigned long n); - -void *__va_arg(__builtin_va_list ap, - int arg_type, - int size, int align) -{ - size = (size + 7) & ~7; - align = (align + 7) & ~7; - switch ((enum __va_arg_type)arg_type) { - case __va_gen_reg: - if (ap->gp_offset + size <= 48) { - ap->gp_offset += size; - return ap->reg_save_area + ap->gp_offset - size; - } - goto use_overflow_area; - - case __va_float_reg: - if (ap->fp_offset < 128 + 48) { - ap->fp_offset += 16; - if (size == 8) - return ap->reg_save_area + ap->fp_offset - 16; - if (ap->fp_offset < 128 + 48) { - memcpy(ap->reg_save_area + ap->fp_offset - 8, - ap->reg_save_area + ap->fp_offset, 8); - ap->fp_offset += 16; - return ap->reg_save_area + ap->fp_offset - 32; - } - } - goto use_overflow_area; - - 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: /* should never happen */ - abort(); - return 0; - } -} -#endif diff --git a/tinycc/libtcc.c b/tinycc/libtcc.c deleted file mode 100644 index 0f6ebe5..0000000 --- a/tinycc/libtcc.c +++ /dev/null @@ -1,2248 +0,0 @@ -/* - * 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 - */ - -#if !defined ONE_SOURCE || ONE_SOURCE -#include "tccpp.c" -#include "tccgen.c" -#include "tccdbg.c" -#include "tccasm.c" -#include "tccelf.c" -#include "tccrun.c" -#ifdef TCC_TARGET_I386 -#include "i386-gen.c" -#include "i386-link.c" -#include "i386-asm.c" -#elif defined(TCC_TARGET_ARM) -#include "arm-gen.c" -#include "arm-link.c" -#include "arm-asm.c" -#elif defined(TCC_TARGET_ARM64) -#include "arm64-gen.c" -#include "arm64-link.c" -#include "arm-asm.c" -#elif defined(TCC_TARGET_C67) -#include "c67-gen.c" -#include "c67-link.c" -#include "tcccoff.c" -#elif defined(TCC_TARGET_X86_64) -#include "x86_64-gen.c" -#include "x86_64-link.c" -#include "i386-asm.c" -#elif defined(TCC_TARGET_RISCV64) -#include "riscv64-gen.c" -#include "riscv64-link.c" -#include "riscv64-asm.c" -#else -#error unknown target -#endif -#ifdef TCC_TARGET_PE -#include "tccpe.c" -#endif -#ifdef TCC_TARGET_MACHO -#include "tccmacho.c" -#endif -#endif /* ONE_SOURCE */ - -#include "tcc.h" - -/********************************************************/ -/* global variables */ - -/* XXX: get rid of this ASAP (or maybe not) */ -ST_DATA struct TCCState *tcc_state; -TCC_SEM(static tcc_compile_sem); -/* an array of pointers to memory to be free'd after errors */ -ST_DATA void** stk_data; -ST_DATA int nb_stk_data; - -/********************************************************/ -#ifdef _WIN32 -ST_FUNC char *normalize_slashes(char *path) -{ - char *p; - for (p = path; *p; ++p) - if (*p == '\\') - *p = '/'; - return path; -} - -#if defined LIBTCC_AS_DLL && !defined CONFIG_TCCDIR -static HMODULE tcc_module; -BOOL WINAPI DllMain (HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved) -{ - if (DLL_PROCESS_ATTACH == dwReason) - tcc_module = hDll; - return TRUE; -} -#else -#define tcc_module NULL /* NULL means executable itself */ -#endif - -#ifndef CONFIG_TCCDIR -/* on win32, we suppose the lib and includes are at the location of 'tcc.exe' */ -static inline char *config_tccdir_w32(char *path) -{ - char temp[1024]; - char try[1024]; - char *p; - int c; - GetModuleFileName(tcc_module, path, MAX_PATH); - p = tcc_basename(normalize_slashes(strlwr(path))); - if (p > path) - --p; - - *p = 0; - - /* - * See if we are perhaps in a "bin/" subfolder of the - * installation path, in which case the real root of - * the installation is one level up. We can test this - * by looking for the 'include' folder. - */ - strncpy(temp, path, sizeof(temp)-1); - strcat(temp, "/include"); - - if (_access(temp, 0) != 0) { - /* No 'include' folder found, so go up one level. */ - strncpy(temp, path, sizeof(temp)-1); - - /* Try this for several "levels" up. */ - for (c = 0; c < 4; c++) { - p = tcc_basename(temp); - if (p > temp) { - --p; - *p = '\0'; - } - - strncpy(try, temp, sizeof(try)-1); - strcat(try, "/include"); - - if (_access(try, 0) == 0) { - if (p != NULL) - p = '\0'; - strcpy(path, temp); - break; - } - } - } - - return path; -} -#define CONFIG_TCCDIR config_tccdir_w32(alloca(MAX_PATH)) -#endif - -#ifdef TCC_TARGET_PE -static void tcc_add_systemdir(TCCState *s) -{ - char buf[1000]; - GetSystemDirectory(buf, sizeof buf); - tcc_add_library_path(s, normalize_slashes(buf)); -} -#endif -#endif - -/********************************************************/ -#if CONFIG_TCC_SEMLOCK -#if defined _WIN32 -ST_FUNC void wait_sem(TCCSem *p) -{ - if (!p->init) - InitializeCriticalSection(&p->cr), p->init = 1; - EnterCriticalSection(&p->cr); -} -ST_FUNC void post_sem(TCCSem *p) -{ - LeaveCriticalSection(&p->cr); -} -#elif defined __APPLE__ -/* Half-compatible MacOS doesn't have non-shared (process local) - semaphores. Use the dispatch framework for lightweight locks. */ -ST_FUNC void wait_sem(TCCSem *p) -{ - if (!p->init) - p->sem = dispatch_semaphore_create(1), p->init = 1; - dispatch_semaphore_wait(p->sem, DISPATCH_TIME_FOREVER); -} -ST_FUNC void post_sem(TCCSem *p) -{ - dispatch_semaphore_signal(p->sem); -} -#else -ST_FUNC void wait_sem(TCCSem *p) -{ - if (!p->init) - sem_init(&p->sem, 0, 1), p->init = 1; - while (sem_wait(&p->sem) < 0 && errno == EINTR); -} -ST_FUNC void post_sem(TCCSem *p) -{ - sem_post(&p->sem); -} -#endif -#endif - -PUB_FUNC void tcc_enter_state(TCCState *s1) -{ - if (s1->error_set_jmp_enabled) - return; - WAIT_SEM(&tcc_compile_sem); - tcc_state = s1; -} - -PUB_FUNC void tcc_exit_state(TCCState *s1) -{ - if (s1->error_set_jmp_enabled) - return; - tcc_state = NULL; - POST_SEM(&tcc_compile_sem); -} - -/********************************************************/ -/* copy a string and truncate it. */ -ST_FUNC char *pstrcpy(char *buf, size_t buf_size, const char *s) -{ - char *q, *q_end; - int c; - - if (buf_size > 0) { - q = buf; - q_end = buf + buf_size - 1; - while (q < q_end) { - c = *s++; - if (c == '\0') - break; - *q++ = c; - } - *q = '\0'; - } - return buf; -} - -/* strcat and truncate. */ -ST_FUNC char *pstrcat(char *buf, size_t buf_size, const char *s) -{ - size_t len; - len = strlen(buf); - if (len < buf_size) - pstrcpy(buf + len, buf_size - len, s); - return buf; -} - -ST_FUNC char *pstrncpy(char *out, const char *in, size_t num) -{ - memcpy(out, in, num); - out[num] = '\0'; - return out; -} - -/* extract the basename of a file */ -PUB_FUNC char *tcc_basename(const char *name) -{ - char *p = strchr(name, 0); - while (p > name && !IS_DIRSEP(p[-1])) - --p; - return p; -} - -/* extract extension part of a file - * - * (if no extension, return pointer to end-of-string) - */ -PUB_FUNC char *tcc_fileextension (const char *name) -{ - char *b = tcc_basename(name); - char *e = strrchr(b, '.'); - return e ? e : strchr(b, 0); -} - -ST_FUNC char *tcc_load_text(int fd) -{ - int len = lseek(fd, 0, SEEK_END); - char *buf = load_data(fd, 0, len + 1); - buf[len] = 0; - return buf; -} - -/********************************************************/ -/* memory management */ - -#undef free -#undef malloc -#undef realloc - -void mem_error(const char *msg) -{ - fprintf(stderr, "%s\n", msg); - exit (1); -} - -#ifndef MEM_DEBUG - -PUB_FUNC void tcc_free(void *ptr) -{ - free(ptr); -} - -PUB_FUNC void *tcc_malloc(unsigned long size) -{ - void *ptr; - ptr = malloc(size); - if (!ptr && size) - mem_error("memory full (malloc)"); - return ptr; -} - -PUB_FUNC void *tcc_mallocz(unsigned long size) -{ - void *ptr; - ptr = tcc_malloc(size); - if (size) - memset(ptr, 0, size); - return ptr; -} - -PUB_FUNC void *tcc_realloc(void *ptr, unsigned long size) -{ - void *ptr1; - ptr1 = realloc(ptr, size); - if (!ptr1 && size) - mem_error("memory full (realloc)"); - return ptr1; -} - -PUB_FUNC char *tcc_strdup(const char *str) -{ - char *ptr; - ptr = tcc_malloc(strlen(str) + 1); - strcpy(ptr, str); - return ptr; -} - -#else - -#define MEM_DEBUG_MAGIC1 0xFEEDDEB1 -#define MEM_DEBUG_MAGIC2 0xFEEDDEB2 -#define MEM_DEBUG_MAGIC3 0xFEEDDEB3 -#define MEM_DEBUG_FILE_LEN 40 -#define MEM_DEBUG_CHECK3(header) \ - ((mem_debug_header_t*)((char*)header + header->size))->magic3 -#define MEM_USER_PTR(header) \ - ((char *)header + offsetof(mem_debug_header_t, magic3)) -#define MEM_HEADER_PTR(ptr) \ - (mem_debug_header_t *)((char*)ptr - offsetof(mem_debug_header_t, magic3)) - -struct mem_debug_header { - unsigned magic1; - unsigned size; - struct mem_debug_header *prev; - struct mem_debug_header *next; - int line_num; - char file_name[MEM_DEBUG_FILE_LEN + 1]; - unsigned magic2; - ALIGNED(16) unsigned char magic3[4]; -}; - -typedef struct mem_debug_header mem_debug_header_t; - -TCC_SEM(static mem_sem); -static mem_debug_header_t *mem_debug_chain; -static unsigned mem_cur_size; -static unsigned mem_max_size; -static int nb_states; - -static mem_debug_header_t *malloc_check(void *ptr, const char *msg) -{ - mem_debug_header_t * header = MEM_HEADER_PTR(ptr); - if (header->magic1 != MEM_DEBUG_MAGIC1 || - header->magic2 != MEM_DEBUG_MAGIC2 || - read32le(MEM_DEBUG_CHECK3(header)) != MEM_DEBUG_MAGIC3 || - header->size == (unsigned)-1) { - fprintf(stderr, "%s check failed\n", msg); - if (header->magic1 == MEM_DEBUG_MAGIC1) - fprintf(stderr, "%s:%u: block allocated here.\n", - header->file_name, header->line_num); - exit(1); - } - return header; -} - -PUB_FUNC void *tcc_malloc_debug(unsigned long size, const char *file, int line) -{ - int ofs; - mem_debug_header_t *header; - - header = malloc(sizeof(mem_debug_header_t) + size); - if (!header) - mem_error("memory full (malloc)"); - - header->magic1 = MEM_DEBUG_MAGIC1; - header->magic2 = MEM_DEBUG_MAGIC2; - header->size = size; - write32le(MEM_DEBUG_CHECK3(header), MEM_DEBUG_MAGIC3); - header->line_num = line; - ofs = strlen(file) - MEM_DEBUG_FILE_LEN; - strncpy(header->file_name, file + (ofs > 0 ? ofs : 0), MEM_DEBUG_FILE_LEN); - header->file_name[MEM_DEBUG_FILE_LEN] = 0; - - WAIT_SEM(&mem_sem); - header->next = mem_debug_chain; - header->prev = NULL; - if (header->next) - header->next->prev = header; - mem_debug_chain = header; - mem_cur_size += size; - if (mem_cur_size > mem_max_size) - mem_max_size = mem_cur_size; - POST_SEM(&mem_sem); - - return MEM_USER_PTR(header); -} - -PUB_FUNC void tcc_free_debug(void *ptr) -{ - mem_debug_header_t *header; - if (!ptr) - return; - header = malloc_check(ptr, "tcc_free"); - - WAIT_SEM(&mem_sem); - mem_cur_size -= header->size; - header->size = (unsigned)-1; - if (header->next) - header->next->prev = header->prev; - if (header->prev) - header->prev->next = header->next; - if (header == mem_debug_chain) - mem_debug_chain = header->next; - POST_SEM(&mem_sem); - free(header); -} - -PUB_FUNC void *tcc_mallocz_debug(unsigned long size, const char *file, int line) -{ - void *ptr; - ptr = tcc_malloc_debug(size,file,line); - memset(ptr, 0, size); - return ptr; -} - -PUB_FUNC void *tcc_realloc_debug(void *ptr, unsigned long size, const char *file, int line) -{ - mem_debug_header_t *header; - int mem_debug_chain_update = 0; - if (!ptr) - return tcc_malloc_debug(size, file, line); - header = malloc_check(ptr, "tcc_realloc"); - - WAIT_SEM(&mem_sem); - mem_cur_size -= header->size; - mem_debug_chain_update = (header == mem_debug_chain); - header = realloc(header, sizeof(mem_debug_header_t) + size); - if (!header) - mem_error("memory full (realloc)"); - header->size = size; - write32le(MEM_DEBUG_CHECK3(header), MEM_DEBUG_MAGIC3); - if (header->next) - header->next->prev = header; - if (header->prev) - header->prev->next = header; - if (mem_debug_chain_update) - mem_debug_chain = header; - mem_cur_size += size; - if (mem_cur_size > mem_max_size) - mem_max_size = mem_cur_size; - POST_SEM(&mem_sem); - - return MEM_USER_PTR(header); -} - -PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line) -{ - char *ptr; - ptr = tcc_malloc_debug(strlen(str) + 1, file, line); - strcpy(ptr, str); - return ptr; -} - -PUB_FUNC void tcc_memcheck(int d) -{ - WAIT_SEM(&mem_sem); - nb_states += d; - if (0 == nb_states && mem_cur_size) { - mem_debug_header_t *header = mem_debug_chain; - fflush(stdout); - fprintf(stderr, "MEM_DEBUG: mem_leak= %d bytes, mem_max_size= %d bytes\n", - mem_cur_size, mem_max_size); - while (header) { - fprintf(stderr, "%s:%u: error: %u bytes leaked\n", - header->file_name, header->line_num, header->size); - header = header->next; - } - fflush(stderr); - mem_cur_size = 0; - mem_debug_chain = NULL; -#if MEM_DEBUG-0 == 2 - exit(2); -#endif - } - POST_SEM(&mem_sem); -} -#endif /* MEM_DEBUG */ - -#define free(p) use_tcc_free(p) -#define malloc(s) use_tcc_malloc(s) -#define realloc(p, s) use_tcc_realloc(p, s) - -/********************************************************/ -/* dynarrays */ - -ST_FUNC void dynarray_add(void *ptab, int *nb_ptr, void *data) -{ - int nb, nb_alloc; - void **pp; - - nb = *nb_ptr; - pp = *(void ***)ptab; - /* every power of two we double array size */ - if ((nb & (nb - 1)) == 0) { - if (!nb) - nb_alloc = 1; - else - nb_alloc = nb * 2; - pp = tcc_realloc(pp, nb_alloc * sizeof(void *)); - *(void***)ptab = pp; - } - pp[nb++] = data; - *nb_ptr = nb; -} - -ST_FUNC void dynarray_reset(void *pp, int *n) -{ - void **p; - for (p = *(void***)pp; *n; ++p, --*n) - if (*p) - tcc_free(*p); - tcc_free(*(void**)pp); - *(void**)pp = NULL; -} - -static void tcc_split_path(TCCState *s, void *p_ary, int *p_nb_ary, const char *in) -{ - const char *p; - do { - int c; - CString str; - - cstr_new(&str); - for (p = in; c = *p, c != '\0' && c != PATHSEP[0]; ++p) { - if (c == '{' && p[1] && p[2] == '}') { - c = p[1], p += 2; - if (c == 'B') - cstr_cat(&str, s->tcc_lib_path, -1); - if (c == 'R') - cstr_cat(&str, CONFIG_SYSROOT, -1); - if (c == 'f' && file) { - /* substitute current file's dir */ - const char *f = file->true_filename; - const char *b = tcc_basename(f); - if (b > f) - cstr_cat(&str, f, b - f - 1); - else - cstr_cat(&str, ".", 1); - } - } else { - cstr_ccat(&str, c); - } - } - if (str.size) { - cstr_ccat(&str, '\0'); - dynarray_add(p_ary, p_nb_ary, tcc_strdup(str.data)); - } - cstr_free(&str); - in = p+1; - } while (*p); -} - -/********************************************************/ -/* warning / error */ - -/* warn_... option bits */ -#define WARN_ON 1 /* warning is on (-Woption) */ -#define WARN_ERR 2 /* warning is an error (-Werror=option) */ -#define WARN_NOE 4 /* warning is not an error (-Wno-error=option) */ - -/* error1() modes */ -enum { ERROR_WARN, ERROR_NOABORT, ERROR_ERROR }; - -static void error1(int mode, const char *fmt, va_list ap) -{ - BufferedFile **pf, *f; - TCCState *s1 = tcc_state; - CString cs; - - tcc_exit_state(s1); - - if (mode == ERROR_WARN) { - if (s1->warn_error) - mode = ERROR_ERROR; - if (s1->warn_num) { - /* handle tcc_warning_c(warn_option)(fmt, ...) */ - int wopt = *(&s1->warn_none + s1->warn_num); - s1->warn_num = 0; - if (0 == (wopt & WARN_ON)) - return; - if (wopt & WARN_ERR) - mode = ERROR_ERROR; - if (wopt & WARN_NOE) - mode = ERROR_WARN; - } - if (s1->warn_none) - return; - } - - cstr_new(&cs); - f = NULL; - if (s1->error_set_jmp_enabled) { /* we're called while parsing a file */ - /* use upper file if inline ":asm:" or token ":paste:" */ - for (f = file; f && f->filename[0] == ':'; f = f->prev) - ; - } - if (f) { - for(pf = s1->include_stack; pf < s1->include_stack_ptr; pf++) - cstr_printf(&cs, "In file included from %s:%d:\n", - (*pf)->filename, (*pf)->line_num - 1); - cstr_printf(&cs, "%s:%d: ", - f->filename, f->line_num - !!(tok_flags & TOK_FLAG_BOL)); - } else if (s1->current_filename) { - cstr_printf(&cs, "%s: ", s1->current_filename); - } - if (0 == cs.size) - cstr_printf(&cs, "tcc: "); - cstr_printf(&cs, mode == ERROR_WARN ? "warning: " : "error: "); - cstr_vprintf(&cs, fmt, ap); - if (!s1 || !s1->error_func) { - /* default case: stderr */ - if (s1 && s1->output_type == TCC_OUTPUT_PREPROCESS && s1->ppfp == stdout) - printf("\n"); /* print a newline during tcc -E */ - fflush(stdout); /* flush -v output */ - fprintf(stderr, "%s\n", (char*)cs.data); - fflush(stderr); /* print error/warning now (win32) */ - } else { - s1->error_func(s1->error_opaque, (char*)cs.data); - } - cstr_free(&cs); - if (mode != ERROR_WARN) - s1->nb_errors++; - if (mode == ERROR_ERROR && s1->error_set_jmp_enabled) { - while (nb_stk_data) - tcc_free(*(void**)stk_data[--nb_stk_data]); - longjmp(s1->error_jmp_buf, 1); - } -} - -LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, TCCErrorFunc error_func) -{ - s->error_opaque = error_opaque; - s->error_func = error_func; -} - -LIBTCCAPI TCCErrorFunc tcc_get_error_func(TCCState *s) -{ - return s->error_func; -} - -LIBTCCAPI void *tcc_get_error_opaque(TCCState *s) -{ - return s->error_opaque; -} - -/* error without aborting current compilation */ -PUB_FUNC int _tcc_error_noabort(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - error1(ERROR_NOABORT, fmt, ap); - va_end(ap); - return -1; -} - -#undef _tcc_error -PUB_FUNC void _tcc_error(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - error1(ERROR_ERROR, fmt, ap); - exit(1); -} -#define _tcc_error use_tcc_error_noabort - -PUB_FUNC void _tcc_warning(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - error1(ERROR_WARN, fmt, ap); - va_end(ap); -} - - -/********************************************************/ -/* I/O layer */ - -ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen) -{ - BufferedFile *bf; - int buflen = initlen ? initlen : IO_BUF_SIZE; - - bf = tcc_mallocz(sizeof(BufferedFile) + buflen); - bf->buf_ptr = bf->buffer; - bf->buf_end = bf->buffer + initlen; - bf->buf_end[0] = CH_EOB; /* put eob symbol */ - pstrcpy(bf->filename, sizeof(bf->filename), filename); -#ifdef _WIN32 - normalize_slashes(bf->filename); -#endif - bf->true_filename = bf->filename; - bf->line_num = 1; - bf->ifdef_stack_ptr = s1->ifdef_stack_ptr; - bf->fd = -1; - bf->prev = file; - file = bf; - tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; -} - -ST_FUNC void tcc_close(void) -{ - TCCState *s1 = tcc_state; - BufferedFile *bf = file; - if (bf->fd > 0) { - close(bf->fd); - total_lines += bf->line_num - 1; - } - if (bf->true_filename != bf->filename) - tcc_free(bf->true_filename); - file = bf->prev; - tcc_free(bf); -} - -static int _tcc_open(TCCState *s1, const char *filename) -{ - int fd; - if (strcmp(filename, "-") == 0) - fd = 0, filename = "<stdin>"; - else - fd = open(filename, O_RDONLY | O_BINARY); - if ((s1->verbose == 2 && fd >= 0) || s1->verbose == 3) - printf("%s %*s%s\n", fd < 0 ? "nf":"->", - (int)(s1->include_stack_ptr - s1->include_stack), "", filename); - return fd; -} - -ST_FUNC int tcc_open(TCCState *s1, const char *filename) -{ - int fd = _tcc_open(s1, filename); - if (fd < 0) - return -1; - tcc_open_bf(s1, filename, 0); - file->fd = fd; - return 0; -} - -/* compile the file opened in 'file'. Return non zero if errors. */ -static int tcc_compile(TCCState *s1, int filetype, const char *str, int fd) -{ - /* Here we enter the code section where we use the global variables for - parsing and code generation (tccpp.c, tccgen.c, <target>-gen.c). - Other threads need to wait until we're done. - - Alternatively we could use thread local storage for those global - variables, which may or may not have advantages */ - - tcc_enter_state(s1); - s1->error_set_jmp_enabled = 1; - - if (setjmp(s1->error_jmp_buf) == 0) { - s1->nb_errors = 0; - - if (fd == -1) { - int len = strlen(str); - tcc_open_bf(s1, "<string>", len); - memcpy(file->buffer, str, len); - } else { - tcc_open_bf(s1, str, 0); - file->fd = fd; - } - - preprocess_start(s1, filetype); - tccgen_init(s1); - - if (s1->output_type == TCC_OUTPUT_PREPROCESS) { - tcc_preprocess(s1); - } else { - tccelf_begin_file(s1); - if (filetype & (AFF_TYPE_ASM | AFF_TYPE_ASMPP)) { - tcc_assemble(s1, !!(filetype & AFF_TYPE_ASMPP)); - } else { - tccgen_compile(s1); - } - tccelf_end_file(s1); - } - } - tccgen_finish(s1); - preprocess_end(s1); - s1->error_set_jmp_enabled = 0; - tcc_exit_state(s1); - return s1->nb_errors != 0 ? -1 : 0; -} - -LIBTCCAPI int tcc_compile_string(TCCState *s, const char *str) -{ - return tcc_compile(s, s->filetype, str, -1); -} - -/* define a preprocessor symbol. value can be NULL, sym can be "sym=val" */ -LIBTCCAPI void tcc_define_symbol(TCCState *s1, const char *sym, const char *value) -{ - const char *eq; - if (NULL == (eq = strchr(sym, '='))) - eq = strchr(sym, 0); - if (NULL == value) - value = *eq ? eq + 1 : "1"; - cstr_printf(&s1->cmdline_defs, "#define %.*s %s\n", (int)(eq-sym), sym, value); -} - -/* undefine a preprocessor symbol */ -LIBTCCAPI void tcc_undefine_symbol(TCCState *s1, const char *sym) -{ - cstr_printf(&s1->cmdline_defs, "#undef %s\n", sym); -} - - -LIBTCCAPI TCCState *tcc_new(void) -{ - TCCState *s; - - s = tcc_mallocz(sizeof(TCCState)); - if (!s) - return NULL; -#ifdef MEM_DEBUG - tcc_memcheck(1); -#endif - -#undef gnu_ext - - s->gnu_ext = 1; - s->tcc_ext = 1; - s->nocommon = 1; - s->dollars_in_identifiers = 1; /*on by default like in gcc/clang*/ - s->cversion = 199901; /* default unless -std=c11 is supplied */ - s->warn_implicit_function_declaration = 1; - s->warn_discarded_qualifiers = 1; - s->ms_extensions = 1; - -#ifdef CHAR_IS_UNSIGNED - s->char_is_unsigned = 1; -#endif -#ifdef TCC_TARGET_I386 - s->seg_size = 32; -#endif - /* enable this if you want symbols with leading underscore on windows: */ -#if defined TCC_TARGET_MACHO /* || defined TCC_TARGET_PE */ - s->leading_underscore = 1; -#endif -#ifdef TCC_TARGET_ARM - s->float_abi = ARM_FLOAT_ABI; -#endif -#ifdef CONFIG_NEW_DTAGS - s->enable_new_dtags = 1; -#endif - s->ppfp = stdout; - /* might be used in error() before preprocess_start() */ - s->include_stack_ptr = s->include_stack; - - tcc_set_lib_path(s, CONFIG_TCCDIR); - return s; -} - -LIBTCCAPI void tcc_delete(TCCState *s1) -{ - /* free sections */ - tccelf_delete(s1); - - /* free library paths */ - dynarray_reset(&s1->library_paths, &s1->nb_library_paths); - dynarray_reset(&s1->crt_paths, &s1->nb_crt_paths); - - /* free include paths */ - dynarray_reset(&s1->include_paths, &s1->nb_include_paths); - dynarray_reset(&s1->sysinclude_paths, &s1->nb_sysinclude_paths); - - tcc_free(s1->tcc_lib_path); - tcc_free(s1->soname); - tcc_free(s1->rpath); - tcc_free(s1->elf_entryname); - tcc_free(s1->init_symbol); - tcc_free(s1->fini_symbol); - tcc_free(s1->mapfile); - tcc_free(s1->outfile); - tcc_free(s1->deps_outfile); -#if defined TCC_TARGET_MACHO - tcc_free(s1->install_name); -#endif - dynarray_reset(&s1->files, &s1->nb_files); - dynarray_reset(&s1->target_deps, &s1->nb_target_deps); - dynarray_reset(&s1->pragma_libs, &s1->nb_pragma_libs); - dynarray_reset(&s1->argv, &s1->argc); - cstr_free(&s1->cmdline_defs); - cstr_free(&s1->cmdline_incl); - cstr_free(&s1->linker_arg); -#ifdef TCC_IS_NATIVE - /* free runtime memory */ - tcc_run_free(s1); -#endif - tcc_free(s1->dState); - tcc_free(s1); -#ifdef MEM_DEBUG - tcc_memcheck(-1); -#endif -} - -LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type) -{ -#ifdef CONFIG_TCC_PIE - if (output_type == TCC_OUTPUT_EXE) - output_type |= TCC_OUTPUT_DYN; -#endif - s->output_type = output_type; - - if (!s->nostdinc) { - /* default include paths */ - /* -isystem paths have already been handled */ - tcc_add_sysinclude_path(s, CONFIG_TCC_SYSINCLUDEPATHS); - } - - if (output_type == TCC_OUTPUT_PREPROCESS) { - s->do_debug = 0; - return 0; - } - - tccelf_new(s); - if (s->do_debug) { - /* add debug sections */ - tcc_debug_new(s); - } -#ifdef CONFIG_TCC_BCHECK - if (s->do_bounds_check) { - /* if bound checking, then add corresponding sections */ - tccelf_bounds_new(s); - } -#endif - - if (output_type == TCC_OUTPUT_OBJ) { - /* always elf for objects */ - s->output_format = TCC_OUTPUT_FORMAT_ELF; - return 0; - } - - tcc_add_library_path(s, CONFIG_TCC_LIBPATHS); - -#ifdef TCC_TARGET_PE -# ifdef _WIN32 - /* allow linking with system dll's directly */ - tcc_add_systemdir(s); -# endif - /* target PE has its own startup code in libtcc1.a */ - return 0; - -#elif defined TCC_TARGET_MACHO -# ifdef TCC_IS_NATIVE - tcc_add_macos_sdkpath(s); -# endif - /* Mach-O with LC_MAIN doesn't need any crt startup code. */ - return 0; - -#else - /* paths for crt objects */ - tcc_split_path(s, &s->crt_paths, &s->nb_crt_paths, CONFIG_TCC_CRTPREFIX); - - /* add libc crt1/crti objects */ - if (output_type != TCC_OUTPUT_MEMORY && !s->nostdlib) { -#if TARGETOS_OpenBSD - if (output_type != TCC_OUTPUT_DLL) - tcc_add_crt(s, "crt0.o"); - if (output_type == TCC_OUTPUT_DLL) - tcc_add_crt(s, "crtbeginS.o"); - else - tcc_add_crt(s, "crtbegin.o"); -#elif TARGETOS_FreeBSD - if (output_type != TCC_OUTPUT_DLL) - tcc_add_crt(s, "crt1.o"); - tcc_add_crt(s, "crti.o"); - if (s->static_link) - tcc_add_crt(s, "crtbeginT.o"); - else if (output_type & TCC_OUTPUT_DYN) - tcc_add_crt(s, "crtbeginS.o"); - else - tcc_add_crt(s, "crtbegin.o"); -#elif TARGETOS_NetBSD - if (output_type != TCC_OUTPUT_DLL) - tcc_add_crt(s, "crt0.o"); - tcc_add_crt(s, "crti.o"); - if (s->static_link) - tcc_add_crt(s, "crtbeginT.o"); - else if (output_type & TCC_OUTPUT_DYN) - tcc_add_crt(s, "crtbeginS.o"); - else - tcc_add_crt(s, "crtbegin.o"); -#elif defined TARGETOS_ANDROID - if (output_type != TCC_OUTPUT_DLL) - tcc_add_crt(s, "crtbegin_dynamic.o"); - else - tcc_add_crt(s, "crtbegin_so.o"); -#else - if (output_type != TCC_OUTPUT_DLL) - tcc_add_crt(s, "crt1.o"); - tcc_add_crt(s, "crti.o"); -#endif - } - return 0; -#endif -} - -LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname) -{ - tcc_split_path(s, &s->include_paths, &s->nb_include_paths, pathname); - return 0; -} - -LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname) -{ - tcc_split_path(s, &s->sysinclude_paths, &s->nb_sysinclude_paths, pathname); - return 0; -} - -/* add/update a 'DLLReference', Just find if level == -1 */ -ST_FUNC DLLReference *tcc_add_dllref(TCCState *s1, const char *dllname, int level) -{ - DLLReference *ref = NULL; - int i; - for (i = 0; i < s1->nb_loaded_dlls; i++) - if (0 == strcmp(s1->loaded_dlls[i]->name, dllname)) { - ref = s1->loaded_dlls[i]; - break; - } - if (level == -1) - return ref; - if (ref) { - if (level < ref->level) - ref->level = level; - ref->found = 1; - return ref; - } - ref = tcc_mallocz(sizeof(DLLReference) + strlen(dllname)); - strcpy(ref->name, dllname); - dynarray_add(&s1->loaded_dlls, &s1->nb_loaded_dlls, ref); - ref->level = level; - ref->index = s1->nb_loaded_dlls; - return ref; -} - -/* OpenBSD: choose latest from libxxx.so.x.y versions */ -#if defined TARGETOS_OpenBSD && !defined _WIN32 -#include <glob.h> -static int tcc_glob_so(TCCState *s1, const char *pattern, char *buf, int size) -{ - const char *star; - glob_t g; - char *p; - int i, v, v1, v2, v3; - - star = strchr(pattern, '*'); - if (!star || glob(pattern, 0, NULL, &g)) - return -1; - for (v = -1, i = 0; i < g.gl_pathc; ++i) { - p = g.gl_pathv[i]; - if (2 != sscanf(p + (star - pattern), "%d.%d.%d", &v1, &v2, &v3)) - continue; - if ((v1 = v1 * 1000 + v2) > v) - v = v1, pstrcpy(buf, size, p); - } - globfree(&g); - return v; -} -#endif - -ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) -{ - int fd, ret = -1; - -#if defined TARGETOS_OpenBSD && !defined _WIN32 - char buf[1024]; - if (tcc_glob_so(s1, filename, buf, sizeof buf) >= 0) - filename = buf; -#endif - - /* ignore binary files with -E */ - if (s1->output_type == TCC_OUTPUT_PREPROCESS - && (flags & AFF_TYPE_BIN)) - return 0; - - /* open the file */ - fd = _tcc_open(s1, filename); - if (fd < 0) { - if (flags & AFF_PRINT_ERROR) - tcc_error_noabort("file '%s' not found", filename); - return ret; - } - - s1->current_filename = filename; - if (flags & AFF_TYPE_BIN) { - ElfW(Ehdr) ehdr; - int obj_type; - - obj_type = tcc_object_type(fd, &ehdr); - lseek(fd, 0, SEEK_SET); - - switch (obj_type) { - - case AFF_BINTYPE_REL: - ret = tcc_load_object_file(s1, fd, 0); - break; - - case AFF_BINTYPE_AR: - ret = tcc_load_archive(s1, fd, !(flags & AFF_WHOLE_ARCHIVE)); - break; - -#ifdef TCC_TARGET_PE - default: - ret = pe_load_file(s1, fd, filename); - goto check_success; - -#elif defined TCC_TARGET_MACHO - case AFF_BINTYPE_DYN: - case_dyn_or_tbd: - if (s1->output_type == TCC_OUTPUT_MEMORY) { -#ifdef TCC_IS_NATIVE - void* dl; - const char* soname = filename; - if (obj_type != AFF_BINTYPE_DYN) - soname = macho_tbd_soname(filename); - dl = dlopen(soname, RTLD_GLOBAL | RTLD_LAZY); - if (dl) - tcc_add_dllref(s1, soname, 0)->handle = dl, ret = 0; - if (filename != soname) - tcc_free((void *)soname); -#endif - } else if (obj_type == AFF_BINTYPE_DYN) { - ret = macho_load_dll(s1, fd, filename, (flags & AFF_REFERENCED_DLL) != 0); - } else { - ret = macho_load_tbd(s1, fd, filename, (flags & AFF_REFERENCED_DLL) != 0); - } - break; - default: - { - const char *ext = tcc_fileextension(filename); - if (!strcmp(ext, ".tbd")) - goto case_dyn_or_tbd; - if (!strcmp(ext, ".dylib")) { - obj_type = AFF_BINTYPE_DYN; - goto case_dyn_or_tbd; - } - goto check_success; - } - -#else /* unix */ - case AFF_BINTYPE_DYN: - if (s1->output_type == TCC_OUTPUT_MEMORY) { -#ifdef TCC_IS_NATIVE - void* dl = dlopen(filename, RTLD_GLOBAL | RTLD_LAZY); - if (dl) - tcc_add_dllref(s1, filename, 0)->handle = dl, ret = 0; -#endif - } else - ret = tcc_load_dll(s1, fd, filename, (flags & AFF_REFERENCED_DLL) != 0); - break; - - default: - /* as GNU ld, consider it is an ld script if not recognized */ - ret = tcc_load_ldscript(s1, fd); - goto check_success; - -#endif /* pe / macos / unix */ - -check_success: - if (ret < 0) - tcc_error_noabort("%s: unrecognized file type", filename); - break; - -#ifdef TCC_TARGET_COFF - case AFF_BINTYPE_C67: - ret = tcc_load_coff(s1, fd); - break; -#endif - } - close(fd); - } else { - /* update target deps */ - dynarray_add(&s1->target_deps, &s1->nb_target_deps, tcc_strdup(filename)); - ret = tcc_compile(s1, flags, filename, fd); - } - s1->current_filename = NULL; - return ret; -} - -LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename) -{ - int filetype = s->filetype; - if (0 == (filetype & AFF_TYPE_MASK)) { - /* use a file extension to detect a filetype */ - const char *ext = tcc_fileextension(filename); - if (ext[0]) { - ext++; - if (!strcmp(ext, "S")) - filetype = AFF_TYPE_ASMPP; - else if (!strcmp(ext, "s")) - filetype = AFF_TYPE_ASM; - else if (!PATHCMP(ext, "c") - || !PATHCMP(ext, "h") - || !PATHCMP(ext, "i")) - filetype = AFF_TYPE_C; - else - filetype |= AFF_TYPE_BIN; - } else { - filetype = AFF_TYPE_C; - } - } - return tcc_add_file_internal(s, filename, filetype | AFF_PRINT_ERROR); -} - -LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname) -{ - tcc_split_path(s, &s->library_paths, &s->nb_library_paths, pathname); - return 0; -} - -static int tcc_add_library_internal(TCCState *s, const char *fmt, - const char *filename, int flags, char **paths, int nb_paths) -{ - char buf[1024]; - int i; - - for(i = 0; i < nb_paths; i++) { - snprintf(buf, sizeof(buf), fmt, paths[i], filename); - if (tcc_add_file_internal(s, buf, flags | AFF_TYPE_BIN) == 0) - return 0; - } - return -1; -} - -/* find and load a dll. Return non zero if not found */ -ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags) -{ - return tcc_add_library_internal(s, "%s/%s", filename, flags, - s->library_paths, s->nb_library_paths); -} - -/* find [cross-]libtcc1.a and tcc helper objects in library path */ -ST_FUNC void tcc_add_support(TCCState *s1, const char *filename) -{ - char buf[100]; - if (CONFIG_TCC_CROSSPREFIX[0]) - filename = strcat(strcpy(buf, CONFIG_TCC_CROSSPREFIX), filename); - if (tcc_add_dll(s1, filename, 0) < 0) - tcc_error_noabort("%s not found", filename); -} - -#if !defined TCC_TARGET_PE && !defined TCC_TARGET_MACHO -ST_FUNC int tcc_add_crt(TCCState *s1, const char *filename) -{ - if (-1 == tcc_add_library_internal(s1, "%s/%s", - filename, 0, s1->crt_paths, s1->nb_crt_paths)) - return tcc_error_noabort("file '%s' not found", filename); - return 0; -} -#endif - -/* the library name is the same as the argument of the '-l' option */ -LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname) -{ -#if defined TCC_TARGET_PE - static const char * const libs[] = { "%s/%s.def", "%s/lib%s.def", "%s/%s.dll", "%s/lib%s.dll", "%s/lib%s.a", NULL }; - const char * const *pp = s->static_link ? libs + 4 : libs; -#elif defined TCC_TARGET_MACHO - static const char * const libs[] = { "%s/lib%s.dylib", "%s/lib%s.tbd", "%s/lib%s.a", NULL }; - const char * const *pp = s->static_link ? libs + 2 : libs; -#elif defined TARGETOS_OpenBSD - static const char * const libs[] = { "%s/lib%s.so.*", "%s/lib%s.a", NULL }; - const char * const *pp = s->static_link ? libs + 1 : libs; -#else - static const char * const libs[] = { "%s/lib%s.so", "%s/lib%s.a", NULL }; - const char * const *pp = s->static_link ? libs + 1 : libs; -#endif - int flags = s->filetype & AFF_WHOLE_ARCHIVE; - while (*pp) { - if (0 == tcc_add_library_internal(s, *pp, - libraryname, flags, s->library_paths, s->nb_library_paths)) - return 0; - ++pp; - } - return -1; -} - -PUB_FUNC int tcc_add_library_err(TCCState *s1, const char *libname) -{ - int ret = tcc_add_library(s1, libname); - if (ret < 0) - tcc_error_noabort("library '%s' not found", libname); - return ret; -} - -/* handle #pragma comment(lib,) */ -ST_FUNC void tcc_add_pragma_libs(TCCState *s1) -{ - int i; - for (i = 0; i < s1->nb_pragma_libs; i++) - tcc_add_library_err(s1, s1->pragma_libs[i]); -} - -LIBTCCAPI int tcc_add_symbol(TCCState *s1, const char *name, const void *val) -{ -#ifdef TCC_TARGET_PE - /* On x86_64 'val' might not be reachable with a 32bit offset. - So it is handled here as if it were in a DLL. */ - pe_putimport(s1, 0, name, (uintptr_t)val); -#else - char buf[256]; - if (s1->leading_underscore) { - buf[0] = '_'; - pstrcpy(buf + 1, sizeof(buf) - 1, name); - name = buf; - } - set_global_sym(s1, name, NULL, (addr_t)(uintptr_t)val); /* NULL: SHN_ABS */ -#endif - return 0; -} - -LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path) -{ - tcc_free(s->tcc_lib_path); - s->tcc_lib_path = tcc_strdup(path); -} - -/********************************************************/ -/* options parser */ - -static int strstart(const char *val, const char **str) -{ - const char *p, *q; - p = *str; - q = val; - while (*q) { - if (*p != *q) - return 0; - p++; - q++; - } - *str = p; - return 1; -} - -/* Like strstart, but automatically takes into account that ld options can - * - * - start with double or single dash (e.g. '--soname' or '-soname') - * - arguments can be given as separate or after '=' (e.g. '-Wl,-soname,x.so' - * or '-Wl,-soname=x.so') - * - * you provide `val` always in 'option[=]' form (no leading -) - */ -static int link_option(const char *str, const char *val, const char **ptr) -{ - const char *p, *q; - int ret; - - /* there should be 1 or 2 dashes */ - if (*str++ != '-') - return 0; - if (*str == '-') - str++; - - /* then str & val should match (potentially up to '=') */ - p = str; - q = val; - - ret = 1; - if (q[0] == '?') { - ++q; - if (strstart("no-", &p)) - ret = -1; - } - - while (*q != '\0' && *q != '=') { - if (*p != *q) - return 0; - p++; - q++; - } - - /* '=' near eos means ',' or '=' is ok */ - if (*q == '=') { - if (*p == 0) - *ptr = p; - if (*p != ',' && *p != '=') - return 0; - p++; - } else if (*p) { - return 0; - } - *ptr = p; - return ret; -} - -static const char *skip_linker_arg(const char **str) -{ - const char *s1 = *str; - const char *s2 = strchr(s1, ','); - *str = s2 ? s2++ : (s2 = s1 + strlen(s1)); - return s2; -} - -static void copy_linker_arg(char **pp, const char *s, int sep) -{ - const char *q = s; - char *p = *pp; - int l = 0; - if (p && sep) - p[l = strlen(p)] = sep, ++l; - skip_linker_arg(&q); - pstrncpy(l + (*pp = tcc_realloc(p, q - s + l + 1)), s, q - s); -} - -static void args_parser_add_file(TCCState *s, const char* filename, int filetype) -{ - struct filespec *f = tcc_malloc(sizeof *f + strlen(filename)); - f->type = filetype; - strcpy(f->name, filename); - dynarray_add(&s->files, &s->nb_files, f); -} - -/* set linker options */ -static int tcc_set_linker(TCCState *s, const char *option) -{ - TCCState *s1 = s; - while (*option) { - - const char *p = NULL; - char *end = NULL; - int ignoring = 0; - int ret; - - if (link_option(option, "Bsymbolic", &p)) { - s->symbolic = 1; - } else if (link_option(option, "nostdlib", &p)) { - s->nostdlib = 1; - } else if (link_option(option, "e=", &p) - || link_option(option, "entry=", &p)) { - copy_linker_arg(&s->elf_entryname, p, 0); - } else if (link_option(option, "fini=", &p)) { - copy_linker_arg(&s->fini_symbol, p, 0); - ignoring = 1; - } else if (link_option(option, "image-base=", &p) - || link_option(option, "Ttext=", &p)) { - s->text_addr = strtoull(p, &end, 16); - s->has_text_addr = 1; - } else if (link_option(option, "init=", &p)) { - copy_linker_arg(&s->init_symbol, p, 0); - ignoring = 1; - } else if (link_option(option, "Map=", &p)) { - copy_linker_arg(&s->mapfile, p, 0); - ignoring = 1; - } else if (link_option(option, "oformat=", &p)) { -#if defined(TCC_TARGET_PE) - if (strstart("pe-", &p)) { -#elif PTR_SIZE == 8 - if (strstart("elf64-", &p)) { -#else - if (strstart("elf32-", &p)) { -#endif - s->output_format = TCC_OUTPUT_FORMAT_ELF; - } else if (!strcmp(p, "binary")) { - s->output_format = TCC_OUTPUT_FORMAT_BINARY; -#ifdef TCC_TARGET_COFF - } else if (!strcmp(p, "coff")) { - s->output_format = TCC_OUTPUT_FORMAT_COFF; -#endif - } else - goto err; - - } else if (link_option(option, "as-needed", &p)) { - ignoring = 1; - } else if (link_option(option, "O", &p)) { - ignoring = 1; - } else if (link_option(option, "export-all-symbols", &p)) { - s->rdynamic = 1; - } else if (link_option(option, "export-dynamic", &p)) { - s->rdynamic = 1; - } else if (link_option(option, "rpath=", &p)) { - copy_linker_arg(&s->rpath, p, ':'); - } else if (link_option(option, "enable-new-dtags", &p)) { - s->enable_new_dtags = 1; - } else if (link_option(option, "section-alignment=", &p)) { - s->section_align = strtoul(p, &end, 16); - } else if (link_option(option, "soname=", &p)) { - copy_linker_arg(&s->soname, p, 0); - } else if (link_option(option, "install_name=", &p)) { - copy_linker_arg(&s->soname, p, 0); -#ifdef TCC_TARGET_PE - } else if (link_option(option, "large-address-aware", &p)) { - s->pe_characteristics |= 0x20; - } else if (link_option(option, "file-alignment=", &p)) { - s->pe_file_align = strtoul(p, &end, 16); - } else if (link_option(option, "stack=", &p)) { - s->pe_stack_size = strtoul(p, &end, 10); - } else if (link_option(option, "subsystem=", &p)) { -#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) - if (!strcmp(p, "native")) { - s->pe_subsystem = 1; - } else if (!strcmp(p, "console")) { - s->pe_subsystem = 3; - } else if (!strcmp(p, "gui") || !strcmp(p, "windows")) { - s->pe_subsystem = 2; - } else if (!strcmp(p, "posix")) { - s->pe_subsystem = 7; - } else if (!strcmp(p, "efiapp")) { - s->pe_subsystem = 10; - } else if (!strcmp(p, "efiboot")) { - s->pe_subsystem = 11; - } else if (!strcmp(p, "efiruntime")) { - s->pe_subsystem = 12; - } else if (!strcmp(p, "efirom")) { - s->pe_subsystem = 13; -#elif defined(TCC_TARGET_ARM) - if (!strcmp(p, "wince")) { - s->pe_subsystem = 9; -#endif - } else - goto err; -#endif -#ifdef TCC_TARGET_MACHO - } else if (link_option(option, "all_load", &p)) { - s->filetype |= AFF_WHOLE_ARCHIVE; - } else if (link_option(option, "force_load", &p)) { - s->filetype |= AFF_WHOLE_ARCHIVE; - args_parser_add_file(s, p, AFF_TYPE_LIB | (s->filetype & ~AFF_TYPE_MASK)); - s->nb_libraries++; - } else if (link_option(option, "single_module", &p)) { - ignoring = 1; -#endif - } else if (ret = link_option(option, "?whole-archive", &p), ret) { - if (ret > 0) - s->filetype |= AFF_WHOLE_ARCHIVE; - else - s->filetype &= ~AFF_WHOLE_ARCHIVE; - } else if (link_option(option, "z=", &p)) { - ignoring = 1; - } else if (p) { - return 0; - } else { - err: - return tcc_error_noabort("unsupported linker option '%s'", option); - } - if (ignoring) - tcc_warning_c(warn_unsupported)("unsupported linker option '%s'", option); - option = skip_linker_arg(&p); - } - return 1; -} - -typedef struct TCCOption { - const char *name; - uint16_t index; - uint16_t flags; -} TCCOption; - -enum { - TCC_OPTION_ignored = 0, - TCC_OPTION_HELP, - TCC_OPTION_HELP2, - TCC_OPTION_v, - TCC_OPTION_I, - TCC_OPTION_D, - TCC_OPTION_U, - TCC_OPTION_P, - TCC_OPTION_L, - TCC_OPTION_B, - TCC_OPTION_l, - TCC_OPTION_bench, - TCC_OPTION_bt, - TCC_OPTION_b, - TCC_OPTION_ba, - TCC_OPTION_g, - TCC_OPTION_c, - TCC_OPTION_dumpversion, - TCC_OPTION_d, - TCC_OPTION_static, - TCC_OPTION_std, - TCC_OPTION_shared, - TCC_OPTION_soname, - TCC_OPTION_o, - TCC_OPTION_r, - TCC_OPTION_Wl, - TCC_OPTION_Wp, - TCC_OPTION_W, - TCC_OPTION_O, - TCC_OPTION_mfloat_abi, - TCC_OPTION_m, - TCC_OPTION_f, - TCC_OPTION_isystem, - TCC_OPTION_iwithprefix, - TCC_OPTION_include, - TCC_OPTION_nostdinc, - TCC_OPTION_nostdlib, - TCC_OPTION_print_search_dirs, - TCC_OPTION_rdynamic, - TCC_OPTION_pthread, - TCC_OPTION_run, - TCC_OPTION_w, - TCC_OPTION_E, - TCC_OPTION_M, - TCC_OPTION_MD, - TCC_OPTION_MF, - TCC_OPTION_MM, - TCC_OPTION_MMD, - TCC_OPTION_x, - TCC_OPTION_ar, - TCC_OPTION_impdef, - TCC_OPTION_dynamiclib, - TCC_OPTION_flat_namespace, - TCC_OPTION_two_levelnamespace, - TCC_OPTION_undefined, - TCC_OPTION_install_name, - TCC_OPTION_compatibility_version , - TCC_OPTION_current_version, -}; - -#define TCC_OPTION_HAS_ARG 0x0001 -#define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */ - -static const TCCOption tcc_options[] = { - { "h", TCC_OPTION_HELP, 0 }, - { "-help", TCC_OPTION_HELP, 0 }, - { "?", TCC_OPTION_HELP, 0 }, - { "hh", TCC_OPTION_HELP2, 0 }, - { "v", TCC_OPTION_v, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "-version", TCC_OPTION_v, 0 }, /* handle as verbose, also prints version*/ - { "I", TCC_OPTION_I, TCC_OPTION_HAS_ARG }, - { "D", TCC_OPTION_D, TCC_OPTION_HAS_ARG }, - { "U", TCC_OPTION_U, TCC_OPTION_HAS_ARG }, - { "P", TCC_OPTION_P, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "L", TCC_OPTION_L, TCC_OPTION_HAS_ARG }, - { "B", TCC_OPTION_B, TCC_OPTION_HAS_ARG }, - { "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG }, - { "bench", TCC_OPTION_bench, 0 }, -#ifdef CONFIG_TCC_BACKTRACE - { "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, -#endif -#ifdef CONFIG_TCC_BCHECK - { "b", TCC_OPTION_b, 0 }, -#endif - { "g", TCC_OPTION_g, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, -#ifdef TCC_TARGET_MACHO - { "compatibility_version", TCC_OPTION_compatibility_version, TCC_OPTION_HAS_ARG }, - { "current_version", TCC_OPTION_current_version, TCC_OPTION_HAS_ARG }, -#endif - { "c", TCC_OPTION_c, 0 }, -#ifdef TCC_TARGET_MACHO - { "dynamiclib", TCC_OPTION_dynamiclib, 0 }, -#endif - { "dumpversion", TCC_OPTION_dumpversion, 0}, - { "d", TCC_OPTION_d, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "static", TCC_OPTION_static, 0 }, - { "std", TCC_OPTION_std, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "shared", TCC_OPTION_shared, 0 }, - { "soname", TCC_OPTION_soname, TCC_OPTION_HAS_ARG }, - { "o", TCC_OPTION_o, TCC_OPTION_HAS_ARG }, - { "pthread", TCC_OPTION_pthread, 0}, - { "run", TCC_OPTION_run, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "rdynamic", TCC_OPTION_rdynamic, 0 }, - { "r", TCC_OPTION_r, 0 }, - { "Wl,", TCC_OPTION_Wl, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "Wp,", TCC_OPTION_Wp, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "W", TCC_OPTION_W, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "O", TCC_OPTION_O, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, -#ifdef TCC_TARGET_ARM - { "mfloat-abi", TCC_OPTION_mfloat_abi, TCC_OPTION_HAS_ARG }, -#endif - { "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, -#ifdef TCC_TARGET_MACHO - { "flat_namespace", TCC_OPTION_flat_namespace, 0 }, -#endif - { "f", TCC_OPTION_f, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "isystem", TCC_OPTION_isystem, TCC_OPTION_HAS_ARG }, - { "include", TCC_OPTION_include, TCC_OPTION_HAS_ARG }, - { "nostdinc", TCC_OPTION_nostdinc, 0 }, - { "nostdlib", TCC_OPTION_nostdlib, 0 }, - { "print-search-dirs", TCC_OPTION_print_search_dirs, 0 }, - { "w", TCC_OPTION_w, 0 }, - { "E", TCC_OPTION_E, 0}, - { "M", TCC_OPTION_M, 0}, - { "MD", TCC_OPTION_MD, 0}, - { "MF", TCC_OPTION_MF, TCC_OPTION_HAS_ARG }, - { "MM", TCC_OPTION_MM, 0}, - { "MMD", TCC_OPTION_MMD, 0}, - { "x", TCC_OPTION_x, TCC_OPTION_HAS_ARG }, - { "ar", TCC_OPTION_ar, 0}, -#ifdef TCC_TARGET_PE - { "impdef", TCC_OPTION_impdef, 0}, -#endif -#ifdef TCC_TARGET_MACHO - { "install_name", TCC_OPTION_install_name, TCC_OPTION_HAS_ARG }, - { "two_levelnamespace", TCC_OPTION_two_levelnamespace, 0 }, - { "undefined", TCC_OPTION_undefined, TCC_OPTION_HAS_ARG }, -#endif - /* ignored (silently, except after -Wunsupported) */ - { "arch", 0, TCC_OPTION_HAS_ARG}, - { "C", 0, 0 }, - { "-param", 0, TCC_OPTION_HAS_ARG }, - { "pedantic", 0, 0 }, - { "pipe", 0, 0 }, - { "s", 0, 0 }, - { "traditional", 0, 0 }, - { NULL, 0, 0 }, -}; - -typedef struct FlagDef { - uint16_t offset; - uint16_t flags; - const char *name; -} FlagDef; - -#define WD_ALL 0x0001 /* warning is activated when using -Wall */ -#define FD_INVERT 0x0002 /* invert value before storing */ - -static const FlagDef options_W[] = { - { offsetof(TCCState, warn_all), WD_ALL, "all" }, - { offsetof(TCCState, warn_error), 0, "error" }, - { offsetof(TCCState, warn_write_strings), 0, "write-strings" }, - { offsetof(TCCState, warn_unsupported), 0, "unsupported" }, - { offsetof(TCCState, warn_implicit_function_declaration), WD_ALL, "implicit-function-declaration" }, - { offsetof(TCCState, warn_discarded_qualifiers), WD_ALL, "discarded-qualifiers" }, - { 0, 0, NULL } -}; - -static const FlagDef options_f[] = { - { offsetof(TCCState, char_is_unsigned), 0, "unsigned-char" }, - { offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" }, - { offsetof(TCCState, nocommon), FD_INVERT, "common" }, - { offsetof(TCCState, leading_underscore), 0, "leading-underscore" }, - { offsetof(TCCState, ms_extensions), 0, "ms-extensions" }, - { offsetof(TCCState, dollars_in_identifiers), 0, "dollars-in-identifiers" }, - { offsetof(TCCState, test_coverage), 0, "test-coverage" }, - { 0, 0, NULL } -}; - -static const FlagDef options_m[] = { - { offsetof(TCCState, ms_bitfields), 0, "ms-bitfields" }, -#ifdef TCC_TARGET_X86_64 - { offsetof(TCCState, nosse), FD_INVERT, "sse" }, -#endif - { 0, 0, NULL } -}; - -static int set_flag(TCCState *s, const FlagDef *flags, const char *name) -{ - int value, mask, ret; - const FlagDef *p; - const char *r; - unsigned char *f; - - r = name, value = !strstart("no-", &r), mask = 0; - - /* when called with options_W, look for -W[no-]error=<option> */ - if ((flags->flags & WD_ALL) && strstart("error=", &r)) - value = value ? WARN_ON|WARN_ERR : WARN_NOE, mask = WARN_ON; - - for (ret = -1, p = flags; p->name; ++p) { - if (ret) { - if (strcmp(r, p->name)) - continue; - } else { - if (0 == (p->flags & WD_ALL)) - continue; - } - - f = (unsigned char *)s + p->offset; - *f = (*f & mask) | (value ^ !!(p->flags & FD_INVERT)); - - if (ret) { - ret = 0; - if (strcmp(r, "all")) - break; - } - } - return ret; -} - -static int args_parser_make_argv(const char *r, int *argc, char ***argv) -{ - int ret = 0, q, c; - CString str; - for(;;) { - while (c = (unsigned char)*r, c && c <= ' ') - ++r; - if (c == 0) - break; - q = 0; - cstr_new(&str); - while (c = (unsigned char)*r, c) { - ++r; - if (c == '\\' && (*r == '"' || *r == '\\')) { - c = *r++; - } else if (c == '"') { - q = !q; - continue; - } else if (q == 0 && c <= ' ') { - break; - } - cstr_ccat(&str, c); - } - cstr_ccat(&str, 0); - //printf("<%s>\n", str.data), fflush(stdout); - dynarray_add(argv, argc, tcc_strdup(str.data)); - cstr_free(&str); - ++ret; - } - return ret; -} - -/* read list file */ -static int args_parser_listfile(TCCState *s, - const char *filename, int optind, int *pargc, char ***pargv) -{ - TCCState *s1 = s; - int fd, i; - char *p; - int argc = 0; - char **argv = NULL; - - fd = open(filename, O_RDONLY | O_BINARY); - if (fd < 0) - return tcc_error_noabort("listfile '%s' not found", filename); - - p = tcc_load_text(fd); - for (i = 0; i < *pargc; ++i) - if (i == optind) - args_parser_make_argv(p, &argc, &argv); - else - dynarray_add(&argv, &argc, tcc_strdup((*pargv)[i])); - - tcc_free(p); - dynarray_reset(&s->argv, &s->argc); - *pargc = s->argc = argc, *pargv = s->argv = argv; - return 0; -} - -#if defined TCC_TARGET_MACHO -static uint32_t parse_version(TCCState *s1, const char *version) -{ - uint32_t a = 0; - uint32_t b = 0; - uint32_t c = 0; - char* last; - - a = strtoul(version, &last, 10); - if (*last == '.') { - b = strtoul(&last[1], &last, 10); - if (*last == '.') - c = strtoul(&last[1], &last, 10); - } - if (*last || a > 0xffff || b > 0xff || c > 0xff) - tcc_error_noabort("version a.b.c not correct: %s", version); - return (a << 16) | (b << 8) | c; -} -#endif - -PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv, int optind) -{ - TCCState *s1 = s; - const TCCOption *popt; - const char *optarg, *r; - const char *run = NULL; - int x; - int tool = 0, arg_start = 0, noaction = optind; - char **argv = *pargv; - int argc = *pargc; - - cstr_reset(&s->linker_arg); - - while (optind < argc) { - r = argv[optind]; - if (r[0] == '@' && r[1] != '\0') { - if (args_parser_listfile(s, r + 1, optind, &argc, &argv)) - return -1; - continue; - } - optind++; - if (tool) { - if (r[0] == '-' && r[1] == 'v' && r[2] == 0) - ++s->verbose; - continue; - } -reparse: - if (r[0] != '-' || r[1] == '\0') { - args_parser_add_file(s, r, s->filetype); - if (run) { -dorun: - if (tcc_set_options(s, run)) - return -1; - arg_start = optind - 1; - break; - } - continue; - } - - /* allow "tcc files... -run -- args ..." */ - if (r[1] == '-' && r[2] == '\0' && run) - goto dorun; - - /* find option in table */ - for(popt = tcc_options; ; ++popt) { - const char *p1 = popt->name; - const char *r1 = r + 1; - if (p1 == NULL) - return tcc_error_noabort("invalid option -- '%s'", r); - if (!strstart(p1, &r1)) - continue; - optarg = r1; - if (popt->flags & TCC_OPTION_HAS_ARG) { - if (*r1 == '\0' && !(popt->flags & TCC_OPTION_NOSEP)) { - if (optind >= argc) - arg_err: - return tcc_error_noabort("argument to '%s' is missing", r); - optarg = argv[optind++]; - } - } else if (*r1 != '\0') - continue; - break; - } - - switch(popt->index) { - case TCC_OPTION_HELP: - x = OPT_HELP; - goto extra_action; - case TCC_OPTION_HELP2: - x = OPT_HELP2; - goto extra_action; - case TCC_OPTION_I: - tcc_add_include_path(s, optarg); - break; - case TCC_OPTION_D: - tcc_define_symbol(s, optarg, NULL); - break; - case TCC_OPTION_U: - tcc_undefine_symbol(s, optarg); - break; - case TCC_OPTION_L: - tcc_add_library_path(s, optarg); - break; - case TCC_OPTION_B: - /* set tcc utilities path (mainly for tcc development) */ - tcc_set_lib_path(s, optarg); - ++noaction; - break; - case TCC_OPTION_l: - args_parser_add_file(s, optarg, AFF_TYPE_LIB | (s->filetype & ~AFF_TYPE_MASK)); - s->nb_libraries++; - break; - case TCC_OPTION_pthread: - s->option_pthread = 1; - break; - case TCC_OPTION_bench: - s->do_bench = 1; - break; -#ifdef CONFIG_TCC_BACKTRACE - case TCC_OPTION_bt: - s->rt_num_callers = atoi(optarg); - s->do_backtrace = 1; - s->do_debug = 1; - s->dwarf = DWARF_VERSION; - break; -#endif -#ifdef CONFIG_TCC_BCHECK - case TCC_OPTION_b: - s->do_bounds_check = 1; - s->do_backtrace = 1; - s->do_debug = 1; - s->dwarf = DWARF_VERSION; - break; -#endif - case TCC_OPTION_g: - s->do_debug = 1; - s->dwarf = DWARF_VERSION; - - if (strstart("dwarf", &optarg)) - s->dwarf = (*optarg) ? (0 - atoi(optarg)) : DEFAULT_DWARF_VERSION; - break; - case TCC_OPTION_c: - x = TCC_OUTPUT_OBJ; - set_output_type: - if (s->output_type) - tcc_warning("-%s: overriding compiler action already specified", popt->name); - s->output_type = x; - break; - case TCC_OPTION_d: - if (*optarg == 'D') - s->dflag = 3; - else if (*optarg == 'M') - s->dflag = 7; - else if (*optarg == 't') - s->dflag = 16; - else if (isnum(*optarg)) - s->g_debug |= atoi(optarg); - else - goto unsupported_option; - break; - case TCC_OPTION_static: - s->static_link = 1; - break; - case TCC_OPTION_std: - if (strcmp(optarg, "=c11") == 0) - s->cversion = 201112; - break; - case TCC_OPTION_shared: - x = TCC_OUTPUT_DLL; - goto set_output_type; - case TCC_OPTION_soname: - s->soname = tcc_strdup(optarg); - break; - case TCC_OPTION_o: - if (s->outfile) { - tcc_warning("multiple -o option"); - tcc_free(s->outfile); - } - s->outfile = tcc_strdup(optarg); - break; - case TCC_OPTION_r: - /* generate a .o merging several output files */ - s->option_r = 1; - x = TCC_OUTPUT_OBJ; - goto set_output_type; - case TCC_OPTION_isystem: - tcc_add_sysinclude_path(s, optarg); - break; - case TCC_OPTION_include: - cstr_printf(&s->cmdline_incl, "#include \"%s\"\n", optarg); - break; - case TCC_OPTION_nostdinc: - s->nostdinc = 1; - break; - case TCC_OPTION_nostdlib: - s->nostdlib = 1; - break; - case TCC_OPTION_run: -#ifndef TCC_IS_NATIVE - return tcc_error_noabort("-run is not available in a cross compiler"); -#else - run = optarg; - x = TCC_OUTPUT_MEMORY; - goto set_output_type; -#endif - case TCC_OPTION_v: - do ++s->verbose; while (*optarg++ == 'v'); - ++noaction; - break; - case TCC_OPTION_f: - if (set_flag(s, options_f, optarg) < 0) - goto unsupported_option; - break; -#ifdef TCC_TARGET_ARM - case TCC_OPTION_mfloat_abi: - /* tcc doesn't support soft float yet */ - if (!strcmp(optarg, "softfp")) { - s->float_abi = ARM_SOFTFP_FLOAT; - } else if (!strcmp(optarg, "hard")) - s->float_abi = ARM_HARD_FLOAT; - else - return tcc_error_noabort("unsupported float abi '%s'", optarg); - break; -#endif - case TCC_OPTION_m: - if (set_flag(s, options_m, optarg) < 0) { - if (x = atoi(optarg), x != 32 && x != 64) - goto unsupported_option; - if (PTR_SIZE != x/8) - return x; - ++noaction; - } - break; - case TCC_OPTION_W: - s->warn_none = 0; - if (optarg[0] && set_flag(s, options_W, optarg) < 0) - goto unsupported_option; - break; - case TCC_OPTION_w: - s->warn_none = 1; - break; - case TCC_OPTION_rdynamic: - s->rdynamic = 1; - break; - case TCC_OPTION_Wl: - if (s->linker_arg.size) - ((char*)s->linker_arg.data)[s->linker_arg.size - 1] = ','; - cstr_cat(&s->linker_arg, optarg, 0); - x = tcc_set_linker(s, s->linker_arg.data); - if (x) - cstr_reset(&s->linker_arg); - if (x < 0) - return -1; - break; - case TCC_OPTION_Wp: - r = optarg; - goto reparse; - case TCC_OPTION_E: - x = TCC_OUTPUT_PREPROCESS; - goto set_output_type; - case TCC_OPTION_P: - s->Pflag = atoi(optarg) + 1; - break; - case TCC_OPTION_M: - s->include_sys_deps = 1; - // fall through - case TCC_OPTION_MM: - s->just_deps = 1; - if(!s->deps_outfile) - s->deps_outfile = tcc_strdup("-"); - // fall through - case TCC_OPTION_MMD: - s->gen_deps = 1; - break; - case TCC_OPTION_MD: - s->gen_deps = 1; - s->include_sys_deps = 1; - break; - case TCC_OPTION_MF: - s->deps_outfile = tcc_strdup(optarg); - break; - case TCC_OPTION_dumpversion: - printf ("%s\n", TCC_VERSION); - exit(0); - break; - case TCC_OPTION_x: - x = 0; - if (*optarg == 'c') - x = AFF_TYPE_C; - else if (*optarg == 'a') - x = AFF_TYPE_ASMPP; - else if (*optarg == 'b') - x = AFF_TYPE_BIN; - else if (*optarg == 'n') - x = AFF_TYPE_NONE; - else - tcc_warning("unsupported language '%s'", optarg); - s->filetype = x | (s->filetype & ~AFF_TYPE_MASK); - break; - case TCC_OPTION_O: - s->optimize = atoi(optarg); - break; - case TCC_OPTION_print_search_dirs: - x = OPT_PRINT_DIRS; - goto extra_action; - case TCC_OPTION_impdef: - x = OPT_IMPDEF; - goto extra_action; -#if defined TCC_TARGET_MACHO - case TCC_OPTION_dynamiclib: - x = TCC_OUTPUT_DLL; - goto set_output_type; - case TCC_OPTION_flat_namespace: - break; - case TCC_OPTION_two_levelnamespace: - break; - case TCC_OPTION_undefined: - break; - case TCC_OPTION_install_name: - s->install_name = tcc_strdup(optarg); - break; - case TCC_OPTION_compatibility_version: - s->compatibility_version = parse_version(s, optarg); - break; - case TCC_OPTION_current_version: - s->current_version = parse_version(s, optarg);; - break; -#endif - case TCC_OPTION_ar: - x = OPT_AR; - extra_action: - arg_start = optind - 1; - if (arg_start != noaction) - return tcc_error_noabort("cannot parse %s here", r); - tool = x; - break; - default: -unsupported_option: - tcc_warning_c(warn_unsupported)("unsupported option '%s'", r); - break; - } - } - if (s->linker_arg.size) { - r = s->linker_arg.data; - goto arg_err; - } - *pargc = argc - arg_start; - *pargv = argv + arg_start; - if (tool) - return tool; - if (optind != noaction) - return 0; - if (s->verbose == 2) - return OPT_PRINT_DIRS; - if (s->verbose) - return OPT_V; - return OPT_HELP; -} - -LIBTCCAPI int tcc_set_options(TCCState *s, const char *r) -{ - char **argv = NULL; - int argc = 0, ret; - args_parser_make_argv(r, &argc, &argv); - ret = tcc_parse_args(s, &argc, &argv, 0); - dynarray_reset(&argv, &argc); - return ret < 0 ? ret : 0; -} - -PUB_FUNC void tcc_print_stats(TCCState *s1, unsigned total_time) -{ - if (!total_time) - total_time = 1; - fprintf(stderr, "# %d idents, %d lines, %u bytes\n" - "# %0.3f s, %u lines/s, %0.1f MB/s\n", - total_idents, total_lines, total_bytes, - (double)total_time/1000, - (unsigned)total_lines*1000/total_time, - (double)total_bytes/1000/total_time); - fprintf(stderr, "# text %u, data.rw %u, data.ro %u, bss %u bytes\n", - s1->total_output[0], - s1->total_output[1], - s1->total_output[2], - s1->total_output[3] - ); -#ifdef MEM_DEBUG - fprintf(stderr, "# %d bytes memory used\n", mem_max_size); -#endif -} diff --git a/tinycc/libtcc.h b/tinycc/libtcc.h deleted file mode 100644 index 8450ba8..0000000 --- a/tinycc/libtcc.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef LIBTCC_H -#define LIBTCC_H - -#ifndef LIBTCCAPI -# define LIBTCCAPI -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -struct TCCState; - -typedef struct TCCState TCCState; - -typedef void (*TCCErrorFunc)(void *opaque, const char *msg); - -/* create a new TCC compilation context */ -LIBTCCAPI TCCState *tcc_new(void); - -/* free a TCC compilation context */ -LIBTCCAPI void tcc_delete(TCCState *s); - -/* set CONFIG_TCCDIR at runtime */ -LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path); - -/* set error/warning display callback */ -LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, TCCErrorFunc error_func); - -/* return error/warning callback */ -LIBTCCAPI TCCErrorFunc tcc_get_error_func(TCCState *s); - -/* return error/warning callback opaque pointer */ -LIBTCCAPI void *tcc_get_error_opaque(TCCState *s); - -/* set options as from command line (multiple supported) */ -LIBTCCAPI int tcc_set_options(TCCState *s, const char *str); - -/*****************************/ -/* preprocessor */ - -/* add include path */ -LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname); - -/* add in system include path */ -LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname); - -/* define preprocessor symbol 'sym'. value can be NULL, sym can be "sym=val" */ -LIBTCCAPI void tcc_define_symbol(TCCState *s, const char *sym, const char *value); - -/* undefine preprocess symbol 'sym' */ -LIBTCCAPI void tcc_undefine_symbol(TCCState *s, const char *sym); - -/*****************************/ -/* compiling */ - -/* add a file (C file, dll, object, library, ld script). Return -1 if error. */ -LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename); - -/* compile a string containing a C source. Return -1 if error. */ -LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf); - -/*****************************/ -/* linking commands */ - -/* set output type. MUST BE CALLED before any compilation */ -LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type); -#define TCC_OUTPUT_MEMORY 1 /* output will be run in memory */ -#define TCC_OUTPUT_EXE 2 /* executable file */ -#define TCC_OUTPUT_DLL 4 /* dynamic library */ -#define TCC_OUTPUT_OBJ 3 /* object file */ -#define TCC_OUTPUT_PREPROCESS 5 /* only preprocess */ - -/* equivalent to -Lpath option */ -LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname); - -/* the library name is the same as the argument of the '-l' option */ -LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname); - -/* add a symbol to the compiled program */ -LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, const void *val); - -/* output an executable, library or object file. DO NOT call - tcc_relocate() before. */ -LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename); - -/* link and run main() function and return its value. DO NOT call - tcc_relocate() before. */ -LIBTCCAPI int tcc_run(TCCState *s, int argc, char **argv); - -/* do all relocations (needed before using tcc_get_symbol()) */ -LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr); -/* possible values for 'ptr': - - TCC_RELOCATE_AUTO : Allocate and manage memory internally - - NULL : return required memory size for the step below - - memory address : copy code to memory passed by the caller - returns -1 if error. */ -#define TCC_RELOCATE_AUTO (void*)1 - -/* return symbol value or NULL if not found */ -LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name); - -/* return symbol value or NULL if not found */ -LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx, - void (*symbol_cb)(void *ctx, const char *name, const void *val)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/tinycc/stab.def b/tinycc/stab.def deleted file mode 100644 index 48ea231..0000000 --- a/tinycc/stab.def +++ /dev/null @@ -1,234 +0,0 @@ -/* Table of DBX symbol codes for the GNU system. - Copyright (C) 1988, 1997 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -/* This contains contribution from Cygnus Support. */ - -/* Global variable. Only the name is significant. - To find the address, look in the corresponding external symbol. */ -__define_stab (N_GSYM, 0x20, "GSYM") - -/* Function name for BSD Fortran. Only the name is significant. - To find the address, look in the corresponding external symbol. */ -__define_stab (N_FNAME, 0x22, "FNAME") - -/* Function name or text-segment variable for C. Value is its address. - Desc is supposedly starting line number, but GCC doesn't set it - and DBX seems not to miss it. */ -__define_stab (N_FUN, 0x24, "FUN") - -/* Data-segment variable with internal linkage. Value is its address. - "Static Sym". */ -__define_stab (N_STSYM, 0x26, "STSYM") - -/* BSS-segment variable with internal linkage. Value is its address. */ -__define_stab (N_LCSYM, 0x28, "LCSYM") - -/* Name of main routine. Only the name is significant. - This is not used in C. */ -__define_stab (N_MAIN, 0x2a, "MAIN") - -/* Global symbol in Pascal. - Supposedly the value is its line number; I'm skeptical. */ -__define_stab (N_PC, 0x30, "PC") - -/* Number of symbols: 0, files,,funcs,lines according to Ultrix V4.0. */ -__define_stab (N_NSYMS, 0x32, "NSYMS") - -/* "No DST map for sym: name, ,0,type,ignored" according to Ultrix V4.0. */ -__define_stab (N_NOMAP, 0x34, "NOMAP") - -/* New stab from Solaris. I don't know what it means, but it - don't seem to contain useful information. */ -__define_stab (N_OBJ, 0x38, "OBJ") - -/* New stab from Solaris. I don't know what it means, but it - don't seem to contain useful information. Possibly related to the - optimization flags used in this module. */ -__define_stab (N_OPT, 0x3c, "OPT") - -/* Register variable. Value is number of register. */ -__define_stab (N_RSYM, 0x40, "RSYM") - -/* Modula-2 compilation unit. Can someone say what info it contains? */ -__define_stab (N_M2C, 0x42, "M2C") - -/* Line number in text segment. Desc is the line number; - value is corresponding address. */ -__define_stab (N_SLINE, 0x44, "SLINE") - -/* Similar, for data segment. */ -__define_stab (N_DSLINE, 0x46, "DSLINE") - -/* Similar, for bss segment. */ -__define_stab (N_BSLINE, 0x48, "BSLINE") - -/* Sun's source-code browser stabs. ?? Don't know what the fields are. - Supposedly the field is "path to associated .cb file". THIS VALUE - OVERLAPS WITH N_BSLINE! */ -__define_stab (N_BROWS, 0x48, "BROWS") - -/* GNU Modula-2 definition module dependency. Value is the modification time - of the definition file. Other is non-zero if it is imported with the - GNU M2 keyword %INITIALIZE. Perhaps N_M2C can be used if there - are enough empty fields? */ -__define_stab(N_DEFD, 0x4a, "DEFD") - -/* THE FOLLOWING TWO STAB VALUES CONFLICT. Happily, one is for Modula-2 - and one is for C++. Still,... */ -/* GNU C++ exception variable. Name is variable name. */ -__define_stab (N_EHDECL, 0x50, "EHDECL") -/* Modula2 info "for imc": name,,0,0,0 according to Ultrix V4.0. */ -__define_stab (N_MOD2, 0x50, "MOD2") - -/* GNU C++ `catch' clause. Value is its address. Desc is nonzero if - this entry is immediately followed by a CAUGHT stab saying what exception - was caught. Multiple CAUGHT stabs means that multiple exceptions - can be caught here. If Desc is 0, it means all exceptions are caught - here. */ -__define_stab (N_CATCH, 0x54, "CATCH") - -/* Structure or union element. Value is offset in the structure. */ -__define_stab (N_SSYM, 0x60, "SSYM") - -/* Name of main source file. - Value is starting text address of the compilation. */ -__define_stab (N_SO, 0x64, "SO") - -/* Automatic variable in the stack. Value is offset from frame pointer. - Also used for type descriptions. */ -__define_stab (N_LSYM, 0x80, "LSYM") - -/* Beginning of an include file. Only Sun uses this. - In an object file, only the name is significant. - The Sun linker puts data into some of the other fields. */ -__define_stab (N_BINCL, 0x82, "BINCL") - -/* Name of sub-source file (#include file). - Value is starting text address of the compilation. */ -__define_stab (N_SOL, 0x84, "SOL") - -/* Parameter variable. Value is offset from argument pointer. - (On most machines the argument pointer is the same as the frame pointer. */ -__define_stab (N_PSYM, 0xa0, "PSYM") - -/* End of an include file. No name. - This and N_BINCL act as brackets around the file's output. - In an object file, there is no significant data in this entry. - The Sun linker puts data into some of the fields. */ -__define_stab (N_EINCL, 0xa2, "EINCL") - -/* Alternate entry point. Value is its address. */ -__define_stab (N_ENTRY, 0xa4, "ENTRY") - -/* Beginning of lexical block. - The desc is the nesting level in lexical blocks. - The value is the address of the start of the text for the block. - The variables declared inside the block *precede* the N_LBRAC symbol. */ -__define_stab (N_LBRAC, 0xc0, "LBRAC") - -/* Place holder for deleted include file. Replaces a N_BINCL and everything - up to the corresponding N_EINCL. The Sun linker generates these when - it finds multiple identical copies of the symbols from an include file. - This appears only in output from the Sun linker. */ -__define_stab (N_EXCL, 0xc2, "EXCL") - -/* Modula-2 scope information. Can someone say what info it contains? */ -__define_stab (N_SCOPE, 0xc4, "SCOPE") - -/* End of a lexical block. Desc matches the N_LBRAC's desc. - The value is the address of the end of the text for the block. */ -__define_stab (N_RBRAC, 0xe0, "RBRAC") - -/* Begin named common block. Only the name is significant. */ -__define_stab (N_BCOMM, 0xe2, "BCOMM") - -/* End named common block. Only the name is significant - (and it should match the N_BCOMM). */ -__define_stab (N_ECOMM, 0xe4, "ECOMM") - -/* End common (local name): value is address. - I'm not sure how this is used. */ -__define_stab (N_ECOML, 0xe8, "ECOML") - -/* These STAB's are used on Gould systems for Non-Base register symbols - or something like that. FIXME. I have assigned the values at random - since I don't have a Gould here. Fixups from Gould folk welcome... */ -__define_stab (N_NBTEXT, 0xF0, "NBTEXT") -__define_stab (N_NBDATA, 0xF2, "NBDATA") -__define_stab (N_NBBSS, 0xF4, "NBBSS") -__define_stab (N_NBSTS, 0xF6, "NBSTS") -__define_stab (N_NBLCS, 0xF8, "NBLCS") - -/* Second symbol entry containing a length-value for the preceding entry. - The value is the length. */ -__define_stab (N_LENG, 0xfe, "LENG") - -/* The above information, in matrix format. - - STAB MATRIX - _________________________________________________ - | 00 - 1F are not dbx stab symbols | - | In most cases, the low bit is the EXTernal bit| - - | 00 UNDEF | 02 ABS | 04 TEXT | 06 DATA | - | 01 |EXT | 03 |EXT | 05 |EXT | 07 |EXT | - - | 08 BSS | 0A INDR | 0C FN_SEQ | 0E | - | 09 |EXT | 0B | 0D | 0F | - - | 10 | 12 COMM | 14 SETA | 16 SETT | - | 11 | 13 | 15 | 17 | - - | 18 SETD | 1A SETB | 1C SETV | 1E WARNING| - | 19 | 1B | 1D | 1F FN | - - |_______________________________________________| - | Debug entries with bit 01 set are unused. | - | 20 GSYM | 22 FNAME | 24 FUN | 26 STSYM | - | 28 LCSYM | 2A MAIN | 2C | 2E | - | 30 PC | 32 NSYMS | 34 NOMAP | 36 | - | 38 OBJ | 3A | 3C OPT | 3E | - | 40 RSYM | 42 M2C | 44 SLINE | 46 DSLINE | - | 48 BSLINE*| 4A DEFD | 4C | 4E | - | 50 EHDECL*| 52 | 54 CATCH | 56 | - | 58 | 5A | 5C | 5E | - | 60 SSYM | 62 | 64 SO | 66 | - | 68 | 6A | 6C | 6E | - | 70 | 72 | 74 | 76 | - | 78 | 7A | 7C | 7E | - | 80 LSYM | 82 BINCL | 84 SOL | 86 | - | 88 | 8A | 8C | 8E | - | 90 | 92 | 94 | 96 | - | 98 | 9A | 9C | 9E | - | A0 PSYM | A2 EINCL | A4 ENTRY | A6 | - | A8 | AA | AC | AE | - | B0 | B2 | B4 | B6 | - | B8 | BA | BC | BE | - | C0 LBRAC | C2 EXCL | C4 SCOPE | C6 | - | C8 | CA | CC | CE | - | D0 | D2 | D4 | D6 | - | D8 | DA | DC | DE | - | E0 RBRAC | E2 BCOMM | E4 ECOMM | E6 | - | E8 ECOML | EA | EC | EE | - | F0 | F2 | F4 | F6 | - | F8 | FA | FC | FE LENG | - +-----------------------------------------------+ - * 50 EHDECL is also MOD2. - * 48 BSLINE is also BROWS. - */ diff --git a/tinycc/stab.h b/tinycc/stab.h deleted file mode 100644 index 80bd594..0000000 --- a/tinycc/stab.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef __GNU_STAB__ - -/* Indicate the GNU stab.h is in use. */ - -#define __GNU_STAB__ - -#define __define_stab(NAME, CODE, STRING) NAME=CODE, - -enum __stab_debug_code -{ -#include "stab.def" -LAST_UNUSED_STAB_CODE -}; - -#undef __define_stab - -#endif /* __GNU_STAB_ */ diff --git a/tinycc/tcc-doc.texi b/tinycc/tcc-doc.texi deleted file mode 100644 index 411cdd5..0000000 --- a/tinycc/tcc-doc.texi +++ /dev/null @@ -1,1396 +0,0 @@ -\input texinfo @c -*- texinfo -*- -@c %**start of header -@setfilename tcc-doc.info -@settitle Tiny C Compiler Reference Documentation -@dircategory Software development -@direntry -* TCC: (tcc-doc). The Tiny C Compiler. -@end direntry -@c %**end of header - -@include config.texi - -@iftex -@titlepage -@afourpaper -@sp 7 -@center @titlefont{Tiny C Compiler Reference Documentation} -@sp 3 -@end titlepage -@headings double -@end iftex - -@contents - -@node Top, Introduction, (dir), (dir) -@top Tiny C Compiler Reference Documentation - -This manual documents version @value{VERSION} of the Tiny C Compiler. - -@menu -* Introduction:: Introduction to tcc. -* Invoke:: Invocation of tcc (command line, options). -* Clang:: ANSI C and extensions. -* asm:: Assembler syntax. -* linker:: Output file generation and supported targets. -* Bounds:: Automatic bounds-checking of C code. -* Libtcc:: The libtcc library. -* devel:: Guide for Developers. -@end menu - - -@node Introduction -@chapter Introduction - -TinyCC (aka TCC) is a small but hyper fast C compiler. Unlike other C -compilers, it is meant to be self-relying: you do not need an -external assembler or linker because TCC does that for you. - -TCC compiles so @emph{fast} that even for big projects @code{Makefile}s may -not be necessary. - -TCC not only supports ANSI C, but also most of the new ISO C99 -standard and many GNUC extensions including inline assembly. - -TCC can also be used to make @emph{C scripts}, i.e. pieces of C source -that you run as a Perl or Python script. Compilation is so fast that -your script will be as fast as if it was an executable. - -TCC can also automatically generate memory and bound checks -(@pxref{Bounds}) while allowing all C pointers operations. TCC can do -these checks even if non patched libraries are used. - -With @code{libtcc}, you can use TCC as a backend for dynamic code -generation (@pxref{Libtcc}). - -TCC mainly supports the i386 target on Linux and Windows. There are alpha -ports for the ARM (@code{arm-tcc}) and the TMS320C67xx targets -(@code{c67-tcc}). More information about the ARM port is available at -@url{http://lists.gnu.org/archive/html/tinycc-devel/2003-10/msg00044.html}. - -For usage on Windows, see also @url{tcc-win32.txt}. - -@node Invoke -@chapter Command line invocation - -@section Quick start - -@example -@c man begin SYNOPSIS -usage: tcc [options] [@var{infile1} @var{infile2}@dots{}] [@option{-run} @var{infile} @var{args}@dots{}] -@c man end -@end example - -@noindent -@c man begin DESCRIPTION -TCC options are a very much like gcc options. The main difference is that TCC -can also execute directly the resulting program and give it runtime -arguments. - -Here are some examples to understand the logic: - -@table @code -@item @samp{tcc -run a.c} -Compile @file{a.c} and execute it directly - -@item @samp{tcc -run a.c arg1} -Compile a.c and execute it directly. arg1 is given as first argument to -the @code{main()} of a.c. - -@item @samp{tcc a.c -run b.c arg1} -Compile @file{a.c} and @file{b.c}, link them together and execute them. arg1 is given -as first argument to the @code{main()} of the resulting program. -@ignore -Because multiple C files are specified, @option{--} are necessary to clearly -separate the program arguments from the TCC options. -@end ignore - -@item @samp{tcc -o myprog a.c b.c} -Compile @file{a.c} and @file{b.c}, link them and generate the executable @file{myprog}. - -@item @samp{tcc -o myprog a.o b.o} -link @file{a.o} and @file{b.o} together and generate the executable @file{myprog}. - -@item @samp{tcc -c a.c} -Compile @file{a.c} and generate object file @file{a.o}. - -@item @samp{tcc -c asmfile.S} -Preprocess with C preprocess and assemble @file{asmfile.S} and generate -object file @file{asmfile.o}. - -@item @samp{tcc -c asmfile.s} -Assemble (but not preprocess) @file{asmfile.s} and generate object file -@file{asmfile.o}. - -@item @samp{tcc -r -o ab.o a.c b.c} -Compile @file{a.c} and @file{b.c}, link them together and generate the object file @file{ab.o}. - -@end table - -Scripting: - -TCC can be invoked from @emph{scripts}, just as shell scripts. You just -need to add @code{#!/usr/local/bin/tcc -run} at the start of your C source: - -@example -#!/usr/local/bin/tcc -run -#include <stdio.h> - -int main() -@{ - printf("Hello World\n"); - return 0; -@} -@end example - -TCC can read C source code from @emph{standard input} when @option{-} is used in -place of @option{infile}. Example: - -@example -echo 'main()@{puts("hello");@}' | tcc -run - -@end example -@c man end - -@section Option summary - -General Options: - -@c man begin OPTIONS -@table @option -@item -c -Generate an object file. - -@item -o outfile -Put object file, executable, or dll into output file @file{outfile}. - -@item -run source [args...] -Compile file @var{source} and run it with the command line arguments -@var{args}. In order to be able to give more than one argument to a -script, several TCC options can be given @emph{after} the -@option{-run} option, separated by spaces: -@example -tcc "-run -L/usr/X11R6/lib -lX11" ex4.c -@end example -In a script, it gives the following header: -@example -#!/usr/local/bin/tcc -run -L/usr/X11R6/lib -lX11 -@end example - -@item -v -Display TCC version. - -@item -vv -Show included files. As sole argument, print search dirs. -vvv shows tries too. - -@item -bench -Display compilation statistics. - -@end table - -Preprocessor options: - -@table @option -@item -Idir -Specify an additional include path. Include paths are searched in the -order they are specified. - -System include paths are always searched after. The default system -include paths are: @file{/usr/local/include}, @file{/usr/include} -and @file{PREFIX/lib/tcc/include}. (@file{PREFIX} is usually -@file{/usr} or @file{/usr/local}). - -@item -Dsym[=val] -Define preprocessor symbol @samp{sym} to -val. If val is not present, its value is @samp{1}. Function-like macros can -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 options has a negative form beginning with -@option{-fno-}. - -@table @option -@item -funsigned-char -Let the @code{char} type be unsigned. - -@item -fsigned-char -Let the @code{char} type be signed. - -@item -fno-common -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 - -@item -ftest-coverage -Create code coverage code. After running the resulting code an executable.tcov -or sofile.tcov file is generated with code coverage. - -@end table - -Warning options: - -@table @option -@item -w -Disable all warnings. - -@end table - -Note: each of the following warning options has a negative form beginning with -@option{-Wno-}. - -@table @option -@item -Wimplicit-function-declaration -Warn about implicit function declaration. - -@item -Wunsupported -Warn about unsupported GCC features that are ignored by TCC. - -@item -Wwrite-strings -Make string constants be of type @code{const char *} instead of @code{char -*}. - -@item -Werror -Abort compilation if a warning is issued. Can be given an option to enable -the specified warning and turn it into an error, for example -@option{-Werror=unsupported}. - -@item -Wall -Activate some useful warnings. - -@end table - -Linker options: - -@table @option -@item -Ldir -Specify an additional static library path for the @option{-l} option. The -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 and @env{LIBRARY_PATH} variable. - -@item -Bdir -Set the path where the tcc internal libraries (and include files) can be -found (default is @file{PREFIX/lib/tcc}). - -@item -shared -Generate a shared library instead of an executable. - -@item -soname name -set name for shared library to be used at runtime - -@item -static -Generate a statically linked executable (default is a shared linked -executable). - -@item -rdynamic -Export global symbols to the dynamic linker. It is useful when a library -opened with @code{dlopen()} needs to access executable symbols. - -@item -r -Generate an object file combining all input files. - -@item -Wl,-rpath=path -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: -@table @code -@item elf32-i386 -ELF output format (default) -@item binary -Binary image (only for executable output) -@item coff -COFF output format (only for executable output for TMS320C67xx target) -@end table - -@item -Wl,--export-all-symbols -@item -Wl,--export-dynamic -Export global symbols to the dynamic linker. It is useful when a library -opened with @code{dlopen()} needs to access executable symbols. - -@item -Wl,-subsystem=console/gui/wince/... -Set type for PE (Windows) executables. - -@item -Wl,-[Ttext=# | section-alignment=# | file-alignment=# | image-base=# | stack=#] -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: - -@table @option -@item -g -Generate run time stab debug information so that you get clear run time -error messages: @code{ test.c:68: in function 'test5()': dereferencing -invalid pointer} instead of the laconic @code{Segmentation -fault}. - -@item -gdwarf[-x] -Generate run time dwarf debug information instead of stab debug information. - -@item -b -Generate additional support code to check memory allocations and array/pointer -bounds (@pxref{Bounds}). @option{-g} is implied. - -@item -bt[N] -Display N callers in stack traces. This is useful with @option{-g} or @option{-b}. -With executables, additional support for stack traces is included. - -A function @code{ int tcc_backtrace(const char *fmt, ...); } is provided -to trigger a stack trace with a message on demand. - -@end table - -Misc options: - -@table @option - -@item -M -Just output makefile fragment with dependencies - -@item -MM -Like -M except mention only user header files, not system header files. - -@item -MD -Generate makefile fragment with dependencies. - -@item -MMD -Like -MD except mention only user header files, not system header files. - -@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 - -@c man begin AUTHOR -Fabrice Bellard -@c man end - -@end ignore - -@node Clang -@chapter C language support - -@section ANSI C - -TCC implements all the ANSI C standard, including structure bit fields -and floating point numbers (@code{long double}, @code{double}, and -@code{float} fully supported). - -@section ISOC99 extensions - -TCC implements many features of the new C standard: ISO C99. Currently -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. - -@item @code{__func__} is a string variable containing the current -function name. - -@item Variadic macros: @code{__VA_ARGS__} can be used for - function-like macros: -@example - #define dprintf(level, __VA_ARGS__) printf(__VA_ARGS__) -@end example - -@noindent -@code{dprintf} can then be used with a variable number of parameters. - -@item Declarations can appear anywhere in a block (as in C++). - -@item Array and struct/union elements can be initialized in any order by - using designators: -@example - struct @{ int x, y; @} st[10] = @{ [0].x = 1, [0].y = 2 @}; - - int tab[10] = @{ 1, 2, [5] = 5, [9] = 9@}; -@end example - -@item Compound initializers are supported: -@example - int *p = (int [])@{ 1, 2, 3 @}; -@end example -to initialize a pointer pointing to an initialized array. The same -works for structures and strings. - -@item Hexadecimal floating point constants are supported: -@example - double d = 0x1234p10; -@end example - -@noindent -is the same as writing -@example - double d = 4771840.0; -@end example - -@item @code{inline} keyword is ignored. - -@item @code{restrict} keyword is ignored. -@end itemize - -@section GNU C extensions - -TCC implements some GNU C extensions: - -@itemize - -@item array designators can be used without '=': -@example - int a[10] = @{ [0] 1, [5] 2, 3, 4 @}; -@end example - -@item Structure field designators can be a label: -@example - struct @{ int x, y; @} st = @{ x: 1, y: 1@}; -@end example -instead of -@example - struct @{ int x, y; @} st = @{ .x = 1, .y = 1@}; -@end example - -@item @code{\e} is ASCII character 27. - -@item case ranges : ranges can be used in @code{case}s: -@example - switch(a) @{ - case 1 @dots{} 9: - printf("range 1 to 9\n"); - break; - default: - printf("unexpected\n"); - break; - @} -@end example - -@cindex aligned attribute -@cindex packed attribute -@cindex section attribute -@cindex unused attribute -@cindex cdecl attribute -@cindex stdcall attribute -@cindex regparm attribute -@cindex dllexport attribute -@cindex nodecorate attribute - -@item The keyword @code{__attribute__} is handled to specify variable or -function attributes. The following attributes are supported: - @itemize - - @item @code{aligned(n)}: align a variable or a structure field to n bytes -(must be a power of two). - - @item @code{packed}: force alignment of a variable or a structure field to - 1. - - @item @code{section(name)}: generate function or data in assembly section -name (name is a string containing the section name) instead of the default -section. - - @item @code{unused}: specify that the variable or the function is unused. - - @item @code{cdecl}: use standard C calling convention (default). - - @item @code{stdcall}: use Pascal-like calling convention. - - @item @code{regparm(n)}: use fast i386 calling convention. @var{n} must be -between 1 and 3. The first @var{n} function parameters are respectively put in -registers @code{%eax}, @code{%edx} and @code{%ecx}. - - @item @code{dllexport}: export function from dll/executable (win32 only) - - @item @code{nodecorate}: do not apply any decorations that would otherwise be applied when exporting function from dll/executable (win32 only) - - @end itemize - -Here are some examples: -@example - int a __attribute__ ((aligned(8), section(".mysection"))); -@end example - -@noindent -align variable @code{a} to 8 bytes and put it in section @code{.mysection}. - -@example - int my_add(int a, int b) __attribute__ ((section(".mycodesection"))) - @{ - return a + b; - @} -@end example - -@noindent -generate function @code{my_add} in section @code{.mycodesection}. - -@item GNU style variadic macros: -@example - #define dprintf(fmt, args@dots{}) printf(fmt, ## args) - - dprintf("no arg\n"); - dprintf("one arg %d\n", 1); -@end example - -@item @code{__FUNCTION__} is interpreted as C99 @code{__func__} -(so it has not exactly the same semantics as string literal GNUC -where it is a string literal). - -@item The @code{__alignof__} keyword can be used as @code{sizeof} -to get the alignment of a type or an expression. - -@item The @code{typeof(x)} returns the type of @code{x}. -@code{x} is an expression or a type. - -@item Computed gotos: @code{&&label} returns a pointer of type -@code{void *} on the goto label @code{label}. @code{goto *expr} can be -used to jump on the pointer resulting from @code{expr}. - -@item Inline assembly with asm instruction: -@cindex inline assembly -@cindex assembly, inline -@cindex __asm__ -@example -static inline void * my_memcpy(void * to, const void * from, size_t n) -@{ -int d0, d1, d2; -__asm__ __volatile__( - "rep ; movsl\n\t" - "testb $2,%b4\n\t" - "je 1f\n\t" - "movsw\n" - "1:\ttestb $1,%b4\n\t" - "je 2f\n\t" - "movsb\n" - "2:" - : "=&c" (d0), "=&D" (d1), "=&S" (d2) - :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from) - : "memory"); -return (to); -@} -@end example - -@noindent -@cindex gas -TCC includes its own x86 inline assembler with a @code{gas}-like (GNU -assembler) syntax. No intermediate files are generated. GCC 3.x named -operands are supported. - -@item @code{__builtin_types_compatible_p()} and @code{__builtin_constant_p()} -are supported. - -@item @code{#pragma pack} is supported for win32 compatibility. - -@end itemize - -@section TinyCC extensions - -@itemize - -@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. - -@item Binary digits can be entered (@code{0b101} instead of -@code{5}). - -@end itemize - -@node asm -@chapter TinyCC Assembler - -Since version 0.9.16, TinyCC integrates its own assembler. TinyCC -assembler supports a gas-like syntax (GNU assembler). You can -deactivate assembler support if you want a smaller TinyCC executable -(the C compiler does not rely on the assembler). - -TinyCC Assembler is used to handle files with @file{.S} (C -preprocessed assembler) and @file{.s} extensions. It is also used to -handle the GNU inline assembler with the @code{asm} keyword. - -@section Syntax - -TinyCC Assembler supports most of the gas syntax. The tokens are the -same as C. - -@itemize - -@item C and C++ comments are supported. - -@item Identifiers are the same as C, so you cannot use '.' or '$'. - -@item Only 32 bit integer numbers are supported. - -@end itemize - -@section Expressions - -@itemize - -@item Integers in decimal, octal and hexa are supported. - -@item Unary operators: +, -, ~. - -@item Binary operators in decreasing priority order: - -@enumerate -@item *, /, % -@item &, |, ^ -@item +, - -@end enumerate - -@item A value is either an absolute number or a label plus an offset. -All operators accept absolute values except '+' and '-'. '+' or '-' can be -used to add an offset to a label. '-' supports two labels only if they -are the same or if they are both defined and in the same section. - -@end itemize - -@section Labels - -@itemize - -@item All labels are considered as local, except undefined ones. - -@item Numeric labels can be used as local @code{gas}-like labels. -They can be defined several times in the same source. Use 'b' -(backward) or 'f' (forward) as suffix to reference them: - -@example - 1: - jmp 1b /* jump to '1' label before */ - jmp 1f /* jump to '1' label after */ - 1: -@end example - -@end itemize - -@section Directives -@cindex assembler directives -@cindex directives, assembler -@cindex align directive -@cindex skip directive -@cindex space directive -@cindex byte directive -@cindex word directive -@cindex short directive -@cindex int directive -@cindex long directive -@cindex quad directive -@cindex globl directive -@cindex global directive -@cindex section directive -@cindex text directive -@cindex data directive -@cindex bss directive -@cindex fill directive -@cindex org directive -@cindex previous directive -@cindex string directive -@cindex asciz directive -@cindex ascii directive - -All directives are preceded by a '.'. The following directives are -supported: - -@itemize -@item .align n[,value] -@item .skip n[,value] -@item .space n[,value] -@item .byte value1[,...] -@item .word value1[,...] -@item .short value1[,...] -@item .int value1[,...] -@item .long value1[,...] -@item .quad immediate_value1[,...] -@item .globl symbol -@item .global symbol -@item .section section -@item .text -@item .data -@item .bss -@item .fill repeat[,size[,value]] -@item .org n -@item .previous -@item .string string[,...] -@item .asciz string[,...] -@item .ascii string[,...] -@end itemize - -@section X86 Assembler -@cindex assembler - -All X86 opcodes are supported. Only ATT syntax is supported (source -then destination operand order). If no size suffix is given, TinyCC -tries to guess it from the operand sizes. - -Currently, MMX opcodes are supported but not SSE ones. - -@node linker -@chapter TinyCC Linker -@cindex linker - -@section ELF file generation -@cindex ELF - -TCC can directly output relocatable ELF files (object files), -executable ELF files and dynamic ELF libraries without relying on an -external linker. - -Dynamic ELF libraries can be output but the C compiler does not generate -position independent code (PIC). It means that the dynamic library -code generated by TCC cannot be factorized among processes yet. - -TCC linker eliminates unreferenced object code in libraries. A single pass is -done on the object and library list, so the order in which object files and -libraries are specified is important (same constraint as GNU ld). No grouping -options (@option{--start-group} and @option{--end-group}) are supported. - -@section ELF file loader - -TCC can load ELF object files, archives (.a files) and dynamic -libraries (.so). - -@section PE-i386 file generation -@cindex PE-i386 - -TCC for Windows supports the native Win32 executable file format (PE-i386). It -generates EXE files (console and gui) and DLL files. - -For usage on Windows, see also tcc-win32.txt. - -@section GNU Linker Scripts -@cindex scripts, linker -@cindex linker scripts -@cindex GROUP, linker command -@cindex FILE, linker command -@cindex OUTPUT_FORMAT, linker command -@cindex TARGET, linker command - -Because on many Linux systems some dynamic libraries (such as -@file{/usr/lib/libc.so}) are in fact GNU ld link scripts (horrible!), -the TCC linker also supports a subset of GNU ld scripts. - -The @code{GROUP} and @code{FILE} commands are supported. @code{OUTPUT_FORMAT} -and @code{TARGET} are ignored. - -Example from @file{/usr/lib/libc.so}: -@example -/* GNU ld script - Use the shared library, but some functions are only in - the static library, so try that secondarily. */ -GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a ) -@end example - -@node Bounds -@chapter TinyCC Memory and Bound checks -@cindex bound checks -@cindex memory checks - -This feature is activated with the @option{-b} option (@pxref{Invoke}). -Here are some examples of caught errors: - -@table @asis - -@item Invalid range with standard string function: -@example -@{ - char tab[10]; - memset(tab, 0, 11); -@} -@end example - -@item Out of bounds-error in global or local arrays: -@example -@{ - int tab[10]; - for(i=0;i<11;i++) @{ - sum += tab[i]; - @} -@} -@end example - -@item Out of bounds-error in malloc'ed data: -@example -@{ - int *tab; - tab = malloc(20 * sizeof(int)); - for(i=0;i<21;i++) @{ - sum += tab[i]; - @} - free(tab); -@} -@end example - -@item Access of freed memory: -@example -@{ - int *tab; - tab = malloc(20 * sizeof(int)); - free(tab); - for(i=0;i<20;i++) @{ - sum += tab[i]; - @} -@} -@end example - -@item Double free: -@example -@{ - int *tab; - tab = malloc(20 * sizeof(int)); - free(tab); - free(tab); -@} -@end example -@end table - -TCC defines @code{__BOUNDS_CHECKING_ON} if activated. - -There are five environment variables that can be used to control the behavior: -@itemize -@item TCC_BOUNDS_WARN_POINTER_ADD -- Print warning when pointer add creates an illegal pointer. -@item TCC_BOUNDS_PRINT_CALLS -- Print bound checking calls. Can be used for debugging. -@item TCC_BOUNDS_PRINT_HEAP -- Print heap objects that are not freed at exit of program. -@item TCC_BOUNDS_PRINT_STATISTIC -- Print statistic information at exit of program. -@item TCC_BOUNDS_NEVER_FATAL -- Try to continue in case of a bound checking error. -@end itemize - -Also, a function @code{__bounds_checking(x)} can be used to turn off/on bounds -checking from usercode (see below). - -Notes: -@itemize -@item Only available on i386 (linux and windows), x86_64 (linux and windows), -arm, arm64 and riscv64 for the moment. -@item The generated code is slower and bigger. -@item The bound checking code is not included in shared libraries. The main -executable should always be compiled with the @option{-b}. -@item Pointer size is @emph{unchanged} and code generated with bound checks is -@emph{fully compatible} with unchecked code. When a pointer comes from -unchecked code, it is assumed to be valid. Even very obscure C code with -casts should work correctly. -@item Signal handlers are not compatible with bounds checking. The -bounds checking code disables checking in signal/sigaction handlers. -The fork() function call in a multi threaded application is also a problem. -The bound checking code fixes this for the child process. -@item The reason that signals and fork have problems is that we use locking -inside the bounds checking code. -Inside a signal handler we can not use locks. Also in a multi threaded -application after a fork the child process can have the lock set -by another thread. -@item The BOUNDS_CHECKING_OFF and BOUNDS_CHECKING_ON can also be used to -disable bounds checking for some code. -@item The __bounds_checking call adds a value to a thread local value. -The value starts at 0. If the value is not 0 the code is not checked -for bounds checking errors. -@end itemize - -@example -#if defined(__TINYC__) && __BOUNDS_CHECKING_ON -extern void __bounds_checking (int x); -# define BOUNDS_CHECKING_OFF __bounds_checking(1) -# define BOUNDS_CHECKING_ON __bounds_checking(-1) -#else -# define BOUNDS_CHECKING_OFF -# define BOUNDS_CHECKING_ON -#endif -@end example - -For more information about the ideas behind this method, see -@url{http://www.doc.ic.ac.uk/~phjk/BoundsChecking.html}. - -@node Libtcc -@chapter The @code{libtcc} library - -The @code{libtcc} library enables you to use TCC as a backend for -dynamic code generation. - -Read the @file{libtcc.h} to have an overview of the API. Read -@file{libtcc_test.c} to have a very simple example. - -The idea consists in giving a C string containing the program you want -to compile directly to @code{libtcc}. Then you can access to any global -symbol (function or variable) defined. - -@node devel -@chapter Developer's guide - -This chapter gives some hints to understand how TCC works. You can skip -it if you do not intend to modify the TCC code. - -@section File reading - -The @code{BufferedFile} structure contains the context needed to read a -file, including the current line number. @code{tcc_open()} opens a new -file and @code{tcc_close()} closes it. @code{inp()} returns the next -character. - -@section Lexer - -@code{next()} reads the next token in the current -file. @code{next_nomacro()} reads the next token without macro -expansion. - -@code{tok} contains the current token (see @code{TOK_xxx}) -constants. Identifiers and keywords are also keywords. @code{tokc} -contains additional infos about the token (for example a constant value -if number or string token). - -@section Parser - -The parser is hardcoded (yacc is not necessary). It does only one pass, -except: - -@itemize - -@item For initialized arrays with unknown size, a first pass -is done to count the number of elements. - -@item For architectures where arguments are evaluated in -reverse order, a first pass is done to reverse the argument order. - -@end itemize - -@section Types - -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. - -@example -#define VT_INT 0 /* integer type */ -#define VT_BYTE 1 /* signed byte type */ -#define VT_SHORT 2 /* short type */ -#define VT_VOID 3 /* void type */ -#define VT_PTR 4 /* pointer */ -#define VT_ENUM 5 /* enum definition */ -#define VT_FUNC 6 /* function type */ -#define VT_STRUCT 7 /* struct/union definition */ -#define VT_FLOAT 8 /* IEEE float */ -#define VT_DOUBLE 9 /* IEEE double */ -#define VT_LDOUBLE 10 /* IEEE long double */ -#define VT_BOOL 11 /* ISOC99 boolean type */ -#define VT_LLONG 12 /* 64 bit integer */ -#define VT_LONG 13 /* long integer (NEVER USED as type, only - during parsing) */ -#define VT_BTYPE 0x000f /* mask for basic type */ -#define VT_UNSIGNED 0x0010 /* unsigned type */ -#define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */ -#define VT_VLA 0x20000 /* VLA type (also has VT_PTR and VT_ARRAY) */ -#define VT_BITFIELD 0x0040 /* bitfield modifier */ -#define VT_CONSTANT 0x0800 /* const modifier */ -#define VT_VOLATILE 0x1000 /* volatile modifier */ -#define VT_DEFSIGN 0x2000 /* signed type */ - -#define VT_STRUCT_SHIFT 18 /* structure/enum name shift (14 bits left) */ -@end example - -When a reference to another type is needed (for pointers, functions and -structures), the @code{32 - VT_STRUCT_SHIFT} high order bits are used to -store an identifier reference. - -The @code{VT_UNSIGNED} flag can be set for chars, shorts, ints and long -longs. - -Arrays are considered as pointers @code{VT_PTR} with the flag -@code{VT_ARRAY} set. Variable length arrays are considered as special -arrays and have flag @code{VT_VLA} set instead of @code{VT_ARRAY}. - -The @code{VT_BITFIELD} flag can be set for chars, shorts, ints and long -longs. If it is set, then the bitfield position is stored from bits -VT_STRUCT_SHIFT to VT_STRUCT_SHIFT + 5 and the bit field size is stored -from bits VT_STRUCT_SHIFT + 6 to VT_STRUCT_SHIFT + 11. - -@code{VT_LONG} is never used except during parsing. - -During parsing, the storage of an object is also stored in the type -integer: - -@example -#define VT_EXTERN 0x00000080 /* extern definition */ -#define VT_STATIC 0x00000100 /* static variable */ -#define VT_TYPEDEF 0x00000200 /* typedef definition */ -#define VT_INLINE 0x00000400 /* inline definition */ -#define VT_IMPORT 0x00004000 /* win32: extern data imported from dll */ -#define VT_EXPORT 0x00008000 /* win32: data exported from dll */ -#define VT_WEAK 0x00010000 /* win32: data exported from dll */ -@end example - -@section Symbols - -All symbols are stored in hashed symbol stacks. Each symbol stack -contains @code{Sym} structures. - -@code{Sym.v} contains the symbol name (remember -an identifier is also a token, so a string is never necessary to store -it). @code{Sym.t} gives the type of the symbol. @code{Sym.r} is usually -the register in which the corresponding variable is stored. @code{Sym.c} is -usually a constant associated to the symbol like its address for normal -symbols, and the number of entries for symbols representing arrays. -Variable length array types use @code{Sym.c} as a location on the stack -which holds the runtime sizeof for the type. - -Four main symbol stacks are defined: - -@table @code - -@item define_stack -for the macros (@code{#define}s). - -@item global_stack -for the global variables, functions and types. - -@item local_stack -for the local variables, functions and types. - -@item global_label_stack -for the local labels (for @code{goto}). - -@item label_stack -for GCC block local labels (see the @code{__label__} keyword). - -@end table - -@code{sym_push()} is used to add a new symbol in the local symbol -stack. If no local symbol stack is active, it is added in the global -symbol stack. - -@code{sym_pop(st,b)} pops symbols from the symbol stack @var{st} until -the symbol @var{b} is on the top of stack. If @var{b} is NULL, the stack -is emptied. - -@code{sym_find(v)} return the symbol associated to the identifier -@var{v}. The local stack is searched first from top to bottom, then the -global stack. - -@section Sections - -The generated code and data are written in sections. The structure -@code{Section} contains all the necessary information for a given -section. @code{new_section()} creates a new section. ELF file semantics -is assumed for each section. - -The following sections are predefined: - -@table @code - -@item text_section -is the section containing the generated code. @var{ind} contains the -current position in the code section. - -@item data_section -contains initialized data - -@item bss_section -contains uninitialized data - -@item bounds_section -@itemx lbounds_section -are used when bound checking is activated - -@item stab_section -@itemx stabstr_section -are used when debugging is active to store debug information - -@item symtab_section -@itemx strtab_section -contain the exported symbols (currently only used for debugging). - -@end table - -@section Code generation -@cindex code generation - -@subsection Introduction - -The TCC code generator directly generates linked binary code in one -pass. It is rather unusual these days (see gcc for example which -generates text assembly), but it can be very fast and surprisingly -little complicated. - -The TCC code generator is register based. Optimization is only done at -the expression level. No intermediate representation of expression is -kept except the current values stored in the @emph{value stack}. - -On x86, three temporary registers are used. When more registers are -needed, one register is spilled into a new temporary variable on the stack. - -@subsection The value stack -@cindex value stack, introduction - -When an expression is parsed, its value is pushed on the value stack -(@var{vstack}). The top of the value stack is @var{vtop}. Each value -stack entry is the structure @code{SValue}. - -@code{SValue.t} is the type. @code{SValue.r} indicates how the value is -currently stored in the generated code. It is usually a CPU register -index (@code{REG_xxx} constants), but additional values and flags are -defined: - -@example -#define VT_CONST 0x00f0 -#define VT_LLOCAL 0x00f1 -#define VT_LOCAL 0x00f2 -#define VT_CMP 0x00f3 -#define VT_JMP 0x00f4 -#define VT_JMPI 0x00f5 -#define VT_LVAL 0x0100 -#define VT_SYM 0x0200 -#define VT_MUSTCAST 0x0400 -#define VT_MUSTBOUND 0x0800 -#define VT_BOUNDED 0x8000 -#define VT_LVAL_BYTE 0x1000 -#define VT_LVAL_SHORT 0x2000 -#define VT_LVAL_UNSIGNED 0x4000 -#define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED) -@end example - -@table @code - -@item VT_CONST -indicates that the value is a constant. It is stored in the union -@code{SValue.c}, depending on its type. - -@item VT_LOCAL -indicates a local variable pointer at offset @code{SValue.c.i} in the -stack. - -@item VT_CMP -indicates that the value is actually stored in the CPU flags (i.e. the -value is the consequence of a test). The value is either 0 or 1. The -actual CPU flags used is indicated in @code{SValue.c.i}. - -If any code is generated which destroys the CPU flags, this value MUST be -put in a normal register. - -@item VT_JMP -@itemx VT_JMPI -indicates that the value is the consequence of a conditional jump. For VT_JMP, -it is 1 if the jump is taken, 0 otherwise. For VT_JMPI it is inverted. - -These values are used to compile the @code{||} and @code{&&} logical -operators. - -If any code is generated, this value MUST be put in a normal -register. Otherwise, the generated code won't be executed if the jump is -taken. - -@item VT_LVAL -is a flag indicating that the value is actually an lvalue (left value of -an assignment). It means that the value stored is actually a pointer to -the wanted value. - -Understanding the use @code{VT_LVAL} is very important if you want to -understand how TCC works. - -@item VT_LVAL_BYTE -@itemx VT_LVAL_SHORT -@itemx VT_LVAL_UNSIGNED -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_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 -is used (lazy casting). - -@item VT_SYM -indicates that the symbol @code{SValue.sym} must be added to the constant. - -@item VT_MUSTBOUND -@itemx VT_BOUNDED -are only used for optional bound checking. - -@end table - -@subsection Manipulating the value stack -@cindex value stack - -@code{vsetc()} and @code{vset()} pushes a new value on the value -stack. If the previous @var{vtop} was stored in a very unsafe place(for -example in the CPU flags), then some code is generated to put the -previous @var{vtop} in a safe storage. - -@code{vpop()} pops @var{vtop}. In some cases, it also generates cleanup -code (for example if stacked floating point registers are used as on -x86). - -The @code{gv(rc)} function generates code to evaluate @var{vtop} (the -top value of the stack) into registers. @var{rc} selects in which -register class the value should be put. @code{gv()} is the @emph{most -important function} of the code generator. - -@code{gv2()} is the same as @code{gv()} but for the top two stack -entries. - -@subsection CPU dependent code generation -@cindex CPU dependent -See the @file{i386-gen.c} file to have an example. - -@table @code - -@item load() -must generate the code needed to load a stack value into a register. - -@item store() -must generate the code needed to store a register into a stack value -lvalue. - -@item gfunc_start() -@itemx gfunc_param() -@itemx gfunc_call() -should generate a function call - -@item gfunc_prolog() -@itemx gfunc_epilog() -should generate a function prolog/epilog. - -@item gen_opi(op) -must generate the binary integer operation @var{op} on the two top -entries of the stack which are guaranteed to contain integer types. - -The result value should be put on the stack. - -@item gen_opf(op) -same as @code{gen_opi()} for floating point operations. The two top -entries of the stack are guaranteed to contain floating point values of -same types. - -@item gen_cvt_itof() -integer to floating point conversion. - -@item gen_cvt_ftoi() -floating point to integer conversion. - -@item gen_cvt_ftof() -floating point to floating point of different size conversion. - -@end table - -@section Optimizations done -@cindex optimizations -@cindex constant propagation -@cindex strength reduction -@cindex comparison operators -@cindex caching processor flags -@cindex flags, caching -@cindex jump optimization -Constant propagation is done for all operations. Multiplications and -divisions are optimized to shifts when appropriate. Comparison -operators are optimized by maintaining a special cache for the -processor flags. &&, || and ! are optimized by maintaining a special -'jump target' value. No other jump optimization is currently performed -because it would require to store the code in a more abstract fashion. - -@unnumbered Concept Index -@printindex cp - -@bye - -@c Local variables: -@c fill-column: 78 -@c texinfo-column-for-description: 32 -@c End: diff --git a/tinycc/tcc.c b/tinycc/tcc.c deleted file mode 100644 index 0c6f6ac..0000000 --- a/tinycc/tcc.c +++ /dev/null @@ -1,412 +0,0 @@ -/* - * 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 - */ - -#include "tcc.h" -#if ONE_SOURCE -# include "libtcc.c" -#endif -#include "tcctools.c" - -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 (or --) [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" - " -std=c99 Conform to the ISO 1999 C standard (default).\n" - " -std=c11 Conform to the ISO 2011 C standard.\n" - " -Wwarning set or reset (with 'no-' prefix) 'warning' (see tcc -hh)\n" - " -w disable all warnings\n" - " -v --version show version\n" - " -vv 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" - " -C keep comments (not yet implemented)\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 stab runtime debug info\n" - " -gdwarf[-x] generate dwarf runtime debug info\n" -#ifdef CONFIG_TCC_BCHECK - " -b compile with built-in memory and bounds checker (implies -g)\n" -#endif -#ifdef CONFIG_TCC_BACKTRACE - " -bt[N] link with backtrace (stack dump) support [show max N callers]\n" -#endif - "Misc. options:\n" - " -x[c|a|b|n] specify type of the next infile (C,ASM,BIN,NONE)\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" - " -M[M]D generate make dependency file [ignore system files]\n" - " -M[M] as above but no other output\n" - " -MF file specify dependency file name\n" -#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) - " -m32/64 defer to i386/x86_64 cross compiler\n" -#endif - "Tools:\n" - " create library : tcc -ar [crstvx] lib [files]\n" -#ifdef TCC_TARGET_PE - " create def file : tcc -impdef lib.dll [-v] [-o lib.def]\n" -#endif - ; - -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" - " -static link to static libraries (not recommended)\n" - " -dumpversion print version\n" - " -print-search-dirs print search paths\n" - " -dt with -run/-E: auto-define 'test_...' macros\n" - "Ignored options:\n" - " -arch -C --param -pedantic -pipe -s -traditional\n" - "-W[no-]... warnings:\n" - " all turn on some (*) warnings\n" - " error[=warning] stop after warning (any or specified)\n" - " write-strings strings are const\n" - " unsupported warn about ignored options, pragmas, etc.\n" - " implicit-function-declaration warn for missing prototype (*)\n" - " discarded-qualifiers warn when const is dropped (*)\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" - " test-coverage create code coverage code\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" - " -export-dynamic 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 - " -rpath= set dynamic library search path\n" - " -enable-new-dtags set DT_RUNPATH instead of DT_RPATH\n" - " -soname= set DT_SONAME elf tag\n" -#if defined(TCC_TARGET_MACHO) - " -install_name= set DT_SONAME elf tag (soname macOS alias)\n" -#endif - " -Bsymbolic set DT_SYMBOLIC elf tag\n" - " -oformat=[elf32/64-* binary] set executable output format\n" - " -init= -fini= -Map= -as-needed -O (ignored)\n" - "Predefined macros:\n" - " tcc -E -dM - < /dev/null\n" -#endif - "See also the manual for more details.\n" - ; - -static const char version[] = - "tcc version "TCC_VERSION -#ifdef TCC_GITHASH - " "TCC_GITHASH -#endif - " (" -#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" -# ifdef TCC_ARM_EABI - " eabi" -# ifdef TCC_ARM_HARDFLOAT - "hf" -# endif -# endif -#elif defined TCC_TARGET_ARM64 - "AArch64" -#elif defined TCC_TARGET_RISCV64 - "riscv64" -#endif -#ifdef TCC_TARGET_PE - " Windows" -#elif defined(TCC_TARGET_MACHO) - " Darwin" -#elif TARGETOS_FreeBSD || TARGETOS_FreeBSD_kernel - " FreeBSD" -#elif TARGETOS_OpenBSD - " OpenBSD" -#elif TARGETOS_NetBSD - " NetBSD" -#else - " Linux" -#endif - ")\n" - ; - -static void print_dirs(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 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); - printf("libtcc1:\n %s/%s\n", s->library_paths[0], CONFIG_TCC_CROSSPREFIX TCC_LIBTCC1); -#if !defined TCC_TARGET_PE && !defined TCC_TARGET_MACHO - print_dirs("crt", s->crt_paths, s->nb_crt_paths); - 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_sysinclude_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); - } -} - -static char *default_outputfile(TCCState *s, const char *first_file) -{ - char buf[1024]; - char *ext; - const char *name = "a"; - - if (first_file && strcmp(first_file, "-")) - name = tcc_basename(first_file); - snprintf(buf, sizeof(buf), "%s", name); - ext = tcc_fileextension(buf); -#ifdef TCC_TARGET_PE - if (s->output_type == TCC_OUTPUT_DLL) - strcpy(ext, ".dll"); - else - if (s->output_type == TCC_OUTPUT_EXE) - strcpy(ext, ".exe"); - else -#endif - if ((s->just_deps || s->output_type == TCC_OUTPUT_OBJ) && !s->option_r && *ext) - strcpy(ext, ".o"); - else - strcpy(buf, "a.out"); - return tcc_strdup(buf); -} - -static unsigned getclock_ms(void) -{ -#ifdef _WIN32 - return GetTickCount(); -#else - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_sec*1000 + (tv.tv_usec+500)/1000; -#endif -} - -int main(int argc0, char **argv0) -{ - TCCState *s, *s1; - int ret, opt, n = 0, t = 0, done; - unsigned start_time = 0, end_time = 0; - const char *first_file; - int argc; char **argv; - FILE *ppfp = stdout; - -redo: - argc = argc0, argv = argv0; - s = s1 = tcc_new(); -#ifdef CONFIG_TCC_SWITCHES /* predefined options */ - tcc_set_options(s, CONFIG_TCC_SWITCHES); -#endif - opt = tcc_parse_args(s, &argc, &argv, 1); - if (opt < 0) - return 1; - - if (n == 0) { - if (opt == OPT_HELP) { - fputs(help, stdout); - if (!s->verbose) - return 0; - ++opt; - } - if (opt == OPT_HELP2) { - fputs(help2, stdout); - return 0; - } - if (opt == OPT_M32 || opt == OPT_M64) - return tcc_tool_cross(s, argv, opt); - 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 */ - set_environment(s); - tcc_set_output_type(s, TCC_OUTPUT_MEMORY); - print_search_dirs(s); - return 0; - } - - if (s->nb_files == 0) { - tcc_error_noabort("no input files"); - } else if (s->output_type == TCC_OUTPUT_PREPROCESS) { - if (s->outfile && 0!=strcmp("-",s->outfile)) { - ppfp = fopen(s->outfile, "w"); - if (!ppfp) - tcc_error_noabort("could not write '%s'", s->outfile); - } - } else if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) { - if (s->nb_libraries) - tcc_error_noabort("cannot specify libraries with -c"); - else if (s->nb_files > 1 && s->outfile) - tcc_error_noabort("cannot specify output file with -c many files"); - } - if (s->nb_errors) - return 1; - if (s->do_bench) - start_time = getclock_ms(); - } - - set_environment(s); - if (s->output_type == 0) - s->output_type = TCC_OUTPUT_EXE; - tcc_set_output_type(s, s->output_type); - s->ppfp = ppfp; - - if ((s->output_type == TCC_OUTPUT_MEMORY - || s->output_type == TCC_OUTPUT_PREPROCESS) - && (s->dflag & 16)) { /* -dt option */ - if (t) - s->dflag |= 32; - s->run_test = ++t; - if (n) - --n; - } - - /* compile or add each files or library */ - first_file = NULL, ret = 0; - do { - struct filespec *f = s->files[n]; - s->filetype = f->type; - 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", f->name); - if (!first_file) - first_file = f->name; - if (tcc_add_file(s, f->name) < 0) - ret = 1; - } - done = ret || ++n >= s->nb_files; - } while (!done && (s->output_type != TCC_OUTPUT_OBJ || s->option_r)); - - if (s->do_bench) - end_time = getclock_ms(); - - if (s->run_test) { - t = 0; - } else if (s->output_type == TCC_OUTPUT_PREPROCESS) { - ; - } else if (0 == ret) { - if (s->output_type == TCC_OUTPUT_MEMORY) { -#ifdef TCC_IS_NATIVE - ret = tcc_run(s, argc, argv); -#endif - } else { - if (!s->outfile) - s->outfile = default_outputfile(s, first_file); - if (!s->just_deps && tcc_output_file(s, s->outfile)) - ret = 1; - else if (s->gen_deps) - ret = gen_makedeps(s, s->outfile, s->deps_outfile); - } - } - - if (done && 0 == t && 0 == ret && s->do_bench) - tcc_print_stats(s, end_time - start_time); - - tcc_delete(s); - if (!done) - goto redo; /* compile more files with -c */ - if (t) - goto redo; /* run more tests with -dt -run */ - - if (ppfp && ppfp != stdout) - fclose(ppfp); - return ret; -} diff --git a/tinycc/tcc.h b/tinycc/tcc.h deleted file mode 100644 index a4abccf..0000000 --- a/tinycc/tcc.h +++ /dev/null @@ -1,1937 +0,0 @@ -/* - * 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 - */ - -#ifndef _TCC_H -#define _TCC_H - -#define _GNU_SOURCE -#define _DARWIN_C_SOURCE -#include "config.h" - -#include <stdarg.h> -#include <stdlib.h> -#include <stdio.h> -/* gnu headers use to #define __attribute__ to empty for non-gcc compilers */ -#ifdef __TINYC__ -# undef __attribute__ -#endif -#include <string.h> -#include <errno.h> -#include <math.h> -#include <fcntl.h> -#include <setjmp.h> -#include <time.h> -#include <sys/stat.h> - -#ifndef _WIN32 -# include <unistd.h> -# include <sys/time.h> -# ifndef CONFIG_TCC_STATIC -# include <dlfcn.h> -# endif -/* XXX: need to define this to use them in non ISOC99 context */ -extern float strtof (const char *__nptr, char **__endptr); -extern long double strtold (const char *__nptr, char **__endptr); -#endif - -#ifdef _WIN32 -# define WIN32_LEAN_AND_MEAN 1 -# include <windows.h> -# include <io.h> /* open, close etc. */ -# include <direct.h> /* getcwd */ -# include <malloc.h> /* alloca */ -# ifdef __GNUC__ -# include <stdint.h> -# endif -# define inline __inline -# define snprintf _snprintf -# define vsnprintf _vsnprintf -# ifndef __GNUC__ -# define strtold (long double)strtod -# define strtof (float)strtod -# define strtoll _strtoi64 -# define strtoull _strtoui64 -# endif -# ifdef LIBTCC_AS_DLL -# define LIBTCCAPI __declspec(dllexport) -# define PUB_FUNC LIBTCCAPI -# endif -# ifdef _MSC_VER -# pragma warning (disable : 4244) // conversion from 'uint64_t' to 'int', possible loss of data -# pragma warning (disable : 4267) // conversion from 'size_t' to 'int', possible loss of data -# pragma warning (disable : 4996) // The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name -# pragma warning (disable : 4018) // signed/unsigned mismatch -# pragma warning (disable : 4146) // unary minus operator applied to unsigned type, result still unsigned -# define ssize_t intptr_t -# ifdef _X86_ -# define __i386__ 1 -# endif -# ifdef _AMD64_ -# define __x86_64__ 1 -# endif -# endif -# ifndef va_copy -# define va_copy(a,b) a = b -# endif -# undef CONFIG_TCC_STATIC -#endif - -#ifndef PAGESIZE -# ifdef _SC_PAGESIZE -# define PAGESIZE sysconf(_SC_PAGESIZE) -# else -# define PAGESIZE 4096 -# endif -#endif - -#ifndef O_BINARY -# define O_BINARY 0 -#endif - -#ifndef offsetof -#define offsetof(type, field) ((size_t) &((type *)0)->field) -#endif - -#ifndef countof -#define countof(tab) (sizeof(tab) / sizeof((tab)[0])) -#endif - -#ifdef _MSC_VER -# define NORETURN __declspec(noreturn) -# define ALIGNED(x) __declspec(align(x)) -# define PRINTF_LIKE(x,y) -#else -# define NORETURN __attribute__((noreturn)) -# define ALIGNED(x) __attribute__((aligned(x))) -# define PRINTF_LIKE(x,y) __attribute__ ((format (printf, (x), (y)))) -#endif - -#ifdef _WIN32 -# define IS_DIRSEP(c) (c == '/' || c == '\\') -# define IS_ABSPATH(p) (IS_DIRSEP(p[0]) || (p[0] && p[1] == ':' && IS_DIRSEP(p[2]))) -# define PATHCMP stricmp -# define PATHSEP ";" -#else -# define IS_DIRSEP(c) (c == '/') -# define IS_ABSPATH(p) IS_DIRSEP(p[0]) -# define PATHCMP strcmp -# define PATHSEP ":" -#endif - -/* -------------------------------------------- */ - -/* parser debug */ -/* #define PARSE_DEBUG */ -/* preprocessor debug */ -/* #define PP_DEBUG */ -/* include file debug */ -/* #define INC_DEBUG */ -/* memory leak debug (only for single threaded usage) */ -/* #define MEM_DEBUG */ -/* assembler debug */ -/* #define ASM_DEBUG */ - -/* target selection */ -/* #define TCC_TARGET_I386 *//* i386 code generator */ -/* #define TCC_TARGET_X86_64 *//* x86-64 code generator */ -/* #define TCC_TARGET_ARM *//* ARMv4 code generator */ -/* #define TCC_TARGET_ARM64 *//* ARMv8 code generator */ -/* #define TCC_TARGET_C67 *//* TMS320C67xx code generator */ -/* #define TCC_TARGET_RISCV64 *//* risc-v code generator */ - -/* default target is I386 */ -#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_ARM) && \ - !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_C67) && \ - !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_RISCV64) -# if defined __x86_64__ -# define TCC_TARGET_X86_64 -# elif defined __arm__ -# define TCC_TARGET_ARM -# define TCC_ARM_EABI -# define TCC_ARM_VFP -# define TCC_ARM_HARDFLOAT -# elif defined __aarch64__ -# define TCC_TARGET_ARM64 -# elif defined __riscv -# define TCC_TARGET_RISCV64 -# else -# define TCC_TARGET_I386 -# endif -# ifdef _WIN32 -# define TCC_TARGET_PE 1 -# endif -# ifdef __APPLE__ -# define TCC_TARGET_MACHO 1 -# endif -#endif - -/* only native compiler supports -run */ -#if defined _WIN32 == defined TCC_TARGET_PE \ - && defined __APPLE__ == defined TCC_TARGET_MACHO -# if defined __i386__ && defined TCC_TARGET_I386 -# define TCC_IS_NATIVE -# elif defined __x86_64__ && defined TCC_TARGET_X86_64 -# define TCC_IS_NATIVE -# elif defined __arm__ && defined TCC_TARGET_ARM -# define TCC_IS_NATIVE -# elif defined __aarch64__ && defined TCC_TARGET_ARM64 -# define TCC_IS_NATIVE -# elif defined __riscv && defined __LP64__ && defined TCC_TARGET_RISCV64 -# define TCC_IS_NATIVE -# endif -#endif - -#if defined CONFIG_TCC_BACKTRACE && CONFIG_TCC_BACKTRACE==0 -# undef CONFIG_TCC_BACKTRACE -#else -# define CONFIG_TCC_BACKTRACE 1 /* enable builtin stack backtraces */ -#endif - -#if defined CONFIG_TCC_BCHECK && CONFIG_TCC_BCHECK==0 -# undef CONFIG_TCC_BCHECK -#else -# define CONFIG_TCC_BCHECK 1 /* enable bound checking code */ -#endif - -#if defined CONFIG_NEW_MACHO && CONFIG_NEW_MACHO==0 -# undef CONFIG_NEW_MACHO -#else -# define CONFIG_NEW_MACHO 1 /* enable new macho code */ -#endif - -#if defined TARGETOS_OpenBSD \ - || defined TARGETOS_FreeBSD \ - || defined TARGETOS_NetBSD \ - || defined TARGETOS_FreeBSD_kernel -# define TARGETOS_BSD 1 -#elif !(defined TCC_TARGET_PE || defined TCC_TARGET_MACHO) -# define TARGETOS_Linux 1 -#endif - -#if defined TCC_TARGET_PE || defined TCC_TARGET_MACHO -# define ELF_OBJ_ONLY /* create elf .o but native executables */ -#endif - -/* No ten-byte long doubles on window and macos except in - cross-compilers made by a mingw-GCC */ -#if defined TCC_TARGET_PE \ - || (defined TCC_TARGET_MACHO && defined TCC_TARGET_ARM64) \ - || (defined _WIN32 && !defined __GNUC__) -# define TCC_USING_DOUBLE_FOR_LDOUBLE 1 -#endif - -#ifdef CONFIG_TCC_PIE -# define CONFIG_TCC_PIC 1 -#endif - -/* ------------ path configuration ------------ */ - -#ifndef CONFIG_SYSROOT -# define CONFIG_SYSROOT "" -#endif -#if !defined CONFIG_TCCDIR && !defined _WIN32 -# define CONFIG_TCCDIR "/usr/local/lib/tcc" -#endif -#ifndef CONFIG_LDDIR -# define CONFIG_LDDIR "lib" -#endif -#ifdef CONFIG_TRIPLET -# define USE_TRIPLET(s) s "/" CONFIG_TRIPLET -# define ALSO_TRIPLET(s) USE_TRIPLET(s) ":" s -#else -# define USE_TRIPLET(s) s -# define ALSO_TRIPLET(s) s -#endif - -/* path to find crt1.o, crti.o and crtn.o */ -#ifndef CONFIG_TCC_CRTPREFIX -# define CONFIG_TCC_CRTPREFIX USE_TRIPLET(CONFIG_SYSROOT "/usr/" CONFIG_LDDIR) -#endif - -#ifndef CONFIG_USR_INCLUDE -# define CONFIG_USR_INCLUDE "/usr/include" -#endif - -/* Below: {B} is substituted by CONFIG_TCCDIR (rsp. -B option) */ - -/* system include paths */ -#ifndef CONFIG_TCC_SYSINCLUDEPATHS -# if defined TCC_TARGET_PE || defined _WIN32 -# define CONFIG_TCC_SYSINCLUDEPATHS "{B}/include"PATHSEP"{B}/include/winapi" -# else -# define CONFIG_TCC_SYSINCLUDEPATHS \ - "{B}/include" \ - ":" ALSO_TRIPLET(CONFIG_SYSROOT "/usr/local/include") \ - ":" ALSO_TRIPLET(CONFIG_SYSROOT CONFIG_USR_INCLUDE) -# endif -#endif - -/* library search paths */ -#ifndef CONFIG_TCC_LIBPATHS -# ifdef TCC_TARGET_PE -# define CONFIG_TCC_LIBPATHS "{B}/lib" -# else -# define CONFIG_TCC_LIBPATHS \ - "{B}" \ - ":" ALSO_TRIPLET(CONFIG_SYSROOT "/usr/" CONFIG_LDDIR) \ - ":" ALSO_TRIPLET(CONFIG_SYSROOT "/" CONFIG_LDDIR) \ - ":" ALSO_TRIPLET(CONFIG_SYSROOT "/usr/local/" CONFIG_LDDIR) -# endif -#endif - -/* name of ELF interpreter */ -#ifndef CONFIG_TCC_ELFINTERP -# if TARGETOS_FreeBSD -# define CONFIG_TCC_ELFINTERP "/libexec/ld-elf.so.1" -# elif TARGETOS_FreeBSD_kernel -# if defined(TCC_TARGET_X86_64) -# define CONFIG_TCC_ELFINTERP "/lib/ld-kfreebsd-x86-64.so.1" -# else -# define CONFIG_TCC_ELFINTERP "/lib/ld.so.1" -# endif -# elif TARGETOS_DragonFly -# define CONFIG_TCC_ELFINTERP "/usr/libexec/ld-elf.so.2" -# elif TARGETOS_NetBSD -# define CONFIG_TCC_ELFINTERP "/usr/libexec/ld.elf_so" -# elif TARGETOS_OpenBSD -# define CONFIG_TCC_ELFINTERP "/usr/libexec/ld.so" -# elif defined __GNU__ -# define CONFIG_TCC_ELFINTERP "/lib/ld.so" -# elif defined(TCC_TARGET_PE) -# define CONFIG_TCC_ELFINTERP "-" -# elif defined(TCC_UCLIBC) -# define CONFIG_TCC_ELFINTERP "/lib/ld-uClibc.so.0" /* is there a uClibc for x86_64 ? */ -# elif defined TCC_TARGET_ARM64 -# if defined(TCC_MUSL) -# define CONFIG_TCC_ELFINTERP "/lib/ld-musl-aarch64.so.1" -# else -# define CONFIG_TCC_ELFINTERP "/lib/ld-linux-aarch64.so.1" -# endif -# elif defined(TCC_TARGET_X86_64) -# if defined(TCC_MUSL) -# define CONFIG_TCC_ELFINTERP "/lib/ld-musl-x86_64.so.1" -# else -# define CONFIG_TCC_ELFINTERP "/lib64/ld-linux-x86-64.so.2" -# endif -# elif defined(TCC_TARGET_RISCV64) -# define CONFIG_TCC_ELFINTERP "/lib/ld-linux-riscv64-lp64d.so.1" -# elif !defined(TCC_ARM_EABI) -# if defined(TCC_MUSL) -# if defined(TCC_TARGET_I386) -# define CONFIG_TCC_ELFINTERP "/lib/ld-musl-i386.so.1" -# else -# define CONFIG_TCC_ELFINTERP "/lib/ld-musl-arm.so.1" -# endif -# else -# define CONFIG_TCC_ELFINTERP "/lib/ld-linux.so.2" -# endif -# endif -#endif - -/* var elf_interp dans *-gen.c */ -#ifdef CONFIG_TCC_ELFINTERP -# define DEFAULT_ELFINTERP(s) CONFIG_TCC_ELFINTERP -#else -# define DEFAULT_ELFINTERP(s) default_elfinterp(s) -#endif - -/* (target specific) libtcc1.a */ -#ifndef TCC_LIBTCC1 -# define TCC_LIBTCC1 "\0" -#endif - -#ifndef CONFIG_TCC_CROSSPREFIX -# define CONFIG_TCC_CROSSPREFIX "" -#endif - -/* library to use with CONFIG_USE_LIBGCC instead of libtcc1.a */ -#if defined CONFIG_USE_LIBGCC && !defined TCC_LIBGCC -#define TCC_LIBGCC USE_TRIPLET(CONFIG_SYSROOT "/" CONFIG_LDDIR) "/libgcc_s.so.1" -#endif - -/* -------------------------------------------- */ - -#include "libtcc.h" -#include "elf.h" -#include "stab.h" -#include "dwarf.h" - -/* -------------------------------------------- */ - -#ifndef PUB_FUNC /* functions used by tcc.c but not in libtcc.h */ -# define PUB_FUNC -#endif - -#ifndef ONE_SOURCE -# define ONE_SOURCE 1 -#endif - -/* support using libtcc from threads */ -#ifndef CONFIG_TCC_SEMLOCK -# define CONFIG_TCC_SEMLOCK 1 -#endif - -#if ONE_SOURCE -#define ST_INLN static inline -#define ST_FUNC static -#define ST_DATA static -#else -#define ST_INLN -#define ST_FUNC -#define ST_DATA extern -#endif - -#ifdef TCC_PROFILE /* profile all functions */ -# define static -#endif - -/* -------------------------------------------- */ -/* include the target specific definitions */ - -#define TARGET_DEFS_ONLY -#ifdef TCC_TARGET_I386 -# include "i386-gen.c" -# include "i386-link.c" -#elif defined TCC_TARGET_X86_64 -# include "x86_64-gen.c" -# include "x86_64-link.c" -#elif defined TCC_TARGET_ARM -# include "arm-gen.c" -# include "arm-link.c" -# include "arm-asm.c" -#elif defined TCC_TARGET_ARM64 -# include "arm64-gen.c" -# include "arm64-link.c" -# include "arm-asm.c" -#elif defined TCC_TARGET_C67 -# define TCC_TARGET_COFF -# include "coff.h" -# include "c67-gen.c" -# include "c67-link.c" -#elif defined(TCC_TARGET_RISCV64) -# include "riscv64-gen.c" -# include "riscv64-link.c" -# include "riscv64-asm.c" -#else -#error unknown target -#endif -#undef TARGET_DEFS_ONLY - -/* -------------------------------------------- */ - -#if PTR_SIZE == 8 -# define ELFCLASSW ELFCLASS64 -# define ElfW(type) Elf##64##_##type -# define ELFW(type) ELF##64##_##type -# define ElfW_Rel ElfW(Rela) -# define SHT_RELX SHT_RELA -# define REL_SECTION_FMT ".rela%s" -#else -# define ELFCLASSW ELFCLASS32 -# define ElfW(type) Elf##32##_##type -# define ELFW(type) ELF##32##_##type -# define ElfW_Rel ElfW(Rel) -# define SHT_RELX SHT_REL -# define REL_SECTION_FMT ".rel%s" -#endif -/* target address type */ -#define addr_t ElfW(Addr) -#define ElfSym ElfW(Sym) - -#if PTR_SIZE == 8 && !defined TCC_TARGET_PE -# define LONG_SIZE 8 -#else -# define LONG_SIZE 4 -#endif - -/* -------------------------------------------- */ - -#define INCLUDE_STACK_SIZE 32 -#define IFDEF_STACK_SIZE 64 -#define VSTACK_SIZE 512 -#define STRING_MAX_SIZE 1024 -#define TOKSTR_MAX_SIZE 256 -#define PACK_STACK_SIZE 8 - -#define TOK_HASH_SIZE 16384 /* must be a power of two */ -#define TOK_ALLOC_INCR 512 /* must be a power of two */ -#define TOK_MAX_SIZE 4 /* token max size in int unit when stored in string */ - -/* token symbol management */ -typedef struct TokenSym { - struct TokenSym *hash_next; - struct Sym *sym_define; /* direct pointer to define */ - struct Sym *sym_label; /* direct pointer to label */ - struct Sym *sym_struct; /* direct pointer to structure */ - struct Sym *sym_identifier; /* direct pointer to identifier */ - int tok; /* token number */ - int len; - char str[1]; -} TokenSym; - -#ifdef TCC_TARGET_PE -typedef unsigned short nwchar_t; -#else -typedef int nwchar_t; -#endif - -typedef struct CString { - int size; /* size in bytes */ - int size_allocated; - void *data; /* either 'char *' or 'nwchar_t *' */ - struct CString *prev; -} CString; - -/* type definition */ -typedef struct CType { - int t; - struct Sym *ref; -} CType; - -/* constant value */ -typedef union CValue { - long double ld; - double d; - float f; - uint64_t i; - struct { - const void *data; - int size; - } str; - int tab[LDOUBLE_SIZE/4]; -} CValue; - -/* value on stack */ -typedef struct SValue { - CType type; /* type */ - unsigned short r; /* register + flags */ - unsigned short r2; /* second register, used for 'long long' - type. If not used, set to VT_CONST */ - union { - struct { int jtrue, jfalse; }; /* forward jmps */ - CValue c; /* constant, if VT_CONST */ - }; - union { - struct { unsigned short cmp_op, cmp_r; }; /* VT_CMP operation */ - struct Sym *sym; /* symbol, if (VT_SYM | VT_CONST), or if */ - }; /* result of unary() for an identifier. */ - -} SValue; - -/* symbol attributes */ -struct SymAttr { - unsigned short - aligned : 5, /* alignment as log2+1 (0 == unspecified) */ - packed : 1, - weak : 1, - visibility : 2, - dllexport : 1, - nodecorate : 1, - dllimport : 1, - addrtaken : 1, - nodebug : 1, - xxxx : 2; /* not used */ -}; - -/* function attributes or temporary attributes for parsing */ -struct FuncAttr { - unsigned - func_call : 3, /* calling convention (0..5), see below */ - func_type : 2, /* FUNC_OLD/NEW/ELLIPSIS */ - func_noreturn : 1, /* attribute((noreturn)) */ - func_ctor : 1, /* attribute((constructor)) */ - func_dtor : 1, /* attribute((destructor)) */ - func_args : 8, /* PE __stdcall args */ - func_alwinl : 1, /* always_inline */ - xxxx : 15; -}; - -/* symbol management */ -typedef struct Sym { - int v; /* symbol token */ - unsigned short r; /* associated register or VT_CONST/VT_LOCAL and LVAL type */ - struct SymAttr a; /* symbol attributes */ - union { - struct { - int c; /* associated number or Elf symbol index */ - union { - int sym_scope; /* scope level for locals */ - int jnext; /* next jump label */ - struct FuncAttr f; /* function attributes */ - int auxtype; /* bitfield access type */ - }; - }; - long long enum_val; /* enum constant if IS_ENUM_VAL */ - int *d; /* define token stream */ - struct Sym *ncl; /* next cleanup */ - }; - CType type; /* associated type */ - union { - int *vla_array_str; /* vla array code */ - struct Sym *next; /* next related symbol (for fields and anoms) */ - struct Sym *cleanupstate; /* in defined labels */ - int asm_label; /* associated asm label */ - }; - struct Sym *prev; /* prev symbol in stack */ - struct Sym *prev_tok; /* previous symbol for this token */ -} Sym; - -/* section definition */ -typedef struct Section { - unsigned long data_offset; /* current data offset */ - unsigned char *data; /* section data */ - unsigned long data_allocated; /* used for realloc() handling */ - TCCState *s1; - int sh_name; /* elf section name (only used during output) */ - int sh_num; /* elf section number */ - int sh_type; /* elf section type */ - int sh_flags; /* elf section flags */ - int sh_info; /* elf section info */ - int sh_addralign; /* elf section alignment */ - int sh_entsize; /* elf entry size */ - unsigned long sh_size; /* section size (only used during output) */ - addr_t sh_addr; /* address at which the section is relocated */ - unsigned long sh_offset; /* file offset */ - int nb_hashed_syms; /* used to resize the hash table */ - struct Section *link; /* link to another section */ - struct Section *reloc; /* corresponding section for relocation, if any */ - struct Section *hash; /* hash table for symbols */ - struct Section *prev; /* previous section on section stack */ - char name[1]; /* section name */ -} Section; - -typedef struct DLLReference { - int level; - void *handle; - unsigned char found, index; - char name[1]; -} DLLReference; - -/* -------------------------------------------------- */ - -#define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */ -#define SYM_FIELD 0x20000000 /* struct/union field symbol space */ -#define SYM_FIRST_ANOM 0x10000000 /* first anonymous sym */ - -/* stored in 'Sym->f.func_type' field */ -#define FUNC_NEW 1 /* ansi function prototype */ -#define FUNC_OLD 2 /* old function prototype */ -#define FUNC_ELLIPSIS 3 /* ansi function prototype with ... */ - -/* stored in 'Sym->f.func_call' field */ -#define FUNC_CDECL 0 /* standard c call */ -#define FUNC_STDCALL 1 /* pascal c call */ -#define FUNC_FASTCALL1 2 /* first param in %eax */ -#define FUNC_FASTCALL2 3 /* first parameters in %eax, %edx */ -#define FUNC_FASTCALL3 4 /* first parameter in %eax, %edx, %ecx */ -#define FUNC_FASTCALLW 5 /* first parameter in %ecx, %edx */ - -/* field 'Sym.t' for macros */ -#define MACRO_OBJ 0 /* object like macro */ -#define MACRO_FUNC 1 /* function like macro */ - -/* field 'Sym.r' for C labels */ -#define LABEL_DEFINED 0 /* label is defined */ -#define LABEL_FORWARD 1 /* label is forward defined */ -#define LABEL_DECLARED 2 /* label is declared but never used */ -#define LABEL_GONE 3 /* label isn't in scope, but not yet popped - from local_label_stack (stmt exprs) */ - -/* type_decl() types */ -#define TYPE_ABSTRACT 1 /* type without variable */ -#define TYPE_DIRECT 2 /* type with variable */ -#define TYPE_PARAM 4 /* type declares function parameter */ -#define TYPE_NEST 8 /* nested call to post_type */ - -#define IO_BUF_SIZE 8192 - -typedef struct BufferedFile { - uint8_t *buf_ptr; - uint8_t *buf_end; - int fd; - struct BufferedFile *prev; - int line_num; /* current line number - here to simplify code */ - int line_ref; /* tcc -E: last printed line */ - int ifndef_macro; /* #ifndef macro / #endif search */ - int ifndef_macro_saved; /* saved ifndef_macro */ - int *ifdef_stack_ptr; /* ifdef_stack value at the start of the file */ - int include_next_index; /* next search path */ - char filename[1024]; /* filename */ - char *true_filename; /* filename not modified by # line directive */ - unsigned char unget[4]; - unsigned char buffer[1]; /* extra size for CH_EOB char */ -} BufferedFile; - -#define CH_EOB '\\' /* end of buffer or '\0' char in file */ -#define CH_EOF (-1) /* end of file */ - -/* used to record tokens */ -typedef struct TokenString { - int *str; - int len; - int lastlen; - int allocated_len; - int last_line_num; - int save_line_num; - /* used to chain token-strings with begin/end_macro() */ - struct TokenString *prev; - const int *prev_ptr; - char alloc; -} TokenString; - -/* GNUC attribute definition */ -typedef struct AttributeDef { - struct SymAttr a; - struct FuncAttr f; - struct Section *section; - Sym *cleanup_func; - int alias_target; /* token */ - int asm_label; /* associated asm label */ - char attr_mode; /* __attribute__((__mode__(...))) */ -} AttributeDef; - -/* inline functions */ -typedef struct InlineFunc { - TokenString *func_str; - Sym *sym; - char filename[1]; -} InlineFunc; - -/* include file cache, used to find files faster and also to eliminate - inclusion if the include file is protected by #ifndef ... #endif */ -typedef struct CachedInclude { - struct stat st; -#ifdef _WIN32 - unsigned long long hash; -#endif - int ifndef_macro; - int once; - int hash_next; /* -1 if none */ - char filename[1]; /* path specified in #include */ -} CachedInclude; - -#define CACHED_INCLUDES_HASH_SIZE 32 - -#ifdef CONFIG_TCC_ASM -typedef struct ExprValue { - uint64_t v; - Sym *sym; - int pcrel; -} ExprValue; - -#define MAX_ASM_OPERANDS 30 -typedef struct ASMOperand { - int id; /* GCC 3 optional identifier (0 if number only supported) */ - char constraint[16]; - char asm_str[16]; /* computed asm string for operand */ - SValue *vt; /* C value of the expression */ - int ref_index; /* if >= 0, gives reference to a output constraint */ - int input_index; /* if >= 0, gives reference to an input constraint */ - int priority; /* priority, used to assign registers */ - int reg; /* if >= 0, register number used for this operand */ - int is_llong; /* true if double register value */ - int is_memory; /* true if memory operand */ - int is_rw; /* for '+' modifier */ - int is_label; /* for asm goto */ -} ASMOperand; -#endif - -/* extra symbol attributes (not in symbol table) */ -struct sym_attr { - unsigned got_offset; - unsigned plt_offset; - int plt_sym; - int dyn_index; -#ifdef TCC_TARGET_ARM - unsigned char plt_thumb_stub:1; -#endif -}; - -struct TCCState { - unsigned char verbose; /* if true, display some information during compilation */ - unsigned char nostdinc; /* if true, no standard headers are added */ - unsigned char nostdlib; /* if true, no standard libraries are added */ - unsigned char nocommon; /* if true, do not use common symbols for .bss data */ - unsigned char static_link; /* if true, static linking is performed */ - unsigned char rdynamic; /* if true, all symbols are exported */ - unsigned char symbolic; /* if true, resolve symbols in the current module first */ - unsigned char filetype; /* file type for compilation (NONE,C,ASM) */ - unsigned char optimize; /* only to #define __OPTIMIZE__ */ - unsigned char option_pthread; /* -pthread option */ - unsigned char enable_new_dtags; /* -Wl,--enable-new-dtags */ - unsigned int cversion; /* supported C ISO version, 199901 (the default), 201112, ... */ - - /* C language options */ - unsigned char char_is_unsigned; - unsigned char leading_underscore; - unsigned char ms_extensions; /* allow nested named struct w/o identifier behave like unnamed */ - unsigned char dollars_in_identifiers; /* allows '$' char in identifiers */ - unsigned char ms_bitfields; /* if true, emulate MS algorithm for aligning bitfields */ - - /* warning switches */ - unsigned char warn_none; - unsigned char warn_all; - unsigned char warn_error; - unsigned char warn_write_strings; - unsigned char warn_unsupported; - unsigned char warn_implicit_function_declaration; - unsigned char warn_discarded_qualifiers; - #define WARN_ON 1 /* warning is on (-Woption) */ - unsigned char warn_num; /* temp var for tcc_warning_c() */ - - unsigned char option_r; /* option -r */ - unsigned char do_bench; /* option -bench */ - unsigned char just_deps; /* option -M */ - unsigned char gen_deps; /* option -MD */ - unsigned char include_sys_deps; /* option -MD */ - - /* compile with debug symbol (and use them if error during execution) */ - unsigned char do_debug; - unsigned char dwarf; - unsigned char do_backtrace; -#ifdef CONFIG_TCC_BCHECK - /* compile with built-in memory and bounds checker */ - unsigned char do_bounds_check; -#endif - unsigned char test_coverage; /* generate test coverage code */ - - /* use GNU C extensions */ - unsigned char gnu_ext; - /* use TinyCC extensions */ - unsigned char tcc_ext; - - unsigned char dflag; /* -dX value */ - unsigned char Pflag; /* -P switch (LINE_MACRO_OUTPUT_FORMAT) */ - -#ifdef TCC_TARGET_X86_64 - unsigned char nosse; /* For -mno-sse support. */ -#endif -#ifdef TCC_TARGET_ARM - unsigned char float_abi; /* float ABI of the generated code*/ -#endif - - unsigned char has_text_addr; - addr_t text_addr; /* address of text section */ - unsigned section_align; /* section alignment */ -#ifdef TCC_TARGET_I386 - int seg_size; /* 32. Can be 16 with i386 assembler (.code16) */ -#endif - - char *tcc_lib_path; /* CONFIG_TCCDIR or -B option */ - char *soname; /* as specified on the command line (-soname) */ - char *rpath; /* as specified on the command line (-Wl,-rpath=) */ - char *elf_entryname; /* "_start" unless set */ - char *init_symbol; /* symbols to call at load-time (not used currently) */ - char *fini_symbol; /* symbols to call at unload-time (not used currently) */ - char *mapfile; /* create a mapfile (not used currently) */ - - /* output type, see TCC_OUTPUT_XXX */ - int output_type; - /* output format, see TCC_OUTPUT_FORMAT_xxx */ - int output_format; - /* nth test to run with -dt -run */ - int run_test; - - /* array of all loaded dlls (including those referenced by loaded dlls) */ - DLLReference **loaded_dlls; - int nb_loaded_dlls; - - /* include paths */ - char **include_paths; - int nb_include_paths; - - char **sysinclude_paths; - int nb_sysinclude_paths; - - /* library paths */ - char **library_paths; - int nb_library_paths; - - /* crt?.o object path */ - char **crt_paths; - int nb_crt_paths; - - /* -D / -U options */ - CString cmdline_defs; - /* -include options */ - CString cmdline_incl; - - /* error handling */ - void *error_opaque; - void (*error_func)(void *opaque, const char *msg); - int error_set_jmp_enabled; - jmp_buf error_jmp_buf; - int nb_errors; - - /* output file for preprocessing (-E) */ - FILE *ppfp; - - /* for -MD/-MF: collected dependencies for this compilation */ - char **target_deps; - int nb_target_deps; - - /* compilation */ - BufferedFile *include_stack[INCLUDE_STACK_SIZE]; - BufferedFile **include_stack_ptr; - - int ifdef_stack[IFDEF_STACK_SIZE]; - int *ifdef_stack_ptr; - - /* included files enclosed with #ifndef MACRO */ - int cached_includes_hash[CACHED_INCLUDES_HASH_SIZE]; - CachedInclude **cached_includes; - int nb_cached_includes; - - /* #pragma pack stack */ - int pack_stack[PACK_STACK_SIZE]; - int *pack_stack_ptr; - char **pragma_libs; - int nb_pragma_libs; - - /* inline functions are stored as token lists and compiled last - only if referenced */ - struct InlineFunc **inline_fns; - int nb_inline_fns; - - /* sections */ - Section **sections; - int nb_sections; /* number of sections, including first dummy section */ - - Section **priv_sections; - int nb_priv_sections; /* number of private sections */ - - /* predefined sections */ - Section *text_section, *data_section, *rodata_section, *bss_section; - Section *common_section; - Section *cur_text_section; /* current section where function code is generated */ -#ifdef CONFIG_TCC_BCHECK - /* bound check related sections */ - Section *bounds_section; /* contains global data bound description */ - Section *lbounds_section; /* contains local data bound description */ -#endif - /* symbol section */ - Section *symtab_section; - /* temporary dynamic symbol sections (for dll loading) */ - Section *dynsymtab_section; - /* exported dynamic symbol section */ - Section *dynsym; - /* copy of the global symtab_section variable */ - Section *symtab; - /* got & plt handling */ - Section *got, *plt; - /* debug sections */ - Section *stab_section; - Section *dwarf_info_section; - Section *dwarf_abbrev_section; - Section *dwarf_line_section; - Section *dwarf_aranges_section; - Section *dwarf_str_section; - Section *dwarf_line_str_section; - int dwlo, dwhi; /* dwarf section range */ - /* test coverage */ - Section *tcov_section; - /* debug state */ - struct _tccdbg *dState; - - /* Is there a new undefined sym since last new_undef_sym() */ - int new_undef_sym; - /* extra attributes (eg. GOT/PLT value) for symtab symbols */ - struct sym_attr *sym_attrs; - int nb_sym_attrs; - /* ptr to next reloc entry reused */ - ElfW_Rel *qrel; - #define qrel s1->qrel - -#ifdef TCC_TARGET_RISCV64 - struct pcrel_hi { addr_t addr, val; } last_hi; - #define last_hi s1->last_hi -#endif - -#ifdef TCC_TARGET_PE - /* PE info */ - int pe_subsystem; - unsigned pe_characteristics; - unsigned pe_file_align; - unsigned pe_stack_size; - addr_t pe_imagebase; -# ifdef TCC_TARGET_X86_64 - Section *uw_pdata; - int uw_sym; - unsigned uw_offs; -# endif -#endif - -#if defined TCC_TARGET_MACHO - char *install_name; - uint32_t compatibility_version; - uint32_t current_version; -#endif - -#ifndef ELF_OBJ_ONLY - int nb_sym_versions; - struct sym_version *sym_versions; - int nb_sym_to_version; - int *sym_to_version; - int dt_verneednum; - Section *versym_section; - Section *verneed_section; -#endif - -#ifdef TCC_IS_NATIVE - const char *runtime_main; - void **runtime_mem; - int nb_runtime_mem; -#endif - -#ifdef CONFIG_TCC_BACKTRACE - int rt_num_callers; -#endif - - /* benchmark info */ - int total_idents; - int total_lines; - unsigned int total_bytes; - unsigned int total_output[4]; - - /* option -dnum (for general development purposes) */ - int g_debug; - - /* used by tcc_load_ldscript */ - int fd, cc; - - /* for warnings/errors for object files */ - const char *current_filename; - - /* used by main and tcc_parse_args only */ - struct filespec **files; /* files seen on command line */ - int nb_files; /* number thereof */ - int nb_libraries; /* number of libs thereof */ - char *outfile; /* output filename */ - char *deps_outfile; /* option -MF */ - int argc; - char **argv; - CString linker_arg; /* collect -Wl options */ -}; - -struct filespec { - char type; - char name[1]; -}; - -/* The current value can be: */ -#define VT_VALMASK 0x003f /* mask for value location, register or: */ -#define VT_CONST 0x0030 /* constant in vc (must be first non register value) */ -#define VT_LLOCAL 0x0031 /* lvalue, offset on stack */ -#define VT_LOCAL 0x0032 /* offset on stack */ -#define VT_CMP 0x0033 /* the value is stored in processor flags (in vc) */ -#define VT_JMP 0x0034 /* value is the consequence of jmp true (even) */ -#define VT_JMPI 0x0035 /* value is the consequence of jmp false (odd) */ -#define VT_LVAL 0x0100 /* var is an lvalue */ -#define VT_SYM 0x0200 /* a symbol value is added */ -#define VT_MUSTCAST 0x0C00 /* value must be casted to be correct (used for - char/short stored in integer registers) */ -#define VT_NONCONST 0x1000 /* VT_CONST, but not an (C standard) integer - constant expression */ -#define VT_MUSTBOUND 0x4000 /* bound checking must be done before - dereferencing value */ -#define VT_BOUNDED 0x8000 /* value is bounded. The address of the - bounding function call point is in vc */ -/* types */ -#define VT_BTYPE 0x000f /* mask for basic type */ -#define VT_VOID 0 /* void type */ -#define VT_BYTE 1 /* signed byte type */ -#define VT_SHORT 2 /* short type */ -#define VT_INT 3 /* integer type */ -#define VT_LLONG 4 /* 64 bit integer */ -#define VT_PTR 5 /* pointer */ -#define VT_FUNC 6 /* function type */ -#define VT_STRUCT 7 /* struct/union definition */ -#define VT_FLOAT 8 /* IEEE float */ -#define VT_DOUBLE 9 /* IEEE double */ -#define VT_LDOUBLE 10 /* IEEE long double */ -#define VT_BOOL 11 /* ISOC99 boolean type */ -#define VT_QLONG 13 /* 128-bit integer. Only used for x86-64 ABI */ -#define VT_QFLOAT 14 /* 128-bit float. Only used for x86-64 ABI */ - -#define VT_UNSIGNED 0x0010 /* unsigned type */ -#define VT_DEFSIGN 0x0020 /* explicitly signed or unsigned */ -#define VT_ARRAY 0x0040 /* array type (also has VT_PTR) */ -#define VT_BITFIELD 0x0080 /* bitfield modifier */ -#define VT_CONSTANT 0x0100 /* const modifier */ -#define VT_VOLATILE 0x0200 /* volatile modifier */ -#define VT_VLA 0x0400 /* VLA type (also has VT_PTR and VT_ARRAY) */ -#define VT_LONG 0x0800 /* long type (also has VT_INT rsp. VT_LLONG) */ - -/* storage */ -#define VT_EXTERN 0x00001000 /* extern definition */ -#define VT_STATIC 0x00002000 /* static variable */ -#define VT_TYPEDEF 0x00004000 /* typedef definition */ -#define VT_INLINE 0x00008000 /* inline definition */ -/* currently unused: 0x000[1248]0000 */ - -#define VT_STRUCT_SHIFT 20 /* shift for bitfield shift values (32 - 2*6) */ -#define VT_STRUCT_MASK (((1U << (6+6)) - 1) << VT_STRUCT_SHIFT | VT_BITFIELD) -#define BIT_POS(t) (((t) >> VT_STRUCT_SHIFT) & 0x3f) -#define BIT_SIZE(t) (((t) >> (VT_STRUCT_SHIFT + 6)) & 0x3f) - -#define VT_UNION (1 << VT_STRUCT_SHIFT | VT_STRUCT) -#define VT_ENUM (2 << VT_STRUCT_SHIFT) /* integral type is an enum really */ -#define VT_ENUM_VAL (3 << VT_STRUCT_SHIFT) /* integral type is an enum constant really */ - -#define IS_ENUM(t) ((t & VT_STRUCT_MASK) == VT_ENUM) -#define IS_ENUM_VAL(t) ((t & VT_STRUCT_MASK) == VT_ENUM_VAL) -#define IS_UNION(t) ((t & (VT_STRUCT_MASK|VT_BTYPE)) == VT_UNION) - -#define VT_ATOMIC VT_VOLATILE - -/* type mask (except storage) */ -#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE) -#define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK)) - -/* symbol was created by tccasm.c first */ -#define VT_ASM (VT_VOID | 1 << VT_STRUCT_SHIFT) -#define VT_ASM_FUNC (VT_ASM | 2 << VT_STRUCT_SHIFT) -#define IS_ASM_SYM(sym) (((sym)->type.t & (VT_BTYPE | VT_ASM)) == VT_ASM) - -/* general: set/get the pseudo-bitfield value for bit-mask M */ -#define BFVAL(M,N) ((unsigned)((M) & ~((M) << 1)) * (N)) -#define BFGET(X,M) (((X) & (M)) / BFVAL(M,1)) -#define BFSET(X,M,N) ((X) = ((X) & ~(M)) | BFVAL(M,N)) - -/* token values */ - -/* conditional ops */ -#define TOK_LAND 0x90 -#define TOK_LOR 0x91 -/* warning: the following compare tokens depend on i386 asm code */ -#define TOK_ULT 0x92 -#define TOK_UGE 0x93 -#define TOK_EQ 0x94 -#define TOK_NE 0x95 -#define TOK_ULE 0x96 -#define TOK_UGT 0x97 -#define TOK_Nset 0x98 -#define TOK_Nclear 0x99 -#define TOK_LT 0x9c -#define TOK_GE 0x9d -#define TOK_LE 0x9e -#define TOK_GT 0x9f - -#define TOK_ISCOND(t) (t >= TOK_LAND && t <= TOK_GT) - -#define TOK_DEC 0x80 /* -- */ -#define TOK_MID 0x81 /* inc/dec, to void constant */ -#define TOK_INC 0x82 /* ++ */ -#define TOK_UDIV 0x83 /* unsigned division */ -#define TOK_UMOD 0x84 /* unsigned modulo */ -#define TOK_PDIV 0x85 /* fast division with undefined rounding for pointers */ -#define TOK_UMULL 0x86 /* unsigned 32x32 -> 64 mul */ -#define TOK_ADDC1 0x87 /* add with carry generation */ -#define TOK_ADDC2 0x88 /* add with carry use */ -#define TOK_SUBC1 0x89 /* add with carry generation */ -#define TOK_SUBC2 0x8a /* add with carry use */ -#define TOK_SHL '<' /* shift left */ -#define TOK_SAR '>' /* signed shift right */ -#define TOK_SHR 0x8b /* unsigned shift right */ -#define TOK_NEG TOK_MID /* unary minus operation (for floats) */ - -#define TOK_ARROW 0xa0 /* -> */ -#define TOK_DOTS 0xa1 /* three dots */ -#define TOK_TWODOTS 0xa2 /* C++ token ? */ -#define TOK_TWOSHARPS 0xa3 /* ## preprocessing token */ -#define TOK_PLCHLDR 0xa4 /* placeholder token as defined in C99 */ -#define TOK_NOSUBST 0xa5 /* means following token has already been pp'd */ -#define TOK_PPJOIN 0xa6 /* A '##' in the right position to mean pasting */ - -/* assignment operators */ -#define TOK_A_ADD 0xb0 -#define TOK_A_SUB 0xb1 -#define TOK_A_MUL 0xb2 -#define TOK_A_DIV 0xb3 -#define TOK_A_MOD 0xb4 -#define TOK_A_AND 0xb5 -#define TOK_A_OR 0xb6 -#define TOK_A_XOR 0xb7 -#define TOK_A_SHL 0xb8 -#define TOK_A_SAR 0xb9 - -#define TOK_ASSIGN(t) (t >= TOK_A_ADD && t <= TOK_A_SAR) -#define TOK_ASSIGN_OP(t) ("+-*/%&|^<>"[t - TOK_A_ADD]) - -/* tokens that carry values (in additional token string space / tokc) --> */ -#define TOK_CCHAR 0xc0 /* char constant in tokc */ -#define TOK_LCHAR 0xc1 -#define TOK_CINT 0xc2 /* number in tokc */ -#define TOK_CUINT 0xc3 /* unsigned int constant */ -#define TOK_CLLONG 0xc4 /* long long constant */ -#define TOK_CULLONG 0xc5 /* unsigned long long constant */ -#define TOK_CLONG 0xc6 /* long constant */ -#define TOK_CULONG 0xc7 /* unsigned long constant */ -#define TOK_STR 0xc8 /* pointer to string in tokc */ -#define TOK_LSTR 0xc9 -#define TOK_CFLOAT 0xca /* float constant */ -#define TOK_CDOUBLE 0xcb /* double constant */ -#define TOK_CLDOUBLE 0xcc /* long double constant */ -#define TOK_PPNUM 0xcd /* preprocessor number */ -#define TOK_PPSTR 0xce /* preprocessor string */ -#define TOK_LINENUM 0xcf /* line number info */ - -#define TOK_HAS_VALUE(t) (t >= TOK_CCHAR && t <= TOK_LINENUM) - -#define TOK_EOF (-1) /* end of file */ -#define TOK_LINEFEED 10 /* line feed */ - -/* all identifiers and strings have token above that */ -#define TOK_IDENT 256 - -enum tcc_token { - TOK_LAST = TOK_IDENT - 1 -#define DEF(id, str) ,id -#include "tcctok.h" -#undef DEF -}; - -/* keywords: tok >= TOK_IDENT && tok < TOK_UIDENT */ -#define TOK_UIDENT TOK_DEFINE - -/* ------------ libtcc.c ------------ */ - -ST_DATA struct TCCState *tcc_state; -ST_DATA void** stk_data; -ST_DATA int nb_stk_data; - -/* public functions currently used by the tcc main function */ -ST_FUNC char *pstrcpy(char *buf, size_t buf_size, const char *s); -ST_FUNC char *pstrcat(char *buf, size_t buf_size, const char *s); -ST_FUNC char *pstrncpy(char *out, const char *in, size_t num); -PUB_FUNC char *tcc_basename(const char *name); -PUB_FUNC char *tcc_fileextension (const char *name); - -#ifndef MEM_DEBUG -PUB_FUNC void tcc_free(void *ptr); -PUB_FUNC void *tcc_malloc(unsigned long size); -PUB_FUNC void *tcc_mallocz(unsigned long size); -PUB_FUNC void *tcc_realloc(void *ptr, unsigned long size); -PUB_FUNC char *tcc_strdup(const char *str); -#else -#define tcc_free(ptr) tcc_free_debug(ptr) -#define tcc_malloc(size) tcc_malloc_debug(size, __FILE__, __LINE__) -#define tcc_mallocz(size) tcc_mallocz_debug(size, __FILE__, __LINE__) -#define tcc_realloc(ptr,size) tcc_realloc_debug(ptr, size, __FILE__, __LINE__) -#define tcc_strdup(str) tcc_strdup_debug(str, __FILE__, __LINE__) -PUB_FUNC void tcc_free_debug(void *ptr); -PUB_FUNC void *tcc_malloc_debug(unsigned long size, const char *file, int line); -PUB_FUNC void *tcc_mallocz_debug(unsigned long size, const char *file, int line); -PUB_FUNC void *tcc_realloc_debug(void *ptr, unsigned long size, const char *file, int line); -PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line); -#endif - -#define free(p) use_tcc_free(p) -#define malloc(s) use_tcc_malloc(s) -#define realloc(p, s) use_tcc_realloc(p, s) -#undef strdup -#define strdup(s) use_tcc_strdup(s) -PUB_FUNC int _tcc_error_noabort(const char *fmt, ...) PRINTF_LIKE(1,2); -PUB_FUNC NORETURN void _tcc_error(const char *fmt, ...) PRINTF_LIKE(1,2); -PUB_FUNC void _tcc_warning(const char *fmt, ...) PRINTF_LIKE(1,2); -#define tcc_internal_error(msg) tcc_error("internal compiler error\n"\ - "%s:%d: in %s(): " msg, __FILE__,__LINE__,__FUNCTION__) - -/* other utilities */ -ST_FUNC void dynarray_add(void *ptab, int *nb_ptr, void *data); -ST_FUNC void dynarray_reset(void *pp, int *n); -ST_INLN void cstr_ccat(CString *cstr, int ch); -ST_FUNC void cstr_cat(CString *cstr, const char *str, int len); -ST_FUNC void cstr_wccat(CString *cstr, int ch); -ST_FUNC void cstr_new(CString *cstr); -ST_FUNC void cstr_free(CString *cstr); -ST_FUNC int cstr_printf(CString *cs, const char *fmt, ...) PRINTF_LIKE(2,3); -ST_FUNC int cstr_vprintf(CString *cstr, const char *fmt, va_list ap); -ST_FUNC void cstr_reset(CString *cstr); -ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen); -ST_FUNC int tcc_open(TCCState *s1, const char *filename); -ST_FUNC void tcc_close(void); - -/* mark a memory pointer on stack for cleanup after errors */ -#define stk_push(p) dynarray_add(&stk_data, &nb_stk_data, p) -#define stk_pop() (--nb_stk_data) -/* mark CString on stack for cleanup errors */ -#define cstr_new_s(cstr) (cstr_new(cstr), stk_push(&(cstr)->data)) -#define cstr_free_s(cstr) (cstr_free(cstr), stk_pop()) - -ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags); -/* flags: */ -#define AFF_PRINT_ERROR 0x10 /* print error if file not found */ -#define AFF_REFERENCED_DLL 0x20 /* load a referenced dll from another dll */ -#define AFF_TYPE_BIN 0x40 /* file to add is binary */ -#define AFF_WHOLE_ARCHIVE 0x80 /* load all objects from archive */ -/* s->filetype: */ -#define AFF_TYPE_NONE 0 -#define AFF_TYPE_C 1 -#define AFF_TYPE_ASM 2 -#define AFF_TYPE_ASMPP 4 -#define AFF_TYPE_LIB 8 -#define AFF_TYPE_MASK (15 | AFF_TYPE_BIN) -/* values from tcc_object_type(...) */ -#define AFF_BINTYPE_REL 1 -#define AFF_BINTYPE_DYN 2 -#define AFF_BINTYPE_AR 3 -#define AFF_BINTYPE_C67 4 - -#ifndef ELF_OBJ_ONLY -ST_FUNC int tcc_add_crt(TCCState *s, const char *filename); -#endif -ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags); -ST_FUNC void tcc_add_support(TCCState *s1, const char *filename); -#ifdef CONFIG_TCC_BCHECK -ST_FUNC void tcc_add_bcheck(TCCState *s1); -#endif -#ifdef CONFIG_TCC_BACKTRACE -ST_FUNC void tcc_add_btstub(TCCState *s1); -#endif -ST_FUNC void tcc_add_pragma_libs(TCCState *s1); -PUB_FUNC int tcc_add_library_err(TCCState *s, const char *f); -PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time); -PUB_FUNC int tcc_parse_args(TCCState *s, int *argc, char ***argv, int optind); -#ifdef _WIN32 -ST_FUNC char *normalize_slashes(char *path); -#endif -ST_FUNC DLLReference *tcc_add_dllref(TCCState *s1, const char *dllname, int level); -ST_FUNC char *tcc_load_text(int fd); - -/* tcc_parse_args return codes: */ -#define OPT_HELP 1 -#define OPT_HELP2 2 -#define OPT_V 3 -#define OPT_PRINT_DIRS 4 -#define OPT_AR 5 -#define OPT_IMPDEF 6 -#define OPT_M32 32 -#define OPT_M64 64 - -/* ------------ tccpp.c ------------ */ - -ST_DATA struct BufferedFile *file; -ST_DATA int tok; -ST_DATA CValue tokc; -ST_DATA const int *macro_ptr; -ST_DATA int parse_flags; -ST_DATA int tok_flags; -ST_DATA CString tokcstr; /* current parsed string, if any */ - -/* display benchmark infos */ -ST_DATA int tok_ident; -ST_DATA TokenSym **table_ident; - -#define TOK_FLAG_BOL 0x0001 /* beginning of line before */ -#define TOK_FLAG_BOF 0x0002 /* beginning of file before */ -#define TOK_FLAG_ENDIF 0x0004 /* a endif was found matching starting #ifdef */ -#define TOK_FLAG_EOF 0x0008 /* end of file */ - -#define PARSE_FLAG_PREPROCESS 0x0001 /* activate preprocessing */ -#define PARSE_FLAG_TOK_NUM 0x0002 /* return numbers instead of TOK_PPNUM */ -#define PARSE_FLAG_LINEFEED 0x0004 /* line feed is returned as a - token. line feed is also - returned at eof */ -#define PARSE_FLAG_ASM_FILE 0x0008 /* we processing an asm file: '#' can be used for line comment, etc. */ -#define PARSE_FLAG_SPACES 0x0010 /* next() returns space tokens (for -E) */ -#define PARSE_FLAG_ACCEPT_STRAYS 0x0020 /* next() returns '\\' token */ -#define PARSE_FLAG_TOK_STR 0x0040 /* return parsed strings instead of TOK_PPSTR */ - -/* isidnum_table flags: */ -#define IS_SPC 1 -#define IS_ID 2 -#define IS_NUM 4 - -enum line_macro_output_format { - LINE_MACRO_OUTPUT_FORMAT_GCC, - LINE_MACRO_OUTPUT_FORMAT_NONE, - LINE_MACRO_OUTPUT_FORMAT_STD, - LINE_MACRO_OUTPUT_FORMAT_P10 = 11 -}; - -ST_FUNC TokenSym *tok_alloc(const char *str, int len); -ST_FUNC int tok_alloc_const(const char *str); -ST_FUNC const char *get_tok_str(int v, CValue *cv); -ST_FUNC void begin_macro(TokenString *str, int alloc); -ST_FUNC void end_macro(void); -ST_FUNC int set_idnum(int c, int val); -ST_INLN void tok_str_new(TokenString *s); -ST_FUNC TokenString *tok_str_alloc(void); -ST_FUNC void tok_str_free(TokenString *s); -ST_FUNC void tok_str_free_str(int *str); -ST_FUNC void tok_str_add(TokenString *s, int t); -ST_FUNC void tok_str_add_tok(TokenString *s); -ST_INLN void define_push(int v, int macro_type, int *str, Sym *first_arg); -ST_FUNC void define_undef(Sym *s); -ST_INLN Sym *define_find(int v); -ST_FUNC void free_defines(Sym *b); -ST_FUNC void parse_define(void); -ST_FUNC void preprocess(int is_bof); -ST_FUNC void next(void); -ST_INLN void unget_tok(int last_tok); -ST_FUNC void preprocess_start(TCCState *s1, int filetype); -ST_FUNC void preprocess_end(TCCState *s1); -ST_FUNC void tccpp_new(TCCState *s); -ST_FUNC void tccpp_delete(TCCState *s); -ST_FUNC int tcc_preprocess(TCCState *s1); -ST_FUNC void skip(int c); -ST_FUNC NORETURN void expect(const char *msg); - -/* space excluding newline */ -static inline int is_space(int ch) { - return ch == ' ' || ch == '\t' || ch == '\v' || ch == '\f' || ch == '\r'; -} -static inline int isid(int c) { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'; -} -static inline int isnum(int c) { - return c >= '0' && c <= '9'; -} -static inline int isoct(int c) { - return c >= '0' && c <= '7'; -} -static inline int toup(int c) { - return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; -} - -/* ------------ tccgen.c ------------ */ - -#define SYM_POOL_NB (8192 / sizeof(Sym)) - -ST_DATA Sym *global_stack; -ST_DATA Sym *local_stack; -ST_DATA Sym *local_label_stack; -ST_DATA Sym *global_label_stack; -ST_DATA Sym *define_stack; -ST_DATA CType int_type, func_old_type, char_pointer_type; -ST_DATA SValue *vtop; -ST_DATA int rsym, anon_sym, ind, loc; -ST_DATA char debug_modes; - -ST_DATA int nocode_wanted; /* true if no code generation wanted for an expression */ -ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */ -ST_DATA CType func_vt; /* current function return type (used by return instruction) */ -ST_DATA int func_var; /* true if current function is variadic */ -ST_DATA int func_vc; -ST_DATA int func_ind; -ST_DATA const char *funcname; - -ST_FUNC void tccgen_init(TCCState *s1); -ST_FUNC int tccgen_compile(TCCState *s1); -ST_FUNC void tccgen_finish(TCCState *s1); -ST_FUNC void check_vstack(void); - -ST_INLN int is_float(int t); -ST_FUNC int ieee_finite(double d); -ST_FUNC int exact_log2p1(int i); -ST_FUNC void test_lvalue(void); - -ST_FUNC ElfSym *elfsym(Sym *); -ST_FUNC void update_storage(Sym *sym); -ST_FUNC void put_extern_sym2(Sym *sym, int sh_num, addr_t value, unsigned long size, int can_add_underscore); -ST_FUNC void put_extern_sym(Sym *sym, Section *section, addr_t value, unsigned long size); -#if PTR_SIZE == 4 -ST_FUNC void greloc(Section *s, Sym *sym, unsigned long offset, int type); -#endif -ST_FUNC void greloca(Section *s, Sym *sym, unsigned long offset, int type, addr_t addend); - -ST_INLN void sym_free(Sym *sym); -ST_FUNC Sym *sym_push(int v, CType *type, int r, int c); -ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep); -ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, int c); -ST_FUNC Sym *sym_find2(Sym *s, int v); -ST_INLN Sym *sym_find(int v); -ST_FUNC Sym *label_find(int v); -ST_FUNC Sym *label_push(Sym **ptop, int v, int flags); -ST_FUNC void label_pop(Sym **ptop, Sym *slast, int keep); -ST_INLN Sym *struct_find(int v); - -ST_FUNC Sym *global_identifier_push(int v, int t, int c); -ST_FUNC Sym *external_global_sym(int v, CType *type); -ST_FUNC Sym *external_helper_sym(int v); -ST_FUNC void vpush_helper_func(int v); -ST_FUNC void vset(CType *type, int r, int v); -ST_FUNC void vset_VT_CMP(int op); -ST_FUNC void vpushi(int v); -ST_FUNC void vpushv(SValue *v); -ST_FUNC void vpushsym(CType *type, Sym *sym); -ST_FUNC void vswap(void); -ST_FUNC void vrote(SValue *e, int n); -ST_FUNC void vrott(int n); -ST_FUNC void vrotb(int n); -ST_FUNC void vpop(void); -#if PTR_SIZE == 4 -ST_FUNC void lexpand(void); -#endif -#ifdef TCC_TARGET_ARM -ST_FUNC int get_reg_ex(int rc, int rc2); -#endif -ST_FUNC void save_reg(int r); -ST_FUNC void save_reg_upstack(int r, int n); -ST_FUNC int get_reg(int rc); -ST_FUNC void save_regs(int n); -ST_FUNC void gaddrof(void); -ST_FUNC int gv(int rc); -ST_FUNC void gv2(int rc1, int rc2); -ST_FUNC void gen_op(int op); -ST_FUNC int type_size(CType *type, int *a); -ST_FUNC void mk_pointer(CType *type); -ST_FUNC void vstore(void); -ST_FUNC void inc(int post, int c); -ST_FUNC CString* parse_mult_str(const char *msg); -ST_FUNC CString* parse_asm_str(void); -ST_FUNC void indir(void); -ST_FUNC void unary(void); -ST_FUNC void gexpr(void); -ST_FUNC int expr_const(void); -#if defined CONFIG_TCC_BCHECK || defined TCC_TARGET_C67 -ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsigned long size); -#endif -#if defined TCC_TARGET_X86_64 && !defined TCC_TARGET_PE -ST_FUNC int classify_x86_64_va_arg(CType *ty); -#endif -#ifdef CONFIG_TCC_BCHECK -ST_FUNC void gbound_args(int nb_args); -ST_DATA int func_bound_add_epilog; -#endif - -/* ------------ tccelf.c ------------ */ - -#define TCC_OUTPUT_FORMAT_ELF 0 /* default output format: ELF */ -#define TCC_OUTPUT_FORMAT_BINARY 1 /* binary image output */ -#define TCC_OUTPUT_FORMAT_COFF 2 /* COFF */ -#define TCC_OUTPUT_DYN TCC_OUTPUT_DLL - -#define ARMAG "!<arch>\n" /* For COFF and a.out archives */ - -typedef struct { - unsigned int n_strx; /* index into string table of name */ - unsigned char n_type; /* type of symbol */ - unsigned char n_other; /* misc info (usually empty) */ - unsigned short n_desc; /* description field */ - unsigned int n_value; /* value of symbol */ -} Stab_Sym; - -ST_FUNC void tccelf_new(TCCState *s); -ST_FUNC void tccelf_delete(TCCState *s); -ST_FUNC void tccelf_begin_file(TCCState *s1); -ST_FUNC void tccelf_end_file(TCCState *s1); -#ifdef CONFIG_TCC_BCHECK -ST_FUNC void tccelf_bounds_new(TCCState *s); -#endif -ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags); -ST_FUNC void section_realloc(Section *sec, unsigned long new_size); -ST_FUNC size_t section_add(Section *sec, addr_t size, int align); -ST_FUNC void *section_ptr_add(Section *sec, addr_t size); -ST_FUNC Section *find_section(TCCState *s1, const char *name); -ST_FUNC Section *new_symtab(TCCState *s1, const char *symtab_name, int sh_type, int sh_flags, const char *strtab_name, const char *hash_name, int hash_sh_flags); - -ST_FUNC int put_elf_str(Section *s, const char *sym); -ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size, int info, int other, int shndx, const char *name); -ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size, int info, int other, int shndx, const char *name); -ST_FUNC int find_elf_sym(Section *s, const char *name); -ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, int type, int symbol); -ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset, int type, int symbol, addr_t addend); - -ST_FUNC void resolve_common_syms(TCCState *s1); -ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve); -ST_FUNC void relocate_sections(TCCState *s1); - -ST_FUNC ssize_t full_read(int fd, void *buf, size_t count); -ST_FUNC void *load_data(int fd, unsigned long file_offset, unsigned long size); -ST_FUNC int tcc_object_type(int fd, ElfW(Ehdr) *h); -ST_FUNC int tcc_load_object_file(TCCState *s1, int fd, unsigned long file_offset); -ST_FUNC int tcc_load_archive(TCCState *s1, int fd, int alacarte); -ST_FUNC void add_array(TCCState *s1, const char *sec, int c); - -ST_FUNC struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc); -ST_FUNC addr_t get_sym_addr(TCCState *s, const char *name, int err, int forc); -ST_FUNC void list_elf_symbols(TCCState *s, void *ctx, - void (*symbol_cb)(void *ctx, const char *name, const void *val)); -ST_FUNC int set_global_sym(TCCState *s1, const char *name, Section *sec, addr_t offs); - -/* Browse each elem of type <type> in section <sec> starting at elem <startoff> - using variable <elem> */ -#define for_each_elem(sec, startoff, elem, type) \ - for (elem = (type *) sec->data + startoff; \ - elem < (type *) (sec->data + sec->data_offset); elem++) - -#ifndef ELF_OBJ_ONLY -ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level); -ST_FUNC int tcc_load_ldscript(TCCState *s1, int fd); -#endif -#ifndef TCC_TARGET_PE -ST_FUNC void tcc_add_runtime(TCCState *s1); -#endif - -/* ------------ xxx-link.c ------------ */ - -#if !defined ELF_OBJ_ONLY || defined TCC_TARGET_MACHO -ST_FUNC int code_reloc (int reloc_type); -ST_FUNC int gotplt_entry_type (int reloc_type); -/* Whether to generate a GOT/PLT entry and when. NO_GOTPLT_ENTRY is first so - that unknown relocation don't create a GOT or PLT entry */ -enum gotplt_entry { - NO_GOTPLT_ENTRY, /* never generate (eg. GLOB_DAT & JMP_SLOT relocs) */ - BUILD_GOT_ONLY, /* only build GOT (eg. TPOFF relocs) */ - AUTO_GOTPLT_ENTRY, /* generate if sym is UNDEF */ - ALWAYS_GOTPLT_ENTRY /* always generate (eg. PLTOFF relocs) */ -}; -#define NEED_RELOC_TYPE - -#if !defined TCC_TARGET_MACHO || defined TCC_IS_NATIVE -ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr); -ST_FUNC void relocate_plt(TCCState *s1); -ST_FUNC void build_got_entries(TCCState *s1, int got_sym); /* in tccelf.c */ -#define NEED_BUILD_GOT - -#endif -#endif - -ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val); - -/* ------------ xxx-gen.c ------------ */ -ST_DATA const char * const target_machine_defs; -ST_DATA const int reg_classes[NB_REGS]; - -ST_FUNC void gsym_addr(int t, int a); -ST_FUNC void gsym(int t); -ST_FUNC void load(int r, SValue *sv); -ST_FUNC void store(int r, SValue *v); -ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize); -ST_FUNC void gfunc_call(int nb_args); -ST_FUNC void gfunc_prolog(Sym *func_sym); -ST_FUNC void gfunc_epilog(void); -ST_FUNC void gen_fill_nops(int); -ST_FUNC int gjmp(int t); -ST_FUNC void gjmp_addr(int a); -ST_FUNC int gjmp_cond(int op, int t); -ST_FUNC int gjmp_append(int n, int t); -ST_FUNC void gen_opi(int op); -ST_FUNC void gen_opf(int op); -ST_FUNC void gen_cvt_ftoi(int t); -ST_FUNC void gen_cvt_itof(int t); -ST_FUNC void gen_cvt_ftof(int t); -ST_FUNC void ggoto(void); -#ifndef TCC_TARGET_C67 -ST_FUNC void o(unsigned int c); -#endif -ST_FUNC void gen_vla_sp_save(int addr); -ST_FUNC void gen_vla_sp_restore(int addr); -ST_FUNC void gen_vla_alloc(CType *type, int align); - -static inline uint16_t read16le(unsigned char *p) { - return p[0] | (uint16_t)p[1] << 8; -} -static inline void write16le(unsigned char *p, uint16_t x) { - p[0] = x & 255; p[1] = x >> 8 & 255; -} -static inline uint32_t read32le(unsigned char *p) { - return read16le(p) | (uint32_t)read16le(p + 2) << 16; -} -static inline void write32le(unsigned char *p, uint32_t x) { - write16le(p, x); write16le(p + 2, x >> 16); -} -static inline void add32le(unsigned char *p, int32_t x) { - write32le(p, read32le(p) + x); -} -static inline uint64_t read64le(unsigned char *p) { - return read32le(p) | (uint64_t)read32le(p + 4) << 32; -} -static inline void write64le(unsigned char *p, uint64_t x) { - write32le(p, x); write32le(p + 4, x >> 32); -} -static inline void add64le(unsigned char *p, int64_t x) { - write64le(p, read64le(p) + x); -} - -/* ------------ i386-gen.c ------------ */ -#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 || defined TCC_TARGET_ARM -ST_FUNC void g(int c); -ST_FUNC void gen_le16(int c); -ST_FUNC void gen_le32(int c); -#endif -#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 -ST_FUNC void gen_addr32(int r, Sym *sym, int c); -ST_FUNC void gen_addrpc32(int r, Sym *sym, int c); -ST_FUNC void gen_cvt_csti(int t); -ST_FUNC void gen_increment_tcov (SValue *sv); -#endif - -/* ------------ x86_64-gen.c ------------ */ -#ifdef TCC_TARGET_X86_64 -ST_FUNC void gen_addr64(int r, Sym *sym, int64_t c); -ST_FUNC void gen_opl(int op); -#ifdef TCC_TARGET_PE -ST_FUNC void gen_vla_result(int addr); -#endif -ST_FUNC void gen_cvt_sxtw(void); -ST_FUNC void gen_cvt_csti(int t); -#endif - -/* ------------ arm-gen.c ------------ */ -#ifdef TCC_TARGET_ARM -#if defined(TCC_ARM_EABI) && !defined(CONFIG_TCC_ELFINTERP) -PUB_FUNC const char *default_elfinterp(struct TCCState *s); -#endif -ST_FUNC void arm_init(struct TCCState *s); -ST_FUNC void gen_increment_tcov (SValue *sv); -#endif - -/* ------------ arm64-gen.c ------------ */ -#ifdef TCC_TARGET_ARM64 -ST_FUNC void gen_opl(int op); -ST_FUNC void gfunc_return(CType *func_type); -ST_FUNC void gen_va_start(void); -ST_FUNC void gen_va_arg(CType *t); -ST_FUNC void gen_clear_cache(void); -ST_FUNC void gen_cvt_sxtw(void); -ST_FUNC void gen_cvt_csti(int t); -ST_FUNC void gen_increment_tcov (SValue *sv); -#endif - -/* ------------ riscv64-gen.c ------------ */ -#ifdef TCC_TARGET_RISCV64 -ST_FUNC void gen_opl(int op); -//ST_FUNC void gfunc_return(CType *func_type); -ST_FUNC void gen_va_start(void); -ST_FUNC void arch_transfer_ret_regs(int); -ST_FUNC void gen_cvt_sxtw(void); -ST_FUNC void gen_increment_tcov (SValue *sv); -#endif - -/* ------------ c67-gen.c ------------ */ -#ifdef TCC_TARGET_C67 -#endif - -/* ------------ tcccoff.c ------------ */ -#ifdef TCC_TARGET_COFF -ST_FUNC int tcc_output_coff(TCCState *s1, FILE *f); -ST_FUNC int tcc_load_coff(TCCState * s1, int fd); -#endif - -/* ------------ tccasm.c ------------ */ -ST_FUNC void asm_instr(void); -ST_FUNC void asm_global_instr(void); -ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess); -#ifdef CONFIG_TCC_ASM -ST_FUNC int find_constraint(ASMOperand *operands, int nb_operands, const char *name, const char **pp); -ST_FUNC Sym* get_asm_sym(int name, Sym *csym); -ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe); -ST_FUNC int asm_int_expr(TCCState *s1); -/* ------------ i386-asm.c ------------ */ -ST_FUNC void gen_expr32(ExprValue *pe); -#ifdef TCC_TARGET_X86_64 -ST_FUNC void gen_expr64(ExprValue *pe); -#endif -ST_FUNC void asm_opcode(TCCState *s1, int opcode); -ST_FUNC int asm_parse_regvar(int t); -ST_FUNC void asm_compute_constraints(ASMOperand *operands, int nb_operands, int nb_outputs, const uint8_t *clobber_regs, int *pout_reg); -ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier); -ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, int nb_outputs, int is_output, uint8_t *clobber_regs, int out_reg); -ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str); -#endif - -/* ------------ tccpe.c -------------- */ -#ifdef TCC_TARGET_PE -ST_FUNC int pe_load_file(struct TCCState *s1, int fd, const char *filename); -ST_FUNC int pe_output_file(TCCState * s1, const char *filename); -ST_FUNC int pe_putimport(TCCState *s1, int dllindex, const char *name, addr_t value); -#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 -ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2); -#endif -#ifdef TCC_TARGET_X86_64 -ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack); -#endif -PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp); -/* symbol properties stored in Elf32_Sym->st_other */ -# define ST_PE_EXPORT 0x10 -# define ST_PE_IMPORT 0x20 -# define ST_PE_STDCALL 0x40 -#endif -#define ST_ASM_SET 0x04 - -/* ------------ tccmacho.c ----------------- */ -#ifdef TCC_TARGET_MACHO -ST_FUNC int macho_output_file(TCCState * s1, const char *filename); -ST_FUNC int macho_load_dll(TCCState *s1, int fd, const char *filename, int lev); -ST_FUNC int macho_load_tbd(TCCState *s1, int fd, const char *filename, int lev); -#ifdef TCC_IS_NATIVE -ST_FUNC void tcc_add_macos_sdkpath(TCCState* s); -ST_FUNC const char* macho_tbd_soname(const char* filename); -#endif -#endif -/* ------------ tccrun.c ----------------- */ -#ifdef TCC_IS_NATIVE -#ifdef CONFIG_TCC_STATIC -#define RTLD_LAZY 0x001 -#define RTLD_NOW 0x002 -#define RTLD_GLOBAL 0x100 -#define RTLD_DEFAULT NULL -/* dummy function for profiling */ -ST_FUNC void *dlopen(const char *filename, int flag); -ST_FUNC void dlclose(void *p); -ST_FUNC const char *dlerror(void); -ST_FUNC void *dlsym(void *handle, const char *symbol); -#endif -ST_FUNC void tcc_run_free(TCCState *s1); -#endif - -/* ------------ tcctools.c ----------------- */ -#if 0 /* included in tcc.c */ -ST_FUNC int tcc_tool_ar(TCCState *s, int argc, char **argv); -#ifdef TCC_TARGET_PE -ST_FUNC int tcc_tool_impdef(TCCState *s, int argc, char **argv); -#endif -ST_FUNC int tcc_tool_cross(TCCState *s, char **argv, int option); -ST_FUNC int gen_makedeps(TCCState *s, const char *target, const char *filename); -#endif - -/* ------------ tccdbg.c ------------ */ - -ST_FUNC void tcc_debug_new(TCCState *s); - -ST_FUNC void tcc_debug_start(TCCState *s1); -ST_FUNC void tcc_debug_end(TCCState *s1); -ST_FUNC void tcc_debug_bincl(TCCState *s1); -ST_FUNC void tcc_debug_eincl(TCCState *s1); -ST_FUNC void tcc_debug_putfile(TCCState *s1, const char *filename); - -ST_FUNC void tcc_debug_line(TCCState *s1); -ST_FUNC void tcc_add_debug_info(TCCState *s1, int param, Sym *s, Sym *e); -ST_FUNC void tcc_debug_funcstart(TCCState *s1, Sym *sym); -ST_FUNC void tcc_debug_prolog_epilog(TCCState *s1, int value); -ST_FUNC void tcc_debug_funcend(TCCState *s1, int size); -ST_FUNC void tcc_debug_extern_sym(TCCState *s1, Sym *sym, int sh_num, int sym_bind, int sym_type); -ST_FUNC void tcc_debug_typedef(TCCState *s1, Sym *sym); -ST_FUNC void tcc_debug_stabn(TCCState *s1, int type, int value); -ST_FUNC void tcc_debug_fix_anon(TCCState *s1, CType *t); - -ST_FUNC void tcc_tcov_start(TCCState *s1); -ST_FUNC void tcc_tcov_end(TCCState *s1); -ST_FUNC void tcc_tcov_check_line(TCCState *s1, int start); -ST_FUNC void tcc_tcov_block_end(TCCState *s1, int line); -ST_FUNC void tcc_tcov_block_begin(TCCState *s1); -ST_FUNC void tcc_tcov_reset_ind(TCCState *s1); - -#define stab_section s1->stab_section -#define stabstr_section stab_section->link -#define tcov_section s1->tcov_section -#define dwarf_info_section s1->dwarf_info_section -#define dwarf_abbrev_section s1->dwarf_abbrev_section -#define dwarf_line_section s1->dwarf_line_section -#define dwarf_aranges_section s1->dwarf_aranges_section -#define dwarf_str_section s1->dwarf_str_section -#define dwarf_line_str_section s1->dwarf_line_str_section - -/* default dwarf version for "-g". use 0 to emit stab debug infos */ -#ifndef DWARF_VERSION -# define DWARF_VERSION 0 -#endif - -/* default dwarf version for "-gdwarf" */ -#ifdef TCC_TARGET_MACHO -# define DEFAULT_DWARF_VERSION 2 -#else -# define DEFAULT_DWARF_VERSION 5 -#endif - -#if defined TCC_TARGET_PE -# define R_DATA_32DW 'Z' /* fake code to avoid DLL relocs */ -#elif defined TCC_TARGET_X86_64 -# define R_DATA_32DW R_X86_64_32 -#else -# define R_DATA_32DW R_DATA_32 -#endif - -/********************************************************/ -#if CONFIG_TCC_SEMLOCK -#if defined _WIN32 -typedef struct { int init; CRITICAL_SECTION cr; } TCCSem; -#elif defined __APPLE__ -#include <dispatch/dispatch.h> -typedef struct { int init; dispatch_semaphore_t sem; } TCCSem; -#else -#include <semaphore.h> -typedef struct { int init; sem_t sem; } TCCSem; -#endif -ST_FUNC void wait_sem(TCCSem *p); -ST_FUNC void post_sem(TCCSem *p); -#define TCC_SEM(s) TCCSem s -#define WAIT_SEM wait_sem -#define POST_SEM post_sem -#else -#define TCC_SEM(s) -#define WAIT_SEM(p) -#define POST_SEM(p) -#endif - -/********************************************************/ -#undef ST_DATA -#if ONE_SOURCE -#define ST_DATA static -#else -#define ST_DATA -#endif -/********************************************************/ - -#define text_section TCC_STATE_VAR(text_section) -#define data_section TCC_STATE_VAR(data_section) -#define rodata_section TCC_STATE_VAR(rodata_section) -#define bss_section TCC_STATE_VAR(bss_section) -#define common_section TCC_STATE_VAR(common_section) -#define cur_text_section TCC_STATE_VAR(cur_text_section) -#define bounds_section TCC_STATE_VAR(bounds_section) -#define lbounds_section TCC_STATE_VAR(lbounds_section) -#define symtab_section TCC_STATE_VAR(symtab_section) -#define gnu_ext TCC_STATE_VAR(gnu_ext) -#define tcc_error_noabort TCC_SET_STATE(_tcc_error_noabort) -#define tcc_error TCC_SET_STATE(_tcc_error) -#define tcc_warning TCC_SET_STATE(_tcc_warning) - -#define total_idents TCC_STATE_VAR(total_idents) -#define total_lines TCC_STATE_VAR(total_lines) -#define total_bytes TCC_STATE_VAR(total_bytes) - -PUB_FUNC void tcc_enter_state(TCCState *s1); -PUB_FUNC void tcc_exit_state(TCCState *s1); - -/* conditional warning depending on switch */ -#define tcc_warning_c(sw) TCC_SET_STATE((\ - tcc_state->warn_num = offsetof(TCCState, sw) \ - - offsetof(TCCState, warn_none), _tcc_warning)) - -/********************************************************/ -#endif /* _TCC_H */ - -#undef TCC_STATE_VAR -#undef TCC_SET_STATE - -#ifdef USING_GLOBALS -# define TCC_STATE_VAR(sym) tcc_state->sym -# define TCC_SET_STATE(fn) fn -# undef USING_GLOBALS -# undef _tcc_error -#else -# define TCC_STATE_VAR(sym) s1->sym -# define TCC_SET_STATE(fn) (tcc_enter_state(s1),fn) -# define _tcc_error use_tcc_error_noabort -#endif diff --git a/tinycc/tccasm.c b/tinycc/tccasm.c deleted file mode 100644 index fcae05e..0000000 --- a/tinycc/tccasm.c +++ /dev/null @@ -1,1363 +0,0 @@ -/* - * GAS like assembler for TCC - * - * 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 - */ - -#define USING_GLOBALS -#include "tcc.h" -#ifdef CONFIG_TCC_ASM - -static Section *last_text_section; /* to handle .previous asm directive */ -static int asmgoto_n; - -static int asm_get_prefix_name(TCCState *s1, const char *prefix, unsigned int n) -{ - char buf[64]; - snprintf(buf, sizeof(buf), "%s%u", prefix, n); - return tok_alloc_const(buf); -} - -ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n) -{ - return asm_get_prefix_name(s1, "L..", n); -} - -static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global); -static Sym* asm_new_label(TCCState *s1, int label, int is_local); -static Sym* asm_new_label1(TCCState *s1, int label, int is_local, int sh_num, int value); - -/* If a C name has an _ prepended then only asm labels that start - with _ are representable in C, by removing the first _. ASM names - without _ at the beginning don't correspond to C names, but we use - the global C symbol table to track ASM names as well, so we need to - transform those into ones that don't conflict with a C name, - so prepend a '.' for them, but force the ELF asm name to be set. */ -static int asm2cname(int v, int *addeddot) -{ - const char *name; - *addeddot = 0; - if (!tcc_state->leading_underscore) - return v; - name = get_tok_str(v, NULL); - if (!name) - return v; - if (name[0] == '_') { - v = tok_alloc_const(name + 1); - } else if (!strchr(name, '.')) { - char newname[256]; - snprintf(newname, sizeof newname, ".%s", name); - v = tok_alloc_const(newname); - *addeddot = 1; - } - return v; -} - -static Sym *asm_label_find(int v) -{ - Sym *sym; - int addeddot; - v = asm2cname(v, &addeddot); - sym = sym_find(v); - while (sym && sym->sym_scope && !(sym->type.t & VT_STATIC)) - sym = sym->prev_tok; - return sym; -} - -static Sym *asm_label_push(int v) -{ - int addeddot, v2 = asm2cname(v, &addeddot); - /* We always add VT_EXTERN, for sym definition that's tentative - (for .set, removed for real defs), for mere references it's correct - as is. */ - Sym *sym = global_identifier_push(v2, VT_ASM | VT_EXTERN | VT_STATIC, 0); - if (addeddot) - sym->asm_label = v; - return sym; -} - -/* Return a symbol we can use inside the assembler, having name NAME. - Symbols from asm and C source share a namespace. If we generate - an asm symbol it's also a (file-global) C symbol, but it's - either not accessible by name (like "L.123"), or its type information - is such that it's not usable without a proper C declaration. - - Sometimes we need symbols accessible by name from asm, which - are anonymous in C, in this case CSYM can be used to transfer - all information from that symbol to the (possibly newly created) - asm symbol. */ -ST_FUNC Sym* get_asm_sym(int name, Sym *csym) -{ - Sym *sym = asm_label_find(name); - if (!sym) { - sym = asm_label_push(name); - if (csym) - sym->c = csym->c; - } - return sym; -} - -static Sym* asm_section_sym(TCCState *s1, Section *sec) -{ - char buf[100]; int label; Sym *sym; - snprintf(buf, sizeof buf, "L.%s", sec->name); - label = tok_alloc_const(buf); - sym = asm_label_find(label); - return sym ? sym : asm_new_label1(s1, label, 1, sec->sh_num, 0); -} - -/* We do not use the C expression parser to handle symbols. Maybe the - C expression parser could be tweaked to do so. */ - -static void asm_expr_unary(TCCState *s1, ExprValue *pe) -{ - Sym *sym; - int op, label; - uint64_t n; - const char *p; - - switch(tok) { - case TOK_PPNUM: - p = tokc.str.data; - n = strtoull(p, (char **)&p, 0); - if (*p == 'b' || *p == 'f') { - /* backward or forward label */ - label = asm_get_local_label_name(s1, n); - sym = asm_label_find(label); - if (*p == 'b') { - /* backward : find the last corresponding defined label */ - if (sym && (!sym->c || elfsym(sym)->st_shndx == SHN_UNDEF)) - sym = sym->prev_tok; - if (!sym) - tcc_error("local label '%d' not found backward", (int)n); - } else { - /* forward */ - if (!sym || (sym->c && elfsym(sym)->st_shndx != SHN_UNDEF)) { - /* if the last label is defined, then define a new one */ - sym = asm_label_push(label); - } - } - 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"); - } - next(); - break; - case '+': - next(); - asm_expr_unary(s1, pe); - break; - case '-': - case '~': - op = tok; - next(); - asm_expr_unary(s1, pe); - if (pe->sym) - tcc_error("invalid operation with label"); - if (op == '-') - pe->v = -pe->v; - else - pe->v = ~pe->v; - break; - case TOK_CCHAR: - case TOK_LCHAR: - pe->v = tokc.i; - pe->sym = NULL; - pe->pcrel = 0; - next(); - break; - case '(': - next(); - asm_expr(s1, pe); - skip(')'); - break; - case '.': - pe->v = ind; - pe->sym = asm_section_sym(s1, cur_text_section); - pe->pcrel = 0; - next(); - break; - default: - if (tok >= TOK_IDENT) { - ElfSym *esym; - /* label case : if the label was not found, add one */ - sym = get_asm_sym(tok, NULL); - esym = elfsym(sym); - if (esym && esym->st_shndx == SHN_ABS) { - /* if absolute symbol, no need to put a symbol value */ - pe->v = esym->st_value; - pe->sym = NULL; - pe->pcrel = 0; - } else { - pe->v = 0; - pe->sym = sym; - pe->pcrel = 0; - } - next(); - } else { - tcc_error("bad expression syntax [%s]", get_tok_str(tok, &tokc)); - } - break; - } -} - -static void asm_expr_prod(TCCState *s1, ExprValue *pe) -{ - int op; - ExprValue e2; - - asm_expr_unary(s1, pe); - for(;;) { - op = tok; - if (op != '*' && op != '/' && op != '%' && - op != TOK_SHL && op != TOK_SAR) - break; - next(); - asm_expr_unary(s1, &e2); - if (pe->sym || e2.sym) - tcc_error("invalid operation with label"); - switch(op) { - case '*': - pe->v *= e2.v; - break; - case '/': - if (e2.v == 0) { - div_error: - tcc_error("division by zero"); - } - pe->v /= e2.v; - break; - case '%': - if (e2.v == 0) - goto div_error; - pe->v %= e2.v; - break; - case TOK_SHL: - pe->v <<= e2.v; - break; - default: - case TOK_SAR: - pe->v >>= e2.v; - break; - } - } -} - -static void asm_expr_logic(TCCState *s1, ExprValue *pe) -{ - int op; - ExprValue e2; - - asm_expr_prod(s1, pe); - for(;;) { - op = tok; - if (op != '&' && op != '|' && op != '^') - break; - next(); - asm_expr_prod(s1, &e2); - if (pe->sym || e2.sym) - tcc_error("invalid operation with label"); - switch(op) { - case '&': - pe->v &= e2.v; - break; - case '|': - pe->v |= e2.v; - break; - default: - case '^': - pe->v ^= e2.v; - break; - } - } -} - -static inline void asm_expr_sum(TCCState *s1, ExprValue *pe) -{ - int op; - ExprValue e2; - - asm_expr_logic(s1, pe); - for(;;) { - op = tok; - if (op != '+' && op != '-') - break; - next(); - asm_expr_logic(s1, &e2); - if (op == '+') { - if (pe->sym != NULL && e2.sym != NULL) - goto cannot_relocate; - pe->v += e2.v; - if (pe->sym == NULL && e2.sym != NULL) - pe->sym = e2.sym; - } else { - pe->v -= e2.v; - /* NOTE: we are less powerful than gas in that case - because we store only one symbol in the expression */ - if (!e2.sym) { - /* OK */ - } else if (pe->sym == e2.sym) { - /* OK */ - pe->sym = NULL; /* same symbols can be subtracted to NULL */ - } else { - ElfSym *esym1, *esym2; - esym1 = elfsym(pe->sym); - esym2 = elfsym(e2.sym); - if (esym1 && esym1->st_shndx == esym2->st_shndx - && esym1->st_shndx != SHN_UNDEF) { - /* we also accept defined symbols in the same section */ - pe->v += esym1->st_value - esym2->st_value; - pe->sym = NULL; - } else if (esym2->st_shndx == cur_text_section->sh_num) { - /* When subtracting a defined symbol in current section - this actually makes the value PC-relative. */ - pe->v -= esym2->st_value - ind - 4; - pe->pcrel = 1; - e2.sym = NULL; - } else { -cannot_relocate: - tcc_error("invalid operation with label"); - } - } - } - } -} - -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_cmp(s1, pe); -} - -ST_FUNC int asm_int_expr(TCCState *s1) -{ - ExprValue e; - asm_expr(s1, &e); - if (e.sym) - expect("constant"); - return e.v; -} - -static Sym* asm_new_label1(TCCState *s1, int label, int is_local, - int sh_num, int value) -{ - Sym *sym; - ElfSym *esym; - - sym = asm_label_find(label); - if (sym) { - esym = elfsym(sym); - /* 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 (esym && esym->st_shndx != SHN_UNDEF) { - /* the label is already defined */ - if (IS_ASM_SYM(sym) - && (is_local == 1 || (sym->type.t & VT_EXTERN))) - goto new_label; - if (!(sym->type.t & VT_EXTERN)) - tcc_error("assembler label '%s' already defined", - get_tok_str(label, NULL)); - } - } else { - new_label: - sym = asm_label_push(label); - } - if (!sym->c) - put_extern_sym2(sym, SHN_UNDEF, 0, 0, 1); - esym = elfsym(sym); - esym->st_shndx = sh_num; - esym->st_value = value; - if (is_local != 2) - sym->type.t &= ~VT_EXTERN; - return sym; -} - -static Sym* asm_new_label(TCCState *s1, int label, int is_local) -{ - 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; - Sym *sym; - ElfSym *esym; - next(); - asm_expr(s1, &e); - n = e.v; - esym = elfsym(e.sym); - if (esym) - n += esym->st_value; - sym = asm_new_label1(s1, label, 2, esym ? esym->st_shndx : SHN_ABS, n); - elfsym(sym)->st_other |= ST_ASM_SET; - return sym; -} - -static void use_section1(TCCState *s1, Section *sec) -{ - cur_text_section->data_offset = ind; - cur_text_section = sec; - ind = cur_text_section->data_offset; -} - -static void use_section(TCCState *s1, const char *name) -{ - Section *sec; - sec = find_section(s1, name); - use_section1(s1, sec); -} - -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 */ - sec = cur_text_section; - switch(tok) { - 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_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; - size = offset - ind; - /* the section must have a compatible alignment */ - if (sec->sh_addralign < n) - sec->sh_addralign = n; - } else { - if (n < 0) - n = 0; - size = n; - } - v = 0; - if (tok == ',') { - next(); - v = asm_int_expr(s1); - } - zero_pad: - if (sec->sh_type != SHT_NOBITS) { - sec->data_offset = ind; - ptr = section_ptr_add(sec, size); - memset(ptr, v, size); - } - ind += size; - break; - 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.str.data; - if (tok != TOK_PPNUM) { - error_constant: - tcc_error("64 bit constant"); - } - vl = strtoll(p, (char **)&p, 0); - if (*p != '\0') - goto error_constant; - next(); - if (sec->sh_type != SHT_NOBITS) { - /* XXX: endianness */ - gen_le32(vl); - gen_le32(vl >> 32); - } else { - ind += 8; - } - if (tok != ',') - break; - next(); - } - break; -#endif - case TOK_ASMDIR_byte: - size = 1; - goto asm_data; - case TOK_ASMDIR_word: - case TOK_ASMDIR_short: - size = 2; - goto asm_data; - case TOK_ASMDIR_long: - case TOK_ASMDIR_int: - size = 4; - asm_data: - next(); - for(;;) { - ExprValue e; - asm_expr(s1, &e); - 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"); - if (size == 1) - g(e.v); - else - gen_le16(e.v); - } - } else { - ind += size; - } - if (tok != ',') - break; - next(); - } - break; - case TOK_ASMDIR_fill: - { - int repeat, size, val, i, j; - uint8_t repeat_buf[8]; - next(); - repeat = asm_int_expr(s1); - if (repeat < 0) { - tcc_error("repeat < 0; .fill ignored"); - break; - } - size = 1; - val = 0; - if (tok == ',') { - next(); - size = asm_int_expr(s1); - if (size < 0) { - tcc_error("size < 0; .fill ignored"); - break; - } - if (size > 8) - size = 8; - if (tok == ',') { - next(); - val = asm_int_expr(s1); - } - } - /* XXX: endianness */ - repeat_buf[0] = val; - repeat_buf[1] = val >> 8; - repeat_buf[2] = val >> 16; - repeat_buf[3] = val >> 24; - repeat_buf[4] = 0; - repeat_buf[5] = 0; - repeat_buf[6] = 0; - repeat_buf[7] = 0; - for(i = 0; i < repeat; i++) { - for(j = 0; j < size; j++) { - g(repeat_buf[j]); - } - } - } - break; - case TOK_ASMDIR_rept: - { - int repeat; - TokenString *init_str; - next(); - repeat = asm_int_expr(s1); - init_str = tok_str_alloc(); - while (next(), tok != TOK_ASMDIR_endr) { - if (tok == CH_EOF) - tcc_error("we at end of file, .endr not found"); - tok_str_add_tok(init_str); - } - tok_str_add(init_str, -1); - tok_str_add(init_str, 0); - 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(); - next(); - break; - } - case TOK_ASMDIR_org: - { - unsigned long n; - ExprValue e; - ElfSym *esym; - next(); - asm_expr(s1, &e); - n = e.v; - esym = elfsym(e.sym); - if (esym) { - if (esym->st_shndx != cur_text_section->sh_num) - expect("constant or same-section symbol"); - n += esym->st_value; - } - if (n < ind) - tcc_error("attempt to .org backwards"); - v = 0; - size = n - ind; - goto zero_pad; - } - break; - 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 = get_asm_sym(tok, NULL); - if (tok1 != TOK_ASMDIR_hidden) - sym->type.t &= ~VT_STATIC; - if (tok1 == TOK_ASMDIR_weak) - sym->a.weak = 1; - else if (tok1 == TOK_ASMDIR_hidden) - sym->a.visibility = STV_HIDDEN; - update_storage(sym); - next(); - } while (tok == ','); - break; - case TOK_ASMDIR_string: - case TOK_ASMDIR_ascii: - case TOK_ASMDIR_asciz: - { - const uint8_t *p; - int i, size, t; - - t = tok; - next(); - for(;;) { - if (tok != TOK_STR) - expect("string constant"); - 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]); - next(); - if (tok == ',') { - next(); - } else if (tok != TOK_STR) { - break; - } - } - } - break; - case TOK_ASMDIR_text: - case TOK_ASMDIR_data: - case TOK_ASMDIR_bss: - { - char sname[64]; - tok1 = tok; - n = 0; - next(); - if (tok != ';' && tok != TOK_LINEFEED) { - n = asm_int_expr(s1); - next(); - } - 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_ASMDIR_file: - { - char filename[512]; - - filename[0] = '\0'; - next(); - if (tok == TOK_STR) - pstrcat(filename, sizeof(filename), tokc.str.data); - else - pstrcat(filename, sizeof(filename), get_tok_str(tok, NULL)); - tcc_warning_c(warn_unsupported)("ignoring .file %s", filename); - next(); - } - break; - case TOK_ASMDIR_ident: - { - char ident[256]; - - ident[0] = '\0'; - next(); - if (tok == TOK_STR) - pstrcat(ident, sizeof(ident), tokc.str.data); - else - pstrcat(ident, sizeof(ident), get_tok_str(tok, NULL)); - tcc_warning_c(warn_unsupported)("ignoring .ident %s", ident); - next(); - } - break; - case TOK_ASMDIR_size: - { - Sym *sym; - - next(); - sym = asm_label_find(tok); - if (!sym) { - tcc_error("label not found: %s", get_tok_str(tok, NULL)); - } - /* XXX .size name,label2-label1 */ - tcc_warning_c(warn_unsupported)("ignoring .size %s,*", get_tok_str(tok, NULL)); - next(); - skip(','); - while (tok != TOK_LINEFEED && tok != ';' && tok != CH_EOF) { - next(); - } - } - break; - case TOK_ASMDIR_type: - { - Sym *sym; - const char *newtype; - - next(); - sym = get_asm_sym(tok, NULL); - next(); - skip(','); - if (tok == TOK_STR) { - newtype = tokc.str.data; - } else { - if (tok == '@' || tok == '%') - next(); - newtype = get_tok_str(tok, NULL); - } - - if (!strcmp(newtype, "function") || !strcmp(newtype, "STT_FUNC")) { - sym->type.t = (sym->type.t & ~VT_BTYPE) | VT_FUNC; - } else - tcc_warning_c(warn_unsupported)("change type of '%s' from 0x%x to '%s' ignored", - get_tok_str(sym->v, NULL), sym->type.t, newtype); - - next(); - } - break; - 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.str.data); - else - pstrcat(sname, sizeof(sname), get_tok_str(tok, NULL)); - next(); - } - if (tok == ',') { - /* skip section options */ - next(); - if (tok != TOK_STR) - expect("string constant"); - next(); - if (tok == ',') { - next(); - if (tok == '@' || tok == '%') - next(); - next(); - } - } - last_text_section = cur_text_section; - 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_ASMDIR_previous: - { - Section *sec; - next(); - if (!last_text_section) - tcc_error("no previous section referenced"); - sec = cur_text_section; - use_section1(s1, last_text_section); - last_text_section = sec; - } - break; - case TOK_ASMDIR_popsection: - next(); - pop_section(s1); - break; -#ifdef TCC_TARGET_I386 - case TOK_ASMDIR_code16: - { - next(); - s1->seg_size = 16; - } - break; - case TOK_ASMDIR_code32: - { - next(); - s1->seg_size = 32; - } - break; -#endif -#ifdef TCC_TARGET_X86_64 - /* added for compatibility with GAS */ - case TOK_ASMDIR_code64: - next(); - break; -#endif - default: - tcc_error("unknown assembler directive '.%s'", get_tok_str(tok, NULL)); - break; - } -} - - -/* assemble a file */ -static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global) -{ - int opcode; - int saved_parse_flags = parse_flags; - - parse_flags = PARSE_FLAG_ASM_FILE | PARSE_FLAG_TOK_STR; - if (do_preprocess) - parse_flags |= PARSE_FLAG_PREPROCESS; - for(;;) { - next(); - if (tok == TOK_EOF) - break; - parse_flags |= PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */ - redo: - if (tok == '#') { - /* horrible gas comment */ - while (tok != TOK_LINEFEED) - next(); - } else if (tok >= TOK_ASMDIR_FIRST && tok <= TOK_ASMDIR_LAST) { - asm_parse_directive(s1, global); - } else if (tok == TOK_PPNUM) { - const char *p; - int n; - 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); - next(); - skip(':'); - goto redo; - } else if (tok >= TOK_IDENT) { - /* instruction or label */ - opcode = tok; - next(); - if (tok == ':') { - /* new label */ - asm_new_label(s1, opcode, 0); - next(); - goto redo; - } else if (tok == '=') { - set_symbol(s1, opcode); - goto redo; - } else { - asm_opcode(s1, opcode); - } - } - /* end of line */ - if (tok != ';' && tok != TOK_LINEFEED) - expect("end of line"); - parse_flags &= ~PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */ - } - - parse_flags = saved_parse_flags; - return 0; -} - -/* Assemble the current file */ -ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess) -{ - int ret; - tcc_debug_start(s1); - /* default section is text */ - cur_text_section = text_section; - ind = cur_text_section->data_offset; - nocode_wanted = 0; - ret = tcc_assemble_internal(s1, do_preprocess, 1); - cur_text_section->data_offset = ind; - tcc_debug_end(s1); - return ret; -} - -/********************************************************************/ -/* GCC inline asm support */ - -/* 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, int global) -{ - const int *saved_macro_ptr = macro_ptr; - int dotid = set_idnum('.', IS_ID); - int dolid = set_idnum('$', 0); - - tcc_open_bf(s1, ":asm:", len); - memcpy(file->buffer, str, len); - macro_ptr = NULL; - tcc_assemble_internal(s1, 0, global); - tcc_close(); - - set_idnum('$', dolid); - set_idnum('.', dotid); - macro_ptr = saved_macro_ptr; -} - -/* find a constraint by its number or id (gcc 3 extended - syntax). return -1 if not found. Return in *pp in char after the - constraint */ -ST_FUNC int find_constraint(ASMOperand *operands, int nb_operands, - const char *name, const char **pp) -{ - int index; - TokenSym *ts; - const char *p; - - if (isnum(*name)) { - index = 0; - while (isnum(*name)) { - index = (index * 10) + (*name) - '0'; - name++; - } - if ((unsigned)index >= nb_operands) - index = -1; - } else if (*name == '[') { - name++; - p = strchr(name, ']'); - if (p) { - ts = tok_alloc(name, p - name); - for(index = 0; index < nb_operands; index++) { - if (operands[index].id == ts->tok) - goto found; - } - index = -1; - found: - name = p + 1; - } else { - index = -1; - } - } else { - index = -1; - } - if (pp) - *pp = name; - return index; -} - -static void subst_asm_operands(ASMOperand *operands, int nb_operands, - CString *out_str, const char *str) -{ - int c, index, modifier; - ASMOperand *op; - SValue sv; - - for(;;) { - c = *str++; - if (c == '%') { - if (*str == '%') { - str++; - goto add_char; - } - modifier = 0; - if (*str == 'c' || *str == 'n' || - *str == 'b' || *str == 'w' || *str == 'h' || *str == 'k' || - *str == 'q' || *str == 'l' || - /* 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) - tcc_error("invalid operand reference after %%"); - op = &operands[index]; - if (modifier == 'l') { - cstr_cat(out_str, get_tok_str(op->is_label, NULL), -1); - } else { - sv = *op->vt; - if (op->reg >= 0) { - sv.r = op->reg; - if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory) - sv.r |= VT_LVAL; - } - subst_asm_operand(out_str, &sv, modifier); - } - } else { - add_char: - cstr_ccat(out_str, c); - if (c == '\0') - break; - } - } -} - - -static void parse_asm_operands(ASMOperand *operands, int *nb_operands_ptr, - int is_output) -{ - ASMOperand *op; - int nb_operands; - char* astr; - - if (tok != ':') { - nb_operands = *nb_operands_ptr; - for(;;) { - if (nb_operands >= MAX_ASM_OPERANDS) - tcc_error("too many asm operands"); - op = &operands[nb_operands++]; - op->id = 0; - if (tok == '[') { - next(); - if (tok < TOK_IDENT) - expect("identifier"); - op->id = tok; - next(); - skip(']'); - } - astr = parse_mult_str("string constant")->data; - pstrcpy(op->constraint, sizeof op->constraint, astr); - skip('('); - gexpr(); - if (is_output) { - 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 - register storage, so we need to convert (reg) - case */ - if ((vtop->r & VT_LVAL) && - ((vtop->r & VT_VALMASK) == VT_LLOCAL || - (vtop->r & VT_VALMASK) < VT_CONST) && - !strchr(op->constraint, 'm')) { - gv(RC_INT); - } - } - op->vt = vtop; - skip(')'); - if (tok == ',') { - next(); - } else { - break; - } - } - *nb_operands_ptr = nb_operands; - } -} - -/* parse the GCC asm() instruction */ -ST_FUNC void asm_instr(void) -{ - CString astr, *astr1; - - ASMOperand operands[MAX_ASM_OPERANDS]; - int nb_outputs, nb_operands, i, must_subst, out_reg, nb_labels; - uint8_t clobber_regs[NB_ASM_REGS]; - Section *sec; - - /* since we always generate the asm() instruction, we can ignore - volatile */ - while (tok == TOK_VOLATILE1 || tok == TOK_VOLATILE2 || tok == TOK_VOLATILE3 - || tok == TOK_GOTO) { - next(); - } - - astr1 = parse_asm_str(); - cstr_new_s(&astr); - cstr_cat(&astr, astr1->data, astr1->size); - - nb_operands = 0; - nb_outputs = 0; - nb_labels = 0; - must_subst = 0; - memset(clobber_regs, 0, sizeof(clobber_regs)); - if (tok == ':') { - next(); - must_subst = 1; - /* output args */ - parse_asm_operands(operands, &nb_operands, 1); - nb_outputs = nb_operands; - if (tok == ':') { - next(); - if (tok != ')') { - /* input args */ - parse_asm_operands(operands, &nb_operands, 0); - if (tok == ':') { - /* clobber list */ - /* XXX: handle registers */ - next(); - for(;;) { - if (tok == ':') - break; - if (tok != TOK_STR) - expect("string constant"); - asm_clobber(clobber_regs, tokc.str.data); - next(); - if (tok == ',') { - next(); - } else { - break; - } - } - } - if (tok == ':') { - /* goto labels */ - next(); - for (;;) { - Sym *csym; - int asmname; - if (nb_operands + nb_labels >= MAX_ASM_OPERANDS) - tcc_error("too many asm operands"); - if (tok < TOK_UIDENT) - expect("label identifier"); - operands[nb_operands + nb_labels++].id = tok; - - csym = label_find(tok); - if (!csym) { - csym = label_push(&global_label_stack, tok, - LABEL_FORWARD); - } else { - if (csym->r == LABEL_DECLARED) - csym->r = LABEL_FORWARD; - } - next(); - asmname = asm_get_prefix_name(tcc_state, "LG.", - ++asmgoto_n); - if (!csym->c) - put_extern_sym2(csym, SHN_UNDEF, 0, 0, 1); - get_asm_sym(asmname, csym); - operands[nb_operands + nb_labels - 1].is_label = asmname; - - if (tok != ',') - break; - next(); - } - } - } - } - } - skip(')'); - /* NOTE: we do not eat the ';' so that we can restore the current - token after the assembler parsing */ - if (tok != ';') - expect("';'"); - - /* save all values in the memory */ - save_regs(0); - - /* compute constraints */ - asm_compute_constraints(operands, nb_operands, nb_outputs, - clobber_regs, &out_reg); - - /* substitute the operands in the asm string. No substitution is - done if no operands (GCC behaviour) */ -#ifdef ASM_DEBUG - printf("asm: \"%s\"\n", (char *)astr.data); -#endif - if (must_subst) { - cstr_reset(astr1); - cstr_cat(astr1, astr.data, astr.size); - cstr_reset(&astr); - subst_asm_operands(operands, nb_operands + nb_labels, &astr, astr1->data); - } - -#ifdef ASM_DEBUG - printf("subst_asm: \"%s\"\n", (char *)astr.data); -#endif - - /* generate loads */ - asm_gen_code(operands, nb_operands, nb_outputs, 0, - clobber_regs, out_reg); - - /* We don't allow switching section within inline asm to - bleed out to surrounding code. */ - sec = cur_text_section; - /* assemble the string with tcc internal assembler */ - tcc_assemble_inline(tcc_state, astr.data, astr.size - 1, 0); - cstr_free_s(&astr); - if (sec != cur_text_section) { - tcc_warning("inline asm tries to change current section"); - use_section1(tcc_state, sec); - } - - /* restore the current C token */ - next(); - - /* store the output values if needed */ - asm_gen_code(operands, nb_operands, nb_outputs, 1, - clobber_regs, out_reg); - - /* free everything */ - for(i=0;i<nb_operands;i++) { - vpop(); - } - -} - -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(); - astr = parse_asm_str(); - skip(')'); - /* NOTE: we do not eat the ';' so that we can restore the current - token after the assembler parsing */ - if (tok != ';') - expect("';'"); - -#ifdef ASM_DEBUG - printf("asm_global: \"%s\"\n", (char *)astr.data); -#endif - cur_text_section = text_section; - ind = cur_text_section->data_offset; - - /* assemble the string with tcc internal assembler */ - tcc_assemble_inline(tcc_state, astr->data, astr->size - 1, 1); - - cur_text_section->data_offset = ind; - - /* restore the current C token */ - next(); - - nocode_wanted = saved_nocode_wanted; -} - -/********************************************************/ -#else -ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess) -{ - tcc_error("asm not supported"); -} - -ST_FUNC void asm_instr(void) -{ - tcc_error("inline asm() not supported"); -} - -ST_FUNC void asm_global_instr(void) -{ - tcc_error("inline asm() not supported"); -} -#endif /* CONFIG_TCC_ASM */ diff --git a/tinycc/tcccoff.c b/tinycc/tcccoff.c deleted file mode 100644 index 56064cd..0000000 --- a/tinycc/tcccoff.c +++ /dev/null @@ -1,951 +0,0 @@ -/* - * COFF file handling for TCC - * - * Copyright (c) 2003, 2004 TK - * Copyright (c) 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 - */ - -#include "tcc.h" - -/* XXX: this file uses tcc_error() to the effect of exit(1) */ -#undef _tcc_error - -#define MAXNSCNS 255 /* MAXIMUM NUMBER OF SECTIONS */ -#define MAX_STR_TABLE 1000000 -AOUTHDR o_filehdr; /* OPTIONAL (A.OUT) FILE HEADER */ - -SCNHDR section_header[MAXNSCNS]; - -#define MAX_FUNCS 1000 -#define MAX_FUNC_NAME_LENGTH 128 - -int nFuncs; -char Func[MAX_FUNCS][MAX_FUNC_NAME_LENGTH]; -char AssociatedFile[MAX_FUNCS][MAX_FUNC_NAME_LENGTH]; -int LineNoFilePtr[MAX_FUNCS]; -int EndAddress[MAX_FUNCS]; -int LastLineNo[MAX_FUNCS]; -int FuncEntries[MAX_FUNCS]; - -int OutputTheSection(Section * sect); -short int GetCoffFlags(const char *s); -void SortSymbolTable(TCCState *s1); -Section *FindSection(TCCState * s1, const char *sname); - -int C67_main_entry_point; - -int FindCoffSymbolIndex(TCCState * s1, const char *func_name); -int nb_syms; - -typedef struct { - long tag; - long size; - long fileptr; - long nextsym; - short int dummy; -} AUXFUNC; - -typedef struct { - long regmask; - unsigned short lineno; - unsigned short nentries; - int localframe; - int nextentry; - short int dummy; -} AUXBF; - -typedef struct { - long dummy; - unsigned short lineno; - unsigned short dummy1; - int dummy2; - int dummy3; - unsigned short dummy4; -} AUXEF; - -ST_FUNC int tcc_output_coff(TCCState *s1, FILE *f) -{ - Section *tcc_sect; - SCNHDR *coff_sec; - int file_pointer; - char *Coff_str_table, *pCoff_str_table; - int CoffTextSectionNo, coff_nb_syms; - FILHDR file_hdr; /* FILE HEADER STRUCTURE */ - Section *stext, *sdata, *sbss; - int i, NSectionsToOutput = 0; - - Coff_str_table = pCoff_str_table = NULL; - - stext = FindSection(s1, ".text"); - sdata = FindSection(s1, ".data"); - sbss = FindSection(s1, ".bss"); - - nb_syms = symtab_section->data_offset / sizeof(Elf32_Sym); - coff_nb_syms = FindCoffSymbolIndex(s1, "XXXXXXXXXX1"); - - file_hdr.f_magic = COFF_C67_MAGIC; /* magic number */ - file_hdr.f_timdat = 0; /* time & date stamp */ - file_hdr.f_opthdr = sizeof(AOUTHDR); /* sizeof(optional hdr) */ - file_hdr.f_flags = 0x1143; /* flags (copied from what code composer does) */ - file_hdr.f_TargetID = 0x99; /* for C6x = 0x0099 */ - - o_filehdr.magic = 0x0108; /* see magic.h */ - o_filehdr.vstamp = 0x0190; /* version stamp */ - o_filehdr.tsize = stext->data_offset; /* text size in bytes, padded to FW bdry */ - o_filehdr.dsize = sdata->data_offset; /* initialized data " " */ - o_filehdr.bsize = sbss->data_offset; /* uninitialized data " " */ - o_filehdr.entrypt = C67_main_entry_point; /* entry pt. */ - o_filehdr.text_start = stext->sh_addr; /* base of text used for this file */ - o_filehdr.data_start = sdata->sh_addr; /* base of data used for this file */ - - - // create all the section headers - - file_pointer = FILHSZ + sizeof(AOUTHDR); - - CoffTextSectionNo = -1; - - for (i = 1; i < s1->nb_sections; i++) { - coff_sec = §ion_header[i]; - tcc_sect = s1->sections[i]; - - if (OutputTheSection(tcc_sect)) { - NSectionsToOutput++; - - if (CoffTextSectionNo == -1 && tcc_sect == stext) - CoffTextSectionNo = NSectionsToOutput; // rem which coff sect number the .text sect is - - strcpy(coff_sec->s_name, tcc_sect->name); /* section name */ - - coff_sec->s_paddr = tcc_sect->sh_addr; /* physical address */ - coff_sec->s_vaddr = tcc_sect->sh_addr; /* virtual address */ - coff_sec->s_size = tcc_sect->data_offset; /* section size */ - coff_sec->s_scnptr = 0; /* file ptr to raw data for section */ - coff_sec->s_relptr = 0; /* file ptr to relocation */ - coff_sec->s_lnnoptr = 0; /* file ptr to line numbers */ - coff_sec->s_nreloc = 0; /* number of relocation entries */ - coff_sec->s_flags = GetCoffFlags(coff_sec->s_name); /* flags */ - coff_sec->s_reserved = 0; /* reserved byte */ - coff_sec->s_page = 0; /* memory page id */ - - file_pointer += sizeof(SCNHDR); - } - } - - file_hdr.f_nscns = NSectionsToOutput; /* number of sections */ - - // now loop through and determine file pointer locations - // for the raw data - - - for (i = 1; i < s1->nb_sections; i++) { - coff_sec = §ion_header[i]; - tcc_sect = s1->sections[i]; - - if (OutputTheSection(tcc_sect)) { - // put raw data - coff_sec->s_scnptr = file_pointer; /* file ptr to raw data for section */ - file_pointer += coff_sec->s_size; - } - } - - // now loop through and determine file pointer locations - // for the relocation data - - for (i = 1; i < s1->nb_sections; i++) { - coff_sec = §ion_header[i]; - tcc_sect = s1->sections[i]; - - if (OutputTheSection(tcc_sect)) { - // put relocations data - if (coff_sec->s_nreloc > 0) { - coff_sec->s_relptr = file_pointer; /* file ptr to relocation */ - file_pointer += coff_sec->s_nreloc * sizeof(struct reloc); - } - } - } - - // now loop through and determine file pointer locations - // for the line number data - - for (i = 1; i < s1->nb_sections; i++) { - coff_sec = §ion_header[i]; - tcc_sect = s1->sections[i]; - - coff_sec->s_nlnno = 0; - coff_sec->s_lnnoptr = 0; - - if (s1->do_debug && tcc_sect == stext) { - // count how many line nos data - - // also find association between source file name and function - // so we can sort the symbol table - - - Stab_Sym *sym, *sym_end; - char func_name[MAX_FUNC_NAME_LENGTH], - last_func_name[MAX_FUNC_NAME_LENGTH]; - unsigned long func_addr, last_pc, pc; - const char *incl_files[INCLUDE_STACK_SIZE]; - int incl_index, len, last_line_num; - const char *str, *p; - - coff_sec->s_lnnoptr = file_pointer; /* file ptr to linno */ - - - func_name[0] = '\0'; - func_addr = 0; - incl_index = 0; - last_func_name[0] = '\0'; - last_pc = 0xffffffff; - last_line_num = 1; - sym = (Stab_Sym *) stab_section->data + 1; - sym_end = - (Stab_Sym *) (stab_section->data + - stab_section->data_offset); - - nFuncs = 0; - while (sym < sym_end) { - switch (sym->n_type) { - /* function start or end */ - case N_FUN: - if (sym->n_strx == 0) { - // end of function - - coff_sec->s_nlnno++; - file_pointer += LINESZ; - - pc = sym->n_value + func_addr; - func_name[0] = '\0'; - func_addr = 0; - EndAddress[nFuncs] = pc; - FuncEntries[nFuncs] = - (file_pointer - - LineNoFilePtr[nFuncs]) / LINESZ - 1; - LastLineNo[nFuncs++] = last_line_num + 1; - } else { - // beginning of function - - LineNoFilePtr[nFuncs] = file_pointer; - coff_sec->s_nlnno++; - file_pointer += LINESZ; - - str = - (const char *) stabstr_section->data + - sym->n_strx; - - p = strchr(str, ':'); - if (!p) { - pstrcpy(func_name, sizeof(func_name), str); - pstrcpy(Func[nFuncs], sizeof(func_name), str); - } else { - len = p - str; - if (len > sizeof(func_name) - 1) - len = sizeof(func_name) - 1; - memcpy(func_name, str, len); - memcpy(Func[nFuncs], str, len); - func_name[len] = '\0'; - } - - // save the file that it came in so we can sort later - pstrcpy(AssociatedFile[nFuncs], sizeof(func_name), - incl_files[incl_index - 1]); - - func_addr = sym->n_value; - } - break; - - /* line number info */ - case N_SLINE: - pc = sym->n_value + func_addr; - - last_pc = pc; - last_line_num = sym->n_desc; - - /* XXX: slow! */ - strcpy(last_func_name, func_name); - - coff_sec->s_nlnno++; - file_pointer += LINESZ; - break; - /* include files */ - case N_BINCL: - str = - (const char *) stabstr_section->data + sym->n_strx; - add_incl: - if (incl_index < INCLUDE_STACK_SIZE) { - incl_files[incl_index++] = str; - } - break; - case N_EINCL: - if (incl_index > 1) - incl_index--; - break; - case N_SO: - if (sym->n_strx == 0) { - incl_index = 0; /* end of translation unit */ - } else { - str = - (const char *) stabstr_section->data + - sym->n_strx; - /* do not add path */ - len = strlen(str); - if (len > 0 && str[len - 1] != '/') - goto add_incl; - } - break; - } - sym++; - } - } - - } - - file_hdr.f_symptr = file_pointer; /* file pointer to symtab */ - - if (s1->do_debug) - file_hdr.f_nsyms = coff_nb_syms; /* number of symtab entries */ - else - file_hdr.f_nsyms = 0; - - file_pointer += file_hdr.f_nsyms * SYMNMLEN; - - // OK now we are all set to write the file - - - fwrite(&file_hdr, FILHSZ, 1, f); - fwrite(&o_filehdr, sizeof(o_filehdr), 1, f); - - // write section headers - for (i = 1; i < s1->nb_sections; i++) { - coff_sec = §ion_header[i]; - tcc_sect = s1->sections[i]; - - if (OutputTheSection(tcc_sect)) { - fwrite(coff_sec, sizeof(SCNHDR), 1, f); - } - } - - // write raw data - for (i = 1; i < s1->nb_sections; i++) { - coff_sec = §ion_header[i]; - tcc_sect = s1->sections[i]; - - if (OutputTheSection(tcc_sect)) { - fwrite(tcc_sect->data, tcc_sect->data_offset, 1, f); - } - } - - // write relocation data - for (i = 1; i < s1->nb_sections; i++) { - coff_sec = §ion_header[i]; - tcc_sect = s1->sections[i]; - - if (OutputTheSection(tcc_sect)) { - // put relocations data - if (coff_sec->s_nreloc > 0) { - fwrite(tcc_sect->reloc, - coff_sec->s_nreloc * sizeof(struct reloc), 1, f); - } - } - } - - - // group the symbols in order of filename, func1, func2, etc - // finally global symbols - - if (s1->do_debug) - SortSymbolTable(s1); - - // write line no data - - for (i = 1; i < s1->nb_sections; i++) { - coff_sec = §ion_header[i]; - tcc_sect = s1->sections[i]; - - if (s1->do_debug && tcc_sect == stext) { - // count how many line nos data - - - Stab_Sym *sym, *sym_end; - char func_name[128], last_func_name[128]; - unsigned long func_addr, last_pc, pc; - const char *incl_files[INCLUDE_STACK_SIZE]; - int incl_index, len, last_line_num; - const char *str, *p; - - LINENO CoffLineNo; - - func_name[0] = '\0'; - func_addr = 0; - incl_index = 0; - last_func_name[0] = '\0'; - last_pc = 0; - last_line_num = 1; - sym = (Stab_Sym *) stab_section->data + 1; - sym_end = - (Stab_Sym *) (stab_section->data + - stab_section->data_offset); - - while (sym < sym_end) { - switch (sym->n_type) { - /* function start or end */ - case N_FUN: - if (sym->n_strx == 0) { - // end of function - - CoffLineNo.l_addr.l_paddr = last_pc; - CoffLineNo.l_lnno = last_line_num + 1; - fwrite(&CoffLineNo, 6, 1, f); - - pc = sym->n_value + func_addr; - func_name[0] = '\0'; - func_addr = 0; - } else { - // beginning of function - - str = - (const char *) stabstr_section->data + - sym->n_strx; - - - p = strchr(str, ':'); - if (!p) { - pstrcpy(func_name, sizeof(func_name), str); - } else { - len = p - str; - if (len > sizeof(func_name) - 1) - len = sizeof(func_name) - 1; - memcpy(func_name, str, len); - func_name[len] = '\0'; - } - func_addr = sym->n_value; - last_pc = func_addr; - last_line_num = -1; - - // output a function begin - - CoffLineNo.l_addr.l_symndx = - FindCoffSymbolIndex(s1, func_name); - CoffLineNo.l_lnno = 0; - - fwrite(&CoffLineNo, 6, 1, f); - } - break; - - /* line number info */ - case N_SLINE: - pc = sym->n_value + func_addr; - - - /* XXX: slow! */ - strcpy(last_func_name, func_name); - - // output a line reference - - CoffLineNo.l_addr.l_paddr = last_pc; - - if (last_line_num == -1) { - CoffLineNo.l_lnno = sym->n_desc; - } else { - CoffLineNo.l_lnno = last_line_num + 1; - } - - fwrite(&CoffLineNo, 6, 1, f); - - last_pc = pc; - last_line_num = sym->n_desc; - - break; - - /* include files */ - case N_BINCL: - str = - (const char *) stabstr_section->data + sym->n_strx; - add_incl2: - if (incl_index < INCLUDE_STACK_SIZE) { - incl_files[incl_index++] = str; - } - break; - case N_EINCL: - if (incl_index > 1) - incl_index--; - break; - case N_SO: - if (sym->n_strx == 0) { - incl_index = 0; /* end of translation unit */ - } else { - str = - (const char *) stabstr_section->data + - sym->n_strx; - /* do not add path */ - len = strlen(str); - if (len > 0 && str[len - 1] != '/') - goto add_incl2; - } - break; - } - sym++; - } - } - } - - // write symbol table - if (s1->do_debug) { - int k; - struct syment csym; - AUXFUNC auxfunc; - AUXBF auxbf; - AUXEF auxef; - int i; - Elf32_Sym *p; - const char *name; - int nstr; - int n = 0; - - Coff_str_table = (char *) tcc_malloc(MAX_STR_TABLE); - pCoff_str_table = Coff_str_table; - nstr = 0; - - p = (Elf32_Sym *) symtab_section->data; - - - for (i = 0; i < nb_syms; i++) { - - name = symtab_section->link->data + p->st_name; - - for (k = 0; k < 8; k++) - csym._n._n_name[k] = 0; - - if (strlen(name) <= 8) { - strcpy(csym._n._n_name, name); - } else { - if (pCoff_str_table - Coff_str_table + strlen(name) > - MAX_STR_TABLE - 1) - tcc_error("String table too large"); - - csym._n._n_n._n_zeroes = 0; - csym._n._n_n._n_offset = - pCoff_str_table - Coff_str_table + 4; - - strcpy(pCoff_str_table, name); - pCoff_str_table += strlen(name) + 1; // skip over null - nstr++; - } - - if (p->st_info == 4) { - // put a filename symbol - csym.n_value = 33; // ????? - csym.n_scnum = N_DEBUG; - csym.n_type = 0; - csym.n_sclass = C_FILE; - csym.n_numaux = 0; - fwrite(&csym, 18, 1, f); - n++; - - } else if (p->st_info == 0x12) { - // find the function data - - for (k = 0; k < nFuncs; k++) { - if (strcmp(name, Func[k]) == 0) - break; - } - - if (k >= nFuncs) { - tcc_error("debug info can't find function: %s", name); - } - // put a Function Name - - csym.n_value = p->st_value; // physical address - csym.n_scnum = CoffTextSectionNo; - csym.n_type = MKTYPE(T_INT, DT_FCN, 0, 0, 0, 0, 0); - csym.n_sclass = C_EXT; - csym.n_numaux = 1; - fwrite(&csym, 18, 1, f); - - // now put aux info - - auxfunc.tag = 0; - auxfunc.size = EndAddress[k] - p->st_value; - auxfunc.fileptr = LineNoFilePtr[k]; - auxfunc.nextsym = n + 6; // tktk - auxfunc.dummy = 0; - fwrite(&auxfunc, 18, 1, f); - - // put a .bf - - strcpy(csym._n._n_name, ".bf"); - csym.n_value = p->st_value; // physical address - csym.n_scnum = CoffTextSectionNo; - csym.n_type = 0; - csym.n_sclass = C_FCN; - csym.n_numaux = 1; - fwrite(&csym, 18, 1, f); - - // now put aux info - - auxbf.regmask = 0; - auxbf.lineno = 0; - auxbf.nentries = FuncEntries[k]; - auxbf.localframe = 0; - auxbf.nextentry = n + 6; - auxbf.dummy = 0; - fwrite(&auxbf, 18, 1, f); - - // put a .ef - - strcpy(csym._n._n_name, ".ef"); - csym.n_value = EndAddress[k]; // physical address - csym.n_scnum = CoffTextSectionNo; - csym.n_type = 0; - csym.n_sclass = C_FCN; - csym.n_numaux = 1; - fwrite(&csym, 18, 1, f); - - // now put aux info - - auxef.dummy = 0; - auxef.lineno = LastLineNo[k]; - auxef.dummy1 = 0; - auxef.dummy2 = 0; - auxef.dummy3 = 0; - auxef.dummy4 = 0; - fwrite(&auxef, 18, 1, f); - - n += 6; - - } else { - // try an put some type info - - if ((p->st_other & VT_BTYPE) == VT_DOUBLE) { - csym.n_type = T_DOUBLE; // int - csym.n_sclass = C_EXT; - } else if ((p->st_other & VT_BTYPE) == VT_FLOAT) { - csym.n_type = T_FLOAT; - csym.n_sclass = C_EXT; - } else if ((p->st_other & VT_BTYPE) == VT_INT) { - csym.n_type = T_INT; // int - csym.n_sclass = C_EXT; - } else if ((p->st_other & VT_BTYPE) == VT_SHORT) { - csym.n_type = T_SHORT; - csym.n_sclass = C_EXT; - } else if ((p->st_other & VT_BTYPE) == VT_BYTE) { - csym.n_type = T_CHAR; - csym.n_sclass = C_EXT; - } else { - csym.n_type = T_INT; // just mark as a label - csym.n_sclass = C_LABEL; - } - - - csym.n_value = p->st_value; - csym.n_scnum = 2; - csym.n_numaux = 1; - fwrite(&csym, 18, 1, f); - - auxfunc.tag = 0; - auxfunc.size = 0x20; - auxfunc.fileptr = 0; - auxfunc.nextsym = 0; - auxfunc.dummy = 0; - fwrite(&auxfunc, 18, 1, f); - n++; - n++; - - } - - p++; - } - } - - if (s1->do_debug) { - // write string table - - // first write the size - i = pCoff_str_table - Coff_str_table; - fwrite(&i, 4, 1, f); - - // then write the strings - fwrite(Coff_str_table, i, 1, f); - - tcc_free(Coff_str_table); - } - - return 0; -} - - - -// group the symbols in order of filename, func1, func2, etc -// finally global symbols - -void SortSymbolTable(TCCState *s1) -{ - int i, j, k, n = 0; - Elf32_Sym *p, *p2, *NewTable; - char *name, *name2; - - NewTable = (Elf32_Sym *) tcc_malloc(nb_syms * sizeof(Elf32_Sym)); - - p = (Elf32_Sym *) symtab_section->data; - - - // find a file symbol, copy it over - // then scan the whole symbol list and copy any function - // symbols that match the file association - - for (i = 0; i < nb_syms; i++) { - if (p->st_info == 4) { - name = (char *) symtab_section->link->data + p->st_name; - - // this is a file symbol, copy it over - - NewTable[n++] = *p; - - p2 = (Elf32_Sym *) symtab_section->data; - - for (j = 0; j < nb_syms; j++) { - if (p2->st_info == 0x12) { - // this is a func symbol - - name2 = - (char *) symtab_section->link->data + p2->st_name; - - // find the function data index - - for (k = 0; k < nFuncs; k++) { - if (strcmp(name2, Func[k]) == 0) - break; - } - - if (k >= nFuncs) { - tcc_error("debug (sort) info can't find function: %s", name2); - } - - if (strcmp(AssociatedFile[k], name) == 0) { - // yes they match copy it over - - NewTable[n++] = *p2; - } - } - p2++; - } - } - p++; - } - - // now all the filename and func symbols should have been copied over - // copy all the rest over (all except file and funcs) - - p = (Elf32_Sym *) symtab_section->data; - for (i = 0; i < nb_syms; i++) { - if (p->st_info != 4 && p->st_info != 0x12) { - NewTable[n++] = *p; - } - p++; - } - - if (n != nb_syms) - tcc_error("Internal Compiler error, debug info"); - - // copy it all back - - p = (Elf32_Sym *) symtab_section->data; - for (i = 0; i < nb_syms; i++) { - *p++ = NewTable[i]; - } - - tcc_free(NewTable); -} - - -int FindCoffSymbolIndex(TCCState *s1, const char *func_name) -{ - int i, n = 0; - Elf32_Sym *p; - char *name; - - p = (Elf32_Sym *) symtab_section->data; - - for (i = 0; i < nb_syms; i++) { - - name = (char *) symtab_section->link->data + p->st_name; - - if (p->st_info == 4) { - // put a filename symbol - n++; - } else if (p->st_info == 0x12) { - - if (strcmp(func_name, name) == 0) - return n; - - n += 6; - - // put a Function Name - - // now put aux info - - // put a .bf - - // now put aux info - - // put a .ef - - // now put aux info - - } else { - n += 2; - } - - p++; - } - - return n; // total number of symbols -} - -int OutputTheSection(Section * sect) -{ - const char *s = sect->name; - - if (!strcmp(s, ".text")) - return 1; - else if (!strcmp(s, ".data")) - return 1; - else - return 0; -} - -short int GetCoffFlags(const char *s) -{ - if (!strcmp(s, ".text")) - return STYP_TEXT | STYP_DATA | STYP_ALIGN | 0x400; - else if (!strcmp(s, ".data")) - return STYP_DATA; - else if (!strcmp(s, ".bss")) - return STYP_BSS; - else if (!strcmp(s, ".stack")) - return STYP_BSS | STYP_ALIGN | 0x200; - else if (!strcmp(s, ".cinit")) - return STYP_COPY | STYP_DATA | STYP_ALIGN | 0x200; - else - return 0; -} - -Section *FindSection(TCCState * s1, const char *sname) -{ - Section *s; - int i; - - for (i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - - if (!strcmp(sname, s->name)) - return s; - } - - tcc_error("could not find section %s", sname); - return 0; -} - -ST_FUNC int tcc_load_coff(TCCState * s1, int fd) -{ -// tktk TokenSym *ts; - - FILE *f; - unsigned int str_size; - char *Coff_str_table, *name; - int i, k; - struct syment csym; - char name2[9]; - FILHDR file_hdr; /* FILE HEADER STRUCTURE */ - - f = fdopen(fd, "rb"); - if (!f) { - tcc_error("Unable to open .out file for input"); - } - - if (fread(&file_hdr, FILHSZ, 1, f) != 1) - tcc_error("error reading .out file for input"); - - if (fread(&o_filehdr, sizeof(o_filehdr), 1, f) != 1) - tcc_error("error reading .out file for input"); - - // first read the string table - - if (fseek(f, file_hdr.f_symptr + file_hdr.f_nsyms * SYMESZ, SEEK_SET)) - tcc_error("error reading .out file for input"); - - if (fread(&str_size, sizeof(int), 1, f) != 1) - tcc_error("error reading .out file for input"); - - - Coff_str_table = (char *) tcc_malloc(str_size); - - if (fread(Coff_str_table, str_size - 4, 1, f) != 1) - tcc_error("error reading .out file for input"); - - // read/process all the symbols - - // seek back to symbols - - if (fseek(f, file_hdr.f_symptr, SEEK_SET)) - tcc_error("error reading .out file for input"); - - for (i = 0; i < file_hdr.f_nsyms; i++) { - if (fread(&csym, SYMESZ, 1, f) != 1) - tcc_error("error reading .out file for input"); - - if (csym._n._n_n._n_zeroes == 0) { - name = Coff_str_table + csym._n._n_n._n_offset - 4; - } else { - name = csym._n._n_name; - - if (name[7] != 0) { - for (k = 0; k < 8; k++) - name2[k] = name[k]; - - name2[8] = 0; - - name = name2; - } - } -// if (strcmp("_DAC_Buffer",name)==0) // tktk -// name[0]=0; - - if (((csym.n_type & 0x30) == 0x20 && csym.n_sclass == 0x2) || ((csym.n_type & 0x30) == 0x30 && csym.n_sclass == 0x2) || (csym.n_type == 0x4 && csym.n_sclass == 0x2) || (csym.n_type == 0x8 && csym.n_sclass == 0x2) || // structures - (csym.n_type == 0x18 && csym.n_sclass == 0x2) || // pointer to structure - (csym.n_type == 0x7 && csym.n_sclass == 0x2) || // doubles - (csym.n_type == 0x6 && csym.n_sclass == 0x2)) // floats - { - // strip off any leading underscore (except for other main routine) - - if (name[0] == '_' && strcmp(name, "_main") != 0) - name++; - - tcc_add_symbol(s1, name, (void*)(uintptr_t)csym.n_value); - } - // skip any aux records - - if (csym.n_numaux == 1) { - if (fread(&csym, SYMESZ, 1, f) != 1) - tcc_error("error reading .out file for input"); - i++; - } - } - - return 0; -} diff --git a/tinycc/tccdbg.c b/tinycc/tccdbg.c deleted file mode 100644 index 18c2cb1..0000000 --- a/tinycc/tccdbg.c +++ /dev/null @@ -1,2176 +0,0 @@ -/* - * 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 - */ - -#include "tcc.h" - -/* stab debug support */ - -static const struct { - int type; - int size; - int encoding; - const char *name; -} default_debug[] = { - { VT_INT, 4, DW_ATE_signed, "int:t1=r1;-2147483648;2147483647;" }, - { VT_BYTE, 1, DW_ATE_signed_char, "char:t2=r2;0;127;" }, -#if LONG_SIZE == 4 - { VT_LONG | VT_INT, 4, DW_ATE_signed, "long int:t3=r3;-2147483648;2147483647;" }, -#else - { VT_LLONG | VT_LONG, 8, DW_ATE_signed, "long int:t3=r3;-9223372036854775808;9223372036854775807;" }, -#endif - { VT_INT | VT_UNSIGNED, 4, DW_ATE_unsigned, "unsigned int:t4=r4;0;037777777777;" }, -#if LONG_SIZE == 4 - { VT_LONG | VT_INT | VT_UNSIGNED, 4, DW_ATE_unsigned, "long unsigned int:t5=r5;0;037777777777;" }, -#else - /* use octal instead of -1 so size_t works (-gstabs+ in gcc) */ - { VT_LLONG | VT_LONG | VT_UNSIGNED, 8, DW_ATE_unsigned, "long unsigned int:t5=r5;0;01777777777777777777777;" }, -#endif - { VT_QLONG, 16, DW_ATE_signed, "__int128:t6=r6;0;-1;" }, - { VT_QLONG | VT_UNSIGNED, 16, DW_ATE_unsigned, "__int128 unsigned:t7=r7;0;-1;" }, - { VT_LLONG, 8, DW_ATE_signed, "long long int:t8=r8;-9223372036854775808;9223372036854775807;" }, - { VT_LLONG | VT_UNSIGNED, 8, DW_ATE_unsigned, "long long unsigned int:t9=r9;0;01777777777777777777777;" }, - { VT_SHORT, 2, DW_ATE_signed, "short int:t10=r10;-32768;32767;" }, - { VT_SHORT | VT_UNSIGNED, 2, DW_ATE_unsigned, "short unsigned int:t11=r11;0;65535;" }, - { VT_BYTE | VT_DEFSIGN, 1, DW_ATE_signed_char, "signed char:t12=r12;-128;127;" }, - { VT_BYTE | VT_DEFSIGN | VT_UNSIGNED, 1, DW_ATE_unsigned_char, "unsigned char:t13=r13;0;255;" }, - { VT_FLOAT, 4, DW_ATE_float, "float:t14=r1;4;0;" }, - { VT_DOUBLE, 8, DW_ATE_float, "double:t15=r1;8;0;" }, -#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE - { VT_DOUBLE | VT_LONG, 8, DW_ATE_float, "long double:t16=r1;8;0;" }, -#else - { VT_LDOUBLE, 16, DW_ATE_float, "long double:t16=r1;16;0;" }, -#endif - { -1, -1, -1, "_Float32:t17=r1;4;0;" }, - { -1, -1, -1, "_Float64:t18=r1;8;0;" }, - { -1, -1, -1, "_Float128:t19=r1;16;0;" }, - { -1, -1, -1, "_Float32x:t20=r1;8;0;" }, - { -1, -1, -1, "_Float64x:t21=r1;16;0;" }, - { -1, -1, -1, "_Decimal32:t22=r1;4;0;" }, - { -1, -1, -1, "_Decimal64:t23=r1;8;0;" }, - { -1, -1, -1, "_Decimal128:t24=r1;16;0;" }, - /* if default char is unsigned */ - { VT_BYTE | VT_UNSIGNED, 1, DW_ATE_unsigned_char, "unsigned char:t25=r25;0;255;" }, - /* boolean type */ - { VT_BOOL, 1, DW_ATE_boolean, "bool:t26=r26;0;255;" }, -#if LONG_SIZE == 4 - { VT_VOID, 1, DW_ATE_unsigned_char, "void:t27=27" }, -#else - /* bitfields use these */ - { VT_LONG | VT_INT, 8, DW_ATE_signed, "long int:t27=r27;-9223372036854775808;9223372036854775807;" }, - { VT_LONG | VT_INT | VT_UNSIGNED, 8, DW_ATE_unsigned, "long unsigned int:t28=r28;0;01777777777777777777777;" }, - { VT_VOID, 1, DW_ATE_unsigned_char, "void:t29=29" }, -#endif -}; - -#define N_DEFAULT_DEBUG (sizeof (default_debug) / sizeof (default_debug[0])) - -/* dwarf debug */ - -#define DWARF_LINE_BASE -5 -#define DWARF_LINE_RANGE 14 -#define DWARF_OPCODE_BASE 13 - -#if defined TCC_TARGET_ARM64 -#define DWARF_MIN_INSTR_LEN 4 -#elif defined TCC_TARGET_ARM -#define DWARF_MIN_INSTR_LEN 2 -#else -#define DWARF_MIN_INSTR_LEN 1 -#endif - -#define DWARF_ABBREV_COMPILE_UNIT 1 -#define DWARF_ABBREV_BASE_TYPE 2 -#define DWARF_ABBREV_VARIABLE_EXTERNAL 3 -#define DWARF_ABBREV_VARIABLE_STATIC 4 -#define DWARF_ABBREV_VARIABLE_LOCAL 5 -#define DWARF_ABBREV_FORMAL_PARAMETER 6 -#define DWARF_ABBREV_POINTER 7 -#define DWARF_ABBREV_ARRAY_TYPE 8 -#define DWARF_ABBREV_SUBRANGE_TYPE 9 -#define DWARF_ABBREV_TYPEDEF 10 -#define DWARF_ABBREV_ENUMERATOR_SIGNED 11 -#define DWARF_ABBREV_ENUMERATOR_UNSIGNED 12 -#define DWARF_ABBREV_ENUMERATION_TYPE 13 -#define DWARF_ABBREV_MEMBER 14 -#define DWARF_ABBREV_MEMBER_BF 15 -#define DWARF_ABBREV_STRUCTURE_TYPE 16 -#define DWARF_ABBREV_STRUCTURE_EMPTY_TYPE 17 -#define DWARF_ABBREV_UNION_TYPE 18 -#define DWARF_ABBREV_UNION_EMPTY_TYPE 19 -#define DWARF_ABBREV_SUBPROGRAM_EXTERNAL 20 -#define DWARF_ABBREV_SUBPROGRAM_STATIC 21 -#define DWARF_ABBREV_LEXICAL_BLOCK 22 -#define DWARF_ABBREV_LEXICAL_EMPTY_BLOCK 23 -#define DWARF_ABBREV_SUBROUTINE_TYPE 24 -#define DWARF_ABBREV_SUBROUTINE_EMPTY_TYPE 25 -#define DWARF_ABBREV_FORMAL_PARAMETER2 26 - -/* all entries should have been generated with dwarf_uleb128 except - has_children. All values are currently below 128 so this currently - works. */ -static const unsigned char dwarf_abbrev_init[] = { - DWARF_ABBREV_COMPILE_UNIT, DW_TAG_compile_unit, 1, - DW_AT_producer, DW_FORM_strp, - DW_AT_language, DW_FORM_data1, - DW_AT_name, DW_FORM_line_strp, - DW_AT_comp_dir, DW_FORM_line_strp, - DW_AT_low_pc, DW_FORM_addr, -#if PTR_SIZE == 4 - DW_AT_high_pc, DW_FORM_data4, -#else - DW_AT_high_pc, DW_FORM_data8, -#endif - DW_AT_stmt_list, DW_FORM_sec_offset, - 0, 0, - DWARF_ABBREV_BASE_TYPE, DW_TAG_base_type, 0, - DW_AT_byte_size, DW_FORM_udata, - DW_AT_encoding, DW_FORM_data1, - DW_AT_name, DW_FORM_strp, - 0, 0, - DWARF_ABBREV_VARIABLE_EXTERNAL, DW_TAG_variable, 0, - DW_AT_name, DW_FORM_strp, - DW_AT_decl_file, DW_FORM_udata, - DW_AT_decl_line, DW_FORM_udata, - DW_AT_type, DW_FORM_ref4, - DW_AT_external, DW_FORM_flag, - DW_AT_location, DW_FORM_exprloc, - 0, 0, - DWARF_ABBREV_VARIABLE_STATIC, DW_TAG_variable, 0, - DW_AT_name, DW_FORM_strp, - DW_AT_decl_file, DW_FORM_udata, - DW_AT_decl_line, DW_FORM_udata, - DW_AT_type, DW_FORM_ref4, - DW_AT_location, DW_FORM_exprloc, - 0, 0, - DWARF_ABBREV_VARIABLE_LOCAL, DW_TAG_variable, 0, - DW_AT_name, DW_FORM_strp, - DW_AT_type, DW_FORM_ref4, - DW_AT_location, DW_FORM_exprloc, - 0, 0, - DWARF_ABBREV_FORMAL_PARAMETER, DW_TAG_formal_parameter, 0, - DW_AT_name, DW_FORM_strp, - DW_AT_type, DW_FORM_ref4, - DW_AT_location, DW_FORM_exprloc, - 0, 0, - DWARF_ABBREV_POINTER, DW_TAG_pointer_type, 0, - DW_AT_byte_size, DW_FORM_data1, - DW_AT_type, DW_FORM_ref4, - 0, 0, - DWARF_ABBREV_ARRAY_TYPE, DW_TAG_array_type, 1, - DW_AT_type, DW_FORM_ref4, - DW_AT_sibling, DW_FORM_ref4, - 0, 0, - DWARF_ABBREV_SUBRANGE_TYPE, DW_TAG_subrange_type, 0, - DW_AT_type, DW_FORM_ref4, - DW_AT_upper_bound, DW_FORM_udata, - 0, 0, - DWARF_ABBREV_TYPEDEF, DW_TAG_typedef, 0, - DW_AT_name, DW_FORM_strp, - DW_AT_decl_file, DW_FORM_udata, - DW_AT_decl_line, DW_FORM_udata, - DW_AT_type, DW_FORM_ref4, - 0, 0, - DWARF_ABBREV_ENUMERATOR_SIGNED, DW_TAG_enumerator, 0, - DW_AT_name, DW_FORM_strp, - DW_AT_const_value, DW_FORM_sdata, - 0, 0, - DWARF_ABBREV_ENUMERATOR_UNSIGNED, DW_TAG_enumerator, 0, - DW_AT_name, DW_FORM_strp, - DW_AT_const_value, DW_FORM_udata, - 0, 0, - DWARF_ABBREV_ENUMERATION_TYPE, DW_TAG_enumeration_type, 1, - DW_AT_name, DW_FORM_strp, - DW_AT_encoding, DW_FORM_data1, - DW_AT_byte_size, DW_FORM_data1, - DW_AT_type, DW_FORM_ref4, - DW_AT_decl_file, DW_FORM_udata, - DW_AT_decl_line, DW_FORM_udata, - DW_AT_sibling, DW_FORM_ref4, - 0, 0, - DWARF_ABBREV_MEMBER, DW_TAG_member, 0, - DW_AT_name, DW_FORM_strp, - DW_AT_decl_file, DW_FORM_udata, - DW_AT_decl_line, DW_FORM_udata, - DW_AT_type, DW_FORM_ref4, - DW_AT_data_member_location, DW_FORM_udata, - 0, 0, - DWARF_ABBREV_MEMBER_BF, DW_TAG_member, 0, - DW_AT_name, DW_FORM_strp, - DW_AT_decl_file, DW_FORM_udata, - DW_AT_decl_line, DW_FORM_udata, - DW_AT_type, DW_FORM_ref4, - DW_AT_bit_size, DW_FORM_udata, - DW_AT_data_bit_offset, DW_FORM_udata, - 0, 0, - DWARF_ABBREV_STRUCTURE_TYPE, DW_TAG_structure_type, 1, - DW_AT_name, DW_FORM_strp, - DW_AT_byte_size, DW_FORM_udata, - DW_AT_decl_file, DW_FORM_udata, - DW_AT_decl_line, DW_FORM_udata, - DW_AT_sibling, DW_FORM_ref4, - 0, 0, - DWARF_ABBREV_STRUCTURE_EMPTY_TYPE, DW_TAG_structure_type, 0, - DW_AT_name, DW_FORM_strp, - DW_AT_byte_size, DW_FORM_udata, - DW_AT_decl_file, DW_FORM_udata, - DW_AT_decl_line, DW_FORM_udata, - 0, 0, - DWARF_ABBREV_UNION_TYPE, DW_TAG_union_type, 1, - DW_AT_name, DW_FORM_strp, - DW_AT_byte_size, DW_FORM_udata, - DW_AT_decl_file, DW_FORM_udata, - DW_AT_decl_line, DW_FORM_udata, - DW_AT_sibling, DW_FORM_ref4, - 0, 0, - DWARF_ABBREV_UNION_EMPTY_TYPE, DW_TAG_union_type, 0, - DW_AT_name, DW_FORM_strp, - DW_AT_byte_size, DW_FORM_udata, - DW_AT_decl_file, DW_FORM_udata, - DW_AT_decl_line, DW_FORM_udata, - 0, 0, - DWARF_ABBREV_SUBPROGRAM_EXTERNAL, DW_TAG_subprogram, 1, - DW_AT_external, DW_FORM_flag, - DW_AT_name, DW_FORM_strp, - DW_AT_decl_file, DW_FORM_udata, - DW_AT_decl_line, DW_FORM_udata, - DW_AT_type, DW_FORM_ref4, - DW_AT_low_pc, DW_FORM_addr, -#if PTR_SIZE == 4 - DW_AT_high_pc, DW_FORM_data4, -#else - DW_AT_high_pc, DW_FORM_data8, -#endif - DW_AT_sibling, DW_FORM_ref4, - DW_AT_frame_base, DW_FORM_exprloc, - 0, 0, - DWARF_ABBREV_SUBPROGRAM_STATIC, DW_TAG_subprogram, 1, - DW_AT_name, DW_FORM_strp, - DW_AT_decl_file, DW_FORM_udata, - DW_AT_decl_line, DW_FORM_udata, - DW_AT_type, DW_FORM_ref4, - DW_AT_low_pc, DW_FORM_addr, -#if PTR_SIZE == 4 - DW_AT_high_pc, DW_FORM_data4, -#else - DW_AT_high_pc, DW_FORM_data8, -#endif - DW_AT_sibling, DW_FORM_ref4, - DW_AT_frame_base, DW_FORM_exprloc, - 0, 0, - DWARF_ABBREV_LEXICAL_BLOCK, DW_TAG_lexical_block, 1, - DW_AT_low_pc, DW_FORM_addr, -#if PTR_SIZE == 4 - DW_AT_high_pc, DW_FORM_data4, -#else - DW_AT_high_pc, DW_FORM_data8, -#endif - 0, 0, - DWARF_ABBREV_LEXICAL_EMPTY_BLOCK, DW_TAG_lexical_block, 0, - DW_AT_low_pc, DW_FORM_addr, -#if PTR_SIZE == 4 - DW_AT_high_pc, DW_FORM_data4, -#else - DW_AT_high_pc, DW_FORM_data8, -#endif - 0, 0, - DWARF_ABBREV_SUBROUTINE_TYPE, DW_TAG_subroutine_type, 1, - DW_AT_type, DW_FORM_ref4, - DW_AT_sibling, DW_FORM_ref4, - 0, 0, - DWARF_ABBREV_SUBROUTINE_EMPTY_TYPE, DW_TAG_subroutine_type, 0, - DW_AT_type, DW_FORM_ref4, - 0, 0, - DWARF_ABBREV_FORMAL_PARAMETER2, DW_TAG_formal_parameter, 0, - DW_AT_type, DW_FORM_ref4, - 0, 0, - 0 -}; - -static const unsigned char dwarf_line_opcodes[] = { - 0 ,1 ,1 ,1 ,1 ,0 ,0 ,0 ,1 ,0 ,0 ,1 -}; - -/* ------------------------------------------------------------------------- */ -/* debug state */ - -struct _tccdbg { - - int last_line_num, new_file; - int section_sym; - - int debug_next_type; - - struct _debug_hash { - int debug_type; - Sym *type; - } *debug_hash; - - struct _debug_anon_hash { - Sym *type; - int n_debug_type; - int *debug_type; - } *debug_anon_hash; - - int n_debug_hash; - int n_debug_anon_hash; - - struct _debug_info { - int start; - int end; - int n_sym; - struct debug_sym { - int type; - unsigned long value; - char *str; - Section *sec; - int sym_index; - int info; - int file; - int line; - } *sym; - struct _debug_info *child, *next, *last, *parent; - } *debug_info, *debug_info_root; - - struct { - int info; - int abbrev; - int line; - int str; - int line_str; - } dwarf_sym; - - struct { - int start; - int dir_size; - char **dir_table; - int filename_size; - struct dwarf_filename_struct { - int dir_entry; - char *name; - } *filename_table; - int line_size; - int line_max_size; - unsigned char *line_data; - int cur_file; - int last_file; - int last_pc; - int last_line; - } dwarf_line; - - struct { - int start; - Sym *func; - int line; - int base_type_used[N_DEFAULT_DEBUG]; - } dwarf_info; - - /* test coverage */ - struct { - unsigned long offset; - unsigned long last_file_name; - unsigned long last_func_name; - int ind; - int line; - } tcov_data; - -}; - -#define last_line_num s1->dState->last_line_num -#define new_file s1->dState->new_file -#define section_sym s1->dState->section_sym -#define debug_next_type s1->dState->debug_next_type -#define debug_hash s1->dState->debug_hash -#define debug_anon_hash s1->dState->debug_anon_hash -#define n_debug_hash s1->dState->n_debug_hash -#define n_debug_anon_hash s1->dState->n_debug_anon_hash -#define debug_info s1->dState->debug_info -#define debug_info_root s1->dState->debug_info_root -#define dwarf_sym s1->dState->dwarf_sym -#define dwarf_line s1->dState->dwarf_line -#define dwarf_info s1->dState->dwarf_info -#define tcov_data s1->dState->tcov_data - -/* ------------------------------------------------------------------------- */ -static void put_stabs(TCCState *s1, const char *str, int type, int other, - int desc, unsigned long value); - -ST_FUNC void tcc_debug_new(TCCState *s1) -{ - int shf = 0; - if (!s1->dState) - s1->dState = tcc_mallocz(sizeof *s1->dState); -#ifdef CONFIG_TCC_BACKTRACE - /* include stab info with standalone backtrace support */ - if (s1->do_backtrace - && (s1->output_type & (TCC_OUTPUT_EXE | TCC_OUTPUT_DLL))) - shf = SHF_ALLOC | SHF_WRITE; // SHF_WRITE needed for musl/SELINUX -#endif - if (s1->dwarf) { - s1->dwlo = s1->nb_sections; - dwarf_info_section = - new_section(s1, ".debug_info", SHT_PROGBITS, shf); - dwarf_abbrev_section = - new_section(s1, ".debug_abbrev", SHT_PROGBITS, shf); - dwarf_line_section = - new_section(s1, ".debug_line", SHT_PROGBITS, shf); - dwarf_aranges_section = - new_section(s1, ".debug_aranges", SHT_PROGBITS, shf); - shf |= SHF_MERGE | SHF_STRINGS; - dwarf_str_section = - new_section(s1, ".debug_str", SHT_PROGBITS, shf); - dwarf_str_section->sh_entsize = 1; - dwarf_info_section->sh_addralign = - dwarf_abbrev_section->sh_addralign = - dwarf_line_section->sh_addralign = - dwarf_aranges_section->sh_addralign = - dwarf_str_section->sh_addralign = 1; - if (s1->dwarf >= 5) { - dwarf_line_str_section = - new_section(s1, ".debug_line_str", SHT_PROGBITS, shf); - dwarf_line_str_section->sh_entsize = 1; - dwarf_line_str_section->sh_addralign = 1; - } - s1->dwhi = s1->nb_sections; - } - else - { - stab_section = new_section(s1, ".stab", SHT_PROGBITS, shf); - stab_section->sh_entsize = sizeof(Stab_Sym); - stab_section->sh_addralign = sizeof ((Stab_Sym*)0)->n_value; - stab_section->link = new_section(s1, ".stabstr", SHT_STRTAB, shf); - /* put first entry */ - put_stabs(s1, "", 0, 0, 0, 0); - } -} - -/* put stab debug information */ -static void put_stabs(TCCState *s1, const char *str, int type, int other, int desc, - unsigned long value) -{ - Stab_Sym *sym; - - unsigned offset; - if (type == N_SLINE - && (offset = stab_section->data_offset) - && (sym = (Stab_Sym*)(stab_section->data + offset) - 1) - && sym->n_type == type - && sym->n_value == value) { - /* just update line_number in previous entry */ - sym->n_desc = desc; - return; - } - - sym = section_ptr_add(stab_section, sizeof(Stab_Sym)); - if (str) { - sym->n_strx = put_elf_str(stab_section->link, str); - } else { - sym->n_strx = 0; - } - sym->n_type = type; - sym->n_other = other; - sym->n_desc = desc; - sym->n_value = value; -} - -static void put_stabs_r(TCCState *s1, const char *str, int type, int other, int desc, - unsigned long value, Section *sec, int sym_index) -{ - put_elf_reloc(symtab_section, stab_section, - stab_section->data_offset + 8, - sizeof ((Stab_Sym*)0)->n_value == PTR_SIZE ? R_DATA_PTR : R_DATA_32, - sym_index); - put_stabs(s1, str, type, other, desc, value); -} - -static void put_stabn(TCCState *s1, int type, int other, int desc, int value) -{ - put_stabs(s1, NULL, type, other, desc, value); -} - -/* ------------------------------------------------------------------------- */ -#define dwarf_data1(s,data) \ - { unsigned char *p = section_ptr_add((s), 1); *p = (data); } -#define dwarf_data2(s,data) \ - write16le(section_ptr_add((s), 2), (data)) -#define dwarf_data4(s,data) \ - write32le(section_ptr_add((s), 4), (data)) -#define dwarf_data8(s,data) \ - write64le(section_ptr_add((s), 8), (data)) - -static int dwarf_get_section_sym(Section *s) -{ - TCCState *s1 = s->s1; - return put_elf_sym(symtab_section, 0, 0, - ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0, - s->sh_num, NULL); -} - -static void dwarf_reloc(Section *s, int sym, int rel) -{ - TCCState *s1 = s->s1; - put_elf_reloca(symtab_section, s, s->data_offset, rel, sym, 0); -} - -static void dwarf_string(Section *s, Section *dw, int sym, const char *str) -{ - TCCState *s1 = s->s1; - int offset, len; - char *ptr; - - len = strlen(str) + 1; - offset = dw->data_offset; - ptr = section_ptr_add(dw, len); - memmove(ptr, str, len); - put_elf_reloca(symtab_section, s, s->data_offset, R_DATA_32DW, sym, - PTR_SIZE == 4 ? 0 : offset); - dwarf_data4(s, PTR_SIZE == 4 ? offset : 0); -} - -static void dwarf_strp(Section *s, const char *str) -{ - TCCState *s1 = s->s1; - dwarf_string(s, dwarf_str_section, dwarf_sym.str, str); -} - -static void dwarf_line_strp(Section *s, const char *str) -{ - TCCState *s1 = s->s1; - dwarf_string(s, dwarf_line_str_section, dwarf_sym.line_str, str); -} - -static void dwarf_line_op(TCCState *s1, unsigned char op) -{ - if (dwarf_line.line_size >= dwarf_line.line_max_size) { - dwarf_line.line_max_size += 1024; - dwarf_line.line_data = - (unsigned char *)tcc_realloc(dwarf_line.line_data, - dwarf_line.line_max_size); - } - dwarf_line.line_data[dwarf_line.line_size++] = op; -} - -static void dwarf_file(TCCState *s1) -{ - int i, j; - char *filename; - int index_offset = s1->dwarf < 5; - - if (!strcmp(file->filename, "<command line>")) { - dwarf_line.cur_file = 1; - return; - } - filename = strrchr(file->filename, '/'); - if (filename == NULL) { - for (i = 1; i < dwarf_line.filename_size; i++) - if (dwarf_line.filename_table[i].dir_entry == 0 && - strcmp(dwarf_line.filename_table[i].name, - file->filename) == 0) { - dwarf_line.cur_file = i + index_offset; - return; - } - i = -index_offset; - filename = file->filename; - } - else { - char *undo = filename; - char *dir = file->filename; - - *filename++ = '\0'; - for (i = 0; i < dwarf_line.dir_size; i++) - if (strcmp(dwarf_line.dir_table[i], dir) == 0) { - for (j = 1; j < dwarf_line.filename_size; j++) - if (dwarf_line.filename_table[j].dir_entry - index_offset - == i && - strcmp(dwarf_line.filename_table[j].name, - filename) == 0) { - *undo = '/'; - dwarf_line.cur_file = j + index_offset; - return; - } - break; - } - if (i == dwarf_line.dir_size) { - dwarf_line.dir_size++; - dwarf_line.dir_table = - (char **) tcc_realloc(dwarf_line.dir_table, - dwarf_line.dir_size * - sizeof (char *)); - dwarf_line.dir_table[i] = tcc_strdup(dir); - } - *undo = '/'; - } - dwarf_line.filename_table = - (struct dwarf_filename_struct *) - tcc_realloc(dwarf_line.filename_table, - (dwarf_line.filename_size + 1) * - sizeof (struct dwarf_filename_struct)); - dwarf_line.filename_table[dwarf_line.filename_size].dir_entry = - i + index_offset; - dwarf_line.filename_table[dwarf_line.filename_size].name = - tcc_strdup(filename); - dwarf_line.cur_file = dwarf_line.filename_size++ + index_offset; - return; -} - -#if 0 -static int dwarf_uleb128_size (unsigned long long value) -{ - int size = 0; - - do { - value >>= 7; - size++; - } while (value != 0); - return size; -} -#endif - -static int dwarf_sleb128_size (long long value) -{ - int size = 0; - long long end = value >> 63; - unsigned char last = end & 0x40; - unsigned char byte; - - do { - byte = value & 0x7f; - value >>= 7; - size++; - } while (value != end || (byte & 0x40) != last); - return size; -} - -static void dwarf_uleb128 (Section *s, unsigned long long value) -{ - do { - unsigned char byte = value & 0x7f; - - value >>= 7; - dwarf_data1(s, byte | (value ? 0x80 : 0)); - } while (value != 0); -} - -static void dwarf_sleb128 (Section *s, long long value) -{ - int more; - long long end = value >> 63; - unsigned char last = end & 0x40; - - do { - unsigned char byte = value & 0x7f; - - value >>= 7; - more = value != end || (byte & 0x40) != last; - dwarf_data1(s, byte | (0x80 * more)); - } while (more); -} - -static void dwarf_uleb128_op (TCCState *s1, unsigned long long value) -{ - do { - unsigned char byte = value & 0x7f; - - value >>= 7; - dwarf_line_op(s1, byte | (value ? 0x80 : 0)); - } while (value != 0); -} - -static void dwarf_sleb128_op (TCCState *s1, long long value) -{ - int more; - long long end = value >> 63; - unsigned char last = end & 0x40; - - do { - unsigned char byte = value & 0x7f; - - value >>= 7; - more = value != end || (byte & 0x40) != last; - dwarf_line_op(s1, byte | (0x80 * more)); - } while (more); -} - -/* start of translation unit info */ -ST_FUNC void tcc_debug_start(TCCState *s1) -{ - int i; - char buf[512]; - char *filename; - - /* an elf symbol of type STT_FILE must be put so that STB_LOCAL - symbols can be safely used */ - filename = file->prev ? file->prev->filename : file->filename; - put_elf_sym(symtab_section, 0, 0, - ELFW(ST_INFO)(STB_LOCAL, STT_FILE), 0, - SHN_ABS, filename); - - if (s1->do_debug) { - - new_file = last_line_num = 0; - debug_next_type = N_DEFAULT_DEBUG; - debug_hash = NULL; - debug_anon_hash = NULL; - n_debug_hash = 0; - n_debug_anon_hash = 0; - - getcwd(buf, sizeof(buf)); -#ifdef _WIN32 - normalize_slashes(buf); -#endif - - if (s1->dwarf) { - int start_abbrev; - unsigned char *ptr; - char *undo; - - /* dwarf_abbrev */ - start_abbrev = dwarf_abbrev_section->data_offset; - ptr = section_ptr_add(dwarf_abbrev_section, sizeof(dwarf_abbrev_init)); - memcpy(ptr, dwarf_abbrev_init, sizeof(dwarf_abbrev_init)); - - if (s1->dwarf < 5) { - while (*ptr) { - ptr += 3; - while (*ptr) { - if (ptr[1] == DW_FORM_line_strp) - ptr[1] = DW_FORM_strp; - if (s1->dwarf < 4) { - /* These are compatable for DW_TAG_compile_unit - DW_AT_stmt_list. */ - if (ptr[1] == DW_FORM_sec_offset) - ptr[1] = DW_FORM_data4; - /* This code uses only size < 0x80 so these are - compatible. */ - if (ptr[1] == DW_FORM_exprloc) - ptr[1] = DW_FORM_block1; - } - ptr += 2; - } - ptr += 2; - } - } - - dwarf_sym.info = dwarf_get_section_sym(dwarf_info_section); - dwarf_sym.abbrev = dwarf_get_section_sym(dwarf_abbrev_section); - dwarf_sym.line = dwarf_get_section_sym(dwarf_line_section); - dwarf_sym.str = dwarf_get_section_sym(dwarf_str_section); - if (tcc_state->dwarf >= 5) - dwarf_sym.line_str = dwarf_get_section_sym(dwarf_line_str_section); - else { - dwarf_line_str_section = dwarf_str_section; - dwarf_sym.line_str = dwarf_sym.str; - } - section_sym = dwarf_get_section_sym(text_section); - - /* dwarf_info */ - dwarf_info.start = dwarf_info_section->data_offset; - dwarf_data4(dwarf_info_section, 0); // size - dwarf_data2(dwarf_info_section, s1->dwarf); // version - if (s1->dwarf >= 5) { - dwarf_data1(dwarf_info_section, DW_UT_compile); // unit type - dwarf_data1(dwarf_info_section, PTR_SIZE); - dwarf_reloc(dwarf_info_section, dwarf_sym.abbrev, R_DATA_32DW); - dwarf_data4(dwarf_info_section, start_abbrev); - } - else { - dwarf_reloc(dwarf_info_section, dwarf_sym.abbrev, R_DATA_32DW); - dwarf_data4(dwarf_info_section, start_abbrev); - dwarf_data1(dwarf_info_section, PTR_SIZE); - } - - dwarf_data1(dwarf_info_section, DWARF_ABBREV_COMPILE_UNIT); - dwarf_strp(dwarf_info_section, "tcc " TCC_VERSION); - dwarf_data1(dwarf_info_section, DW_LANG_C11); - dwarf_line_strp(dwarf_info_section, filename); - dwarf_line_strp(dwarf_info_section, buf); - dwarf_reloc(dwarf_info_section, section_sym, R_DATA_PTR); -#if PTR_SIZE == 4 - dwarf_data4(dwarf_info_section, ind); // low pc - dwarf_data4(dwarf_info_section, 0); // high pc -#else - dwarf_data8(dwarf_info_section, ind); // low pc - dwarf_data8(dwarf_info_section, 0); // high pc -#endif - dwarf_reloc(dwarf_info_section, dwarf_sym.line, R_DATA_32DW); - dwarf_data4(dwarf_info_section, dwarf_line_section->data_offset); // stmt_list - - /* dwarf_line */ - dwarf_line.start = dwarf_line_section->data_offset; - dwarf_data4(dwarf_line_section, 0); // length - dwarf_data2(dwarf_line_section, s1->dwarf); // version - if (s1->dwarf >= 5) { - dwarf_data1(dwarf_line_section, PTR_SIZE); // address size - dwarf_data1(dwarf_line_section, 0); // segment selector - } - dwarf_data4(dwarf_line_section, 0); // prologue Length - dwarf_data1(dwarf_line_section, DWARF_MIN_INSTR_LEN); - if (s1->dwarf >= 4) - dwarf_data1(dwarf_line_section, 1); // maximum ops per instruction - dwarf_data1(dwarf_line_section, 1); // Initial value of 'is_stmt' - dwarf_data1(dwarf_line_section, DWARF_LINE_BASE); - dwarf_data1(dwarf_line_section, DWARF_LINE_RANGE); - dwarf_data1(dwarf_line_section, DWARF_OPCODE_BASE); - ptr = section_ptr_add(dwarf_line_section, sizeof(dwarf_line_opcodes)); - memcpy(ptr, dwarf_line_opcodes, sizeof(dwarf_line_opcodes)); - undo = strrchr(filename, '/'); - if (undo) - *undo = 0; - dwarf_line.dir_size = 1 + (undo != NULL); - dwarf_line.dir_table = (char **) tcc_malloc(sizeof (char *) * - dwarf_line.dir_size); - dwarf_line.dir_table[0] = tcc_strdup(buf); - if (undo) - dwarf_line.dir_table[1] = tcc_strdup(filename); - dwarf_line.filename_size = 2; - dwarf_line.filename_table = - (struct dwarf_filename_struct *) - tcc_malloc(2*sizeof (struct dwarf_filename_struct)); - dwarf_line.filename_table[0].dir_entry = 0; - if (undo) { - dwarf_line.filename_table[0].name = tcc_strdup(undo + 1); - dwarf_line.filename_table[1].dir_entry = 1; - dwarf_line.filename_table[1].name = tcc_strdup(undo + 1); - *undo = '/'; - } - else { - dwarf_line.filename_table[0].name = tcc_strdup(filename); - dwarf_line.filename_table[1].dir_entry = 0; - dwarf_line.filename_table[1].name = tcc_strdup(filename); - } - dwarf_line.line_size = dwarf_line.line_max_size = 0; - dwarf_line.line_data = NULL; - dwarf_line.cur_file = 1; - dwarf_line.last_file = 0; - dwarf_line.last_pc = 0; - dwarf_line.last_line = 1; - dwarf_line_op(s1, 0); // extended - dwarf_uleb128_op(s1, 1 + PTR_SIZE); // extended size - dwarf_line_op(s1, DW_LNE_set_address); - for (i = 0; i < PTR_SIZE; i++) - dwarf_line_op(s1, 0); - memset(&dwarf_info.base_type_used, 0, sizeof(dwarf_info.base_type_used)); - } - else - { - /* file info: full path + filename */ - pstrcat(buf, sizeof(buf), "/"); - section_sym = put_elf_sym(symtab_section, 0, 0, - ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0, - text_section->sh_num, NULL); - put_stabs_r(s1, buf, N_SO, 0, 0, - text_section->data_offset, text_section, section_sym); - put_stabs_r(s1, filename, N_SO, 0, 0, - text_section->data_offset, text_section, section_sym); - for (i = 0; i < N_DEFAULT_DEBUG; i++) - put_stabs(s1, default_debug[i].name, N_LSYM, 0, 0, 0); - } - /* we're currently 'including' the <command line> */ - tcc_debug_bincl(s1); - } -} - -/* put end of translation unit info */ -ST_FUNC void tcc_debug_end(TCCState *s1) -{ - if (!s1->do_debug || debug_next_type == 0) - return; - - if (debug_info_root) - tcc_debug_funcend(s1, 0); /* free stuff in case of errors */ - - if (s1->dwarf) { - int i, j; - int start_aranges; - unsigned char *ptr; - int text_size = text_section->data_offset; - - /* dwarf_info */ - for (i = 0; i < n_debug_anon_hash; i++) { - Sym *t = debug_anon_hash[i].type; - int pos = dwarf_info_section->data_offset; - - dwarf_data1(dwarf_info_section, - IS_UNION (t->type.t) ? DWARF_ABBREV_UNION_EMPTY_TYPE - : DWARF_ABBREV_STRUCTURE_EMPTY_TYPE); - dwarf_strp(dwarf_info_section, - (t->v & ~SYM_STRUCT) >= SYM_FIRST_ANOM - ? "" : get_tok_str(t->v & ~SYM_STRUCT, NULL)); - dwarf_uleb128(dwarf_info_section, 0); - dwarf_uleb128(dwarf_info_section, dwarf_line.cur_file); - dwarf_uleb128(dwarf_info_section, file->line_num); - for (j = 0; j < debug_anon_hash[i].n_debug_type; j++) - write32le(dwarf_info_section->data + - debug_anon_hash[i].debug_type[j], - pos - dwarf_info.start); - tcc_free (debug_anon_hash[i].debug_type); - } - tcc_free (debug_anon_hash); - dwarf_data1(dwarf_info_section, 0); - ptr = dwarf_info_section->data + dwarf_info.start; - write32le(ptr, dwarf_info_section->data_offset - dwarf_info.start - 4); - write32le(ptr + 25 + (s1->dwarf >= 5) + PTR_SIZE, text_size); - - /* dwarf_aranges */ - start_aranges = dwarf_aranges_section->data_offset; - dwarf_data4(dwarf_aranges_section, 0); // size - dwarf_data2(dwarf_aranges_section, 2); // version - dwarf_reloc(dwarf_aranges_section, dwarf_sym.info, R_DATA_32DW); - dwarf_data4(dwarf_aranges_section, 0); // dwarf_info -#if PTR_SIZE == 4 - dwarf_data1(dwarf_aranges_section, 4); // address size -#else - dwarf_data1(dwarf_aranges_section, 8); // address size -#endif - dwarf_data1(dwarf_aranges_section, 0); // segment selector size - dwarf_data4(dwarf_aranges_section, 0); // padding - dwarf_reloc(dwarf_aranges_section, section_sym, R_DATA_PTR); -#if PTR_SIZE == 4 - dwarf_data4(dwarf_aranges_section, 0); // Begin - dwarf_data4(dwarf_aranges_section, text_size); // End - dwarf_data4(dwarf_aranges_section, 0); // End list - dwarf_data4(dwarf_aranges_section, 0); // End list -#else - dwarf_data8(dwarf_aranges_section, 0); // Begin - dwarf_data8(dwarf_aranges_section, text_size); // End - dwarf_data8(dwarf_aranges_section, 0); // End list - dwarf_data8(dwarf_aranges_section, 0); // End list -#endif - ptr = dwarf_aranges_section->data + start_aranges; - write32le(ptr, dwarf_aranges_section->data_offset - start_aranges - 4); - - /* dwarf_line */ - if (s1->dwarf >= 5) { - dwarf_data1(dwarf_line_section, 1); /* col */ - dwarf_uleb128(dwarf_line_section, DW_LNCT_path); - dwarf_uleb128(dwarf_line_section, DW_FORM_line_strp); - dwarf_uleb128(dwarf_line_section, dwarf_line.dir_size); - for (i = 0; i < dwarf_line.dir_size; i++) - dwarf_line_strp(dwarf_line_section, dwarf_line.dir_table[i]); - dwarf_data1(dwarf_line_section, 2); /* col */ - dwarf_uleb128(dwarf_line_section, DW_LNCT_path); - dwarf_uleb128(dwarf_line_section, DW_FORM_line_strp); - dwarf_uleb128(dwarf_line_section, DW_LNCT_directory_index); - dwarf_uleb128(dwarf_line_section, DW_FORM_udata); - dwarf_uleb128(dwarf_line_section, dwarf_line.filename_size); - for (i = 0; i < dwarf_line.filename_size; i++) { - dwarf_line_strp(dwarf_line_section, - dwarf_line.filename_table[i].name); - dwarf_uleb128(dwarf_line_section, - dwarf_line.filename_table[i].dir_entry); - } - } - else { - int len; - - for (i = 0; i < dwarf_line.dir_size; i++) { - len = strlen(dwarf_line.dir_table[i]) + 1; - ptr = section_ptr_add(dwarf_line_section, len); - memmove(ptr, dwarf_line.dir_table[i], len); - } - dwarf_data1(dwarf_line_section, 0); /* end dir */ - for (i = 0; i < dwarf_line.filename_size; i++) { - len = strlen(dwarf_line.filename_table[i].name) + 1; - ptr = section_ptr_add(dwarf_line_section, len); - memmove(ptr, dwarf_line.filename_table[i].name, len); - dwarf_uleb128(dwarf_line_section, - dwarf_line.filename_table[i].dir_entry); - dwarf_uleb128(dwarf_line_section, 0); /* time */ - dwarf_uleb128(dwarf_line_section, 0); /* size */ - } - dwarf_data1(dwarf_line_section, 0); /* end file */ - } - for (i = 0; i < dwarf_line.dir_size; i++) - tcc_free(dwarf_line.dir_table[i]); - tcc_free(dwarf_line.dir_table); - for (i = 0; i < dwarf_line.filename_size; i++) - tcc_free(dwarf_line.filename_table[i].name); - tcc_free(dwarf_line.filename_table); - - dwarf_line_op(s1, 0); // extended - dwarf_uleb128_op(s1, 1); // extended size - dwarf_line_op(s1, DW_LNE_end_sequence); - i = (s1->dwarf >= 5) * 2; - write32le(&dwarf_line_section->data[dwarf_line.start + 6 + i], - dwarf_line_section->data_offset - dwarf_line.start - (10 + i)); - section_ptr_add(dwarf_line_section, 3); - dwarf_reloc(dwarf_line_section, section_sym, R_DATA_PTR); - ptr = section_ptr_add(dwarf_line_section, dwarf_line.line_size - 3); - memmove(ptr - 3, dwarf_line.line_data, dwarf_line.line_size); - tcc_free(dwarf_line.line_data); - write32le(dwarf_line_section->data + dwarf_line.start, - dwarf_line_section->data_offset - dwarf_line.start - 4); - } - else - { - put_stabs_r(s1, NULL, N_SO, 0, 0, - text_section->data_offset, text_section, section_sym); - } - tcc_free(debug_hash); - debug_next_type = 0; -} - -static BufferedFile* put_new_file(TCCState *s1) -{ - BufferedFile *f = file; - /* use upper file if from inline ":asm:" */ - if (f->filename[0] == ':') - f = f->prev; - if (f && new_file) { - new_file = last_line_num = 0; - if (s1->dwarf) - dwarf_file(s1); - else - put_stabs_r(s1, f->filename, N_SOL, 0, 0, ind, text_section, section_sym); - } - return f; -} - -/* put alternative filename */ -ST_FUNC void tcc_debug_putfile(TCCState *s1, const char *filename) -{ - if (0 == strcmp(file->filename, filename)) - return; - pstrcpy(file->filename, sizeof(file->filename), filename); - if (!s1->do_debug) - return; - if (s1->dwarf) - dwarf_file(s1); - new_file = 1; -} - -/* begin of #include */ -ST_FUNC void tcc_debug_bincl(TCCState *s1) -{ - if (!s1->do_debug) - return; - if (s1->dwarf) - dwarf_file(s1); - else - put_stabs(s1, file->filename, N_BINCL, 0, 0, 0); - new_file = 1; -} - -/* end of #include */ -ST_FUNC void tcc_debug_eincl(TCCState *s1) -{ - if (!s1->do_debug) - return; - if (s1->dwarf) - dwarf_file(s1); - else - put_stabn(s1, N_EINCL, 0, 0, 0); - new_file = 1; -} - -/* generate line number info */ -ST_FUNC void tcc_debug_line(TCCState *s1) -{ - BufferedFile *f; - - if (!s1->do_debug) - return; - if (cur_text_section != text_section) - return; - f = put_new_file(s1); - if (!f) - return; - if (last_line_num == f->line_num) - return; - last_line_num = f->line_num; - - if (s1->dwarf) { - int len_pc = (ind - dwarf_line.last_pc) / DWARF_MIN_INSTR_LEN; - int len_line = f->line_num - dwarf_line.last_line; - int n = len_pc * DWARF_LINE_RANGE + len_line + DWARF_OPCODE_BASE - DWARF_LINE_BASE; - - if (dwarf_line.cur_file != dwarf_line.last_file) { - dwarf_line.last_file = dwarf_line.cur_file; - dwarf_line_op(s1, DW_LNS_set_file); - dwarf_uleb128_op(s1, dwarf_line.cur_file); - } - if (len_pc && - len_line >= DWARF_LINE_BASE && len_line <= (DWARF_OPCODE_BASE + DWARF_LINE_BASE) && - n >= DWARF_OPCODE_BASE && n <= 255) - dwarf_line_op(s1, n); - else { - if (len_pc) { - n = len_pc * DWARF_LINE_RANGE + 0 + DWARF_OPCODE_BASE - DWARF_LINE_BASE; - if (n >= DWARF_OPCODE_BASE && n <= 255) - dwarf_line_op(s1, n); - else { - dwarf_line_op(s1, DW_LNS_advance_pc); - dwarf_uleb128_op(s1, len_pc); - } - } - if (len_line) { - n = 0 * DWARF_LINE_RANGE + len_line + DWARF_OPCODE_BASE - DWARF_LINE_BASE; - if (len_line >= DWARF_LINE_BASE && len_line <= (DWARF_OPCODE_BASE + DWARF_LINE_BASE) && - n >= DWARF_OPCODE_BASE && n <= 255) - dwarf_line_op(s1, n); - else { - dwarf_line_op(s1, DW_LNS_advance_line); - dwarf_sleb128_op(s1, len_line); - } - } - } - dwarf_line.last_pc = ind; - dwarf_line.last_line = f->line_num; - } - else - { - if (func_ind != -1) { - put_stabn(s1, N_SLINE, 0, f->line_num, ind - func_ind); - } else { - /* from tcc_assemble */ - put_stabs_r(s1, NULL, N_SLINE, 0, f->line_num, ind, text_section, section_sym); - } - } -} - -static void tcc_debug_stabs (TCCState *s1, const char *str, int type, unsigned long value, - Section *sec, int sym_index, int info) -{ - struct debug_sym *s; - - if (debug_info) { - debug_info->sym = - (struct debug_sym *)tcc_realloc (debug_info->sym, - sizeof(struct debug_sym) * - (debug_info->n_sym + 1)); - s = debug_info->sym + debug_info->n_sym++; - s->type = type; - s->value = value; - s->str = tcc_strdup(str); - s->sec = sec; - s->sym_index = sym_index; - s->info = info; - s->file = dwarf_line.cur_file; - s->line = file->line_num; - } - else if (sec) - put_stabs_r (s1, str, type, 0, 0, value, sec, sym_index); - else - put_stabs (s1, str, type, 0, 0, value); -} - -ST_FUNC void tcc_debug_stabn(TCCState *s1, int type, int value) -{ - if (!s1->do_debug) - return; - if (type == N_LBRAC) { - struct _debug_info *info = - (struct _debug_info *) tcc_mallocz(sizeof (*info)); - - info->start = value; - info->parent = debug_info; - if (debug_info) { - if (debug_info->child) { - if (debug_info->child->last) - debug_info->child->last->next = info; - else - debug_info->child->next = info; - debug_info->child->last = info; - } - else - debug_info->child = info; - } - else - debug_info_root = info; - debug_info = info; - } - else { - debug_info->end = value; - debug_info = debug_info->parent; - } -} - -static int tcc_debug_find(TCCState *s1, Sym *t, int dwarf) -{ - int i; - - if (!debug_info && dwarf && - (t->type.t & VT_BTYPE) == VT_STRUCT && t->c == -1) { - for (i = 0; i < n_debug_anon_hash; i++) - if (t == debug_anon_hash[i].type) - return 0; - debug_anon_hash = (struct _debug_anon_hash *) - tcc_realloc (debug_anon_hash, - (n_debug_anon_hash + 1) * sizeof(*debug_anon_hash)); - debug_anon_hash[n_debug_anon_hash].n_debug_type = 0; - debug_anon_hash[n_debug_anon_hash].debug_type = NULL; - debug_anon_hash[n_debug_anon_hash++].type = t; - return 0; - } - for (i = 0; i < n_debug_hash; i++) - if (t == debug_hash[i].type) - return debug_hash[i].debug_type; - return -1; -} - -static int tcc_get_dwarf_info(TCCState *s1, Sym *s); - -static void tcc_debug_check_anon(TCCState *s1, Sym *t, int debug_type) -{ - int i; - - if (!debug_info && (t->type.t & VT_BTYPE) == VT_STRUCT && t->type.ref->c == -1) - for (i = 0; i < n_debug_anon_hash; i++) - if (t->type.ref == debug_anon_hash[i].type) { - debug_anon_hash[i].debug_type = - tcc_realloc(debug_anon_hash[i].debug_type, - (debug_anon_hash[i].n_debug_type + 1) * sizeof(int)); - debug_anon_hash[i].debug_type[debug_anon_hash[i].n_debug_type++] = - debug_type; - } -} - -ST_FUNC void tcc_debug_fix_anon(TCCState *s1, CType *t) -{ - int i, j, debug_type; - - if (!s1->do_debug || !s1->dwarf || debug_info) - return; - if ((t->t & VT_BTYPE) == VT_STRUCT && t->ref->c != -1) - for (i = 0; i < n_debug_anon_hash; i++) - if (t->ref == debug_anon_hash[i].type) { - Sym sym = {0}; sym .type = *t ; - - /* Trick to not hash this struct */ - debug_info = (struct _debug_info *) t; - debug_type = tcc_get_dwarf_info(s1, &sym); - debug_info = NULL; - for (j = 0; j < debug_anon_hash[i].n_debug_type; j++) - write32le(dwarf_info_section->data + - debug_anon_hash[i].debug_type[j], - debug_type - dwarf_info.start); - tcc_free(debug_anon_hash[i].debug_type); - n_debug_anon_hash--; - for (; i < n_debug_anon_hash; i++) - debug_anon_hash[i] = debug_anon_hash[i + 1]; - } -} - -static int tcc_debug_add(TCCState *s1, Sym *t, int dwarf) -{ - int offset = dwarf ? dwarf_info_section->data_offset : ++debug_next_type; - debug_hash = (struct _debug_hash *) - tcc_realloc (debug_hash, - (n_debug_hash + 1) * sizeof(*debug_hash)); - debug_hash[n_debug_hash].debug_type = offset; - debug_hash[n_debug_hash++].type = t; - return offset; -} - -static void tcc_debug_remove(TCCState *s1, Sym *t) -{ - int i; - - for (i = 0; i < n_debug_hash; i++) - if (t == debug_hash[i].type) { - n_debug_hash--; - for (; i < n_debug_hash; i++) - debug_hash[i] = debug_hash[i+1]; - } -} - -#define STRUCT_NODEBUG(s) \ - (s->a.nodebug || \ - ((s->v & ~SYM_FIELD) >= SYM_FIRST_ANOM && \ - ((s->type.t & VT_BTYPE) == VT_BYTE || \ - (s->type.t & VT_BTYPE) == VT_BOOL || \ - (s->type.t & VT_BTYPE) == VT_SHORT || \ - (s->type.t & VT_BTYPE) == VT_INT || \ - (s->type.t & VT_BTYPE) == VT_LLONG))) - -static void tcc_get_debug_info(TCCState *s1, Sym *s, CString *result) -{ - int type; - int n = 0; - int debug_type = -1; - Sym *t = s; - CString str; - - for (;;) { - type = t->type.t & ~(VT_STORAGE | VT_CONSTANT | VT_VOLATILE | VT_VLA); - if ((type & VT_BTYPE) != VT_BYTE) - type &= ~VT_DEFSIGN; - if (type == VT_PTR || type == (VT_PTR | VT_ARRAY)) - n++, t = t->type.ref; - else - break; - } - if ((type & VT_BTYPE) == VT_STRUCT) { - Sym *e = t; - - t = t->type.ref; - debug_type = tcc_debug_find(s1, t, 0); - if (debug_type == -1) { - debug_type = tcc_debug_add(s1, t, 0); - cstr_new (&str); - cstr_printf (&str, "%s:T%d=%c%d", - (t->v & ~SYM_STRUCT) >= SYM_FIRST_ANOM - ? "" : get_tok_str(t->v & ~SYM_STRUCT, NULL), - debug_type, - IS_UNION (t->type.t) ? 'u' : 's', - t->c); - while (t->next) { - int pos, size, align; - - t = t->next; - if (STRUCT_NODEBUG(t)) - continue; - cstr_printf (&str, "%s:", - get_tok_str(t->v & ~SYM_FIELD, NULL)); - tcc_get_debug_info (s1, t, &str); - if (t->type.t & VT_BITFIELD) { - pos = t->c * 8 + BIT_POS(t->type.t); - size = BIT_SIZE(t->type.t); - } - else { - pos = t->c * 8; - size = type_size(&t->type, &align) * 8; - } - cstr_printf (&str, ",%d,%d;", pos, size); - } - cstr_printf (&str, ";"); - tcc_debug_stabs(s1, str.data, N_LSYM, 0, NULL, 0, 0); - cstr_free (&str); - if (debug_info) - tcc_debug_remove(s1, e); - } - } - else if (IS_ENUM(type)) { - Sym *e = t = t->type.ref; - - debug_type = tcc_debug_find(s1, t, 0); - if (debug_type == -1) { - debug_type = tcc_debug_add(s1, t, 0); - cstr_new (&str); - cstr_printf (&str, "%s:T%d=e", - (t->v & ~SYM_STRUCT) >= SYM_FIRST_ANOM - ? "" : get_tok_str(t->v & ~SYM_STRUCT, NULL), - debug_type); - while (t->next) { - t = t->next; - cstr_printf (&str, "%s:", - (t->v & ~SYM_FIELD) >= SYM_FIRST_ANOM - ? "" : get_tok_str(t->v & ~SYM_FIELD, NULL)); - cstr_printf (&str, e->type.t & VT_UNSIGNED ? "%u," : "%d,", - (int)t->enum_val); - } - cstr_printf (&str, ";"); - tcc_debug_stabs(s1, str.data, N_LSYM, 0, NULL, 0, 0); - cstr_free (&str); - if (debug_info) - tcc_debug_remove(s1, e); - } - } - else if ((type & VT_BTYPE) != VT_FUNC) { - type &= ~VT_STRUCT_MASK; - for (debug_type = 1; debug_type <= N_DEFAULT_DEBUG; debug_type++) - if (default_debug[debug_type - 1].type == type) - break; - if (debug_type > N_DEFAULT_DEBUG) - return; - } - if (n > 0) - cstr_printf (result, "%d=", ++debug_next_type); - t = s; - for (;;) { - type = t->type.t & ~(VT_STORAGE | VT_CONSTANT | VT_VOLATILE | VT_VLA); - if ((type & VT_BTYPE) != VT_BYTE) - type &= ~VT_DEFSIGN; - if (type == VT_PTR) - cstr_printf (result, "%d=*", ++debug_next_type); - else if (type == (VT_PTR | VT_ARRAY)) - cstr_printf (result, "%d=ar1;0;%d;", - ++debug_next_type, t->type.ref->c - 1); - else if (type == VT_FUNC) { - cstr_printf (result, "%d=f", ++debug_next_type); - tcc_get_debug_info (s1, t->type.ref, result); - return; - } - else - break; - t = t->type.ref; - } - cstr_printf (result, "%d", debug_type); -} - -static int tcc_get_dwarf_info(TCCState *s1, Sym *s) -{ - int type; - int debug_type = -1; - Sym *e, *t = s; - int i; - int last_pos = -1; - int retval; - - if (new_file) - put_new_file(s1); - for (;;) { - type = t->type.t & ~(VT_STORAGE | VT_CONSTANT | VT_VOLATILE | VT_VLA); - if ((type & VT_BTYPE) != VT_BYTE) - type &= ~VT_DEFSIGN; - if (type == VT_PTR || type == (VT_PTR | VT_ARRAY)) - t = t->type.ref; - else - break; - } - if ((type & VT_BTYPE) == VT_STRUCT) { - t = t->type.ref; - debug_type = tcc_debug_find(s1, t, 1); - if (debug_type == -1) { - int pos_sib = 0, i, *pos_type; - - debug_type = tcc_debug_add(s1, t, 1); - e = t; - i = 0; - while (e->next) { - e = e->next; - if (STRUCT_NODEBUG(e)) - continue; - i++; - } - pos_type = (int *) tcc_malloc(i * sizeof(int)); - dwarf_data1(dwarf_info_section, - IS_UNION (t->type.t) - ? t->next ? DWARF_ABBREV_UNION_TYPE - : DWARF_ABBREV_UNION_EMPTY_TYPE - : t->next ? DWARF_ABBREV_STRUCTURE_TYPE - : DWARF_ABBREV_STRUCTURE_EMPTY_TYPE); - dwarf_strp(dwarf_info_section, - (t->v & ~SYM_STRUCT) >= SYM_FIRST_ANOM - ? "" : get_tok_str(t->v & ~SYM_STRUCT, NULL)); - dwarf_uleb128(dwarf_info_section, t->c); - dwarf_uleb128(dwarf_info_section, dwarf_line.cur_file); - dwarf_uleb128(dwarf_info_section, file->line_num); - if (t->next) { - pos_sib = dwarf_info_section->data_offset; - dwarf_data4(dwarf_info_section, 0); - } - e = t; - i = 0; - while (e->next) { - e = e->next; - if (STRUCT_NODEBUG(e)) - continue; - dwarf_data1(dwarf_info_section, - e->type.t & VT_BITFIELD ? DWARF_ABBREV_MEMBER_BF - : DWARF_ABBREV_MEMBER); - dwarf_strp(dwarf_info_section, - get_tok_str(e->v & ~SYM_FIELD, NULL)); - dwarf_uleb128(dwarf_info_section, dwarf_line.cur_file); - dwarf_uleb128(dwarf_info_section, file->line_num); - pos_type[i++] = dwarf_info_section->data_offset; - dwarf_data4(dwarf_info_section, 0); - if (e->type.t & VT_BITFIELD) { - int pos = e->c * 8 + BIT_POS(e->type.t); - int size = BIT_SIZE(e->type.t); - - dwarf_uleb128(dwarf_info_section, size); - dwarf_uleb128(dwarf_info_section, pos); - } - else - dwarf_uleb128(dwarf_info_section, e->c); - } - if (t->next) { - dwarf_data1(dwarf_info_section, 0); - write32le(dwarf_info_section->data + pos_sib, - dwarf_info_section->data_offset - dwarf_info.start); - } - e = t; - i = 0; - while (e->next) { - e = e->next; - if (STRUCT_NODEBUG(e)) - continue; - type = tcc_get_dwarf_info(s1, e); - tcc_debug_check_anon(s1, e, pos_type[i]); - write32le(dwarf_info_section->data + pos_type[i++], - type - dwarf_info.start); - } - tcc_free(pos_type); - if (debug_info) - tcc_debug_remove(s1, t); - } - } - else if (IS_ENUM(type)) { - t = t->type.ref; - debug_type = tcc_debug_find(s1, t, 1); - if (debug_type == -1) { - int pos_sib, pos_type; - Sym sym = {0}; sym.type.t = VT_INT | (type & VT_UNSIGNED); - - pos_type = tcc_get_dwarf_info(s1, &sym); - debug_type = tcc_debug_add(s1, t, 1); - dwarf_data1(dwarf_info_section, DWARF_ABBREV_ENUMERATION_TYPE); - dwarf_strp(dwarf_info_section, - (t->v & ~SYM_STRUCT) >= SYM_FIRST_ANOM - ? "" : get_tok_str(t->v & ~SYM_STRUCT, NULL)); - dwarf_data1(dwarf_info_section, - type & VT_UNSIGNED ? DW_ATE_unsigned : DW_ATE_signed ); - dwarf_data1(dwarf_info_section, 4); - dwarf_data4(dwarf_info_section, pos_type - dwarf_info.start); - dwarf_uleb128(dwarf_info_section, dwarf_line.cur_file); - dwarf_uleb128(dwarf_info_section, file->line_num); - pos_sib = dwarf_info_section->data_offset; - dwarf_data4(dwarf_info_section, 0); - e = t; - while (e->next) { - e = e->next; - dwarf_data1(dwarf_info_section, - type & VT_UNSIGNED ? DWARF_ABBREV_ENUMERATOR_UNSIGNED - : DWARF_ABBREV_ENUMERATOR_SIGNED); - dwarf_strp(dwarf_info_section, - (e->v & ~SYM_FIELD) >= SYM_FIRST_ANOM - ? "" : get_tok_str(e->v & ~SYM_FIELD, NULL)); - if (type & VT_UNSIGNED) - dwarf_uleb128(dwarf_info_section, e->enum_val); - else - dwarf_sleb128(dwarf_info_section, e->enum_val); - } - dwarf_data1(dwarf_info_section, 0); - write32le(dwarf_info_section->data + pos_sib, - dwarf_info_section->data_offset - dwarf_info.start); - if (debug_info) - tcc_debug_remove(s1, t); - } - } - else if ((type & VT_BTYPE) != VT_FUNC) { - type &= ~VT_STRUCT_MASK; - for (i = 1; i <= N_DEFAULT_DEBUG; i++) - if (default_debug[i - 1].type == type) - break; - if (i > N_DEFAULT_DEBUG) - return 0; - debug_type = dwarf_info.base_type_used[i - 1]; - if (debug_type == 0) { - char name[100]; - - debug_type = dwarf_info_section->data_offset; - dwarf_data1(dwarf_info_section, DWARF_ABBREV_BASE_TYPE); - dwarf_uleb128(dwarf_info_section, default_debug[i - 1].size); - dwarf_data1(dwarf_info_section, default_debug[i - 1].encoding); - strncpy(name, default_debug[i - 1].name, sizeof(name) -1); - *strchr(name, ':') = 0; - dwarf_strp(dwarf_info_section, name); - dwarf_info.base_type_used[i - 1] = debug_type; - } - } - retval = debug_type; - e = NULL; - t = s; - for (;;) { - type = t->type.t & ~(VT_STORAGE | VT_CONSTANT | VT_VOLATILE | VT_VLA); - if ((type & VT_BTYPE) != VT_BYTE) - type &= ~VT_DEFSIGN; - if (type == VT_PTR) { - i = dwarf_info_section->data_offset; - if (retval == debug_type) - retval = i; - dwarf_data1(dwarf_info_section, DWARF_ABBREV_POINTER); - dwarf_data1(dwarf_info_section, PTR_SIZE); - if (last_pos != -1) { - tcc_debug_check_anon(s1, e, last_pos); - write32le(dwarf_info_section->data + last_pos, - i - dwarf_info.start); - } - last_pos = dwarf_info_section->data_offset; - e = t->type.ref; - dwarf_data4(dwarf_info_section, 0); - } - else if (type == (VT_PTR | VT_ARRAY)) { - int sib_pos, sub_type; -#if LONG_SIZE == 4 - Sym sym = {0}; sym.type.t = VT_LONG | VT_INT | VT_UNSIGNED; -#else - Sym sym = {0}; sym.type.t = VT_LLONG | VT_LONG | VT_UNSIGNED; -#endif - - sub_type = tcc_get_dwarf_info(s1, &sym); - i = dwarf_info_section->data_offset; - if (retval == debug_type) - retval = i; - dwarf_data1(dwarf_info_section, DWARF_ABBREV_ARRAY_TYPE); - if (last_pos != -1) { - tcc_debug_check_anon(s1, e, last_pos); - write32le(dwarf_info_section->data + last_pos, - i - dwarf_info.start); - } - last_pos = dwarf_info_section->data_offset; - e = t->type.ref; - dwarf_data4(dwarf_info_section, 0); - sib_pos = dwarf_info_section->data_offset; - dwarf_data4(dwarf_info_section, 0); - for (;;) { - dwarf_data1(dwarf_info_section, DWARF_ABBREV_SUBRANGE_TYPE); - dwarf_data4(dwarf_info_section, sub_type - dwarf_info.start); - dwarf_uleb128(dwarf_info_section, t->type.ref->c - 1); - s = t->type.ref; - type = s->type.t & ~(VT_STORAGE | VT_CONSTANT | VT_VOLATILE); - if (type != (VT_PTR | VT_ARRAY)) - break; - t = s; - } - dwarf_data1(dwarf_info_section, 0); - write32le(dwarf_info_section->data + sib_pos, - dwarf_info_section->data_offset - dwarf_info.start); - } - else if (type == VT_FUNC) { - int sib_pos = 0, *pos_type; - Sym *f; - - i = dwarf_info_section->data_offset; - debug_type = tcc_get_dwarf_info(s1, t->type.ref); - if (retval == debug_type) - retval = i; - dwarf_data1(dwarf_info_section, - t->type.ref->next ? DWARF_ABBREV_SUBROUTINE_TYPE - : DWARF_ABBREV_SUBROUTINE_EMPTY_TYPE); - if (last_pos != -1) { - tcc_debug_check_anon(s1, e, last_pos); - write32le(dwarf_info_section->data + last_pos, - i - dwarf_info.start); - } - last_pos = dwarf_info_section->data_offset; - e = t->type.ref; - dwarf_data4(dwarf_info_section, 0); - if (t->type.ref->next) { - sib_pos = dwarf_info_section->data_offset; - dwarf_data4(dwarf_info_section, 0); - } - f = t->type.ref; - i = 0; - while (f->next) { - f = f->next; - i++; - } - pos_type = (int *) tcc_malloc(i * sizeof(int)); - f = t->type.ref; - i = 0; - while (f->next) { - f = f->next; - dwarf_data1(dwarf_info_section, DWARF_ABBREV_FORMAL_PARAMETER2); - pos_type[i++] = dwarf_info_section->data_offset; - dwarf_data4(dwarf_info_section, 0); - } - if (t->type.ref->next) { - dwarf_data1(dwarf_info_section, 0); - write32le(dwarf_info_section->data + sib_pos, - dwarf_info_section->data_offset - dwarf_info.start); - } - f = t->type.ref; - i = 0; - while (f->next) { - f = f->next; - type = tcc_get_dwarf_info(s1, f); - tcc_debug_check_anon(s1, f, pos_type[i]); - write32le(dwarf_info_section->data + pos_type[i++], - type - dwarf_info.start); - } - tcc_free(pos_type); - } - else { - if (last_pos != -1) { - tcc_debug_check_anon(s1, e, last_pos); - write32le(dwarf_info_section->data + last_pos, - debug_type - dwarf_info.start); - } - break; - } - t = t->type.ref; - } - return retval; -} - -static void tcc_debug_finish (TCCState *s1, struct _debug_info *cur) -{ - while (cur) { - struct _debug_info *next = cur->next; - int i; - - if (s1->dwarf) { - - for (i = cur->n_sym - 1; i >= 0; i--) { - struct debug_sym *s = &cur->sym[i]; - - dwarf_data1(dwarf_info_section, - s->type == N_PSYM - ? DWARF_ABBREV_FORMAL_PARAMETER - : s->type == N_GSYM - ? DWARF_ABBREV_VARIABLE_EXTERNAL - : s->type == N_STSYM - ? DWARF_ABBREV_VARIABLE_STATIC - : DWARF_ABBREV_VARIABLE_LOCAL); - dwarf_strp(dwarf_info_section, s->str); - if (s->type == N_GSYM || s->type == N_STSYM) { - dwarf_uleb128(dwarf_info_section, s->file); - dwarf_uleb128(dwarf_info_section, s->line); - } - dwarf_data4(dwarf_info_section, s->info - dwarf_info.start); - if (s->type == N_GSYM || s->type == N_STSYM) { - /* global/static */ - if (s->type == N_GSYM) - dwarf_data1(dwarf_info_section, 1); - dwarf_data1(dwarf_info_section, PTR_SIZE + 1); - dwarf_data1(dwarf_info_section, DW_OP_addr); - if (s->type == N_STSYM) - dwarf_reloc(dwarf_info_section, section_sym, R_DATA_PTR); -#if PTR_SIZE == 4 - dwarf_data4(dwarf_info_section, s->value); -#else - dwarf_data8(dwarf_info_section, s->value); -#endif - } - else { - /* param/local */ - dwarf_data1(dwarf_info_section, dwarf_sleb128_size(s->value) + 1); - dwarf_data1(dwarf_info_section, DW_OP_fbreg); - dwarf_sleb128(dwarf_info_section, s->value); - } - tcc_free (s->str); - } - tcc_free (cur->sym); - dwarf_data1(dwarf_info_section, - cur->child ? DWARF_ABBREV_LEXICAL_BLOCK - : DWARF_ABBREV_LEXICAL_EMPTY_BLOCK); - dwarf_reloc(dwarf_info_section, section_sym, R_DATA_PTR); -#if PTR_SIZE == 4 - dwarf_data4(dwarf_info_section, func_ind + cur->start); - dwarf_data4(dwarf_info_section, cur->end - cur->start); -#else - dwarf_data8(dwarf_info_section, func_ind + cur->start); - dwarf_data8(dwarf_info_section, cur->end - cur->start); -#endif - tcc_debug_finish (s1, cur->child); - if (cur->child) - dwarf_data1(dwarf_info_section, 0); - } - else - { - for (i = 0; i < cur->n_sym; i++) { - struct debug_sym *s = &cur->sym[i]; - - if (s->sec) - put_stabs_r(s1, s->str, s->type, 0, 0, s->value, - s->sec, s->sym_index); - else - put_stabs(s1, s->str, s->type, 0, 0, s->value); - tcc_free (s->str); - } - tcc_free (cur->sym); - put_stabn(s1, N_LBRAC, 0, 0, cur->start); - tcc_debug_finish (s1, cur->child); - put_stabn(s1, N_RBRAC, 0, 0, cur->end); - } - tcc_free (cur); - cur = next; - } -} - -ST_FUNC void tcc_add_debug_info(TCCState *s1, int param, Sym *s, Sym *e) -{ - CString debug_str; - if (!s1->do_debug) - return; - cstr_new (&debug_str); - for (; s != e; s = s->prev) { - if (!s->v || (s->r & VT_VALMASK) != VT_LOCAL) - continue; - if (s1->dwarf) { - tcc_debug_stabs(s1, get_tok_str(s->v, NULL), - param ? N_PSYM : N_LSYM, s->c, NULL, 0, - tcc_get_dwarf_info(s1, s)); - } - else - { - cstr_reset (&debug_str); - cstr_printf (&debug_str, "%s:%s", get_tok_str(s->v, NULL), - param ? "p" : ""); - tcc_get_debug_info(s1, s, &debug_str); - tcc_debug_stabs(s1, debug_str.data, param ? N_PSYM : N_LSYM, - s->c, NULL, 0, 0); - } - } - cstr_free (&debug_str); -} - -/* put function symbol */ -ST_FUNC void tcc_debug_funcstart(TCCState *s1, Sym *sym) -{ - CString debug_str; - BufferedFile *f; - - if (!s1->do_debug) - return; - debug_info_root = NULL; - debug_info = NULL; - tcc_debug_stabn(s1, N_LBRAC, ind - func_ind); - f = put_new_file(s1); - if (!f) - return; - - if (s1->dwarf) { - tcc_debug_line(s1); - dwarf_info.func = sym; - dwarf_info.line = file->line_num; - if (s1->do_backtrace) { - int i, len; - - dwarf_line_op(s1, 0); // extended - dwarf_uleb128_op(s1, strlen(funcname) + 2); - dwarf_line_op(s1, DW_LNE_hi_user - 1); - len = strlen(funcname) + 1; - for (i = 0; i < len; i++) - dwarf_line_op(s1, funcname[i]); - } - } - else - { - cstr_new (&debug_str); - cstr_printf(&debug_str, "%s:%c", funcname, sym->type.t & VT_STATIC ? 'f' : 'F'); - tcc_get_debug_info(s1, sym->type.ref, &debug_str); - put_stabs_r(s1, debug_str.data, N_FUN, 0, f->line_num, 0, cur_text_section, sym->c); - cstr_free (&debug_str); - tcc_debug_line(s1); - } -} - -ST_FUNC void tcc_debug_prolog_epilog(TCCState *s1, int value) -{ - if (!s1->do_debug) - return; - if (s1->dwarf) { - dwarf_line_op(s1, value == 0 ? DW_LNS_set_prologue_end - : DW_LNS_set_epilogue_begin); - } -} - -/* put function size */ -ST_FUNC void tcc_debug_funcend(TCCState *s1, int size) -{ - /* lldb does not like function end and next function start at same pc */ - int min_instr_len; - - if (!s1->do_debug) - return; - min_instr_len = dwarf_line.last_pc == ind ? 0 : DWARF_MIN_INSTR_LEN; - ind -= min_instr_len; - tcc_debug_line(s1); - ind += min_instr_len; - tcc_debug_stabn(s1, N_RBRAC, size); - if (s1->dwarf) { - int func_sib = 0; - Sym *sym = dwarf_info.func; - int n_debug_info = tcc_get_dwarf_info(s1, sym->type.ref); - - dwarf_data1(dwarf_info_section, - sym->type.t & VT_STATIC ? DWARF_ABBREV_SUBPROGRAM_STATIC - : DWARF_ABBREV_SUBPROGRAM_EXTERNAL); - if ((sym->type.t & VT_STATIC) == 0) - dwarf_data1(dwarf_info_section, 1); - dwarf_strp(dwarf_info_section, funcname); - dwarf_uleb128(dwarf_info_section, dwarf_line.cur_file); - dwarf_uleb128(dwarf_info_section, dwarf_info.line); - tcc_debug_check_anon(s1, sym->type.ref, dwarf_info_section->data_offset); - dwarf_data4(dwarf_info_section, n_debug_info - dwarf_info.start); - dwarf_reloc(dwarf_info_section, section_sym, R_DATA_PTR); -#if PTR_SIZE == 4 - dwarf_data4(dwarf_info_section, func_ind); // low_pc - dwarf_data4(dwarf_info_section, size); // high_pc -#else - dwarf_data8(dwarf_info_section, func_ind); // low_pc - dwarf_data8(dwarf_info_section, size); // high_pc -#endif - func_sib = dwarf_info_section->data_offset; - dwarf_data4(dwarf_info_section, 0); // sibling - dwarf_data1(dwarf_info_section, 1); -#if defined(TCC_TARGET_I386) - dwarf_data1(dwarf_info_section, DW_OP_reg5); // ebp -#elif defined(TCC_TARGET_X86_64) - dwarf_data1(dwarf_info_section, DW_OP_reg6); // rbp -#elif defined TCC_TARGET_ARM - dwarf_data1(dwarf_info_section, DW_OP_reg13); // sp -#elif defined TCC_TARGET_ARM64 - dwarf_data1(dwarf_info_section, DW_OP_reg29); // reg 29 -#elif defined TCC_TARGET_RISCV64 - dwarf_data1(dwarf_info_section, DW_OP_reg8); // r8(s0) -#else - dwarf_data1(dwarf_info_section, DW_OP_call_frame_cfa); -#endif - tcc_debug_finish (s1, debug_info_root); - dwarf_data1(dwarf_info_section, 0); - write32le(dwarf_info_section->data + func_sib, - dwarf_info_section->data_offset - dwarf_info.start); - } - else - { - tcc_debug_finish (s1, debug_info_root); - } - debug_info_root = 0; -} - - -ST_FUNC void tcc_debug_extern_sym(TCCState *s1, Sym *sym, int sh_num, int sym_bind, int sym_type) -{ - if (!s1->do_debug) - return; - if (sym_type == STT_FUNC || sym->v >= SYM_FIRST_ANOM) - return; - if (s1->dwarf) { - int debug_type; - - debug_type = tcc_get_dwarf_info(s1, sym); - dwarf_data1(dwarf_info_section, - sym_bind == STB_GLOBAL - ? DWARF_ABBREV_VARIABLE_EXTERNAL - : DWARF_ABBREV_VARIABLE_STATIC); - dwarf_strp(dwarf_info_section, get_tok_str(sym->v, NULL)); - dwarf_uleb128(dwarf_info_section, dwarf_line.cur_file); - dwarf_uleb128(dwarf_info_section, file->line_num); - tcc_debug_check_anon(s1, sym, dwarf_info_section->data_offset); - dwarf_data4(dwarf_info_section, debug_type - dwarf_info.start); - if (sym_bind == STB_GLOBAL) - dwarf_data1(dwarf_info_section, 1); - dwarf_data1(dwarf_info_section, PTR_SIZE + 1); - dwarf_data1(dwarf_info_section, DW_OP_addr); - greloca(dwarf_info_section, sym, dwarf_info_section->data_offset, - R_DATA_PTR, 0); -#if PTR_SIZE == 4 - dwarf_data4(dwarf_info_section, 0); -#else - dwarf_data8(dwarf_info_section, 0); -#endif - } - else - { - Section *s = sh_num == SHN_COMMON ? common_section - : s1->sections[sh_num]; - CString str; - - cstr_new (&str); - cstr_printf (&str, "%s:%c", - get_tok_str(sym->v, NULL), - sym_bind == STB_GLOBAL ? 'G' : func_ind != -1 ? 'V' : 'S' - ); - tcc_get_debug_info(s1, sym, &str); - if (sym_bind == STB_GLOBAL) - tcc_debug_stabs(s1, str.data, N_GSYM, 0, NULL, 0, 0); - else - tcc_debug_stabs(s1, str.data, - (sym->type.t & VT_STATIC) && data_section == s - ? N_STSYM : N_LCSYM, 0, s, sym->c, 0); - cstr_free (&str); - } -} - -ST_FUNC void tcc_debug_typedef(TCCState *s1, Sym *sym) -{ - if (!s1->do_debug) - return; - if (s1->dwarf) { - int debug_type; - - debug_type = tcc_get_dwarf_info(s1, sym); - if (debug_type != -1) { - dwarf_data1(dwarf_info_section, DWARF_ABBREV_TYPEDEF); - dwarf_strp(dwarf_info_section, get_tok_str(sym->v & ~SYM_FIELD, NULL)); - dwarf_uleb128(dwarf_info_section, dwarf_line.cur_file); - dwarf_uleb128(dwarf_info_section, file->line_num); - tcc_debug_check_anon(s1, sym, dwarf_info_section->data_offset); - dwarf_data4(dwarf_info_section, debug_type - dwarf_info.start); - } - } - else - { - CString str; - cstr_new (&str); - cstr_printf (&str, "%s:t", - (sym->v & ~SYM_FIELD) >= SYM_FIRST_ANOM - ? "" : get_tok_str(sym->v & ~SYM_FIELD, NULL)); - tcc_get_debug_info(s1, sym, &str); - tcc_debug_stabs(s1, str.data, N_LSYM, 0, NULL, 0, 0); - cstr_free (&str); - } -} - -/* ------------------------------------------------------------------------- */ -/* for section layout see lib/tcov.c */ - -ST_FUNC void tcc_tcov_block_end(TCCState *s1, int line); - -ST_FUNC void tcc_tcov_block_begin(TCCState *s1) -{ - SValue sv; - void *ptr; - unsigned long last_offset = tcov_data.offset; - - tcc_tcov_block_end (tcc_state, 0); - if (s1->test_coverage == 0 || nocode_wanted) - return; - - if (tcov_data.last_file_name == 0 || - strcmp ((const char *)(tcov_section->data + tcov_data.last_file_name), - file->true_filename) != 0) { - char wd[1024]; - CString cstr; - - if (tcov_data.last_func_name) - section_ptr_add(tcov_section, 1); - if (tcov_data.last_file_name) - section_ptr_add(tcov_section, 1); - tcov_data.last_func_name = 0; - cstr_new (&cstr); - if (file->true_filename[0] == '/') { - tcov_data.last_file_name = tcov_section->data_offset; - cstr_printf (&cstr, "%s", file->true_filename); - } - else { - getcwd (wd, sizeof(wd)); - tcov_data.last_file_name = tcov_section->data_offset + strlen(wd) + 1; - cstr_printf (&cstr, "%s/%s", wd, file->true_filename); - } - ptr = section_ptr_add(tcov_section, cstr.size + 1); - strcpy((char *)ptr, cstr.data); -#ifdef _WIN32 - normalize_slashes((char *)ptr); -#endif - cstr_free (&cstr); - } - if (tcov_data.last_func_name == 0 || - strcmp ((const char *)(tcov_section->data + tcov_data.last_func_name), - funcname) != 0) { - size_t len; - - if (tcov_data.last_func_name) - section_ptr_add(tcov_section, 1); - tcov_data.last_func_name = tcov_section->data_offset; - len = strlen (funcname); - ptr = section_ptr_add(tcov_section, len + 1); - strcpy((char *)ptr, funcname); - section_ptr_add(tcov_section, -tcov_section->data_offset & 7); - ptr = section_ptr_add(tcov_section, 8); - write64le (ptr, file->line_num); - } - if (ind == tcov_data.ind && tcov_data.line == file->line_num) - tcov_data.offset = last_offset; - else { - Sym label = {0}; - label.type.t = VT_LLONG | VT_STATIC; - - ptr = section_ptr_add(tcov_section, 16); - tcov_data.line = file->line_num; - write64le (ptr, (tcov_data.line << 8) | 0xff); - put_extern_sym(&label, tcov_section, - ((unsigned char *)ptr - tcov_section->data) + 8, 0); - sv.type = label.type; - sv.r = VT_SYM | VT_LVAL | VT_CONST; - sv.r2 = VT_CONST; - sv.c.i = 0; - sv.sym = &label; -#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 || \ - defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64 || \ - defined TCC_TARGET_RISCV64 - gen_increment_tcov (&sv); -#else - vpushv(&sv); - inc(0, TOK_INC); - vpop(); -#endif - tcov_data.offset = (unsigned char *)ptr - tcov_section->data; - tcov_data.ind = ind; - } -} - -ST_FUNC void tcc_tcov_block_end(TCCState *s1, int line) -{ - if (s1->test_coverage == 0) - return; - if (line == -1) - line = tcov_data.line; - if (tcov_data.offset) { - void *ptr = tcov_section->data + tcov_data.offset; - unsigned long long nline = line ? line : file->line_num; - - write64le (ptr, (read64le (ptr) & 0xfffffffffull) | (nline << 36)); - tcov_data.offset = 0; - } -} - -ST_FUNC void tcc_tcov_check_line(TCCState *s1, int start) -{ - if (s1->test_coverage == 0) - return; - if (tcov_data.line != file->line_num) { - if ((tcov_data.line + 1) != file->line_num) { - tcc_tcov_block_end (s1, -1); - if (start) - tcc_tcov_block_begin (s1); - } - else - tcov_data.line = file->line_num; - } -} - -ST_FUNC void tcc_tcov_start(TCCState *s1) -{ - if (s1->test_coverage == 0) - return; - if (!s1->dState) - s1->dState = tcc_mallocz(sizeof *s1->dState); - memset (&tcov_data, 0, sizeof (tcov_data)); - if (tcov_section == NULL) { - tcov_section = new_section(tcc_state, ".tcov", SHT_PROGBITS, - SHF_ALLOC | SHF_WRITE); - section_ptr_add(tcov_section, 4); // pointer to executable name - } -} - -ST_FUNC void tcc_tcov_end(TCCState *s1) -{ - if (s1->test_coverage == 0) - return; - if (tcov_data.last_func_name) - section_ptr_add(tcov_section, 1); - if (tcov_data.last_file_name) - section_ptr_add(tcov_section, 1); -} - -ST_FUNC void tcc_tcov_reset_ind(TCCState *s1) -{ - tcov_data.ind = 0; -} - -/* ------------------------------------------------------------------------- */ -#undef last_line_num -#undef new_file -#undef section_sym -#undef debug_next_type -#undef debug_hash -#undef n_debug_hash -#undef debug_anon_hash -#undef n_debug_anon_hash -#undef debug_info -#undef debug_info_root -#undef dwarf_sym -#undef dwarf_line -#undef dwarf_info -#undef tcov_data diff --git a/tinycc/tccelf.c b/tinycc/tccelf.c deleted file mode 100644 index b46ad4c..0000000 --- a/tinycc/tccelf.c +++ /dev/null @@ -1,3936 +0,0 @@ -/* - * ELF file handling for TCC - * - * 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 - */ - -#include "tcc.h" - -/* Define this to get some debug output during relocation processing. */ -#undef DEBUG_RELOC - -/********************************************************/ -/* global variables */ - -/* elf version information */ -struct sym_version { - char *lib; - char *version; - int out_index; - int prev_same_lib; -}; - -#define nb_sym_versions s1->nb_sym_versions -#define sym_versions s1->sym_versions -#define nb_sym_to_version s1->nb_sym_to_version -#define sym_to_version s1->sym_to_version -#define dt_verneednum s1->dt_verneednum -#define versym_section s1->versym_section -#define verneed_section s1->verneed_section - -/* special flag to indicate that the section should not be linked to the other ones */ -#define SHF_PRIVATE 0x80000000 -/* section is dynsymtab_section */ -#define SHF_DYNSYM 0x40000000 - -#ifdef TCC_TARGET_PE -static const int shf_RELRO = SHF_ALLOC; -static const char rdata[] = ".rdata"; -#else -static const int shf_RELRO = SHF_ALLOC | SHF_WRITE; -static const char rdata[] = ".data.ro"; -#endif - -/* ------------------------------------------------------------------------- */ - -ST_FUNC void tccelf_new(TCCState *s) -{ - TCCState *s1 = s; - /* no section zero */ - dynarray_add(&s->sections, &s->nb_sections, NULL); - - /* create standard sections */ - text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); - data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); - /* create ro data section (make ro after relocation done with GNU_RELRO) */ - rodata_section = new_section(s, rdata, SHT_PROGBITS, shf_RELRO); - bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE); - common_section = new_section(s, ".common", SHT_NOBITS, SHF_PRIVATE); - common_section->sh_num = SHN_COMMON; - - /* symbols are always generated for linking stage */ - symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0, - ".strtab", - ".hashtab", SHF_PRIVATE); - s->symtab = symtab_section; - - /* private symbol table for dynamic symbols */ - s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE|SHF_DYNSYM, - ".dynstrtab", - ".dynhashtab", SHF_PRIVATE); - get_sym_attr(s, 0, 1); -} - -#ifdef CONFIG_TCC_BCHECK -ST_FUNC void tccelf_bounds_new(TCCState *s) -{ - TCCState *s1 = s; - /* create bounds sections (make ro after relocation done with GNU_RELRO) */ - bounds_section = new_section(s, ".bounds", SHT_PROGBITS, shf_RELRO); - lbounds_section = new_section(s, ".lbounds", SHT_PROGBITS, shf_RELRO); -} -#endif - -static void free_section(Section *s) -{ - tcc_free(s->data); -} - -ST_FUNC void tccelf_delete(TCCState *s1) -{ - int i; - -#ifndef ELF_OBJ_ONLY - /* free symbol versions */ - for (i = 0; i < nb_sym_versions; i++) { - tcc_free(sym_versions[i].version); - tcc_free(sym_versions[i].lib); - } - tcc_free(sym_versions); - tcc_free(sym_to_version); -#endif - - /* free all sections */ - for(i = 1; i < s1->nb_sections; i++) - free_section(s1->sections[i]); - dynarray_reset(&s1->sections, &s1->nb_sections); - - for(i = 0; i < s1->nb_priv_sections; i++) - free_section(s1->priv_sections[i]); - dynarray_reset(&s1->priv_sections, &s1->nb_priv_sections); - - /* free any loaded DLLs */ -#ifdef TCC_IS_NATIVE - for ( i = 0; i < s1->nb_loaded_dlls; i++) { - DLLReference *ref = s1->loaded_dlls[i]; - if ( ref->handle ) -# ifdef _WIN32 - FreeLibrary((HMODULE)ref->handle); -# else - dlclose(ref->handle); -# endif - } -#endif - /* free loaded dlls array */ - dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls); - tcc_free(s1->sym_attrs); - - symtab_section = NULL; /* for tccrun.c:rt_printline() */ -} - -/* save section data state */ -ST_FUNC void tccelf_begin_file(TCCState *s1) -{ - Section *s; int i; - for (i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - s->sh_offset = s->data_offset; - } - /* disable symbol hashing during compilation */ - s = s1->symtab, s->reloc = s->hash, s->hash = NULL; -#if defined TCC_TARGET_X86_64 && defined TCC_TARGET_PE - s1->uw_sym = 0; -#endif -} - -/* At the end of compilation, convert any UNDEF syms to global, and merge - with previously existing symbols */ -ST_FUNC void tccelf_end_file(TCCState *s1) -{ - Section *s = s1->symtab; - int first_sym, nb_syms, *tr, i; - - first_sym = s->sh_offset / sizeof (ElfSym); - nb_syms = s->data_offset / sizeof (ElfSym) - first_sym; - s->data_offset = s->sh_offset; - s->link->data_offset = s->link->sh_offset; - s->hash = s->reloc, s->reloc = NULL; - tr = tcc_mallocz(nb_syms * sizeof *tr); - - for (i = 0; i < nb_syms; ++i) { - ElfSym *sym = (ElfSym*)s->data + first_sym + i; - if (sym->st_shndx == SHN_UNDEF - && ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) - sym->st_info = ELFW(ST_INFO)(STB_GLOBAL, ELFW(ST_TYPE)(sym->st_info)); - tr[i] = set_elf_sym(s, sym->st_value, sym->st_size, sym->st_info, - sym->st_other, sym->st_shndx, (char*)s->link->data + sym->st_name); - } - /* now update relocations */ - for (i = 1; i < s1->nb_sections; i++) { - Section *sr = s1->sections[i]; - if (sr->sh_type == SHT_RELX && sr->link == s) { - ElfW_Rel *rel = (ElfW_Rel*)(sr->data + sr->sh_offset); - ElfW_Rel *rel_end = (ElfW_Rel*)(sr->data + sr->data_offset); - for (; rel < rel_end; ++rel) { - int n = ELFW(R_SYM)(rel->r_info) - first_sym; - if (n < 0) /* zero sym_index in reloc (can happen with asm) */ - continue; - rel->r_info = ELFW(R_INFO)(tr[n], ELFW(R_TYPE)(rel->r_info)); - } - } - } - tcc_free(tr); - - /* record text/data/bss output for -bench info */ - for (i = 0; i < 4; ++i) { - s = s1->sections[i + 1]; - s1->total_output[i] += s->data_offset - s->sh_offset; - } -} - -ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags) -{ - Section *sec; - - sec = tcc_mallocz(sizeof(Section) + strlen(name)); - sec->s1 = s1; - strcpy(sec->name, name); - sec->sh_type = sh_type; - sec->sh_flags = sh_flags; - switch(sh_type) { - case SHT_GNU_versym: - sec->sh_addralign = 2; - break; - case SHT_HASH: - case SHT_GNU_HASH: - case SHT_REL: - case SHT_RELA: - case SHT_DYNSYM: - case SHT_SYMTAB: - case SHT_DYNAMIC: - case SHT_GNU_verneed: - case SHT_GNU_verdef: - sec->sh_addralign = PTR_SIZE; - break; - case SHT_STRTAB: - sec->sh_addralign = 1; - break; - default: - sec->sh_addralign = PTR_SIZE; /* gcc/pcc default alignment */ - break; - } - - if (sh_flags & SHF_PRIVATE) { - dynarray_add(&s1->priv_sections, &s1->nb_priv_sections, sec); - } else { - sec->sh_num = s1->nb_sections; - dynarray_add(&s1->sections, &s1->nb_sections, sec); - } - - return sec; -} - -ST_FUNC Section *new_symtab(TCCState *s1, - const char *symtab_name, int sh_type, int sh_flags, - const char *strtab_name, - const char *hash_name, int hash_sh_flags) -{ - Section *symtab, *strtab, *hash; - int *ptr, nb_buckets; - - symtab = new_section(s1, symtab_name, sh_type, sh_flags); - symtab->sh_entsize = sizeof(ElfW(Sym)); - strtab = new_section(s1, strtab_name, SHT_STRTAB, sh_flags); - put_elf_str(strtab, ""); - symtab->link = strtab; - put_elf_sym(symtab, 0, 0, 0, 0, 0, NULL); - - nb_buckets = 1; - - hash = new_section(s1, hash_name, SHT_HASH, hash_sh_flags); - hash->sh_entsize = sizeof(int); - symtab->hash = hash; - hash->link = symtab; - - ptr = section_ptr_add(hash, (2 + nb_buckets + 1) * sizeof(int)); - ptr[0] = nb_buckets; - ptr[1] = 1; - memset(ptr + 2, 0, (nb_buckets + 1) * sizeof(int)); - return symtab; -} - -/* realloc section and set its content to zero */ -ST_FUNC void section_realloc(Section *sec, unsigned long new_size) -{ - unsigned long size; - unsigned char *data; - - size = sec->data_allocated; - if (size == 0) - size = 1; - while (size < new_size) - size = size * 2; - data = tcc_realloc(sec->data, size); - memset(data + sec->data_allocated, 0, size - sec->data_allocated); - sec->data = data; - sec->data_allocated = size; -} - -/* reserve at least 'size' bytes aligned per 'align' in section - 'sec' from current offset, and return the aligned offset */ -ST_FUNC size_t section_add(Section *sec, addr_t size, int align) -{ - size_t offset, offset1; - - offset = (sec->data_offset + align - 1) & -align; - offset1 = offset + size; - if (sec->sh_type != SHT_NOBITS && offset1 > sec->data_allocated) - section_realloc(sec, offset1); - sec->data_offset = offset1; - if (align > sec->sh_addralign) - sec->sh_addralign = align; - return offset; -} - -/* reserve at least 'size' bytes in section 'sec' from - sec->data_offset. */ -ST_FUNC void *section_ptr_add(Section *sec, addr_t size) -{ - size_t offset = section_add(sec, size, 1); - return sec->data + offset; -} - -#ifndef ELF_OBJ_ONLY -/* reserve at least 'size' bytes from section start */ -static void section_reserve(Section *sec, unsigned long size) -{ - if (size > sec->data_allocated) - section_realloc(sec, size); - if (size > sec->data_offset) - sec->data_offset = size; -} -#endif - -static Section *have_section(TCCState *s1, const char *name) -{ - Section *sec; - int i; - for(i = 1; i < s1->nb_sections; i++) { - sec = s1->sections[i]; - if (!strcmp(name, sec->name)) - return sec; - } - return NULL; -} - -/* return a reference to a section, and create it if it does not - exists */ -ST_FUNC Section *find_section(TCCState *s1, const char *name) -{ - Section *sec = have_section(s1, name); - if (sec) - return sec; - /* sections are created as PROGBITS */ - return new_section(s1, name, SHT_PROGBITS, SHF_ALLOC); -} - -/* ------------------------------------------------------------------------- */ - -ST_FUNC int put_elf_str(Section *s, const char *sym) -{ - int offset, len; - char *ptr; - - len = strlen(sym) + 1; - offset = s->data_offset; - ptr = section_ptr_add(s, len); - memmove(ptr, sym, len); - return offset; -} - -/* elf symbol hashing function */ -static ElfW(Word) elf_hash(const unsigned char *name) -{ - ElfW(Word) h = 0, g; - - while (*name) { - h = (h << 4) + *name++; - g = h & 0xf0000000; - if (g) - h ^= g >> 24; - h &= ~g; - } - return h; -} - -/* rebuild hash table of section s */ -/* NOTE: we do factorize the hash table code to go faster */ -static void rebuild_hash(Section *s, unsigned int nb_buckets) -{ - ElfW(Sym) *sym; - int *ptr, *hash, nb_syms, sym_index, h; - unsigned char *strtab; - - strtab = s->link->data; - nb_syms = s->data_offset / sizeof(ElfW(Sym)); - - if (!nb_buckets) - nb_buckets = ((int*)s->hash->data)[0]; - - s->hash->data_offset = 0; - ptr = section_ptr_add(s->hash, (2 + nb_buckets + nb_syms) * sizeof(int)); - ptr[0] = nb_buckets; - ptr[1] = nb_syms; - ptr += 2; - hash = ptr; - memset(hash, 0, (nb_buckets + 1) * sizeof(int)); - ptr += nb_buckets + 1; - - sym = (ElfW(Sym) *)s->data + 1; - for(sym_index = 1; sym_index < nb_syms; sym_index++) { - if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { - h = elf_hash(strtab + sym->st_name) % nb_buckets; - *ptr = hash[h]; - hash[h] = sym_index; - } else { - *ptr = 0; - } - ptr++; - sym++; - } -} - -/* return the symbol number */ -ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size, - int info, int other, int shndx, const char *name) -{ - int name_offset, sym_index; - int nbuckets, h; - ElfW(Sym) *sym; - Section *hs; - - sym = section_ptr_add(s, sizeof(ElfW(Sym))); - if (name && name[0]) - name_offset = put_elf_str(s->link, name); - else - name_offset = 0; - /* XXX: endianness */ - sym->st_name = name_offset; - sym->st_value = value; - sym->st_size = size; - sym->st_info = info; - sym->st_other = other; - sym->st_shndx = shndx; - sym_index = sym - (ElfW(Sym) *)s->data; - hs = s->hash; - if (hs) { - int *ptr, *base; - ptr = section_ptr_add(hs, sizeof(int)); - base = (int *)hs->data; - /* only add global or weak symbols. */ - if (ELFW(ST_BIND)(info) != STB_LOCAL) { - /* add another hashing entry */ - nbuckets = base[0]; - h = elf_hash((unsigned char *)s->link->data + name_offset) % nbuckets; - *ptr = base[2 + h]; - base[2 + h] = sym_index; - base[1]++; - /* we resize the hash table */ - hs->nb_hashed_syms++; - if (hs->nb_hashed_syms > 2 * nbuckets) { - rebuild_hash(s, 2 * nbuckets); - } - } else { - *ptr = 0; - base[1]++; - } - } - return sym_index; -} - -ST_FUNC int find_elf_sym(Section *s, const char *name) -{ - ElfW(Sym) *sym; - Section *hs; - int nbuckets, sym_index, h; - const char *name1; - - hs = s->hash; - if (!hs) - return 0; - nbuckets = ((int *)hs->data)[0]; - h = elf_hash((unsigned char *) name) % nbuckets; - sym_index = ((int *)hs->data)[2 + h]; - while (sym_index != 0) { - sym = &((ElfW(Sym) *)s->data)[sym_index]; - name1 = (char *) s->link->data + sym->st_name; - if (!strcmp(name, name1)) - return sym_index; - sym_index = ((int *)hs->data)[2 + nbuckets + sym_index]; - } - return 0; -} - -/* return elf symbol value, signal error if 'err' is nonzero, decorate - name if FORC */ -ST_FUNC addr_t get_sym_addr(TCCState *s1, const char *name, int err, int forc) -{ - int sym_index; - ElfW(Sym) *sym; - char buf[256]; - if (forc && s1->leading_underscore -#ifdef TCC_TARGET_PE - /* win32-32bit stdcall symbols always have _ already */ - && !strchr(name, '@') -#endif - ) { - buf[0] = '_'; - pstrcpy(buf + 1, sizeof(buf) - 1, name); - name = buf; - } - sym_index = find_elf_sym(s1->symtab, name); - sym = &((ElfW(Sym) *)s1->symtab->data)[sym_index]; - if (!sym_index || sym->st_shndx == SHN_UNDEF) { - if (err) - tcc_error_noabort("%s not defined", name); - return (addr_t)-1; - } - return sym->st_value; -} - -/* return elf symbol value */ -LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name) -{ - addr_t addr = get_sym_addr(s, name, 0, 1); - return addr == -1 ? NULL : (void*)(uintptr_t)addr; -} - -/* list elf symbol names and values */ -ST_FUNC void list_elf_symbols(TCCState *s, void *ctx, - void (*symbol_cb)(void *ctx, const char *name, const void *val)) -{ - ElfW(Sym) *sym; - Section *symtab; - int sym_index, end_sym; - const char *name; - unsigned char sym_vis, sym_bind; - - symtab = s->symtab; - end_sym = symtab->data_offset / sizeof (ElfSym); - for (sym_index = 0; sym_index < end_sym; ++sym_index) { - sym = &((ElfW(Sym) *)symtab->data)[sym_index]; - if (sym->st_value) { - name = (char *) symtab->link->data + sym->st_name; - sym_bind = ELFW(ST_BIND)(sym->st_info); - sym_vis = ELFW(ST_VISIBILITY)(sym->st_other); - if (sym_bind == STB_GLOBAL && sym_vis == STV_DEFAULT) - symbol_cb(ctx, name, (void*)(uintptr_t)sym->st_value); - } - } -} - -/* list elf symbol names and values */ -LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx, - void (*symbol_cb)(void *ctx, const char *name, const void *val)) -{ - list_elf_symbols(s, ctx, symbol_cb); -} - -#ifndef ELF_OBJ_ONLY -static void -version_add (TCCState *s1) -{ - int i; - ElfW(Sym) *sym; - ElfW(Verneed) *vn = NULL; - Section *symtab; - int sym_index, end_sym, nb_versions = 2, nb_entries = 0; - ElfW(Half) *versym; - const char *name; - - if (0 == nb_sym_versions) - return; - versym_section = new_section(s1, ".gnu.version", SHT_GNU_versym, SHF_ALLOC); - versym_section->sh_entsize = sizeof(ElfW(Half)); - versym_section->link = s1->dynsym; - - /* add needed symbols */ - symtab = s1->dynsym; - end_sym = symtab->data_offset / sizeof (ElfSym); - versym = section_ptr_add(versym_section, end_sym * sizeof(ElfW(Half))); - for (sym_index = 1; sym_index < end_sym; ++sym_index) { - int dllindex, verndx; - sym = &((ElfW(Sym) *)symtab->data)[sym_index]; - if (sym->st_shndx != SHN_UNDEF) - continue; /* defined symbol doesn't need library version */ - name = (char *) symtab->link->data + sym->st_name; - dllindex = find_elf_sym(s1->dynsymtab_section, name); - verndx = (dllindex && dllindex < nb_sym_to_version) - ? sym_to_version[dllindex] : -1; - if (verndx >= 0) { - if (!sym_versions[verndx].out_index) - sym_versions[verndx].out_index = nb_versions++; - versym[sym_index] = sym_versions[verndx].out_index; - } - } - /* generate verneed section, but not when it will be empty. Some - dynamic linkers look at their contents even when DTVERNEEDNUM and - section size is zero. */ - if (nb_versions > 2) { - verneed_section = new_section(s1, ".gnu.version_r", - SHT_GNU_verneed, SHF_ALLOC); - verneed_section->link = s1->dynsym->link; - for (i = nb_sym_versions; i-- > 0;) { - struct sym_version *sv = &sym_versions[i]; - int n_same_libs = 0, prev; - size_t vnofs; - ElfW(Vernaux) *vna = 0; - if (sv->out_index < 1) - continue; - - /* make sure that a DT_NEEDED tag is put */ - /* abitest-tcc fails on older i386-linux with "ld-linux.so.2" DT_NEEDED - ret_int_test... Inconsistency detected by ld.so: dl-minimal.c: 148: - realloc: Assertion `ptr == alloc_last_block' failed! */ - if (strcmp(sv->lib, "ld-linux.so.2")) - tcc_add_dllref(s1, sv->lib, 0); - - vnofs = section_add(verneed_section, sizeof(*vn), 1); - vn = (ElfW(Verneed)*)(verneed_section->data + vnofs); - vn->vn_version = 1; - vn->vn_file = put_elf_str(verneed_section->link, sv->lib); - vn->vn_aux = sizeof (*vn); - do { - prev = sv->prev_same_lib; - if (sv->out_index > 0) { - vna = section_ptr_add(verneed_section, sizeof(*vna)); - vna->vna_hash = elf_hash ((const unsigned char *)sv->version); - vna->vna_flags = 0; - vna->vna_other = sv->out_index; - sv->out_index = -2; - vna->vna_name = put_elf_str(verneed_section->link, sv->version); - vna->vna_next = sizeof (*vna); - n_same_libs++; - } - if (prev >= 0) - sv = &sym_versions[prev]; - } while(prev >= 0); - vna->vna_next = 0; - vn = (ElfW(Verneed)*)(verneed_section->data + vnofs); - vn->vn_cnt = n_same_libs; - vn->vn_next = sizeof(*vn) + n_same_libs * sizeof(*vna); - nb_entries++; - } - if (vn) - vn->vn_next = 0; - verneed_section->sh_info = nb_entries; - } - dt_verneednum = nb_entries; -} -#endif /* ndef ELF_OBJ_ONLY */ - -/* add an elf symbol : check if it is already defined and patch - it. Return symbol index. NOTE that sh_num can be SHN_UNDEF. */ -ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size, - int info, int other, int shndx, const char *name) -{ - TCCState *s1 = s->s1; - ElfW(Sym) *esym; - int sym_bind, sym_index, sym_type, esym_bind; - unsigned char sym_vis, esym_vis, new_vis; - - sym_bind = ELFW(ST_BIND)(info); - sym_type = ELFW(ST_TYPE)(info); - sym_vis = ELFW(ST_VISIBILITY)(other); - - if (sym_bind != STB_LOCAL) { - /* we search global or weak symbols */ - sym_index = find_elf_sym(s, name); - if (!sym_index) - goto do_def; - esym = &((ElfW(Sym) *)s->data)[sym_index]; - if (esym->st_value == value && esym->st_size == size && esym->st_info == info - && esym->st_other == other && esym->st_shndx == shndx) - return sym_index; - if (esym->st_shndx != SHN_UNDEF) { - esym_bind = ELFW(ST_BIND)(esym->st_info); - /* propagate the most constraining visibility */ - /* STV_DEFAULT(0)<STV_PROTECTED(3)<STV_HIDDEN(2)<STV_INTERNAL(1) */ - esym_vis = ELFW(ST_VISIBILITY)(esym->st_other); - if (esym_vis == STV_DEFAULT) { - new_vis = sym_vis; - } else if (sym_vis == STV_DEFAULT) { - new_vis = esym_vis; - } else { - new_vis = (esym_vis < sym_vis) ? esym_vis : sym_vis; - } - esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) - | new_vis; - if (shndx == SHN_UNDEF) { - /* ignore adding of undefined symbol if the - corresponding symbol is already defined */ - } else if (sym_bind == STB_GLOBAL && esym_bind == STB_WEAK) { - /* global overrides weak, so patch */ - goto do_patch; - } else if (sym_bind == STB_WEAK && esym_bind == STB_GLOBAL) { - /* weak is ignored if already global */ - } else if (sym_bind == STB_WEAK && esym_bind == STB_WEAK) { - /* keep first-found weak definition, ignore subsequents */ - } else if (sym_vis == STV_HIDDEN || sym_vis == STV_INTERNAL) { - /* ignore hidden symbols after */ - } else if ((esym->st_shndx == SHN_COMMON - || esym->st_shndx == bss_section->sh_num) - && (shndx < SHN_LORESERVE - && shndx != bss_section->sh_num)) { - /* data symbol gets precedence over common/bss */ - goto do_patch; - } else if (shndx == SHN_COMMON || shndx == bss_section->sh_num) { - /* data symbol keeps precedence over common/bss */ - } else if (s->sh_flags & SHF_DYNSYM) { - /* we accept that two DLL define the same symbol */ - } else if (esym->st_other & ST_ASM_SET) { - /* If the existing symbol came from an asm .set - we can override. */ - goto do_patch; - } else { -#if 0 - printf("new_bind=%x new_shndx=%x new_vis=%x old_bind=%x old_shndx=%x old_vis=%x\n", - sym_bind, shndx, new_vis, esym_bind, esym->st_shndx, esym_vis); -#endif - tcc_error_noabort("'%s' defined twice", name); - } - } else { - esym->st_other = other; - do_patch: - esym->st_info = ELFW(ST_INFO)(sym_bind, sym_type); - esym->st_shndx = shndx; - s1->new_undef_sym = 1; - esym->st_value = value; - esym->st_size = size; - } - } else { - do_def: - sym_index = put_elf_sym(s, value, size, - ELFW(ST_INFO)(sym_bind, sym_type), other, - shndx, name); - } - return sym_index; -} - -/* put relocation */ -ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset, - int type, int symbol, addr_t addend) -{ - TCCState *s1 = s->s1; - char buf[256]; - Section *sr; - ElfW_Rel *rel; - - sr = s->reloc; - if (!sr) { - /* if no relocation section, create it */ - snprintf(buf, sizeof(buf), REL_SECTION_FMT, s->name); - /* if the symtab is allocated, then we consider the relocation - are also */ - sr = new_section(s->s1, buf, SHT_RELX, symtab->sh_flags); - sr->sh_entsize = sizeof(ElfW_Rel); - sr->link = symtab; - sr->sh_info = s->sh_num; - s->reloc = sr; - } - rel = section_ptr_add(sr, sizeof(ElfW_Rel)); - rel->r_offset = offset; - rel->r_info = ELFW(R_INFO)(symbol, type); -#if SHT_RELX == SHT_RELA - rel->r_addend = addend; -#endif - if (SHT_RELX != SHT_RELA && addend) - tcc_error_noabort("non-zero addend on REL architecture"); -} - -ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, - int type, int symbol) -{ - put_elf_reloca(symtab, s, offset, type, symbol, 0); -} - -ST_FUNC struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc) -{ - int n; - struct sym_attr *tab; - - if (index >= s1->nb_sym_attrs) { - if (!alloc) - return s1->sym_attrs; - /* find immediately bigger power of 2 and reallocate array */ - n = 1; - while (index >= n) - n *= 2; - tab = tcc_realloc(s1->sym_attrs, n * sizeof(*s1->sym_attrs)); - s1->sym_attrs = tab; - memset(s1->sym_attrs + s1->nb_sym_attrs, 0, - (n - s1->nb_sym_attrs) * sizeof(*s1->sym_attrs)); - s1->nb_sym_attrs = n; - } - return &s1->sym_attrs[index]; -} - -static void modify_reloctions_old_to_new(TCCState *s1, Section *s, int *old_to_new_syms) -{ - int i, type, sym_index; - Section *sr; - ElfW_Rel *rel; - - for(i = 1; i < s1->nb_sections; i++) { - sr = s1->sections[i]; - if (sr->sh_type == SHT_RELX && sr->link == s) { - for_each_elem(sr, 0, rel, ElfW_Rel) { - sym_index = ELFW(R_SYM)(rel->r_info); - type = ELFW(R_TYPE)(rel->r_info); - sym_index = old_to_new_syms[sym_index]; - rel->r_info = ELFW(R_INFO)(sym_index, type); - } - } - } -} - -/* In an ELF file symbol table, the local symbols must appear below - the global and weak ones. Since TCC cannot sort it while generating - the code, we must do it after. All the relocation tables are also - modified to take into account the symbol table sorting */ -static void sort_syms(TCCState *s1, Section *s) -{ - int *old_to_new_syms; - ElfW(Sym) *new_syms; - int nb_syms, i; - ElfW(Sym) *p, *q; - - nb_syms = s->data_offset / sizeof(ElfW(Sym)); - new_syms = tcc_malloc(nb_syms * sizeof(ElfW(Sym))); - old_to_new_syms = tcc_malloc(nb_syms * sizeof(int)); - - /* first pass for local symbols */ - p = (ElfW(Sym) *)s->data; - q = new_syms; - for(i = 0; i < nb_syms; i++) { - if (ELFW(ST_BIND)(p->st_info) == STB_LOCAL) { - old_to_new_syms[i] = q - new_syms; - *q++ = *p; - } - p++; - } - /* save the number of local symbols in section header */ - if( s->sh_size ) /* this 'if' makes IDA happy */ - s->sh_info = q - new_syms; - - /* then second pass for non local symbols */ - p = (ElfW(Sym) *)s->data; - for(i = 0; i < nb_syms; i++) { - if (ELFW(ST_BIND)(p->st_info) != STB_LOCAL) { - old_to_new_syms[i] = q - new_syms; - *q++ = *p; - } - p++; - } - - /* we copy the new symbols to the old */ - memcpy(s->data, new_syms, nb_syms * sizeof(ElfW(Sym))); - tcc_free(new_syms); - - modify_reloctions_old_to_new(s1, s, old_to_new_syms); - - tcc_free(old_to_new_syms); -} - -#ifndef ELF_OBJ_ONLY -/* See: https://flapenguin.me/elf-dt-gnu-hash */ -#define ELFCLASS_BITS (PTR_SIZE * 8) - -static Section *create_gnu_hash(TCCState *s1) -{ - int nb_syms, i, ndef, nbuckets, symoffset, bloom_size, bloom_shift; - ElfW(Sym) *p; - Section *gnu_hash; - Section *dynsym = s1->dynsym; - Elf32_Word *ptr; - - gnu_hash = new_section(s1, ".gnu.hash", SHT_GNU_HASH, SHF_ALLOC); - gnu_hash->link = dynsym->hash->link; - - nb_syms = dynsym->data_offset / sizeof(ElfW(Sym)); - - /* count def symbols */ - ndef = 0; - p = (ElfW(Sym) *)dynsym->data; - for(i = 0; i < nb_syms; i++, p++) - ndef += p->st_shndx != SHN_UNDEF; - - /* calculate gnu hash sizes and fill header */ - nbuckets = ndef / 4 + 1; - symoffset = nb_syms - ndef; - bloom_shift = PTR_SIZE == 8 ? 6 : 5; - bloom_size = 1; /* must be power of two */ - while (ndef >= bloom_size * (1 << (bloom_shift - 3))) - bloom_size *= 2; - ptr = section_ptr_add(gnu_hash, 4 * 4 + - PTR_SIZE * bloom_size + - nbuckets * 4 + - ndef * 4); - ptr[0] = nbuckets; - ptr[1] = symoffset; - ptr[2] = bloom_size; - ptr[3] = bloom_shift; - return gnu_hash; -} - -static Elf32_Word elf_gnu_hash (const unsigned char *name) -{ - Elf32_Word h = 5381; - unsigned char c; - - while ((c = *name++)) - h = h * 33 + c; - return h; -} - -static void update_gnu_hash(TCCState *s1, Section *gnu_hash) -{ - int *old_to_new_syms; - ElfW(Sym) *new_syms; - int nb_syms, i, nbuckets, bloom_size, bloom_shift; - ElfW(Sym) *p, *q; - Section *vs; - Section *dynsym = s1->dynsym; - Elf32_Word *ptr, *buckets, *chain, *hash; - unsigned int *nextbuck; - addr_t *bloom; - unsigned char *strtab; - struct { int first, last; } *buck; - - strtab = dynsym->link->data; - nb_syms = dynsym->data_offset / sizeof(ElfW(Sym)); - new_syms = tcc_malloc(nb_syms * sizeof(ElfW(Sym))); - old_to_new_syms = tcc_malloc(nb_syms * sizeof(int)); - hash = tcc_malloc(nb_syms * sizeof(Elf32_Word)); - nextbuck = tcc_malloc(nb_syms * sizeof(int)); - - /* calculate hashes and copy undefs */ - p = (ElfW(Sym) *)dynsym->data; - q = new_syms; - for(i = 0; i < nb_syms; i++, p++) { - if (p->st_shndx == SHN_UNDEF) { - old_to_new_syms[i] = q - new_syms; - *q++ = *p; - } - else - hash[i] = elf_gnu_hash(strtab + p->st_name); - } - - ptr = (Elf32_Word *) gnu_hash->data; - nbuckets = ptr[0]; - bloom_size = ptr[2]; - bloom_shift = ptr[3]; - bloom = (addr_t *) (void *) &ptr[4]; - buckets = (Elf32_Word*) (void *) &bloom[bloom_size]; - chain = &buckets[nbuckets]; - buck = tcc_malloc(nbuckets * sizeof(*buck)); - - if (gnu_hash->data_offset != 4 * 4 + - PTR_SIZE * bloom_size + - nbuckets * 4 + - (nb_syms - (q - new_syms)) * 4) - tcc_error_noabort ("gnu_hash size incorrect"); - - /* find buckets */ - for(i = 0; i < nbuckets; i++) - buck[i].first = -1; - - p = (ElfW(Sym) *)dynsym->data; - for(i = 0; i < nb_syms; i++, p++) - if (p->st_shndx != SHN_UNDEF) { - int bucket = hash[i] % nbuckets; - - if (buck[bucket].first == -1) - buck[bucket].first = buck[bucket].last = i; - else { - nextbuck[buck[bucket].last] = i; - buck[bucket].last = i; - } - } - - /* fill buckets/chains/bloom and sort symbols */ - p = (ElfW(Sym) *)dynsym->data; - for(i = 0; i < nbuckets; i++) { - int cur = buck[i].first; - - if (cur != -1) { - buckets[i] = q - new_syms; - for (;;) { - old_to_new_syms[cur] = q - new_syms; - *q++ = p[cur]; - *chain++ = hash[cur] & ~1; - bloom[(hash[cur] / ELFCLASS_BITS) % bloom_size] |= - (addr_t)1 << (hash[cur] % ELFCLASS_BITS) | - (addr_t)1 << ((hash[cur] >> bloom_shift) % ELFCLASS_BITS); - if (cur == buck[i].last) - break; - cur = nextbuck[cur]; - } - chain[-1] |= 1; - } - } - - memcpy(dynsym->data, new_syms, nb_syms * sizeof(ElfW(Sym))); - tcc_free(new_syms); - tcc_free(hash); - tcc_free(buck); - tcc_free(nextbuck); - - modify_reloctions_old_to_new(s1, dynsym, old_to_new_syms); - - /* modify the versions */ - vs = versym_section; - if (vs) { - ElfW(Half) *newver, *versym = (ElfW(Half) *)vs->data; - - if (1/*versym*/) { - newver = tcc_malloc(nb_syms * sizeof(*newver)); - for (i = 0; i < nb_syms; i++) - newver[old_to_new_syms[i]] = versym[i]; - memcpy(vs->data, newver, nb_syms * sizeof(*newver)); - tcc_free(newver); - } - } - - tcc_free(old_to_new_syms); - - /* rebuild hash */ - ptr = (Elf32_Word *) dynsym->hash->data; - rebuild_hash(dynsym, ptr[0]); -} -#endif /* ELF_OBJ_ONLY */ - -/* relocate symbol table, resolve undefined symbols if do_resolve is - true and output error if undefined symbol. */ -ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve) -{ - ElfW(Sym) *sym; - int sym_bind, sh_num; - const char *name; - - for_each_elem(symtab, 1, sym, ElfW(Sym)) { - sh_num = sym->st_shndx; - if (sh_num == SHN_UNDEF) { - if (do_resolve == 2) /* relocating dynsym */ - continue; - name = (char *) s1->symtab->link->data + sym->st_name; - /* Use ld.so to resolve symbol for us (for tcc -run) */ - if (do_resolve) { -#if defined TCC_IS_NATIVE && !defined TCC_TARGET_PE - /* dlsym() needs the undecorated name. */ - void *addr = dlsym(RTLD_DEFAULT, &name[s1->leading_underscore]); -#if TARGETOS_OpenBSD || TARGETOS_FreeBSD || TARGETOS_NetBSD || TARGETOS_ANDROID - if (addr == NULL) { - int i; - for (i = 0; i < s1->nb_loaded_dlls; i++) - if ((addr = dlsym(s1->loaded_dlls[i]->handle, name))) - break; - } -#endif - if (addr) { - sym->st_value = (addr_t) addr; -#ifdef DEBUG_RELOC - printf ("relocate_sym: %s -> 0x%lx\n", name, sym->st_value); -#endif - goto found; - } -#endif - /* if dynamic symbol exist, it will be used in relocate_section */ - } else if (s1->dynsym && find_elf_sym(s1->dynsym, name)) - goto found; - /* XXX: _fp_hw seems to be part of the ABI, so we ignore - it */ - if (!strcmp(name, "_fp_hw")) - goto found; - /* only weak symbols are accepted to be undefined. Their - value is zero */ - sym_bind = ELFW(ST_BIND)(sym->st_info); - if (sym_bind == STB_WEAK) - sym->st_value = 0; - else - tcc_error_noabort("undefined symbol '%s'", name); - - } else if (sh_num < SHN_LORESERVE) { - /* add section base */ - sym->st_value += s1->sections[sym->st_shndx]->sh_addr; - } - found: ; - } -} - -/* relocate a given section (CPU dependent) by applying the relocations - in the associated relocation section */ -static void relocate_section(TCCState *s1, Section *s, Section *sr) -{ - ElfW_Rel *rel; - ElfW(Sym) *sym; - int type, sym_index; - unsigned char *ptr; - addr_t tgt, addr; - int is_dwarf = s->sh_num >= s1->dwlo && s->sh_num < s1->dwhi; - - qrel = (ElfW_Rel *)sr->data; - for_each_elem(sr, 0, rel, ElfW_Rel) { - ptr = s->data + rel->r_offset; - sym_index = ELFW(R_SYM)(rel->r_info); - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - type = ELFW(R_TYPE)(rel->r_info); - tgt = sym->st_value; -#if SHT_RELX == SHT_RELA - tgt += rel->r_addend; -#endif - if (is_dwarf && type == R_DATA_32DW - && sym->st_shndx >= s1->dwlo && sym->st_shndx < s1->dwhi) { - /* dwarf section relocation to each other */ - add32le(ptr, tgt - s1->sections[sym->st_shndx]->sh_addr); - continue; - } - addr = s->sh_addr + rel->r_offset; - relocate(s1, rel, type, ptr, addr, tgt); - } -#ifndef ELF_OBJ_ONLY - /* if the relocation is allocated, we change its symbol table */ - if (sr->sh_flags & SHF_ALLOC) { - sr->link = s1->dynsym; - if (s1->output_type & TCC_OUTPUT_DYN) { - size_t r = (uint8_t*)qrel - sr->data; - if (sizeof ((Stab_Sym*)0)->n_value < PTR_SIZE - && 0 == strcmp(s->name, ".stab")) - r = 0; /* cannot apply 64bit relocation to 32bit value */ - sr->data_offset = sr->sh_size = r; -#ifdef CONFIG_TCC_PIE - if (r && 0 == (s->sh_flags & SHF_WRITE)) - tcc_warning("%d relocations to ro-section %s", (unsigned)(r / sizeof *qrel), s->name); -#endif - } - } -#endif -} - -/* relocate all sections */ -ST_FUNC void relocate_sections(TCCState *s1) -{ - int i; - Section *s, *sr; - - for (i = 1; i < s1->nb_sections; ++i) { - sr = s1->sections[i]; - if (sr->sh_type != SHT_RELX) - continue; - s = s1->sections[sr->sh_info]; -#ifndef TCC_TARGET_MACHO - if (s != s1->got - || s1->static_link - || s1->output_type == TCC_OUTPUT_MEMORY) -#endif - { - relocate_section(s1, s, sr); - } -#ifndef ELF_OBJ_ONLY - if (sr->sh_flags & SHF_ALLOC) { - ElfW_Rel *rel; - /* relocate relocation table in 'sr' */ - for_each_elem(sr, 0, rel, ElfW_Rel) - rel->r_offset += s->sh_addr; - } -#endif - } -} - -#ifndef ELF_OBJ_ONLY -/* count the number of dynamic relocations so that we can reserve - their space */ -static int prepare_dynamic_rel(TCCState *s1, Section *sr) -{ - int count = 0; -#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) || \ - defined(TCC_TARGET_ARM) || defined(TCC_TARGET_ARM64) || \ - defined(TCC_TARGET_RISCV64) - ElfW_Rel *rel; - for_each_elem(sr, 0, rel, ElfW_Rel) { - int sym_index = ELFW(R_SYM)(rel->r_info); - int type = ELFW(R_TYPE)(rel->r_info); - switch(type) { -#if defined(TCC_TARGET_I386) - case R_386_32: - if (!get_sym_attr(s1, sym_index, 0)->dyn_index - && ((ElfW(Sym)*)symtab_section->data + sym_index)->st_shndx == SHN_UNDEF) { - /* don't fixup unresolved (weak) symbols */ - rel->r_info = ELFW(R_INFO)(sym_index, R_386_RELATIVE); - break; - } -#elif defined(TCC_TARGET_X86_64) - case R_X86_64_32: - case R_X86_64_32S: - case R_X86_64_64: -#elif defined(TCC_TARGET_ARM) - case R_ARM_ABS32: - case R_ARM_TARGET1: -#elif defined(TCC_TARGET_ARM64) - case R_AARCH64_ABS32: - case R_AARCH64_ABS64: -#elif defined(TCC_TARGET_RISCV64) - case R_RISCV_32: - case R_RISCV_64: -#endif - count++; - break; -#if defined(TCC_TARGET_I386) - case R_386_PC32: -#elif defined(TCC_TARGET_X86_64) - case R_X86_64_PC32: - { - ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - /* Hidden defined symbols can and must be resolved locally. - We're misusing a PLT32 reloc for this, as that's always - resolved to its address even in shared libs. */ - if (sym->st_shndx != SHN_UNDEF && - ELFW(ST_VISIBILITY)(sym->st_other) == STV_HIDDEN) { - rel->r_info = ELFW(R_INFO)(sym_index, R_X86_64_PLT32); - break; - } - } -#elif defined(TCC_TARGET_ARM64) - case R_AARCH64_PREL32: -#endif - if (s1->output_type != TCC_OUTPUT_DLL) - break; - if (get_sym_attr(s1, sym_index, 0)->dyn_index) - count++; - break; - default: - break; - } - } -#endif - return count; -} -#endif - -#ifdef NEED_BUILD_GOT -static int build_got(TCCState *s1) -{ - /* if no got, then create it */ - s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); - s1->got->sh_entsize = 4; - /* keep space for _DYNAMIC pointer and two dummy got entries */ - section_ptr_add(s1->got, 3 * PTR_SIZE); - return set_elf_sym(symtab_section, 0, 0, ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT), - 0, s1->got->sh_num, "_GLOBAL_OFFSET_TABLE_"); -} - -/* Create a GOT and (for function call) a PLT entry corresponding to a symbol - in s1->symtab. When creating the dynamic symbol table entry for the GOT - relocation, use 'size' and 'info' for the corresponding symbol metadata. - Returns the offset of the GOT or (if any) PLT entry. */ -static struct sym_attr * put_got_entry(TCCState *s1, int dyn_reloc_type, - int sym_index) -{ - int need_plt_entry; - const char *name; - ElfW(Sym) *sym; - struct sym_attr *attr; - unsigned got_offset; - char plt_name[200]; - int len; - Section *s_rel; - - need_plt_entry = (dyn_reloc_type == R_JMP_SLOT); - attr = get_sym_attr(s1, sym_index, 1); - - /* In case a function is both called and its address taken 2 GOT entries - are created, one for taking the address (GOT) and the other for the PLT - entry (PLTGOT). */ - if (need_plt_entry ? attr->plt_offset : attr->got_offset) - return attr; - - s_rel = s1->got; - if (need_plt_entry) { - if (!s1->plt) { - s1->plt = new_section(s1, ".plt", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); - s1->plt->sh_entsize = 4; - } - s_rel = s1->plt; - } - - /* create the GOT entry */ - got_offset = s1->got->data_offset; - section_ptr_add(s1->got, PTR_SIZE); - - /* Create the GOT relocation that will insert the address of the object or - function of interest in the GOT entry. This is a static relocation for - memory output (dlsym will give us the address of symbols) and dynamic - relocation otherwise (executable and DLLs). The relocation should be - done lazily for GOT entry with *_JUMP_SLOT relocation type (the one - associated to a PLT entry) but is currently done at load time for an - unknown reason. */ - - sym = &((ElfW(Sym) *) symtab_section->data)[sym_index]; - name = (char *) symtab_section->link->data + sym->st_name; - //printf("sym %d %s\n", need_plt_entry, name); - - if (s1->dynsym) { - if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) { - /* Hack alarm. We don't want to emit dynamic symbols - and symbol based relocs for STB_LOCAL symbols, but rather - want to resolve them directly. At this point the symbol - values aren't final yet, so we must defer this. We will later - have to create a RELATIVE reloc anyway, so we misuse the - relocation slot to smuggle the symbol reference until - fill_local_got_entries. Not that the sym_index is - relative to symtab_section, not s1->dynsym! Nevertheless - we use s1->dyn_sym so that if this is the first call - that got->reloc is correctly created. Also note that - RELATIVE relocs are not normally created for the .got, - so the types serves as a marker for later (and is retained - also for the final output, which is okay because then the - got is just normal data). */ - put_elf_reloc(s1->dynsym, s1->got, got_offset, R_RELATIVE, - sym_index); - } else { - if (0 == attr->dyn_index) - attr->dyn_index = set_elf_sym(s1->dynsym, sym->st_value, - sym->st_size, sym->st_info, 0, - sym->st_shndx, name); - put_elf_reloc(s1->dynsym, s_rel, got_offset, dyn_reloc_type, - attr->dyn_index); - } - } else { - put_elf_reloc(symtab_section, s1->got, got_offset, dyn_reloc_type, - sym_index); - } - - if (need_plt_entry) { - attr->plt_offset = create_plt_entry(s1, got_offset, attr); - - /* create a symbol 'sym@plt' for the PLT jump vector */ - len = strlen(name); - if (len > sizeof plt_name - 5) - len = sizeof plt_name - 5; - memcpy(plt_name, name, len); - strcpy(plt_name + len, "@plt"); - attr->plt_sym = put_elf_sym(s1->symtab, attr->plt_offset, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_FUNC), 0, s1->plt->sh_num, plt_name); - } else { - attr->got_offset = got_offset; - } - - return attr; -} - -/* build GOT and PLT entries */ -/* Two passes because R_JMP_SLOT should become first. Some targets - (arm, arm64) do not allow mixing R_JMP_SLOT and R_GLOB_DAT. */ -ST_FUNC void build_got_entries(TCCState *s1, int got_sym) -{ - Section *s; - ElfW_Rel *rel; - ElfW(Sym) *sym; - int i, type, gotplt_entry, reloc_type, sym_index; - struct sym_attr *attr; - int pass = 0; -redo: - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - if (s->sh_type != SHT_RELX) - continue; - /* no need to handle got relocations */ - if (s->link != symtab_section) - continue; - for_each_elem(s, 0, rel, ElfW_Rel) { - type = ELFW(R_TYPE)(rel->r_info); - gotplt_entry = gotplt_entry_type(type); - if (gotplt_entry == -1) { - tcc_error_noabort ("Unknown relocation type for got: %d", type); - continue; - } - sym_index = ELFW(R_SYM)(rel->r_info); - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - - if (gotplt_entry == NO_GOTPLT_ENTRY) { - continue; - } - - /* Automatically create PLT/GOT [entry] if it is an undefined - reference (resolved at runtime), or the symbol is absolute, - probably created by tcc_add_symbol, and thus on 64-bit - targets might be too far from application code. */ - if (gotplt_entry == AUTO_GOTPLT_ENTRY) { - if (sym->st_shndx == SHN_UNDEF) { - ElfW(Sym) *esym; - int dynindex; - if (!PCRELATIVE_DLLPLT - && (s1->output_type & TCC_OUTPUT_DYN)) - continue; - /* Relocations for UNDEF symbols would normally need - to be transferred into the executable or shared object. - If that were done AUTO_GOTPLT_ENTRY wouldn't exist. - But TCC doesn't do that (at least for exes), so we - need to resolve all such relocs locally. And that - means PLT slots for functions in DLLs and COPY relocs for - data symbols. COPY relocs were generated in - bind_exe_dynsyms (and the symbol adjusted to be defined), - and for functions we were generated a dynamic symbol - of function type. */ - if (s1->dynsym) { - /* dynsym isn't set for -run :-/ */ - dynindex = get_sym_attr(s1, sym_index, 0)->dyn_index; - esym = (ElfW(Sym) *)s1->dynsym->data + dynindex; - if (dynindex - && (ELFW(ST_TYPE)(esym->st_info) == STT_FUNC - || (ELFW(ST_TYPE)(esym->st_info) == STT_NOTYPE - && ELFW(ST_TYPE)(sym->st_info) == STT_FUNC))) - goto jmp_slot; - } - } else if (sym->st_shndx == SHN_ABS) { - if (sym->st_value == 0) /* from tcc_add_btstub() */ - continue; -#ifndef TCC_TARGET_ARM - if (PTR_SIZE != 8) - continue; -#endif - /* from tcc_add_symbol(): on 64 bit platforms these - need to go through .got */ - } else - continue; - } - -#ifdef TCC_TARGET_X86_64 - if ((type == R_X86_64_PLT32 || type == R_X86_64_PC32) && - sym->st_shndx != SHN_UNDEF && - (ELFW(ST_VISIBILITY)(sym->st_other) != STV_DEFAULT || - ELFW(ST_BIND)(sym->st_info) == STB_LOCAL || - s1->output_type & TCC_OUTPUT_EXE)) { - if (pass != 0) - continue; - rel->r_info = ELFW(R_INFO)(sym_index, R_X86_64_PC32); - continue; - } -#endif - reloc_type = code_reloc(type); - if (reloc_type == -1) { - tcc_error_noabort ("Unknown relocation type: %d", type); - continue; - } - - if (reloc_type != 0) { - jmp_slot: - if (pass != 0) - continue; - reloc_type = R_JMP_SLOT; - } else { - if (pass != 1) - continue; - reloc_type = R_GLOB_DAT; - } - - if (!s1->got) - got_sym = build_got(s1); - - if (gotplt_entry == BUILD_GOT_ONLY) - continue; - - attr = put_got_entry(s1, reloc_type, sym_index); - - if (reloc_type == R_JMP_SLOT) - rel->r_info = ELFW(R_INFO)(attr->plt_sym, type); - } - } - if (++pass < 2) - goto redo; - /* .rel.plt refers to .got actually */ - if (s1->plt && s1->plt->reloc) - s1->plt->reloc->sh_info = s1->got->sh_num; - if (got_sym) /* set size */ - ((ElfW(Sym)*)symtab_section->data)[got_sym].st_size = s1->got->data_offset; -} -#endif /* def NEED_BUILD_GOT */ - -ST_FUNC int set_global_sym(TCCState *s1, const char *name, Section *sec, addr_t offs) -{ - int shn = sec ? sec->sh_num : offs || !name ? SHN_ABS : SHN_UNDEF; - if (sec && offs == -1) - offs = sec->data_offset; - return set_elf_sym(symtab_section, offs, 0, - ELFW(ST_INFO)(name ? STB_GLOBAL : STB_LOCAL, STT_NOTYPE), 0, shn, name); -} - -static void add_init_array_defines(TCCState *s1, const char *section_name) -{ - Section *s; - addr_t end_offset; - char buf[1024]; - s = have_section(s1, section_name); - if (!s || !(s->sh_flags & SHF_ALLOC)) { - end_offset = 0; - s = data_section; - } else { - end_offset = s->data_offset; - } - snprintf(buf, sizeof(buf), "__%s_start", section_name + 1); - set_global_sym(s1, buf, s, 0); - snprintf(buf, sizeof(buf), "__%s_end", section_name + 1); - set_global_sym(s1, buf, s, end_offset); -} - -ST_FUNC void add_array (TCCState *s1, const char *sec, int c) -{ - Section *s; - s = find_section(s1, sec); - s->sh_flags = shf_RELRO; - s->sh_type = sec[1] == 'i' ? SHT_INIT_ARRAY : SHT_FINI_ARRAY; - put_elf_reloc (s1->symtab, s, s->data_offset, R_DATA_PTR, c); - section_ptr_add(s, PTR_SIZE); -} - -#ifdef CONFIG_TCC_BCHECK -ST_FUNC void tcc_add_bcheck(TCCState *s1) -{ - if (0 == s1->do_bounds_check) - return; - section_ptr_add(bounds_section, sizeof(addr_t)); -} -#endif - -/* set symbol to STB_LOCAL and resolve. The point is to not export it as - a dynamic symbol to allow so's to have one each with a different value. */ -static void set_local_sym(TCCState *s1, const char *name, Section *s, int offset) -{ - int c = find_elf_sym(s1->symtab, name); - if (c) { - ElfW(Sym) *esym = (ElfW(Sym)*)s1->symtab->data + c; - esym->st_info = ELFW(ST_INFO)(STB_LOCAL, STT_NOTYPE); - esym->st_value = offset; - esym->st_shndx = s->sh_num; - } -} - -/* avoid generating debug/test_coverage code for stub functions */ -static void tcc_compile_string_no_debug(TCCState *s, const char *str) -{ - int save_do_debug = s->do_debug; - int save_test_coverage = s->test_coverage; - - s->do_debug = 0; - s->test_coverage = 0; - tcc_compile_string(s, str); - s->do_debug = save_do_debug; - s->test_coverage = save_test_coverage; -} - -#ifdef CONFIG_TCC_BACKTRACE -static void put_ptr(TCCState *s1, Section *s, int offs) -{ - int c; - c = set_global_sym(s1, NULL, s, offs); - s = data_section; - put_elf_reloc (s1->symtab, s, s->data_offset, R_DATA_PTR, c); - section_ptr_add(s, PTR_SIZE); -} - -ST_FUNC void tcc_add_btstub(TCCState *s1) -{ - Section *s; - int n, o; - CString cstr; - - s = data_section; - /* Align to PTR_SIZE */ - section_ptr_add(s, -s->data_offset & (PTR_SIZE - 1)); - o = s->data_offset; - /* create (part of) a struct rt_context (see tccrun.c) */ - if (s1->dwarf) { - put_ptr(s1, dwarf_line_section, 0); - put_ptr(s1, dwarf_line_section, -1); - if (s1->dwarf >= 5) - put_ptr(s1, dwarf_line_str_section, 0); - else - put_ptr(s1, dwarf_str_section, 0); - } - else - { - put_ptr(s1, stab_section, 0); - put_ptr(s1, stab_section, -1); - put_ptr(s1, stab_section->link, 0); - } - *(addr_t *)section_ptr_add(s, PTR_SIZE) = s1->dwarf; - /* skip esym_start/esym_end/elf_str (not loaded) */ - section_ptr_add(s, 3 * PTR_SIZE); - /* prog_base : local nameless symbol with offset 0 at SHN_ABS */ - put_ptr(s1, NULL, 0); -#if defined TCC_TARGET_MACHO - /* adjust for __PAGEZERO */ - if (s1->dwarf == 0 && s1->output_type == TCC_OUTPUT_EXE) - write64le(data_section->data + data_section->data_offset - PTR_SIZE, - (uint64_t)1 << 32); -#endif - n = 2 * PTR_SIZE; -#ifdef CONFIG_TCC_BCHECK - if (s1->do_bounds_check) { - put_ptr(s1, bounds_section, 0); - n -= PTR_SIZE; - } -#endif - section_ptr_add(s, n); - cstr_new(&cstr); - cstr_printf(&cstr, - "extern void __bt_init(),__bt_exit(),__bt_init_dll();" - "static void *__rt_info[];" - "__attribute__((constructor)) static void __bt_init_rt(){"); -#ifdef TCC_TARGET_PE - if (s1->output_type == TCC_OUTPUT_DLL) -#ifdef CONFIG_TCC_BCHECK - cstr_printf(&cstr, "__bt_init_dll(%d);", s1->do_bounds_check); -#else - cstr_printf(&cstr, "__bt_init_dll(0);"); -#endif -#endif - cstr_printf(&cstr, "__bt_init(__rt_info,%d);}", - s1->output_type == TCC_OUTPUT_DLL ? 0 : s1->rt_num_callers + 1); - /* In case dlcose is called by application */ - cstr_printf(&cstr, - "__attribute__((destructor)) static void __bt_exit_rt(){" - "__bt_exit(__rt_info);}"); - tcc_compile_string_no_debug(s1, cstr.data); - cstr_free(&cstr); - set_local_sym(s1, &"___rt_info"[!s1->leading_underscore], s, o); -} -#endif /* def CONFIG_TCC_BACKTRACE */ - -static void tcc_tcov_add_file(TCCState *s1, const char *filename) -{ - CString cstr; - void *ptr; - char wd[1024]; - - if (tcov_section == NULL) - return; - section_ptr_add(tcov_section, 1); - write32le (tcov_section->data, tcov_section->data_offset); - - cstr_new (&cstr); - if (filename[0] == '/') - cstr_printf (&cstr, "%s.tcov", filename); - else { - getcwd (wd, sizeof(wd)); - cstr_printf (&cstr, "%s/%s.tcov", wd, filename); - } - ptr = section_ptr_add(tcov_section, cstr.size + 1); - strcpy((char *)ptr, cstr.data); - unlink((char *)ptr); -#ifdef _WIN32 - normalize_slashes((char *)ptr); -#endif - cstr_free (&cstr); - - cstr_new(&cstr); - cstr_printf(&cstr, - "extern char *__tcov_data[];" - "extern void __store_test_coverage ();" - "__attribute__((destructor)) static void __tcov_exit() {" - "__store_test_coverage(__tcov_data);" - "}"); - tcc_compile_string_no_debug(s1, cstr.data); - cstr_free(&cstr); - set_local_sym(s1, &"___tcov_data"[!s1->leading_underscore], tcov_section, 0); -} - -#ifndef TCC_TARGET_PE -/* add tcc runtime libraries */ -ST_FUNC void tcc_add_runtime(TCCState *s1) -{ - s1->filetype = 0; - -#ifdef CONFIG_TCC_BCHECK - tcc_add_bcheck(s1); -#endif - tcc_add_pragma_libs(s1); - - /* add libc */ - if (!s1->nostdlib) { - int lpthread = s1->option_pthread; - -#ifdef CONFIG_TCC_BCHECK - if (s1->do_bounds_check && s1->output_type != TCC_OUTPUT_DLL) { - tcc_add_support(s1, "bcheck.o"); -# if !(TARGETOS_OpenBSD || TARGETOS_NetBSD) - tcc_add_library_err(s1, "dl"); -# endif - lpthread = 1; - } -#endif -#ifdef CONFIG_TCC_BACKTRACE - if (s1->do_backtrace) { - if (s1->output_type & TCC_OUTPUT_EXE) - tcc_add_support(s1, "bt-exe.o"); - if (s1->output_type != TCC_OUTPUT_DLL) - tcc_add_support(s1, "bt-log.o"); - if (s1->output_type != TCC_OUTPUT_MEMORY) - tcc_add_btstub(s1); - } -#endif - if (lpthread) - tcc_add_library_err(s1, "pthread"); - tcc_add_library_err(s1, "c"); -#ifdef TCC_LIBGCC - if (!s1->static_link) { - if (TCC_LIBGCC[0] == '/') - tcc_add_file(s1, TCC_LIBGCC); - else - tcc_add_dll(s1, TCC_LIBGCC, 0); - } -#endif -#if defined TCC_TARGET_ARM && TARGETOS_FreeBSD - tcc_add_library_err(s1, "gcc_s"); // unwind code -#endif - if (TCC_LIBTCC1[0]) - tcc_add_support(s1, TCC_LIBTCC1); - - /* add crt end if not memory output */ - if (s1->output_type != TCC_OUTPUT_MEMORY) { -#if defined TCC_TARGET_MACHO - /* nothing to do */ -#elif TARGETOS_FreeBSD || TARGETOS_NetBSD - if (s1->output_type & TCC_OUTPUT_DYN) - tcc_add_crt(s1, "crtendS.o"); - else - tcc_add_crt(s1, "crtend.o"); - tcc_add_crt(s1, "crtn.o"); -#elif TARGETOS_OpenBSD - if (s1->output_type == TCC_OUTPUT_DLL) - tcc_add_crt(s1, "crtendS.o"); - else - tcc_add_crt(s1, "crtend.o"); -#elif TARGETOS_ANDROID - if (s1->output_type == TCC_OUTPUT_DLL) - tcc_add_crt(s1, "crtend_so.o"); - else - tcc_add_crt(s1, "crtend_android.o"); -#else - tcc_add_crt(s1, "crtn.o"); -#endif - } - } -} -#endif /* ndef TCC_TARGET_PE */ - -/* add various standard linker symbols (must be done after the - sections are filled (for example after allocating common - symbols)) */ -static void tcc_add_linker_symbols(TCCState *s1) -{ - char buf[1024]; - int i; - Section *s; - - set_global_sym(s1, "_etext", text_section, -1); - set_global_sym(s1, "_edata", data_section, -1); - set_global_sym(s1, "_end", bss_section, -1); -#if TARGETOS_OpenBSD - set_global_sym(s1, "__executable_start", NULL, ELF_START_ADDR); -#endif -#ifdef TCC_TARGET_RISCV64 - /* XXX should be .sdata+0x800, not .data+0x800 */ - set_global_sym(s1, "__global_pointer$", data_section, 0x800); -#endif - /* horrible new standard ldscript defines */ - add_init_array_defines(s1, ".preinit_array"); - add_init_array_defines(s1, ".init_array"); - add_init_array_defines(s1, ".fini_array"); - /* add start and stop symbols for sections whose name can be - expressed in C */ - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - if ((s->sh_flags & SHF_ALLOC) - && (s->sh_type == SHT_PROGBITS - || s->sh_type == SHT_STRTAB)) { - const char *p; - /* check if section name can be expressed in C */ - p = s->name; - for(;;) { - int c = *p; - if (!c) - break; - if (!isid(c) && !isnum(c)) - goto next_sec; - p++; - } - snprintf(buf, sizeof(buf), "__start_%s", s->name); - set_global_sym(s1, buf, s, 0); - snprintf(buf, sizeof(buf), "__stop_%s", s->name); - set_global_sym(s1, buf, s, -1); - } - next_sec: ; - } -} - -ST_FUNC void resolve_common_syms(TCCState *s1) -{ - ElfW(Sym) *sym; - - /* Allocate common symbols in BSS. */ - for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { - if (sym->st_shndx == SHN_COMMON) { - /* symbol alignment is in st_value for SHN_COMMONs */ - sym->st_value = section_add(bss_section, sym->st_size, - sym->st_value); - sym->st_shndx = bss_section->sh_num; - } - } - - /* Now assign linker provided symbols their value. */ - tcc_add_linker_symbols(s1); -} - -#ifndef ELF_OBJ_ONLY -ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel) -{ - int sym_index = ELFW(R_SYM) (rel->r_info); - ElfW(Sym) *sym = &((ElfW(Sym) *) symtab_section->data)[sym_index]; - struct sym_attr *attr = get_sym_attr(s1, sym_index, 0); - unsigned offset = attr->got_offset; - - if (0 == offset) - return; - section_reserve(s1->got, offset + PTR_SIZE); -#if PTR_SIZE == 8 - write64le(s1->got->data + offset, sym->st_value); -#else - write32le(s1->got->data + offset, sym->st_value); -#endif -} - -/* Perform relocation to GOT or PLT entries */ -ST_FUNC void fill_got(TCCState *s1) -{ - Section *s; - ElfW_Rel *rel; - int i; - - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - if (s->sh_type != SHT_RELX) - continue; - /* no need to handle got relocations */ - if (s->link != symtab_section) - continue; - for_each_elem(s, 0, rel, ElfW_Rel) { - switch (ELFW(R_TYPE) (rel->r_info)) { - case R_X86_64_GOT32: - case R_X86_64_GOTPCREL: - case R_X86_64_GOTPCRELX: - case R_X86_64_REX_GOTPCRELX: - case R_X86_64_PLT32: - fill_got_entry(s1, rel); - break; - } - } - } -} - -/* See put_got_entry for a description. This is the second stage - where GOT references to local defined symbols are rewritten. */ -static void fill_local_got_entries(TCCState *s1) -{ - ElfW_Rel *rel; - if (!s1->got->reloc) - return; - for_each_elem(s1->got->reloc, 0, rel, ElfW_Rel) { - if (ELFW(R_TYPE)(rel->r_info) == R_RELATIVE) { - int sym_index = ELFW(R_SYM) (rel->r_info); - ElfW(Sym) *sym = &((ElfW(Sym) *) symtab_section->data)[sym_index]; - struct sym_attr *attr = get_sym_attr(s1, sym_index, 0); - unsigned offset = attr->got_offset; - if (offset != rel->r_offset - s1->got->sh_addr) - tcc_error_noabort("fill_local_got_entries: huh?"); - rel->r_info = ELFW(R_INFO)(0, R_RELATIVE); -#if SHT_RELX == SHT_RELA - rel->r_addend = sym->st_value; -#else - /* All our REL architectures also happen to be 32bit LE. */ - write32le(s1->got->data + offset, sym->st_value); -#endif - } - } -} - -/* Bind symbols of executable: resolve undefined symbols from exported symbols - in shared libraries */ -static void bind_exe_dynsyms(TCCState *s1) -{ - const char *name; - int sym_index, index; - ElfW(Sym) *sym, *esym; - int type; - - /* Resolve undefined symbols from dynamic symbols. When there is a match: - - if STT_FUNC or STT_GNU_IFUNC symbol -> add it in PLT - - if STT_OBJECT symbol -> add it in .bss section with suitable reloc */ - for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { - if (sym->st_shndx == SHN_UNDEF) { - name = (char *) symtab_section->link->data + sym->st_name; - sym_index = find_elf_sym(s1->dynsymtab_section, name); - if (sym_index) { - esym = &((ElfW(Sym) *)s1->dynsymtab_section->data)[sym_index]; - type = ELFW(ST_TYPE)(esym->st_info); - if ((type == STT_FUNC) || (type == STT_GNU_IFUNC)) { - /* Indirect functions shall have STT_FUNC type in executable - * dynsym section. Indeed, a dlsym call following a lazy - * resolution would pick the symbol value from the - * executable dynsym entry which would contain the address - * of the function wanted by the caller of dlsym instead of - * the address of the function that would return that - * address */ - int dynindex - = put_elf_sym(s1->dynsym, 0, esym->st_size, - ELFW(ST_INFO)(STB_GLOBAL,STT_FUNC), 0, 0, - name); - int index = sym - (ElfW(Sym) *) symtab_section->data; - get_sym_attr(s1, index, 1)->dyn_index = dynindex; - } else if (type == STT_OBJECT) { - unsigned long offset; - ElfW(Sym) *dynsym; - offset = bss_section->data_offset; - /* XXX: which alignment ? */ - offset = (offset + 16 - 1) & -16; - set_elf_sym (s1->symtab, offset, esym->st_size, - esym->st_info, 0, bss_section->sh_num, name); - index = put_elf_sym(s1->dynsym, offset, esym->st_size, - esym->st_info, 0, bss_section->sh_num, - name); - - /* Ensure R_COPY works for weak symbol aliases */ - if (ELFW(ST_BIND)(esym->st_info) == STB_WEAK) { - for_each_elem(s1->dynsymtab_section, 1, dynsym, ElfW(Sym)) { - if ((dynsym->st_value == esym->st_value) - && (ELFW(ST_BIND)(dynsym->st_info) == STB_GLOBAL)) { - char *dynname = (char *) s1->dynsymtab_section->link->data - + dynsym->st_name; - put_elf_sym(s1->dynsym, offset, dynsym->st_size, - dynsym->st_info, 0, - bss_section->sh_num, dynname); - break; - } - } - } - - put_elf_reloc(s1->dynsym, bss_section, - offset, R_COPY, index); - offset += esym->st_size; - bss_section->data_offset = offset; - } - } else { - /* STB_WEAK undefined symbols are accepted */ - /* XXX: _fp_hw seems to be part of the ABI, so we ignore it */ - if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK || - !strcmp(name, "_fp_hw")) { - } else { - tcc_error_noabort("undefined symbol '%s'", name); - } - } - } - } -} - -/* Bind symbols of libraries: export all non local symbols of executable that - are referenced by shared libraries. The reason is that the dynamic loader - search symbol first in executable and then in libraries. Therefore a - reference to a symbol already defined by a library can still be resolved by - a symbol in the executable. With -rdynamic, export all defined symbols */ -static void bind_libs_dynsyms(TCCState *s1) -{ - const char *name; - int dynsym_index; - ElfW(Sym) *sym, *esym; - - for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { - name = (char *)symtab_section->link->data + sym->st_name; - dynsym_index = find_elf_sym(s1->dynsymtab_section, name); - if (sym->st_shndx != SHN_UNDEF - && ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { - if (dynsym_index || s1->rdynamic) - set_elf_sym(s1->dynsym, sym->st_value, sym->st_size, - sym->st_info, 0, sym->st_shndx, name); - } else if (dynsym_index) { - esym = (ElfW(Sym) *)s1->dynsymtab_section->data + dynsym_index; - if (esym->st_shndx == SHN_UNDEF) { - /* weak symbols can stay undefined */ - if (ELFW(ST_BIND)(esym->st_info) != STB_WEAK) - tcc_warning("undefined dynamic symbol '%s'", name); - } - } - } -} - -/* Export all non local symbols. This is used by shared libraries so that the - non local symbols they define can resolve a reference in another shared - library or in the executable. Correspondingly, it allows undefined local - symbols to be resolved by other shared libraries or by the executable. */ -static void export_global_syms(TCCState *s1) -{ - int dynindex, index; - const char *name; - ElfW(Sym) *sym; - for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { - if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { - name = (char *) symtab_section->link->data + sym->st_name; - dynindex = set_elf_sym(s1->dynsym, sym->st_value, sym->st_size, - sym->st_info, 0, sym->st_shndx, name); - index = sym - (ElfW(Sym) *) symtab_section->data; - get_sym_attr(s1, index, 1)->dyn_index = dynindex; - } - } -} - -/* decide if an unallocated section should be output. */ -static int set_sec_sizes(TCCState *s1) -{ - int i; - Section *s; - int textrel = 0; - int file_type = s1->output_type; - - /* Allocate strings for section names */ - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - if (s->sh_type == SHT_RELX && !(s->sh_flags & SHF_ALLOC)) { - /* when generating a DLL, we include relocations but - we may patch them */ - if ((file_type & TCC_OUTPUT_DYN) - && (s1->sections[s->sh_info]->sh_flags & SHF_ALLOC)) { - int count = prepare_dynamic_rel(s1, s); - if (count) { - /* allocate the section */ - s->sh_flags |= SHF_ALLOC; - s->sh_size = count * sizeof(ElfW_Rel); - if (!(s1->sections[s->sh_info]->sh_flags & SHF_WRITE)) - textrel += count; - } - } - } else if ((s->sh_flags & SHF_ALLOC) -#ifdef TCC_TARGET_ARM - || s->sh_type == SHT_ARM_ATTRIBUTES -#endif - || s1->do_debug) { - s->sh_size = s->data_offset; - } - -#ifdef TCC_TARGET_ARM - /* XXX: Suppress stack unwinding section. */ - if (s->sh_type == SHT_ARM_EXIDX) { - s->sh_flags = 0; - s->sh_size = 0; - } -#endif - - } - return textrel; -} - -/* various data used under elf_output_file() */ -struct dyn_inf { - Section *dynamic; - Section *dynstr; - struct { - /* Info to be copied in dynamic section */ - unsigned long data_offset; - addr_t rel_addr; - addr_t rel_size; - }; - - ElfW(Phdr) *phdr; - int phnum; - Section *interp; - Section *note; - Section *gnu_hash; - - /* read only segment mapping for GNU_RELRO */ - Section _roinf, *roinf; -}; - -/* Decide the layout of sections loaded in memory. This must be done before - program headers are filled since they contain info about the layout. - We do the following ordering: interp, symbol tables, relocations, progbits, - nobits */ -static int sort_sections(TCCState *s1, int *sec_order, Section *interp) -{ - Section *s; - int i, j, k, f, f0, n; - int nb_sections = s1->nb_sections; - int *sec_cls = sec_order + nb_sections; - - for (i = 1; i < nb_sections; i++) { - s = s1->sections[i]; - if (s->sh_flags & SHF_ALLOC) { - j = 0x100; - if (s->sh_flags & SHF_WRITE) - j = 0x200; - if (s->sh_flags & SHF_TLS) - j += 0x200; - } else if (s->sh_name) { - j = 0x700; - } else { - j = 0x900; /* no sh_name: won't go to file */ - } - if (s->sh_type == SHT_SYMTAB || s->sh_type == SHT_DYNSYM) { - k = 0x10; - } else if (s->sh_type == SHT_STRTAB && strcmp(s->name, ".stabstr")) { - k = 0x11; - if (i == nb_sections - 1) /* ".shstrtab" assumed to remain last */ - k = 0xff; - } else if (s->sh_type == SHT_HASH || s->sh_type == SHT_GNU_HASH) { - k = 0x12; - } else if (s->sh_type == SHT_RELX) { - k = 0x20; - if (s1->plt && s == s1->plt->reloc) - k = 0x21; - } else if (s->sh_type == SHT_PREINIT_ARRAY) { - k = 0x41; - } else if (s->sh_type == SHT_INIT_ARRAY) { - k = 0x42; - } else if (s->sh_type == SHT_FINI_ARRAY) { - k = 0x43; -#ifdef CONFIG_TCC_BCHECK - } else if (s == bounds_section || s == lbounds_section) { - k = 0x44; -#endif - } else if (s == rodata_section || 0 == strcmp(s->name, ".data.rel.ro")) { - k = 0x45; - } else if (s->sh_type == SHT_DYNAMIC) { - k = 0x46; - } else if (s == s1->got) { - k = 0x47; /* .got as RELRO needs BIND_NOW in DT_FLAGS */ - } else { - k = 0x50; - if (s->sh_type == SHT_NOTE) - k = 0x60; - if (s->sh_flags & SHF_EXECINSTR) - k = 0x70; - if (s->sh_type == SHT_NOBITS) - k = 0x80; - if (s == interp) - k = 0x00; - } - k += j; - - for (n = i; n > 1 && k < (f = sec_cls[n - 1]); --n) - sec_cls[n] = f, sec_order[n] = sec_order[n - 1]; - sec_cls[n] = k, sec_order[n] = i; - } - sec_order[0] = 0; - - /* count PT_LOAD headers needed */ - n = f0 = 0; - for (i = 1; i < nb_sections; i++) { - s = s1->sections[sec_order[i]]; - k = sec_cls[i]; - f = 0; - if (k < 0x700) { - f = s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR|SHF_TLS); -#if TARGETOS_NetBSD - /* NetBSD only supports 2 PT_LOAD sections. - See: https://blog.netbsd.org/tnf/entry/the_first_report_on_lld */ - if ((f & SHF_WRITE) == 0) f |= SHF_EXECINSTR; -#else - if ((k & 0xfff0) == 0x240) /* RELRO sections */ - f |= 1<<4; -#endif - if (f != f0) /* start new header when flags changed or relro */ - f0 = f, ++n, f |= 1<<8; - } - sec_cls[i] = f; - //printf("ph %d sec %02d : %3X %3X %8.2X %04X %s\n", !!f * n, i, f, k, s->sh_type, s->sh_size, s->name); - } - return n; -} - -static ElfW(Phdr) *fill_phdr(ElfW(Phdr) *ph, int type, Section *s) -{ - if (s) { - ph->p_offset = s->sh_offset; - ph->p_vaddr = s->sh_addr; - ph->p_filesz = s->sh_size; - ph->p_align = s->sh_addralign; - } - ph->p_type = type; - ph->p_flags = PF_R; - ph->p_paddr = ph->p_vaddr; - ph->p_memsz = ph->p_filesz; - return ph; -} - -/* Assign sections to segments and decide how are sections laid out when loaded - in memory. This function also fills corresponding program headers. */ -static int layout_sections(TCCState *s1, int *sec_order, struct dyn_inf *d) -{ - Section *s; - addr_t addr, tmp, align, s_align, base; - ElfW(Phdr) *ph = NULL; - int i, f, n, phnum, phfill; - int file_offset; - - /* compute number of program headers */ - phnum = sort_sections(s1, sec_order, d->interp); - phfill = 0; /* set to 1 to have dll's with a PT_PHDR */ - if (d->interp) - phfill = 2; - phnum += phfill; - if (d->note) - ++phnum; - if (d->dynamic) - ++phnum; - if (d->roinf) - ++phnum; - d->phnum = phnum; - d->phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr))); - - file_offset = 0; - if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) - file_offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); - - s_align = ELF_PAGE_SIZE; - if (s1->section_align) - s_align = s1->section_align; - - addr = ELF_START_ADDR; - if (s1->output_type & TCC_OUTPUT_DYN) - addr = 0; - - if (s1->has_text_addr) { - addr = s1->text_addr; - if (0) { - int a_offset, p_offset; - /* we ensure that (addr % ELF_PAGE_SIZE) == file_offset % - ELF_PAGE_SIZE */ - a_offset = (int) (addr & (s_align - 1)); - p_offset = file_offset & (s_align - 1); - if (a_offset < p_offset) - a_offset += s_align; - file_offset += (a_offset - p_offset); - } - } - base = addr; - /* compute address after headers */ - addr = addr + (file_offset & (s_align - 1)); - - n = 0; - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[sec_order[i]]; - f = sec_order[i + s1->nb_sections]; - align = s->sh_addralign - 1; - - if (f == 0) { /* no alloc */ - file_offset = (file_offset + align) & ~align; - s->sh_offset = file_offset; - if (s->sh_type != SHT_NOBITS) - file_offset += s->sh_size; - continue; - } - - if ((f & 1<<8) && n) { - /* different rwx section flags */ - if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) { - /* if in the middle of a page, w e duplicate the page in - memory so that one copy is RX and the other is RW */ - if ((addr & (s_align - 1)) != 0) - addr += s_align; - } else { - align = s_align - 1; - } - } - - tmp = addr; - addr = (addr + align) & ~align; - file_offset += (int)(addr - tmp); - s->sh_offset = file_offset; - s->sh_addr = addr; - - if (f & 1<<8) { - /* set new program header */ - ph = &d->phdr[phfill + n]; - ph->p_type = PT_LOAD; - ph->p_align = s_align; - ph->p_flags = PF_R; - if (f & SHF_WRITE) - ph->p_flags |= PF_W; - if (f & SHF_EXECINSTR) - ph->p_flags |= PF_X; - if (f & SHF_TLS) { - ph->p_type = PT_TLS; - ph->p_align = align + 1; - } - - ph->p_offset = file_offset; - ph->p_vaddr = addr; - if (n == 0) { - /* Make the first PT_LOAD segment include the program - headers itself (and the ELF header as well), it'll - come out with same memory use but will make various - tools like binutils strip work better. */ - ph->p_offset = 0; - ph->p_vaddr = base; - } - ph->p_paddr = ph->p_vaddr; - ++n; - } - - if (f & 1<<4) { - Section *roinf = &d->_roinf; - if (roinf->sh_size == 0) { - roinf->sh_offset = s->sh_offset; - roinf->sh_addr = s->sh_addr; - roinf->sh_addralign = 1; - } - roinf->sh_size = (addr - roinf->sh_addr) + s->sh_size; - } - - addr += s->sh_size; - if (s->sh_type != SHT_NOBITS) - file_offset += s->sh_size; - - ph->p_filesz = file_offset - ph->p_offset; - ph->p_memsz = addr - ph->p_vaddr; - } - - /* Fill other headers */ - if (d->note) - fill_phdr(++ph, PT_NOTE, d->note); - if (d->dynamic) - fill_phdr(++ph, PT_DYNAMIC, d->dynamic)->p_flags |= PF_W; - if (d->roinf) - fill_phdr(++ph, PT_GNU_RELRO, d->roinf)->p_flags |= PF_W; - if (d->interp) - fill_phdr(&d->phdr[1], PT_INTERP, d->interp); - if (phfill) { - ph = &d->phdr[0]; - ph->p_offset = sizeof(ElfW(Ehdr)); - ph->p_vaddr = base + ph->p_offset; - ph->p_filesz = phnum * sizeof(ElfW(Phdr)); - ph->p_align = 4; - fill_phdr(ph, PT_PHDR, NULL); - } - return file_offset; -} - -/* put dynamic tag */ -static void put_dt(Section *dynamic, int dt, addr_t val) -{ - ElfW(Dyn) *dyn; - dyn = section_ptr_add(dynamic, sizeof(ElfW(Dyn))); - dyn->d_tag = dt; - dyn->d_un.d_val = val; -} - -/* Fill the dynamic section with tags describing the address and size of - sections */ -static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf) -{ - Section *dynamic = dyninf->dynamic; - Section *s; - - /* put dynamic section entries */ - put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr); - put_dt(dynamic, DT_GNU_HASH, dyninf->gnu_hash->sh_addr); - put_dt(dynamic, DT_STRTAB, dyninf->dynstr->sh_addr); - put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr); - put_dt(dynamic, DT_STRSZ, dyninf->dynstr->data_offset); - put_dt(dynamic, DT_SYMENT, sizeof(ElfW(Sym))); -#if PTR_SIZE == 8 - put_dt(dynamic, DT_RELA, dyninf->rel_addr); - put_dt(dynamic, DT_RELASZ, dyninf->rel_size); - put_dt(dynamic, DT_RELAENT, sizeof(ElfW_Rel)); - if (s1->plt && s1->plt->reloc) { - put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr); - put_dt(dynamic, DT_PLTRELSZ, s1->plt->reloc->data_offset); - put_dt(dynamic, DT_JMPREL, s1->plt->reloc->sh_addr); - put_dt(dynamic, DT_PLTREL, DT_RELA); - } - put_dt(dynamic, DT_RELACOUNT, 0); -#else - put_dt(dynamic, DT_REL, dyninf->rel_addr); - put_dt(dynamic, DT_RELSZ, dyninf->rel_size); - put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel)); - if (s1->plt && s1->plt->reloc) { - put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr); - put_dt(dynamic, DT_PLTRELSZ, s1->plt->reloc->data_offset); - put_dt(dynamic, DT_JMPREL, s1->plt->reloc->sh_addr); - put_dt(dynamic, DT_PLTREL, DT_REL); - } - put_dt(dynamic, DT_RELCOUNT, 0); -#endif - if (versym_section && verneed_section) { - /* The dynamic linker can not handle VERSYM without VERNEED */ - put_dt(dynamic, DT_VERSYM, versym_section->sh_addr); - put_dt(dynamic, DT_VERNEED, verneed_section->sh_addr); - put_dt(dynamic, DT_VERNEEDNUM, dt_verneednum); - } - s = have_section(s1, ".preinit_array"); - if (s && s->data_offset) { - put_dt(dynamic, DT_PREINIT_ARRAY, s->sh_addr); - put_dt(dynamic, DT_PREINIT_ARRAYSZ, s->data_offset); - } - s = have_section(s1, ".init_array"); - if (s && s->data_offset) { - put_dt(dynamic, DT_INIT_ARRAY, s->sh_addr); - put_dt(dynamic, DT_INIT_ARRAYSZ, s->data_offset); - } - s = have_section(s1, ".fini_array"); - if (s && s->data_offset) { - put_dt(dynamic, DT_FINI_ARRAY, s->sh_addr); - put_dt(dynamic, DT_FINI_ARRAYSZ, s->data_offset); - } - s = have_section(s1, ".init"); - if (s && s->data_offset) { - put_dt(dynamic, DT_INIT, s->sh_addr); - } - s = have_section(s1, ".fini"); - if (s && s->data_offset) { - put_dt(dynamic, DT_FINI, s->sh_addr); - } - if (s1->do_debug) - put_dt(dynamic, DT_DEBUG, 0); - put_dt(dynamic, DT_NULL, 0); -} - -/* Remove gaps between RELX sections. - These gaps are a result of final_sections_reloc. Here some relocs are removed. - The gaps are then filled with 0 in tcc_output_elf. The 0 is intepreted as - R_...NONE reloc. This does work on most targets but on OpenBSD/arm64 this - is illegal. OpenBSD/arm64 does not support R_...NONE reloc. */ -static void update_reloc_sections(TCCState *s1, struct dyn_inf *dyninf) -{ - int i; - unsigned long file_offset = 0; - Section *s; - Section *relocplt = s1->plt ? s1->plt->reloc : NULL; - - /* dynamic relocation table information, for .dynamic section */ - dyninf->rel_addr = dyninf->rel_size = 0; - - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - if (s->sh_type == SHT_RELX && s != relocplt) { - if (dyninf->rel_size == 0) { - dyninf->rel_addr = s->sh_addr; - file_offset = s->sh_offset; - } - else { - s->sh_addr = dyninf->rel_addr + dyninf->rel_size; - s->sh_offset = file_offset + dyninf->rel_size; - } - dyninf->rel_size += s->sh_size; - } - } -} - -static int tidy_section_headers(TCCState *s1, int *sec_order); -#endif /* ndef ELF_OBJ_ONLY */ - -/* Create an ELF file on disk. - This function handle ELF specific layout requirements */ -static int tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, - int file_offset, int *sec_order) -{ - int i, shnum, offset, size, file_type; - Section *s; - ElfW(Ehdr) ehdr; - ElfW(Shdr) shdr, *sh; - - file_type = s1->output_type; - shnum = s1->nb_sections; - - memset(&ehdr, 0, sizeof(ehdr)); - - if (phnum > 0) { - ehdr.e_phentsize = sizeof(ElfW(Phdr)); - ehdr.e_phnum = phnum; - ehdr.e_phoff = sizeof(ElfW(Ehdr)); -#ifndef ELF_OBJ_ONLY - shnum = tidy_section_headers(s1, sec_order); -#endif - } - - /* align to 4 */ - file_offset = (file_offset + 3) & -4; - - /* fill header */ - ehdr.e_ident[0] = ELFMAG0; - ehdr.e_ident[1] = ELFMAG1; - ehdr.e_ident[2] = ELFMAG2; - ehdr.e_ident[3] = ELFMAG3; - ehdr.e_ident[4] = ELFCLASSW; - ehdr.e_ident[5] = ELFDATA2LSB; - ehdr.e_ident[6] = EV_CURRENT; - -#if TARGETOS_FreeBSD || TARGETOS_FreeBSD_kernel - ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD; -#elif defined TCC_TARGET_ARM && defined TCC_ARM_EABI - ehdr.e_flags = EF_ARM_EABI_VER5; - ehdr.e_flags |= s1->float_abi == ARM_HARD_FLOAT - ? EF_ARM_VFP_FLOAT : EF_ARM_SOFT_FLOAT; -#elif defined TCC_TARGET_ARM - ehdr.e_ident[EI_OSABI] = ELFOSABI_ARM; -#elif defined TCC_TARGET_RISCV64 - ehdr.e_flags = EF_RISCV_FLOAT_ABI_DOUBLE; -#endif - - if (file_type == TCC_OUTPUT_OBJ) { - ehdr.e_type = ET_REL; - } else { - if (file_type & TCC_OUTPUT_DYN) - ehdr.e_type = ET_DYN; - else - ehdr.e_type = ET_EXEC; - if (s1->elf_entryname) - ehdr.e_entry = get_sym_addr(s1, s1->elf_entryname, 1, 0); - else - ehdr.e_entry = get_sym_addr(s1, "_start", !!(file_type & TCC_OUTPUT_EXE), 0); - if (ehdr.e_entry == (addr_t)-1) - ehdr.e_entry = text_section->sh_addr; - if (s1->nb_errors) - return -1; - } - - ehdr.e_machine = EM_TCC_TARGET; - ehdr.e_version = EV_CURRENT; - ehdr.e_shoff = file_offset; - ehdr.e_ehsize = sizeof(ElfW(Ehdr)); - ehdr.e_shentsize = sizeof(ElfW(Shdr)); - ehdr.e_shnum = shnum; - ehdr.e_shstrndx = shnum - 1; - - fwrite(&ehdr, 1, sizeof(ElfW(Ehdr)), f); - if (phdr) - fwrite(phdr, 1, phnum * sizeof(ElfW(Phdr)), f); - offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); - - sort_syms(s1, symtab_section); - - for(i = 1; i < shnum; i++) { - s = s1->sections[sec_order ? sec_order[i] : i]; - if (s->sh_type != SHT_NOBITS) { - while (offset < s->sh_offset) { - fputc(0, f); - offset++; - } - size = s->sh_size; - if (size) - fwrite(s->data, 1, size, f); - offset += size; - } - } - - /* output section headers */ - while (offset < ehdr.e_shoff) { - fputc(0, f); - offset++; - } - - for(i = 0; i < shnum; i++) { - sh = &shdr; - memset(sh, 0, sizeof(ElfW(Shdr))); - s = s1->sections[i]; - if (s) { - sh->sh_name = s->sh_name; - sh->sh_type = s->sh_type; - sh->sh_flags = s->sh_flags; - sh->sh_entsize = s->sh_entsize; - sh->sh_info = s->sh_info; - if (s->link) - sh->sh_link = s->link->sh_num; - sh->sh_addralign = s->sh_addralign; - sh->sh_addr = s->sh_addr; - sh->sh_offset = s->sh_offset; - sh->sh_size = s->sh_size; - } - fwrite(sh, 1, sizeof(ElfW(Shdr)), f); - } - return 0; -} - -static int tcc_output_binary(TCCState *s1, FILE *f, - const int *sec_order) -{ - Section *s; - int i, offset, size; - - offset = 0; - for(i=1;i<s1->nb_sections;i++) { - s = s1->sections[sec_order[i]]; - if (s->sh_type != SHT_NOBITS && - (s->sh_flags & SHF_ALLOC)) { - while (offset < s->sh_offset) { - fputc(0, f); - offset++; - } - size = s->sh_size; - fwrite(s->data, 1, size, f); - offset += size; - } - } - return 0; -} - -/* Write an elf, coff or "binary" file */ -static int tcc_write_elf_file(TCCState *s1, const char *filename, int phnum, - ElfW(Phdr) *phdr, int file_offset, int *sec_order) -{ - int fd, mode, file_type, ret; - FILE *f; - - file_type = s1->output_type; - if (file_type == TCC_OUTPUT_OBJ) - mode = 0666; - else - mode = 0777; - unlink(filename); - fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode); - if (fd < 0 || (f = fdopen(fd, "wb")) == NULL) - return tcc_error_noabort("could not write '%s: %s'", filename, strerror(errno)); - if (s1->verbose) - printf("<- %s\n", filename); -#ifdef TCC_TARGET_COFF - if (s1->output_format == TCC_OUTPUT_FORMAT_COFF) - tcc_output_coff(s1, f); - else -#endif - if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) - ret = tcc_output_elf(s1, f, phnum, phdr, file_offset, sec_order); - else - ret = tcc_output_binary(s1, f, sec_order); - fclose(f); - - return ret; -} - -#ifndef ELF_OBJ_ONLY -/* Sort section headers by assigned sh_addr, remove sections - that we aren't going to output. */ -static int tidy_section_headers(TCCState *s1, int *sec_order) -{ - int i, nnew, l, *backmap; - Section **snew, *s; - ElfW(Sym) *sym; - - snew = tcc_malloc(s1->nb_sections * sizeof(snew[0])); - backmap = tcc_malloc(s1->nb_sections * sizeof(backmap[0])); - for (i = 0, nnew = 0, l = s1->nb_sections; i < s1->nb_sections; i++) { - s = s1->sections[sec_order[i]]; - if (!i || s->sh_name) { - backmap[sec_order[i]] = nnew; - snew[nnew] = s; - ++nnew; - } else { - backmap[sec_order[i]] = 0; - snew[--l] = s; - } - } - for (i = 0; i < nnew; i++) { - s = snew[i]; - if (s) { - s->sh_num = i; - if (s->sh_type == SHT_RELX) - s->sh_info = backmap[s->sh_info]; - } - } - - for_each_elem(symtab_section, 1, sym, ElfW(Sym)) - if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE) - sym->st_shndx = backmap[sym->st_shndx]; - if ( !s1->static_link ) { - for_each_elem(s1->dynsym, 1, sym, ElfW(Sym)) - if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE) - sym->st_shndx = backmap[sym->st_shndx]; - } - for (i = 0; i < s1->nb_sections; i++) - sec_order[i] = i; - tcc_free(s1->sections); - s1->sections = snew; - tcc_free(backmap); - return nnew; -} - -#ifdef TCC_TARGET_ARM -static void create_arm_attribute_section(TCCState *s1) -{ - // Needed for DLL support. - static const unsigned char arm_attr[] = { - 0x41, // 'A' - 0x2c, 0x00, 0x00, 0x00, // size 0x2c - 'a', 'e', 'a', 'b', 'i', 0x00, // "aeabi" - 0x01, 0x22, 0x00, 0x00, 0x00, // 'File Attributes', size 0x22 - 0x05, 0x36, 0x00, // 'CPU_name', "6" - 0x06, 0x06, // 'CPU_arch', 'v6' - 0x08, 0x01, // 'ARM_ISA_use', 'Yes' - 0x09, 0x01, // 'THUMB_ISA_use', 'Thumb-1' - 0x0a, 0x02, // 'FP_arch', 'VFPv2' - 0x12, 0x04, // 'ABI_PCS_wchar_t', 4 - 0x14, 0x01, // 'ABI_FP_denormal', 'Needed' - 0x15, 0x01, // 'ABI_FP_exceptions', 'Needed' - 0x17, 0x03, // 'ABI_FP_number_model', 'IEEE 754' - 0x18, 0x01, // 'ABI_align_needed', '8-byte' - 0x19, 0x01, // 'ABI_align_preserved', '8-byte, except leaf SP' - 0x1a, 0x02, // 'ABI_enum_size', 'int' - 0x1c, 0x01, // 'ABI_VFP_args', 'VFP registers' - 0x22, 0x01 // 'CPU_unaligned_access', 'v6' - }; - Section *attr = new_section(s1, ".ARM.attributes", SHT_ARM_ATTRIBUTES, 0); - unsigned char *ptr = section_ptr_add(attr, sizeof(arm_attr)); - attr->sh_addralign = 1; - memcpy(ptr, arm_attr, sizeof(arm_attr)); - if (s1->float_abi != ARM_HARD_FLOAT) { - ptr[26] = 0x00; // 'FP_arch', 'No' - ptr[41] = 0x1e; // 'ABI_optimization_goals' - ptr[42] = 0x06; // 'Aggressive Debug' - } -} -#endif - -#if TARGETOS_OpenBSD || TARGETOS_NetBSD -static Section *create_bsd_note_section(TCCState *s1, - const char *name, - const char *value) -{ - Section *s = find_section (s1, name); - - if (s->data_offset == 0) { - char *ptr = section_ptr_add(s, sizeof(ElfW(Nhdr)) + 8 + 4); - ElfW(Nhdr) *note = (ElfW(Nhdr) *) ptr; - - s->sh_type = SHT_NOTE; - note->n_namesz = 8; - note->n_descsz = 4; - note->n_type = ELF_NOTE_OS_GNU; - strcpy (ptr + sizeof(ElfW(Nhdr)), value); - } - return s; -} -#endif - -static void alloc_sec_names(TCCState *s1, int is_obj); - -/* Output an elf, coff or binary file */ -/* XXX: suppress unneeded sections */ -static int elf_output_file(TCCState *s1, const char *filename) -{ - int i, ret, file_type, file_offset, *sec_order; - struct dyn_inf dyninf = {0}; - Section *interp, *dynstr, *dynamic; - int textrel, got_sym, dt_flags_1; - - file_type = s1->output_type; - s1->nb_errors = 0; - ret = -1; - interp = dynstr = dynamic = NULL; - sec_order = NULL; - dyninf.roinf = &dyninf._roinf; - -#ifdef TCC_TARGET_ARM - create_arm_attribute_section (s1); -#endif - -#if TARGETOS_OpenBSD - dyninf.note = create_bsd_note_section (s1, ".note.openbsd.ident", "OpenBSD"); -#endif - -#if TARGETOS_NetBSD - dyninf.note = create_bsd_note_section (s1, ".note.netbsd.ident", "NetBSD"); -#endif - -#if TARGETOS_FreeBSD || TARGETOS_NetBSD - dyninf.roinf = NULL; -#endif - /* if linking, also link in runtime libraries (libc, libgcc, etc.) */ - tcc_add_runtime(s1); - resolve_common_syms(s1); - - if (!s1->static_link) { - if (file_type & TCC_OUTPUT_EXE) { - char *ptr; - /* allow override the dynamic loader */ - const char *elfint = getenv("LD_SO"); - if (elfint == NULL) - elfint = DEFAULT_ELFINTERP(s1); - /* add interpreter section only if executable */ - interp = new_section(s1, ".interp", SHT_PROGBITS, SHF_ALLOC); - interp->sh_addralign = 1; - ptr = section_ptr_add(interp, 1 + strlen(elfint)); - strcpy(ptr, elfint); - dyninf.interp = interp; - } - - /* add dynamic symbol table */ - s1->dynsym = new_symtab(s1, ".dynsym", SHT_DYNSYM, SHF_ALLOC, - ".dynstr", - ".hash", SHF_ALLOC); - /* Number of local symbols (readelf complains if not set) */ - s1->dynsym->sh_info = 1; - dynstr = s1->dynsym->link; - /* add dynamic section */ - dynamic = new_section(s1, ".dynamic", SHT_DYNAMIC, - SHF_ALLOC | SHF_WRITE); - dynamic->link = dynstr; - dynamic->sh_entsize = sizeof(ElfW(Dyn)); - - got_sym = build_got(s1); - if (file_type == TCC_OUTPUT_EXE) { - bind_exe_dynsyms(s1); - if (s1->nb_errors) - goto the_end; - } - build_got_entries(s1, got_sym); - if (file_type & TCC_OUTPUT_EXE) { - bind_libs_dynsyms(s1); - } else { - /* shared library case: simply export all global symbols */ - export_global_syms(s1); - } - dyninf.gnu_hash = create_gnu_hash(s1); - } else { - build_got_entries(s1, 0); - } - version_add (s1); - - textrel = set_sec_sizes(s1); - alloc_sec_names(s1, 0); - - if (!s1->static_link) { - /* add a list of needed dlls */ - for(i = 0; i < s1->nb_loaded_dlls; i++) { - DLLReference *dllref = s1->loaded_dlls[i]; - if (dllref->level == 0) - put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, dllref->name)); - } - - if (s1->rpath) - put_dt(dynamic, s1->enable_new_dtags ? DT_RUNPATH : DT_RPATH, - put_elf_str(dynstr, s1->rpath)); - - dt_flags_1 = DF_1_NOW; - if (file_type & TCC_OUTPUT_DYN) { - if (s1->soname) - put_dt(dynamic, DT_SONAME, put_elf_str(dynstr, s1->soname)); - /* XXX: currently, since we do not handle PIC code, we - must relocate the readonly segments */ - if (textrel) - put_dt(dynamic, DT_TEXTREL, 0); - if (file_type & TCC_OUTPUT_EXE) - dt_flags_1 = DF_1_NOW | DF_1_PIE; - } - put_dt(dynamic, DT_FLAGS, DF_BIND_NOW); - put_dt(dynamic, DT_FLAGS_1, dt_flags_1); - if (s1->symbolic) - put_dt(dynamic, DT_SYMBOLIC, 0); - - dyninf.dynamic = dynamic; - dyninf.dynstr = dynstr; - /* remember offset and reserve space for 2nd call below */ - dyninf.data_offset = dynamic->data_offset; - fill_dynamic(s1, &dyninf); - dynamic->sh_size = dynamic->data_offset; - dynstr->sh_size = dynstr->data_offset; - } - - /* this array is used to reorder sections in the output file */ - sec_order = tcc_malloc(sizeof(int) * 2 * s1->nb_sections); - /* compute section to program header mapping */ - file_offset = layout_sections(s1, sec_order, &dyninf); - - if (dynamic) { - /* put in GOT the dynamic section address and relocate PLT */ - write32le(s1->got->data, dynamic->sh_addr); - if (file_type == TCC_OUTPUT_EXE - || (RELOCATE_DLLPLT && (file_type & TCC_OUTPUT_DYN))) - relocate_plt(s1); - /* relocate symbols in .dynsym now that final addresses are known */ - relocate_syms(s1, s1->dynsym, 2); - } - - /* if building executable or DLL, then relocate each section - except the GOT which is already relocated */ - relocate_syms(s1, s1->symtab, 0); - if (s1->nb_errors != 0) - goto the_end; - relocate_sections(s1); - if (dynamic) { - update_reloc_sections (s1, &dyninf); - dynamic->data_offset = dyninf.data_offset; - fill_dynamic(s1, &dyninf); - } - /* Perform relocation to GOT or PLT entries */ - if (file_type == TCC_OUTPUT_EXE && s1->static_link) - fill_got(s1); - else if (s1->got) - fill_local_got_entries(s1); - - if (dyninf.gnu_hash) - update_gnu_hash(s1, dyninf.gnu_hash); - - /* Create the ELF file with name 'filename' */ - ret = tcc_write_elf_file(s1, filename, dyninf.phnum, dyninf.phdr, file_offset, sec_order); - the_end: - tcc_free(sec_order); - tcc_free(dyninf.phdr); - return ret; -} -#endif /* ndef ELF_OBJ_ONLY */ - -/* Allocate strings for section names */ -static void alloc_sec_names(TCCState *s1, int is_obj) -{ - int i; - Section *s, *strsec; - - strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0); - put_elf_str(strsec, ""); - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - if (is_obj) - s->sh_size = s->data_offset; - if (s == strsec || s->sh_size || (s->sh_flags & SHF_ALLOC)) - s->sh_name = put_elf_str(strsec, s->name); - } - strsec->sh_size = strsec->data_offset; -} - -/* Output an elf .o file */ -static int elf_output_obj(TCCState *s1, const char *filename) -{ - Section *s; - int i, ret, file_offset; - s1->nb_errors = 0; - /* Allocate strings for section names */ - alloc_sec_names(s1, 1); - file_offset = sizeof (ElfW(Ehdr)); - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - file_offset = (file_offset + 15) & -16; - s->sh_offset = file_offset; - if (s->sh_type != SHT_NOBITS) - file_offset += s->sh_size; - } - /* Create the ELF file with name 'filename' */ - ret = tcc_write_elf_file(s1, filename, 0, NULL, file_offset, NULL); - return ret; -} - -LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename) -{ - if (s->test_coverage) - tcc_tcov_add_file(s, filename); - if (s->output_type == TCC_OUTPUT_OBJ) - return elf_output_obj(s, filename); -#ifdef TCC_TARGET_PE - return pe_output_file(s, filename); -#elif TCC_TARGET_MACHO - return macho_output_file(s, filename); -#else - return elf_output_file(s, filename); -#endif -} - -ST_FUNC ssize_t full_read(int fd, void *buf, size_t count) { - char *cbuf = buf; - size_t rnum = 0; - while (1) { - ssize_t num = read(fd, cbuf, count-rnum); - if (num < 0) return num; - if (num == 0) return rnum; - rnum += num; - cbuf += num; - } -} - -ST_FUNC void *load_data(int fd, unsigned long file_offset, unsigned long size) -{ - void *data; - - data = tcc_malloc(size); - lseek(fd, file_offset, SEEK_SET); - full_read(fd, data, size); - return data; -} - -typedef struct SectionMergeInfo { - Section *s; /* corresponding existing section */ - unsigned long offset; /* offset of the new section in the existing section */ - uint8_t new_section; /* true if section 's' was added */ - uint8_t link_once; /* true if link once section */ -} SectionMergeInfo; - -ST_FUNC int tcc_object_type(int fd, ElfW(Ehdr) *h) -{ - int size = full_read(fd, h, sizeof *h); - if (size == sizeof *h && 0 == memcmp(h, ELFMAG, 4)) { - if (h->e_type == ET_REL) - return AFF_BINTYPE_REL; - if (h->e_type == ET_DYN) - return AFF_BINTYPE_DYN; - } else if (size >= 8) { - if (0 == memcmp(h, ARMAG, 8)) - return AFF_BINTYPE_AR; -#ifdef TCC_TARGET_COFF - if (((struct filehdr*)h)->f_magic == COFF_C67_MAGIC) - return AFF_BINTYPE_C67; -#endif - } - return 0; -} - -/* load an object file and merge it with current files */ -/* XXX: handle correctly stab (debug) info */ -ST_FUNC int tcc_load_object_file(TCCState *s1, - int fd, unsigned long file_offset) -{ - ElfW(Ehdr) ehdr; - ElfW(Shdr) *shdr, *sh; - unsigned long size, offset, offseti; - int i, j, nb_syms, sym_index, ret, seencompressed; - char *strsec, *strtab; - int stab_index, stabstr_index; - int *old_to_new_syms; - char *sh_name, *name; - SectionMergeInfo *sm_table, *sm; - ElfW(Sym) *sym, *symtab; - ElfW_Rel *rel; - Section *s; - - lseek(fd, file_offset, SEEK_SET); - if (tcc_object_type(fd, &ehdr) != AFF_BINTYPE_REL) - goto invalid; - /* test CPU specific stuff */ - if (ehdr.e_ident[5] != ELFDATA2LSB || - ehdr.e_machine != EM_TCC_TARGET) { -invalid: - return tcc_error_noabort("invalid object file"); - } - /* read sections */ - shdr = load_data(fd, file_offset + ehdr.e_shoff, - sizeof(ElfW(Shdr)) * ehdr.e_shnum); - sm_table = tcc_mallocz(sizeof(SectionMergeInfo) * ehdr.e_shnum); - - /* load section names */ - sh = &shdr[ehdr.e_shstrndx]; - strsec = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); - - /* load symtab and strtab */ - old_to_new_syms = NULL; - symtab = NULL; - strtab = NULL; - nb_syms = 0; - seencompressed = 0; - stab_index = stabstr_index = 0; - ret = -1; - - for(i = 1; i < ehdr.e_shnum; i++) { - sh = &shdr[i]; - if (sh->sh_type == SHT_SYMTAB) { - if (symtab) { - tcc_error_noabort("object must contain only one symtab"); - goto the_end; - } - nb_syms = sh->sh_size / sizeof(ElfW(Sym)); - symtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); - sm_table[i].s = symtab_section; - - /* now load strtab */ - sh = &shdr[sh->sh_link]; - strtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); - } - if (sh->sh_flags & SHF_COMPRESSED) - seencompressed = 1; - } - - /* now examine each section and try to merge its content with the - ones in memory */ - for(i = 1; i < ehdr.e_shnum; i++) { - /* no need to examine section name strtab */ - if (i == ehdr.e_shstrndx) - continue; - sh = &shdr[i]; - if (sh->sh_type == SHT_RELX) - sh = &shdr[sh->sh_info]; - /* ignore sections types we do not handle (plus relocs to those) */ - if (sh->sh_type != SHT_PROGBITS && -#ifdef TCC_ARM_EABI - sh->sh_type != SHT_ARM_EXIDX && -#endif -#if TARGETOS_OpenBSD || TARGETOS_FreeBSD || TARGETOS_NetBSD - sh->sh_type != SHT_X86_64_UNWIND && -#endif - sh->sh_type != SHT_NOTE && - sh->sh_type != SHT_NOBITS && - sh->sh_type != SHT_PREINIT_ARRAY && - sh->sh_type != SHT_INIT_ARRAY && - sh->sh_type != SHT_FINI_ARRAY && - strcmp(strsec + sh->sh_name, ".stabstr") - ) - continue; - if (seencompressed && 0 == strncmp(strsec + sh->sh_name, ".debug_", 7)) - continue; - - sh = &shdr[i]; - sh_name = strsec + sh->sh_name; - if (sh->sh_addralign < 1) - sh->sh_addralign = 1; - /* find corresponding section, if any */ - for(j = 1; j < s1->nb_sections;j++) { - s = s1->sections[j]; - if (!strcmp(s->name, sh_name)) { - if (!strncmp(sh_name, ".gnu.linkonce", - sizeof(".gnu.linkonce") - 1)) { - /* if a 'linkonce' section is already present, we - do not add it again. It is a little tricky as - symbols can still be defined in - it. */ - sm_table[i].link_once = 1; - goto next; - } - if (stab_section) { - if (s == stab_section) - stab_index = i; - if (s == stab_section->link) - stabstr_index = i; - } - goto found; - } - } - /* not found: create new section */ - s = new_section(s1, sh_name, sh->sh_type, sh->sh_flags & ~SHF_GROUP); - /* take as much info as possible from the section. sh_link and - sh_info will be updated later */ - s->sh_addralign = sh->sh_addralign; - s->sh_entsize = sh->sh_entsize; - sm_table[i].new_section = 1; - found: - if (sh->sh_type != s->sh_type -#if TARGETOS_OpenBSD || TARGETOS_FreeBSD || TARGETOS_NetBSD - && strcmp (s->name, ".eh_frame") -#endif - ) { - tcc_error_noabort("invalid section type"); - goto the_end; - } - /* align start of section */ - s->data_offset += -s->data_offset & (sh->sh_addralign - 1); - if (sh->sh_addralign > s->sh_addralign) - s->sh_addralign = sh->sh_addralign; - sm_table[i].offset = s->data_offset; - sm_table[i].s = s; - /* concatenate sections */ - size = sh->sh_size; - if (sh->sh_type != SHT_NOBITS) { - unsigned char *ptr; - lseek(fd, file_offset + sh->sh_offset, SEEK_SET); - ptr = section_ptr_add(s, size); - full_read(fd, ptr, size); - } else { - s->data_offset += size; - } - next: ; - } - - /* gr relocate stab strings */ - if (stab_index && stabstr_index) { - Stab_Sym *a, *b; - unsigned o; - s = sm_table[stab_index].s; - a = (Stab_Sym *)(s->data + sm_table[stab_index].offset); - b = (Stab_Sym *)(s->data + s->data_offset); - o = sm_table[stabstr_index].offset; - while (a < b) { - if (a->n_strx) - a->n_strx += o; - a++; - } - } - - /* second short pass to update sh_link and sh_info fields of new - sections */ - for(i = 1; i < ehdr.e_shnum; i++) { - s = sm_table[i].s; - if (!s || !sm_table[i].new_section) - continue; - sh = &shdr[i]; - if (sh->sh_link > 0) - s->link = sm_table[sh->sh_link].s; - if (sh->sh_type == SHT_RELX) { - s->sh_info = sm_table[sh->sh_info].s->sh_num; - /* update backward link */ - s1->sections[s->sh_info]->reloc = s; - } - } - - /* resolve symbols */ - old_to_new_syms = tcc_mallocz(nb_syms * sizeof(int)); - - sym = symtab + 1; - for(i = 1; i < nb_syms; i++, sym++) { - if (sym->st_shndx != SHN_UNDEF && - sym->st_shndx < SHN_LORESERVE) { - sm = &sm_table[sym->st_shndx]; - if (sm->link_once) { - /* if a symbol is in a link once section, we use the - already defined symbol. It is very important to get - correct relocations */ - if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { - name = strtab + sym->st_name; - sym_index = find_elf_sym(symtab_section, name); - if (sym_index) - old_to_new_syms[i] = sym_index; - } - continue; - } - /* if no corresponding section added, no need to add symbol */ - if (!sm->s) - continue; - /* convert section number */ - sym->st_shndx = sm->s->sh_num; - /* offset value */ - sym->st_value += sm->offset; - } - /* add symbol */ - name = strtab + sym->st_name; - sym_index = set_elf_sym(symtab_section, sym->st_value, sym->st_size, - sym->st_info, sym->st_other, - sym->st_shndx, name); - old_to_new_syms[i] = sym_index; - } - - /* third pass to patch relocation entries */ - for(i = 1; i < ehdr.e_shnum; i++) { - s = sm_table[i].s; - if (!s) - continue; - sh = &shdr[i]; - offset = sm_table[i].offset; - size = sh->sh_size; - switch(s->sh_type) { - case SHT_RELX: - /* take relocation offset information */ - offseti = sm_table[sh->sh_info].offset; - for (rel = (ElfW_Rel *) s->data + (offset / sizeof(*rel)); - rel < (ElfW_Rel *) s->data + ((offset + size) / sizeof(*rel)); - rel++) { - int type; - unsigned sym_index; - /* convert symbol index */ - type = ELFW(R_TYPE)(rel->r_info); - sym_index = ELFW(R_SYM)(rel->r_info); - /* NOTE: only one symtab assumed */ - if (sym_index >= nb_syms) - goto invalid_reloc; - sym_index = old_to_new_syms[sym_index]; - /* ignore link_once in rel section. */ - if (!sym_index && !sm_table[sh->sh_info].link_once -#ifdef TCC_TARGET_ARM - && type != R_ARM_V4BX -#elif defined TCC_TARGET_RISCV64 - && type != R_RISCV_ALIGN - && type != R_RISCV_RELAX -#endif - ) { - invalid_reloc: - tcc_error_noabort("Invalid relocation entry [%2d] '%s' @ %.8x", - i, strsec + sh->sh_name, (int)rel->r_offset); - goto the_end; - } - rel->r_info = ELFW(R_INFO)(sym_index, type); - /* offset the relocation offset */ - rel->r_offset += offseti; -#ifdef TCC_TARGET_ARM - /* Jumps and branches from a Thumb code to a PLT entry need - special handling since PLT entries are ARM code. - Unconditional bl instructions referencing PLT entries are - handled by converting these instructions into blx - instructions. Other case of instructions referencing a PLT - entry require to add a Thumb stub before the PLT entry to - switch to ARM mode. We set bit plt_thumb_stub of the - attribute of a symbol to indicate such a case. */ - if (type == R_ARM_THM_JUMP24) - get_sym_attr(s1, sym_index, 1)->plt_thumb_stub = 1; -#endif - } - break; - default: - break; - } - } - - ret = 0; - the_end: - tcc_free(symtab); - tcc_free(strtab); - tcc_free(old_to_new_syms); - tcc_free(sm_table); - tcc_free(strsec); - tcc_free(shdr); - return ret; -} - -typedef struct ArchiveHeader { - char ar_name[16]; /* name of this member */ - char ar_date[12]; /* file mtime */ - char ar_uid[6]; /* owner uid; printed as decimal */ - char ar_gid[6]; /* owner gid; printed as decimal */ - char ar_mode[8]; /* file mode, printed as octal */ - char ar_size[10]; /* file size, printed as decimal */ - char ar_fmag[2]; /* should contain ARFMAG */ -} ArchiveHeader; - -#define ARFMAG "`\n" - -static unsigned long long get_be(const uint8_t *b, int n) -{ - unsigned long long ret = 0; - while (n) - ret = (ret << 8) | *b++, --n; - return ret; -} - -static int read_ar_header(int fd, int offset, ArchiveHeader *hdr) -{ - char *p, *e; - int len; - lseek(fd, offset, SEEK_SET); - len = full_read(fd, hdr, sizeof(ArchiveHeader)); - if (len != sizeof(ArchiveHeader)) - return len ? -1 : 0; - p = hdr->ar_name; - for (e = p + sizeof hdr->ar_name; e > p && e[-1] == ' ';) - --e; - *e = '\0'; - hdr->ar_size[sizeof hdr->ar_size-1] = 0; - return len; -} - -/* load only the objects which resolve undefined symbols */ -static int tcc_load_alacarte(TCCState *s1, int fd, int size, int entrysize) -{ - int i, bound, nsyms, sym_index, len, ret = -1; - unsigned long long off; - uint8_t *data; - const char *ar_names, *p; - const uint8_t *ar_index; - ElfW(Sym) *sym; - ArchiveHeader hdr; - - data = tcc_malloc(size); - if (full_read(fd, data, size) != size) - goto the_end; - nsyms = get_be(data, entrysize); - ar_index = data + entrysize; - ar_names = (char *) ar_index + nsyms * entrysize; - - do { - bound = 0; - for (p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) { - Section *s = symtab_section; - sym_index = find_elf_sym(s, p); - if (!sym_index) - continue; - sym = &((ElfW(Sym) *)s->data)[sym_index]; - if(sym->st_shndx != SHN_UNDEF) - continue; - off = get_be(ar_index + i * entrysize, entrysize); - len = read_ar_header(fd, off, &hdr); - if (len <= 0 || memcmp(hdr.ar_fmag, ARFMAG, 2)) { - tcc_error_noabort("invalid archive"); - goto the_end; - } - off += len; - if (s1->verbose == 2) - printf(" -> %s\n", hdr.ar_name); - if (tcc_load_object_file(s1, fd, off) < 0) - goto the_end; - ++bound; - } - } while(bound); - ret = 0; - the_end: - tcc_free(data); - return ret; -} - -/* load a '.a' file */ -ST_FUNC int tcc_load_archive(TCCState *s1, int fd, int alacarte) -{ - ArchiveHeader hdr; - /* char magic[8]; */ - int size, len; - unsigned long file_offset; - ElfW(Ehdr) ehdr; - - /* skip magic which was already checked */ - /* full_read(fd, magic, sizeof(magic)); */ - file_offset = sizeof ARMAG - 1; - - for(;;) { - len = read_ar_header(fd, file_offset, &hdr); - if (len == 0) - return 0; - if (len < 0) - return tcc_error_noabort("invalid archive"); - file_offset += len; - size = strtol(hdr.ar_size, NULL, 0); - /* align to even */ - size = (size + 1) & ~1; - if (alacarte) { - /* coff symbol table : we handle it */ - if (!strcmp(hdr.ar_name, "/")) - return tcc_load_alacarte(s1, fd, size, 4); - if (!strcmp(hdr.ar_name, "/SYM64/")) - return tcc_load_alacarte(s1, fd, size, 8); - } else if (tcc_object_type(fd, &ehdr) == AFF_BINTYPE_REL) { - if (s1->verbose == 2) - printf(" -> %s\n", hdr.ar_name); - if (tcc_load_object_file(s1, fd, file_offset) < 0) - return -1; - } - file_offset += size; - } -} - -#ifndef ELF_OBJ_ONLY -/* Set LV[I] to the global index of sym-version (LIB,VERSION). Maybe resizes - LV, maybe create a new entry for (LIB,VERSION). */ -static void set_ver_to_ver(TCCState *s1, int *n, int **lv, int i, char *lib, char *version) -{ - while (i >= *n) { - *lv = tcc_realloc(*lv, (*n + 1) * sizeof(**lv)); - (*lv)[(*n)++] = -1; - } - if ((*lv)[i] == -1) { - int v, prev_same_lib = -1; - for (v = 0; v < nb_sym_versions; v++) { - if (strcmp(sym_versions[v].lib, lib)) - continue; - prev_same_lib = v; - if (!strcmp(sym_versions[v].version, version)) - break; - } - if (v == nb_sym_versions) { - sym_versions = tcc_realloc (sym_versions, - (v + 1) * sizeof(*sym_versions)); - sym_versions[v].lib = tcc_strdup(lib); - sym_versions[v].version = tcc_strdup(version); - sym_versions[v].out_index = 0; - sym_versions[v].prev_same_lib = prev_same_lib; - nb_sym_versions++; - } - (*lv)[i] = v; - } -} - -/* Associates symbol SYM_INDEX (in dynsymtab) with sym-version index - VERNDX. */ -static void -set_sym_version(TCCState *s1, int sym_index, int verndx) -{ - if (sym_index >= nb_sym_to_version) { - int newelems = sym_index ? sym_index * 2 : 1; - sym_to_version = tcc_realloc(sym_to_version, - newelems * sizeof(*sym_to_version)); - memset(sym_to_version + nb_sym_to_version, -1, - (newelems - nb_sym_to_version) * sizeof(*sym_to_version)); - nb_sym_to_version = newelems; - } - if (sym_to_version[sym_index] < 0) - sym_to_version[sym_index] = verndx; -} - -struct versym_info { - int nb_versyms; - ElfW(Verdef) *verdef; - ElfW(Verneed) *verneed; - ElfW(Half) *versym; - int nb_local_ver, *local_ver; -}; - - -static void store_version(TCCState *s1, struct versym_info *v, char *dynstr) -{ - char *lib, *version; - uint32_t next; - int i; - -#define DEBUG_VERSION 0 - - if (v->versym && v->verdef) { - ElfW(Verdef) *vdef = v->verdef; - lib = NULL; - do { - ElfW(Verdaux) *verdaux = - (ElfW(Verdaux) *) (((char *) vdef) + vdef->vd_aux); - -#if DEBUG_VERSION - printf ("verdef: version:%u flags:%u index:%u, hash:%u\n", - vdef->vd_version, vdef->vd_flags, vdef->vd_ndx, - vdef->vd_hash); -#endif - if (vdef->vd_cnt) { - version = dynstr + verdaux->vda_name; - - if (lib == NULL) - lib = version; - else - set_ver_to_ver(s1, &v->nb_local_ver, &v->local_ver, vdef->vd_ndx, - lib, version); -#if DEBUG_VERSION - printf (" verdaux(%u): %s\n", vdef->vd_ndx, version); -#endif - } - next = vdef->vd_next; - vdef = (ElfW(Verdef) *) (((char *) vdef) + next); - } while (next); - } - if (v->versym && v->verneed) { - ElfW(Verneed) *vneed = v->verneed; - do { - ElfW(Vernaux) *vernaux = - (ElfW(Vernaux) *) (((char *) vneed) + vneed->vn_aux); - - lib = dynstr + vneed->vn_file; -#if DEBUG_VERSION - printf ("verneed: %u %s\n", vneed->vn_version, lib); -#endif - for (i = 0; i < vneed->vn_cnt; i++) { - if ((vernaux->vna_other & 0x8000) == 0) { /* hidden */ - version = dynstr + vernaux->vna_name; - set_ver_to_ver(s1, &v->nb_local_ver, &v->local_ver, vernaux->vna_other, - lib, version); -#if DEBUG_VERSION - printf (" vernaux(%u): %u %u %s\n", - vernaux->vna_other, vernaux->vna_hash, - vernaux->vna_flags, version); -#endif - } - vernaux = (ElfW(Vernaux) *) (((char *) vernaux) + vernaux->vna_next); - } - next = vneed->vn_next; - vneed = (ElfW(Verneed) *) (((char *) vneed) + next); - } while (next); - } - -#if DEBUG_VERSION - for (i = 0; i < v->nb_local_ver; i++) { - if (v->local_ver[i] > 0) { - printf ("%d: lib: %s, version %s\n", - i, sym_versions[v->local_ver[i]].lib, - sym_versions[v->local_ver[i]].version); - } - } -#endif -} - -/* load a DLL and all referenced DLLs. 'level = 0' means that the DLL - is referenced by the user (so it should be added as DT_NEEDED in - the generated ELF file) */ -ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level) -{ - ElfW(Ehdr) ehdr; - ElfW(Shdr) *shdr, *sh, *sh1; - int i, nb_syms, nb_dts, sym_bind, ret = -1; - ElfW(Sym) *sym, *dynsym; - ElfW(Dyn) *dt, *dynamic; - - char *dynstr; - int sym_index; - const char *name, *soname; - struct versym_info v; - - full_read(fd, &ehdr, sizeof(ehdr)); - - /* test CPU specific stuff */ - if (ehdr.e_ident[5] != ELFDATA2LSB || - ehdr.e_machine != EM_TCC_TARGET) { - return tcc_error_noabort("bad architecture"); - } - - /* read sections */ - shdr = load_data(fd, ehdr.e_shoff, sizeof(ElfW(Shdr)) * ehdr.e_shnum); - - /* load dynamic section and dynamic symbols */ - nb_syms = 0; - nb_dts = 0; - dynamic = NULL; - dynsym = NULL; /* avoid warning */ - dynstr = NULL; /* avoid warning */ - memset(&v, 0, sizeof v); - - for(i = 0, sh = shdr; i < ehdr.e_shnum; i++, sh++) { - switch(sh->sh_type) { - case SHT_DYNAMIC: - nb_dts = sh->sh_size / sizeof(ElfW(Dyn)); - dynamic = load_data(fd, sh->sh_offset, sh->sh_size); - break; - case SHT_DYNSYM: - nb_syms = sh->sh_size / sizeof(ElfW(Sym)); - dynsym = load_data(fd, sh->sh_offset, sh->sh_size); - sh1 = &shdr[sh->sh_link]; - dynstr = load_data(fd, sh1->sh_offset, sh1->sh_size); - break; - case SHT_GNU_verdef: - v.verdef = load_data(fd, sh->sh_offset, sh->sh_size); - break; - case SHT_GNU_verneed: - v.verneed = load_data(fd, sh->sh_offset, sh->sh_size); - break; - case SHT_GNU_versym: - v.nb_versyms = sh->sh_size / sizeof(ElfW(Half)); - v.versym = load_data(fd, sh->sh_offset, sh->sh_size); - break; - default: - break; - } - } - - if (!dynamic) - goto the_end; - - /* compute the real library name */ - soname = tcc_basename(filename); - for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) - if (dt->d_tag == DT_SONAME) - soname = dynstr + dt->d_un.d_val; - - /* if the dll is already loaded, do not load it */ - if (tcc_add_dllref(s1, soname, level)->found) - goto ret_success; - - if (v.nb_versyms != nb_syms) - tcc_free (v.versym), v.versym = NULL; - else - store_version(s1, &v, dynstr); - - /* add dynamic symbols in dynsym_section */ - for(i = 1, sym = dynsym + 1; i < nb_syms; i++, sym++) { - sym_bind = ELFW(ST_BIND)(sym->st_info); - if (sym_bind == STB_LOCAL) - continue; - name = dynstr + sym->st_name; - sym_index = set_elf_sym(s1->dynsymtab_section, sym->st_value, sym->st_size, - sym->st_info, sym->st_other, sym->st_shndx, name); - if (v.versym) { - ElfW(Half) vsym = v.versym[i]; - if ((vsym & 0x8000) == 0 && vsym > 0 && vsym < v.nb_local_ver) - set_sym_version(s1, sym_index, v.local_ver[vsym]); - } - } - - for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) - if (dt->d_tag == DT_RPATH) - tcc_add_library_path(s1, dynstr + dt->d_un.d_val); - - /* load all referenced DLLs */ - for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) { - switch(dt->d_tag) { - case DT_NEEDED: - name = dynstr + dt->d_un.d_val; - if (tcc_add_dllref(s1, name, -1)) - continue; - if (tcc_add_dll(s1, name, AFF_REFERENCED_DLL) < 0) { - ret = tcc_error_noabort("referenced dll '%s' not found", name); - goto the_end; - } - } - } - - ret_success: - ret = 0; - the_end: - tcc_free(dynstr); - tcc_free(dynsym); - tcc_free(dynamic); - tcc_free(shdr); - tcc_free(v.local_ver); - tcc_free(v.verdef); - tcc_free(v.verneed); - tcc_free(v.versym); - return ret; -} - -#define LD_TOK_NAME 256 -#define LD_TOK_EOF (-1) - -static int ld_inp(TCCState *s1) -{ - char b; - if (s1->cc != -1) { - int c = s1->cc; - s1->cc = -1; - return c; - } - if (1 == read(s1->fd, &b, 1)) - return b; - return CH_EOF; -} - -/* return next ld script token */ -static int ld_next(TCCState *s1, char *name, int name_size) -{ - int c, d, ch; - char *q; - - redo: - ch = ld_inp(s1); - switch(ch) { - case ' ': - case '\t': - case '\f': - case '\v': - case '\r': - case '\n': - goto redo; - case '/': - ch = ld_inp(s1); - if (ch == '*') { /* comment */ - for (d = 0;; d = ch) { - ch = ld_inp(s1); - if (ch == CH_EOF || (ch == '/' && d == '*')) - break; - } - goto redo; - } else { - q = name; - *q++ = '/'; - goto parse_name; - } - break; - case '\\': - /* case 'a' ... 'z': */ - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - case 'g': - case 'h': - case 'i': - case 'j': - case 'k': - case 'l': - case 'm': - case 'n': - case 'o': - case 'p': - case 'q': - case 'r': - case 's': - case 't': - case 'u': - case 'v': - case 'w': - case 'x': - case 'y': - case 'z': - /* case 'A' ... 'z': */ - case 'A': - case 'B': - case 'C': - case 'D': - case 'E': - case 'F': - case 'G': - case 'H': - case 'I': - case 'J': - case 'K': - case 'L': - case 'M': - case 'N': - case 'O': - case 'P': - case 'Q': - case 'R': - case 'S': - case 'T': - case 'U': - case 'V': - case 'W': - case 'X': - case 'Y': - case 'Z': - case '_': - case '.': - case '$': - case '~': - q = name; - parse_name: - for(;;) { - if (!((ch >= 'a' && ch <= 'z') || - (ch >= 'A' && ch <= 'Z') || - (ch >= '0' && ch <= '9') || - strchr("/.-_+=$:\\,~", ch))) - break; - if ((q - name) < name_size - 1) { - *q++ = ch; - } - ch = ld_inp(s1); - } - s1->cc = ch; - *q = '\0'; - c = LD_TOK_NAME; - break; - case CH_EOF: - c = LD_TOK_EOF; - break; - default: - c = ch; - break; - } - return c; -} - -static int ld_add_file(TCCState *s1, const char filename[]) -{ - if (filename[0] == '/') { - if (CONFIG_SYSROOT[0] == '\0' - && tcc_add_file_internal(s1, filename, AFF_TYPE_BIN) == 0) - return 0; - filename = tcc_basename(filename); - } - return tcc_add_dll(s1, filename, 0); -} - -static int ld_add_file_list(TCCState *s1, const char *cmd, int as_needed) -{ - char filename[1024], libname[1024]; - int t, group, nblibs = 0, ret = 0; - char **libs = NULL; - - group = !strcmp(cmd, "GROUP"); - if (!as_needed) - s1->new_undef_sym = 0; - t = ld_next(s1, filename, sizeof(filename)); - if (t != '(') { - ret = tcc_error_noabort("( expected"); - goto lib_parse_error; - } - t = ld_next(s1, filename, sizeof(filename)); - for(;;) { - libname[0] = '\0'; - if (t == LD_TOK_EOF) { - ret = tcc_error_noabort("unexpected end of file"); - goto lib_parse_error; - } else if (t == ')') { - break; - } else if (t == '-') { - t = ld_next(s1, filename, sizeof(filename)); - if ((t != LD_TOK_NAME) || (filename[0] != 'l')) { - ret = tcc_error_noabort("library name expected"); - goto lib_parse_error; - } - pstrcpy(libname, sizeof libname, &filename[1]); - if (s1->static_link) { - snprintf(filename, sizeof filename, "lib%s.a", libname); - } else { - snprintf(filename, sizeof filename, "lib%s.so", libname); - } - } else if (t != LD_TOK_NAME) { - ret = tcc_error_noabort("filename expected"); - goto lib_parse_error; - } - if (!strcmp(filename, "AS_NEEDED")) { - ret = ld_add_file_list(s1, cmd, 1); - if (ret) - goto lib_parse_error; - } else { - /* TODO: Implement AS_NEEDED support. Ignore it for now */ - if (!as_needed) { - ret = ld_add_file(s1, filename); - if (ret) - goto lib_parse_error; - if (group) { - /* Add the filename *and* the libname to avoid future conversions */ - dynarray_add(&libs, &nblibs, tcc_strdup(filename)); - if (libname[0] != '\0') - dynarray_add(&libs, &nblibs, tcc_strdup(libname)); - } - } - } - t = ld_next(s1, filename, sizeof(filename)); - if (t == ',') { - t = ld_next(s1, filename, sizeof(filename)); - } - } - if (group && !as_needed) { - while (s1->new_undef_sym) { - int i; - s1->new_undef_sym = 0; - for (i = 0; i < nblibs; i ++) - ld_add_file(s1, libs[i]); - } - } -lib_parse_error: - dynarray_reset(&libs, &nblibs); - return ret; -} - -/* interpret a subset of GNU ldscripts to handle the dummy libc.so - files */ -ST_FUNC int tcc_load_ldscript(TCCState *s1, int fd) -{ - char cmd[64]; - char filename[1024]; - int t, ret; - - s1->fd = fd; - s1->cc = -1; - for(;;) { - t = ld_next(s1, cmd, sizeof(cmd)); - if (t == LD_TOK_EOF) - return 0; - else if (t != LD_TOK_NAME) - return -1; - if (!strcmp(cmd, "INPUT") || - !strcmp(cmd, "GROUP")) { - ret = ld_add_file_list(s1, cmd, 0); - if (ret) - return ret; - } else if (!strcmp(cmd, "OUTPUT_FORMAT") || - !strcmp(cmd, "TARGET")) { - /* ignore some commands */ - t = ld_next(s1, cmd, sizeof(cmd)); - if (t != '(') - return tcc_error_noabort("( expected"); - for(;;) { - t = ld_next(s1, filename, sizeof(filename)); - if (t == LD_TOK_EOF) { - return tcc_error_noabort("unexpected end of file"); - } else if (t == ')') { - break; - } - } - } else { - return -1; - } - } - return 0; -} -#endif /* !ELF_OBJ_ONLY */ diff --git a/tinycc/tccgen.c b/tinycc/tccgen.c deleted file mode 100644 index c582c4a..0000000 --- a/tinycc/tccgen.c +++ /dev/null @@ -1,8678 +0,0 @@ -/* - * 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 - */ - -#define USING_GLOBALS -#include "tcc.h" - -/********************************************************/ -/* global variables */ - -/* loc : local variable index - ind : output code index - rsym: return symbol - anon_sym: anonymous symbol index -*/ -ST_DATA int rsym, anon_sym, ind, loc; - -ST_DATA Sym *global_stack; -ST_DATA Sym *local_stack; -ST_DATA Sym *define_stack; -ST_DATA Sym *global_label_stack; -ST_DATA Sym *local_label_stack; - -static Sym *sym_free_first; -static void **sym_pools; -static int nb_sym_pools; - -static Sym *all_cleanups, *pending_gotos; -static int local_scope; -static int in_sizeof; -static int constant_p; -ST_DATA char debug_modes; - -ST_DATA SValue *vtop; -static SValue _vstack[1 + VSTACK_SIZE]; -#define vstack (_vstack + 1) - -ST_DATA int nocode_wanted; /* no code generation wanted */ -#define NODATA_WANTED (nocode_wanted > 0) /* no static data output wanted either */ -#define DATA_ONLY_WANTED 0x80000000 /* ON outside of functions and for static initializers */ - -/* no code output after unconditional jumps such as with if (0) ... */ -#define CODE_OFF_BIT 0x20000000 -#define CODE_OFF() if(!nocode_wanted)(nocode_wanted |= CODE_OFF_BIT) -#define CODE_ON() (nocode_wanted &= ~CODE_OFF_BIT) - -/* no code output when parsing sizeof()/typeof() etc. (using nocode_wanted++/--) */ -#define NOEVAL_MASK 0x0000FFFF -#define NOEVAL_WANTED (nocode_wanted & NOEVAL_MASK) - -/* no code output when parsing constant expressions */ -#define CONST_WANTED_BIT 0x00010000 -#define CONST_WANTED_MASK 0x0FFF0000 -#define CONST_WANTED (nocode_wanted & CONST_WANTED_MASK) - -ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */ -ST_DATA CType func_vt; /* current function return type (used by return instruction) */ -ST_DATA int func_var; /* true if current function is variadic (used by return instruction) */ -ST_DATA int func_vc; -ST_DATA int func_ind; -ST_DATA const char *funcname; -ST_DATA CType int_type, func_old_type, char_type, char_pointer_type; -static CString initstr; - -#if PTR_SIZE == 4 -#define VT_SIZE_T (VT_INT | VT_UNSIGNED) -#define VT_PTRDIFF_T VT_INT -#elif LONG_SIZE == 4 -#define VT_SIZE_T (VT_LLONG | VT_UNSIGNED) -#define VT_PTRDIFF_T VT_LLONG -#else -#define VT_SIZE_T (VT_LONG | VT_LLONG | VT_UNSIGNED) -#define VT_PTRDIFF_T (VT_LONG | VT_LLONG) -#endif - -static struct switch_t { - struct case_t { - int64_t v1, v2; - int sym; - } **p; int n; /* list of case ranges */ - int def_sym; /* default symbol */ - int nocode_wanted; - int *bsym; - struct scope *scope; - struct switch_t *prev; - SValue sv; -} *cur_switch; /* current switch */ - -#define MAX_TEMP_LOCAL_VARIABLE_NUMBER 8 -/*list of temporary local variables on the stack in current function. */ -static struct temp_local_variable { - int location; //offset on stack. Svalue.c.i - short size; - short align; -} arr_temp_local_vars[MAX_TEMP_LOCAL_VARIABLE_NUMBER]; -static int nb_temp_local_vars; - -static struct scope { - struct scope *prev; - struct { int loc, locorig, num; } vla; - struct { Sym *s; int n; } cl; - int *bsym, *csym; - Sym *lstk, *llstk; -} *cur_scope, *loop_scope, *root_scope; - -typedef struct { - Section *sec; - int local_offset; - Sym *flex_array_ref; -} init_params; - -#if 1 -#define precedence_parser -static void init_prec(void); -#endif - -static void gen_cast(CType *type); -static void gen_cast_s(int t); -static inline CType *pointed_type(CType *type); -static int is_compatible_types(CType *type1, CType *type2); -static int parse_btype(CType *type, AttributeDef *ad, int ignore_label); -static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td); -static void parse_expr_type(CType *type); -static void init_putv(init_params *p, CType *type, unsigned long c); -static void decl_initializer(init_params *p, CType *type, unsigned long c, int flags); -static void block(int is_expr); -static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope); -static int decl(int l); -static void expr_eq(void); -static void vpush_type_size(CType *type, int *a); -static int is_compatible_unqualified_types(CType *type1, CType *type2); -static inline int64_t expr_const64(void); -static void vpush64(int ty, unsigned long long v); -static void vpush(CType *type); -static int gvtst(int inv, int t); -static void gen_inline_functions(TCCState *s); -static void free_inline_functions(TCCState *s); -static void skip_or_save_block(TokenString **str); -static void gv_dup(void); -static int get_temp_local_var(int size,int align); -static void clear_temp_local_var_list(); -static void cast_error(CType *st, CType *dt); - -/* ------------------------------------------------------------------------- */ -/* Automagical code suppression */ - -/* Clear 'nocode_wanted' at forward label if it was used */ -ST_FUNC void gsym(int t) -{ - if (t) { - gsym_addr(t, ind); - CODE_ON(); - } -} - -/* Clear 'nocode_wanted' if current pc is a label */ -static int gind() -{ - int t = ind; - CODE_ON(); - if (debug_modes) - tcc_tcov_block_begin(tcc_state); - return t; -} - -/* Set 'nocode_wanted' after unconditional (backwards) jump */ -static void gjmp_addr_acs(int t) -{ - gjmp_addr(t); - CODE_OFF(); -} - -/* Set 'nocode_wanted' after unconditional (forwards) jump */ -static int gjmp_acs(int t) -{ - t = gjmp(t); - CODE_OFF(); - return t; -} - -/* These are #undef'd at the end of this file */ -#define gjmp_addr gjmp_addr_acs -#define gjmp gjmp_acs -/* ------------------------------------------------------------------------- */ - -ST_INLN int is_float(int t) -{ - int bt = t & VT_BTYPE; - return bt == VT_LDOUBLE - || bt == VT_DOUBLE - || bt == VT_FLOAT - || bt == VT_QFLOAT; -} - -static inline int is_integer_btype(int bt) -{ - return bt == VT_BYTE - || bt == VT_BOOL - || bt == VT_SHORT - || bt == VT_INT - || bt == VT_LLONG; -} - -static int btype_size(int bt) -{ - return bt == VT_BYTE || bt == VT_BOOL ? 1 : - bt == VT_SHORT ? 2 : - bt == VT_INT ? 4 : - bt == VT_LLONG ? 8 : - bt == VT_PTR ? PTR_SIZE : 0; -} - -/* returns function return register from type */ -static int R_RET(int t) -{ - if (!is_float(t)) - return REG_IRET; -#ifdef TCC_TARGET_X86_64 - if ((t & VT_BTYPE) == VT_LDOUBLE) - return TREG_ST0; -#elif defined TCC_TARGET_RISCV64 - if ((t & VT_BTYPE) == VT_LDOUBLE) - return REG_IRET; -#endif - return REG_FRET; -} - -/* returns 2nd function return register, if any */ -static int R2_RET(int t) -{ - t &= VT_BTYPE; -#if PTR_SIZE == 4 - if (t == VT_LLONG) - return REG_IRE2; -#elif defined TCC_TARGET_X86_64 - if (t == VT_QLONG) - return REG_IRE2; - if (t == VT_QFLOAT) - return REG_FRE2; -#elif defined TCC_TARGET_RISCV64 - if (t == VT_LDOUBLE) - return REG_IRE2; -#endif - return VT_CONST; -} - -/* returns true for two-word types */ -#define USING_TWO_WORDS(t) (R2_RET(t) != VT_CONST) - -/* put function return registers to stack value */ -static void PUT_R_RET(SValue *sv, int t) -{ - sv->r = R_RET(t), sv->r2 = R2_RET(t); -} - -/* returns function return register class for type t */ -static int RC_RET(int t) -{ - return reg_classes[R_RET(t)] & ~(RC_FLOAT | RC_INT); -} - -/* returns generic register class for type t */ -static int RC_TYPE(int t) -{ - if (!is_float(t)) - return RC_INT; -#ifdef TCC_TARGET_X86_64 - if ((t & VT_BTYPE) == VT_LDOUBLE) - return RC_ST0; - if ((t & VT_BTYPE) == VT_QFLOAT) - return RC_FRET; -#elif defined TCC_TARGET_RISCV64 - if ((t & VT_BTYPE) == VT_LDOUBLE) - return RC_INT; -#endif - return RC_FLOAT; -} - -/* returns 2nd register class corresponding to t and rc */ -static int RC2_TYPE(int t, int rc) -{ - if (!USING_TWO_WORDS(t)) - return 0; -#ifdef RC_IRE2 - if (rc == RC_IRET) - return RC_IRE2; -#endif -#ifdef RC_FRE2 - if (rc == RC_FRET) - return RC_FRE2; -#endif - if (rc & RC_FLOAT) - return RC_FLOAT; - return RC_INT; -} - -/* we use our own 'finite' function to avoid potential problems with - non standard math libs */ -/* XXX: endianness dependent */ -ST_FUNC int ieee_finite(double d) -{ - int p[4]; - memcpy(p, &d, sizeof(double)); - return ((unsigned)((p[1] | 0x800fffff) + 1)) >> 31; -} - -/* compiling intel long double natively */ -#if (defined __i386__ || defined __x86_64__) \ - && (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64) -# define TCC_IS_NATIVE_387 -#endif - -ST_FUNC void test_lvalue(void) -{ - if (!(vtop->r & VT_LVAL)) - expect("lvalue"); -} - -ST_FUNC void check_vstack(void) -{ - if (vtop != vstack - 1) - tcc_error("internal compiler error: vstack leak (%d)", - (int)(vtop - vstack + 1)); -} - -/* vstack debugging aid */ -#if 0 -void pv (const char *lbl, int a, int b) -{ - int i; - for (i = a; i < a + b; ++i) { - SValue *p = &vtop[-i]; - printf("%s vtop[-%d] : type.t:%04x r:%04x r2:%04x c.i:%d\n", - lbl, i, p->type.t, p->r, p->r2, (int)p->c.i); - } -} -#endif - -/* ------------------------------------------------------------------------- */ -/* initialize vstack and types. This must be done also for tcc -E */ -ST_FUNC void tccgen_init(TCCState *s1) -{ - vtop = vstack - 1; - memset(vtop, 0, sizeof *vtop); - - /* define some often used types */ - int_type.t = VT_INT; - - char_type.t = VT_BYTE; - if (s1->char_is_unsigned) - char_type.t |= VT_UNSIGNED; - char_pointer_type = char_type; - mk_pointer(&char_pointer_type); - - func_old_type.t = VT_FUNC; - func_old_type.ref = sym_push(SYM_FIELD, &int_type, 0, 0); - func_old_type.ref->f.func_call = FUNC_CDECL; - func_old_type.ref->f.func_type = FUNC_OLD; -#ifdef precedence_parser - init_prec(); -#endif - cstr_new(&initstr); -} - -ST_FUNC int tccgen_compile(TCCState *s1) -{ - cur_text_section = NULL; - funcname = ""; - func_ind = -1; - anon_sym = SYM_FIRST_ANOM; - nocode_wanted = DATA_ONLY_WANTED; /* no code outside of functions */ - local_scope = 0; - debug_modes = (s1->do_debug ? 1 : 0) | s1->test_coverage << 1; - - tcc_debug_start(s1); - tcc_tcov_start (s1); -#ifdef TCC_TARGET_ARM - arm_init(s1); -#endif -#ifdef INC_DEBUG - printf("%s: **** new file\n", file->filename); -#endif - parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | PARSE_FLAG_TOK_STR; - next(); - decl(VT_CONST); - gen_inline_functions(s1); - check_vstack(); - /* end of translation unit info */ - tcc_debug_end(s1); - tcc_tcov_end(s1); - return 0; -} - -ST_FUNC void tccgen_finish(TCCState *s1) -{ - tcc_debug_end(s1); /* just in case of errors: free memory */ - free_inline_functions(s1); - sym_pop(&global_stack, NULL, 0); - sym_pop(&local_stack, NULL, 0); - /* free preprocessor macros */ - free_defines(NULL); - /* free sym_pools */ - dynarray_reset(&sym_pools, &nb_sym_pools); - sym_free_first = NULL; - global_label_stack = local_label_stack = NULL; - cstr_free(&initstr); - dynarray_reset(&stk_data, &nb_stk_data); -} - -/* ------------------------------------------------------------------------- */ -ST_FUNC ElfSym *elfsym(Sym *s) -{ - if (!s || !s->c) - return NULL; - return &((ElfSym *)symtab_section->data)[s->c]; -} - -/* apply storage attributes to Elf symbol */ -ST_FUNC void update_storage(Sym *sym) -{ - ElfSym *esym; - int sym_bind, old_sym_bind; - - esym = elfsym(sym); - if (!esym) - return; - - if (sym->a.visibility) - esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) - | sym->a.visibility; - - if (sym->type.t & (VT_STATIC | VT_INLINE)) - sym_bind = STB_LOCAL; - else if (sym->a.weak) - sym_bind = STB_WEAK; - else - sym_bind = STB_GLOBAL; - old_sym_bind = ELFW(ST_BIND)(esym->st_info); - if (sym_bind != old_sym_bind) { - esym->st_info = ELFW(ST_INFO)(sym_bind, ELFW(ST_TYPE)(esym->st_info)); - } - -#ifdef TCC_TARGET_PE - if (sym->a.dllimport) - esym->st_other |= ST_PE_IMPORT; - if (sym->a.dllexport) - esym->st_other |= ST_PE_EXPORT; -#endif - -#if 0 - printf("storage %s: bind=%c vis=%d exp=%d imp=%d\n", - get_tok_str(sym->v, NULL), - sym_bind == STB_WEAK ? 'w' : sym_bind == STB_LOCAL ? 'l' : 'g', - sym->a.visibility, - sym->a.dllexport, - sym->a.dllimport - ); -#endif -} - -/* ------------------------------------------------------------------------- */ -/* update sym->c so that it points to an external symbol in section - 'section' with value 'value' */ - -ST_FUNC void put_extern_sym2(Sym *sym, int sh_num, - addr_t value, unsigned long size, - int can_add_underscore) -{ - int sym_type, sym_bind, info, other, t; - ElfSym *esym; - const char *name; - char buf1[256]; - - if (!sym->c) { - name = get_tok_str(sym->v, NULL); - t = sym->type.t; - if ((t & VT_BTYPE) == VT_FUNC) { - sym_type = STT_FUNC; - } else if ((t & VT_BTYPE) == VT_VOID) { - sym_type = STT_NOTYPE; - if ((t & (VT_BTYPE|VT_ASM_FUNC)) == VT_ASM_FUNC) - sym_type = STT_FUNC; - } else { - sym_type = STT_OBJECT; - } - if (t & (VT_STATIC | VT_INLINE)) - sym_bind = STB_LOCAL; - else - sym_bind = STB_GLOBAL; - other = 0; - -#ifdef TCC_TARGET_PE - if (sym_type == STT_FUNC && sym->type.ref) { - Sym *ref = sym->type.ref; - if (ref->a.nodecorate) { - can_add_underscore = 0; - } - if (ref->f.func_call == FUNC_STDCALL && can_add_underscore) { - sprintf(buf1, "_%s@%d", name, ref->f.func_args * PTR_SIZE); - name = buf1; - other |= ST_PE_STDCALL; - can_add_underscore = 0; - } - } -#endif - - if (sym->asm_label) { - name = get_tok_str(sym->asm_label, NULL); - can_add_underscore = 0; - } - - if (tcc_state->leading_underscore && can_add_underscore) { - buf1[0] = '_'; - pstrcpy(buf1 + 1, sizeof(buf1) - 1, name); - name = buf1; - } - - info = ELFW(ST_INFO)(sym_bind, sym_type); - sym->c = put_elf_sym(symtab_section, value, size, info, other, sh_num, name); - - if (debug_modes) - tcc_debug_extern_sym(tcc_state, sym, sh_num, sym_bind, sym_type); - - } else { - esym = elfsym(sym); - esym->st_value = value; - esym->st_size = size; - esym->st_shndx = sh_num; - } - update_storage(sym); -} - -ST_FUNC void put_extern_sym(Sym *sym, Section *s, addr_t value, unsigned long size) -{ - if (nocode_wanted && (NODATA_WANTED || (s && s == cur_text_section))) - return; - put_extern_sym2(sym, s ? s->sh_num : SHN_UNDEF, value, size, 1); -} - -/* add a new relocation entry to symbol 'sym' in section 's' */ -ST_FUNC void greloca(Section *s, Sym *sym, unsigned long offset, int type, - addr_t addend) -{ - int c = 0; - - if (nocode_wanted && s == cur_text_section) - return; - - if (sym) { - if (0 == sym->c) - put_extern_sym(sym, NULL, 0, 0); - c = sym->c; - } - - /* now we can add ELF relocation info */ - put_elf_reloca(symtab_section, s, offset, type, c, addend); -} - -#if PTR_SIZE == 4 -ST_FUNC void greloc(Section *s, Sym *sym, unsigned long offset, int type) -{ - greloca(s, sym, offset, type, 0); -} -#endif - -/* ------------------------------------------------------------------------- */ -/* symbol allocator */ -static Sym *__sym_malloc(void) -{ - Sym *sym_pool, *sym, *last_sym; - int i; - - sym_pool = tcc_malloc(SYM_POOL_NB * sizeof(Sym)); - dynarray_add(&sym_pools, &nb_sym_pools, sym_pool); - - last_sym = sym_free_first; - sym = sym_pool; - for(i = 0; i < SYM_POOL_NB; i++) { - sym->next = last_sym; - last_sym = sym; - sym++; - } - sym_free_first = last_sym; - return last_sym; -} - -static inline Sym *sym_malloc(void) -{ - Sym *sym; -#ifndef SYM_DEBUG - sym = sym_free_first; - if (!sym) - sym = __sym_malloc(); - sym_free_first = sym->next; - return sym; -#else - sym = tcc_malloc(sizeof(Sym)); - return sym; -#endif -} - -ST_INLN void sym_free(Sym *sym) -{ -#ifndef SYM_DEBUG - sym->next = sym_free_first; - sym_free_first = sym; -#else - tcc_free(sym); -#endif -} - -/* push, without hashing */ -ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, int c) -{ - Sym *s; - - s = sym_malloc(); - memset(s, 0, sizeof *s); - s->v = v; - s->type.t = t; - s->c = c; - /* add in stack */ - s->prev = *ps; - *ps = s; - return s; -} - -/* find a symbol and return its associated structure. 's' is the top - of the symbol stack */ -ST_FUNC Sym *sym_find2(Sym *s, int v) -{ - while (s) { - if (s->v == v) - return s; - else if (s->v == -1) - return NULL; - s = s->prev; - } - return NULL; -} - -/* structure lookup */ -ST_INLN Sym *struct_find(int v) -{ - v -= TOK_IDENT; - if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) - return NULL; - return table_ident[v]->sym_struct; -} - -/* find an identifier */ -ST_INLN Sym *sym_find(int v) -{ - v -= TOK_IDENT; - if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) - return NULL; - return table_ident[v]->sym_identifier; -} - -static int sym_scope(Sym *s) -{ - if (IS_ENUM_VAL (s->type.t)) - return s->type.ref->sym_scope; - else - return s->sym_scope; -} - -/* push a given symbol on the symbol stack */ -ST_FUNC Sym *sym_push(int v, CType *type, int r, int c) -{ - Sym *s, **ps; - TokenSym *ts; - - if (local_stack) - ps = &local_stack; - else - ps = &global_stack; - s = sym_push2(ps, v, type->t, c); - s->type.ref = type->ref; - s->r = r; - /* don't record fields or anonymous symbols */ - /* XXX: simplify */ - if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { - /* record symbol in token array */ - ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT]; - if (v & SYM_STRUCT) - ps = &ts->sym_struct; - else - ps = &ts->sym_identifier; - s->prev_tok = *ps; - *ps = s; - s->sym_scope = local_scope; - if (s->prev_tok && sym_scope(s->prev_tok) == s->sym_scope) - tcc_error("redeclaration of '%s'", - get_tok_str(v & ~SYM_STRUCT, NULL)); - } - return s; -} - -/* push a global identifier */ -ST_FUNC Sym *global_identifier_push(int v, int t, int c) -{ - Sym *s, **ps; - s = sym_push2(&global_stack, v, t, c); - s->r = VT_CONST | VT_SYM; - /* don't record anonymous symbol */ - if (v < SYM_FIRST_ANOM) { - ps = &table_ident[v - TOK_IDENT]->sym_identifier; - /* modify the top most local identifier, so that sym_identifier will - point to 's' when popped; happens when called from inline asm */ - while (*ps != NULL && (*ps)->sym_scope) - ps = &(*ps)->prev_tok; - s->prev_tok = *ps; - *ps = s; - } - return s; -} - -/* pop symbols until top reaches 'b'. If KEEP is non-zero don't really - pop them yet from the list, but do remove them from the token array. */ -ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep) -{ - Sym *s, *ss, **ps; - TokenSym *ts; - int v; - - s = *ptop; - while(s != b) { - ss = s->prev; - v = s->v; - /* remove symbol in token array */ - /* XXX: simplify */ - if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { - ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT]; - if (v & SYM_STRUCT) - ps = &ts->sym_struct; - else - ps = &ts->sym_identifier; - *ps = s->prev_tok; - } - if (!keep) - sym_free(s); - s = ss; - } - if (!keep) - *ptop = b; -} - -/* label lookup */ -ST_FUNC Sym *label_find(int v) -{ - v -= TOK_IDENT; - if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) - return NULL; - return table_ident[v]->sym_label; -} - -ST_FUNC Sym *label_push(Sym **ptop, int v, int flags) -{ - Sym *s, **ps; - s = sym_push2(ptop, v, VT_STATIC, 0); - s->r = flags; - ps = &table_ident[v - TOK_IDENT]->sym_label; - if (ptop == &global_label_stack) { - /* modify the top most local identifier, so that - sym_identifier will point to 's' when popped */ - while (*ps != NULL) - ps = &(*ps)->prev_tok; - } - s->prev_tok = *ps; - *ps = s; - return s; -} - -/* pop labels until element last is reached. Look if any labels are - undefined. Define symbols if '&&label' was used. */ -ST_FUNC void label_pop(Sym **ptop, Sym *slast, int keep) -{ - Sym *s, *s1; - for(s = *ptop; s != slast; s = s1) { - s1 = s->prev; - if (s->r == LABEL_DECLARED) { - tcc_warning_c(warn_all)("label '%s' declared but not used", get_tok_str(s->v, NULL)); - } else if (s->r == LABEL_FORWARD) { - tcc_error("label '%s' used but not defined", - get_tok_str(s->v, NULL)); - } else { - if (s->c) { - /* define corresponding symbol. A size of - 1 is put. */ - put_extern_sym(s, cur_text_section, s->jnext, 1); - } - } - /* remove label */ - if (s->r != LABEL_GONE) - table_ident[s->v - TOK_IDENT]->sym_label = s->prev_tok; - if (!keep) - sym_free(s); - else - s->r = LABEL_GONE; - } - if (!keep) - *ptop = slast; -} - -/* ------------------------------------------------------------------------- */ -static void vcheck_cmp(void) -{ - /* cannot let cpu flags if other instruction are generated. Also - avoid leaving VT_JMP anywhere except on the top of the stack - because it would complicate the code generator. - - Don't do this when nocode_wanted. vtop might come from - !nocode_wanted regions (see 88_codeopt.c) and transforming - it to a register without actually generating code is wrong - as their value might still be used for real. All values - we push under nocode_wanted will eventually be popped - again, so that the VT_CMP/VT_JMP value will be in vtop - when code is unsuppressed again. */ - - /* However if it's just automatic suppression via CODE_OFF/ON() - then it seems that we better let things work undisturbed. - How can it work at all under nocode_wanted? Well, gv() will - actually clear it at the gsym() in load()/VT_JMP in the - generator backends */ - - if (vtop->r == VT_CMP && 0 == (nocode_wanted & ~CODE_OFF_BIT)) - gv(RC_INT); -} - -static void vsetc(CType *type, int r, CValue *vc) -{ - if (vtop >= vstack + (VSTACK_SIZE - 1)) - tcc_error("memory full (vstack)"); - vcheck_cmp(); - vtop++; - vtop->type = *type; - vtop->r = r; - vtop->r2 = VT_CONST; - vtop->c = *vc; - vtop->sym = NULL; -} - -ST_FUNC void vswap(void) -{ - SValue tmp; - - vcheck_cmp(); - tmp = vtop[0]; - vtop[0] = vtop[-1]; - vtop[-1] = tmp; -} - -/* pop stack value */ -ST_FUNC void vpop(void) -{ - int v; - v = vtop->r & VT_VALMASK; -#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) - /* for x86, we need to pop the FP stack */ - if (v == TREG_ST0) { - o(0xd8dd); /* fstp %st(0) */ - } else -#endif - if (v == VT_CMP) { - /* need to put correct jump if && or || without test */ - gsym(vtop->jtrue); - gsym(vtop->jfalse); - } - vtop--; -} - -/* push constant of type "type" with useless value */ -static void vpush(CType *type) -{ - vset(type, VT_CONST, 0); -} - -/* push arbitrary 64bit constant */ -static void vpush64(int ty, unsigned long long v) -{ - CValue cval; - CType ctype; - ctype.t = ty; - ctype.ref = NULL; - cval.i = v; - vsetc(&ctype, VT_CONST, &cval); -} - -/* push integer constant */ -ST_FUNC void vpushi(int v) -{ - vpush64(VT_INT, v); -} - -/* push a pointer sized constant */ -static void vpushs(addr_t v) -{ - vpush64(VT_SIZE_T, v); -} - -/* push long long constant */ -static inline void vpushll(long long v) -{ - vpush64(VT_LLONG, v); -} - -ST_FUNC void vset(CType *type, int r, int v) -{ - CValue cval; - cval.i = v; - vsetc(type, r, &cval); -} - -static void vseti(int r, int v) -{ - CType type; - type.t = VT_INT; - type.ref = NULL; - vset(&type, r, v); -} - -ST_FUNC void vpushv(SValue *v) -{ - if (vtop >= vstack + (VSTACK_SIZE - 1)) - tcc_error("memory full (vstack)"); - vtop++; - *vtop = *v; -} - -static void vdup(void) -{ - vpushv(vtop); -} - -/* rotate n first stack elements to the bottom - I1 ... In -> I2 ... In I1 [top is right] -*/ -ST_FUNC void vrotb(int n) -{ - int i; - SValue tmp; - - vcheck_cmp(); - tmp = vtop[-n + 1]; - for(i=-n+1;i!=0;i++) - vtop[i] = vtop[i+1]; - vtop[0] = tmp; -} - -/* rotate the n elements before entry e towards the top - I1 ... In ... -> In I1 ... I(n-1) ... [top is right] - */ -ST_FUNC void vrote(SValue *e, int n) -{ - int i; - SValue tmp; - - vcheck_cmp(); - tmp = *e; - for(i = 0;i < n - 1; i++) - e[-i] = e[-i - 1]; - e[-n + 1] = tmp; -} - -/* rotate n first stack elements to the top - I1 ... In -> In I1 ... I(n-1) [top is right] - */ -ST_FUNC void vrott(int n) -{ - vrote(vtop, n); -} - -/* ------------------------------------------------------------------------- */ -/* vtop->r = VT_CMP means CPU-flags have been set from comparison or test. */ - -/* called from generators to set the result from relational ops */ -ST_FUNC void vset_VT_CMP(int op) -{ - vtop->r = VT_CMP; - vtop->cmp_op = op; - vtop->jfalse = 0; - vtop->jtrue = 0; -} - -/* called once before asking generators to load VT_CMP to a register */ -static void vset_VT_JMP(void) -{ - int op = vtop->cmp_op; - - if (vtop->jtrue || vtop->jfalse) { - int origt = vtop->type.t; - /* we need to jump to 'mov $0,%R' or 'mov $1,%R' */ - int inv = op & (op < 2); /* small optimization */ - vseti(VT_JMP+inv, gvtst(inv, 0)); - vtop->type.t |= origt & (VT_UNSIGNED | VT_DEFSIGN); - } else { - /* otherwise convert flags (rsp. 0/1) to register */ - vtop->c.i = op; - if (op < 2) /* doesn't seem to happen */ - vtop->r = VT_CONST; - } -} - -/* Set CPU Flags, doesn't yet jump */ -static void gvtst_set(int inv, int t) -{ - int *p; - - if (vtop->r != VT_CMP) { - vpushi(0); - gen_op(TOK_NE); - if (vtop->r != VT_CMP) /* must be VT_CONST then */ - vset_VT_CMP(vtop->c.i != 0); - } - - p = inv ? &vtop->jfalse : &vtop->jtrue; - *p = gjmp_append(*p, t); -} - -/* Generate value test - * - * Generate a test for any value (jump, comparison and integers) */ -static int gvtst(int inv, int t) -{ - int op, x, u; - - gvtst_set(inv, t); - t = vtop->jtrue, u = vtop->jfalse; - if (inv) - x = u, u = t, t = x; - op = vtop->cmp_op; - - /* jump to the wanted target */ - if (op > 1) - t = gjmp_cond(op ^ inv, t); - else if (op != inv) - t = gjmp(t); - /* resolve complementary jumps to here */ - gsym(u); - - vtop--; - return t; -} - -/* generate a zero or nozero test */ -static void gen_test_zero(int op) -{ - if (vtop->r == VT_CMP) { - int j; - if (op == TOK_EQ) { - j = vtop->jfalse; - vtop->jfalse = vtop->jtrue; - vtop->jtrue = j; - vtop->cmp_op ^= 1; - } - } else { - vpushi(0); - gen_op(op); - } -} - -/* ------------------------------------------------------------------------- */ -/* push a symbol value of TYPE */ -ST_FUNC void vpushsym(CType *type, Sym *sym) -{ - CValue cval; - cval.i = 0; - vsetc(type, VT_CONST | VT_SYM, &cval); - vtop->sym = sym; -} - -/* Return a static symbol pointing to a section */ -ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsigned long size) -{ - int v; - Sym *sym; - - v = anon_sym++; - sym = sym_push(v, type, VT_CONST | VT_SYM, 0); - sym->type.t |= VT_STATIC; - put_extern_sym(sym, sec, offset, size); - return sym; -} - -/* push a reference to a section offset by adding a dummy symbol */ -static void vpush_ref(CType *type, Section *sec, unsigned long offset, unsigned long size) -{ - vpushsym(type, get_sym_ref(type, sec, offset, size)); -} - -/* define a new external reference to a symbol 'v' of type 'u' */ -ST_FUNC Sym *external_global_sym(int v, CType *type) -{ - Sym *s; - - s = sym_find(v); - if (!s) { - /* push forward reference */ - s = global_identifier_push(v, type->t | VT_EXTERN, 0); - s->type.ref = type->ref; - } else if (IS_ASM_SYM(s)) { - s->type.t = type->t | (s->type.t & VT_EXTERN); - s->type.ref = type->ref; - update_storage(s); - } - return s; -} - -/* create an external reference with no specific type similar to asm labels. - This avoids type conflicts if the symbol is used from C too */ -ST_FUNC Sym *external_helper_sym(int v) -{ - CType ct = { VT_ASM_FUNC, NULL }; - return external_global_sym(v, &ct); -} - -/* push a reference to an helper function (such as memmove) */ -ST_FUNC void vpush_helper_func(int v) -{ - vpushsym(&func_old_type, external_helper_sym(v)); -} - -/* Merge symbol attributes. */ -static void merge_symattr(struct SymAttr *sa, struct SymAttr *sa1) -{ - if (sa1->aligned && !sa->aligned) - sa->aligned = sa1->aligned; - sa->packed |= sa1->packed; - sa->weak |= sa1->weak; - sa->nodebug |= sa1->nodebug; - if (sa1->visibility != STV_DEFAULT) { - int vis = sa->visibility; - if (vis == STV_DEFAULT - || vis > sa1->visibility) - vis = sa1->visibility; - sa->visibility = vis; - } - sa->dllexport |= sa1->dllexport; - sa->nodecorate |= sa1->nodecorate; - sa->dllimport |= sa1->dllimport; -} - -/* Merge function attributes. */ -static void merge_funcattr(struct FuncAttr *fa, struct FuncAttr *fa1) -{ - if (fa1->func_call && !fa->func_call) - fa->func_call = fa1->func_call; - if (fa1->func_type && !fa->func_type) - fa->func_type = fa1->func_type; - if (fa1->func_args && !fa->func_args) - fa->func_args = fa1->func_args; - if (fa1->func_noreturn) - fa->func_noreturn = 1; - if (fa1->func_ctor) - fa->func_ctor = 1; - if (fa1->func_dtor) - fa->func_dtor = 1; -} - -/* Merge attributes. */ -static void merge_attr(AttributeDef *ad, AttributeDef *ad1) -{ - merge_symattr(&ad->a, &ad1->a); - merge_funcattr(&ad->f, &ad1->f); - - if (ad1->section) - ad->section = ad1->section; - if (ad1->alias_target) - ad->alias_target = ad1->alias_target; - if (ad1->asm_label) - ad->asm_label = ad1->asm_label; - if (ad1->attr_mode) - ad->attr_mode = ad1->attr_mode; -} - -/* Merge some type attributes. */ -static void patch_type(Sym *sym, CType *type) -{ - if (!(type->t & VT_EXTERN) || IS_ENUM_VAL(sym->type.t)) { - if (!(sym->type.t & VT_EXTERN)) - tcc_error("redefinition of '%s'", get_tok_str(sym->v, NULL)); - sym->type.t &= ~VT_EXTERN; - } - - if (IS_ASM_SYM(sym)) { - /* stay static if both are static */ - sym->type.t = type->t & (sym->type.t | ~VT_STATIC); - sym->type.ref = type->ref; - } - - if (!is_compatible_types(&sym->type, type)) { - tcc_error("incompatible types for redefinition of '%s'", - get_tok_str(sym->v, NULL)); - - } else if ((sym->type.t & VT_BTYPE) == VT_FUNC) { - int static_proto = sym->type.t & VT_STATIC; - /* warn if static follows non-static function declaration */ - if ((type->t & VT_STATIC) && !static_proto - /* XXX this test for inline shouldn't be here. Until we - implement gnu-inline mode again it silences a warning for - mingw caused by our workarounds. */ - && !((type->t | sym->type.t) & VT_INLINE)) - tcc_warning("static storage ignored for redefinition of '%s'", - get_tok_str(sym->v, NULL)); - - /* set 'inline' if both agree or if one has static */ - if ((type->t | sym->type.t) & VT_INLINE) { - if (!((type->t ^ sym->type.t) & VT_INLINE) - || ((type->t | sym->type.t) & VT_STATIC)) - static_proto |= VT_INLINE; - } - - if (0 == (type->t & VT_EXTERN)) { - struct FuncAttr f = sym->type.ref->f; - /* put complete type, use static from prototype */ - sym->type.t = (type->t & ~(VT_STATIC|VT_INLINE)) | static_proto; - sym->type.ref = type->ref; - merge_funcattr(&sym->type.ref->f, &f); - } else { - sym->type.t &= ~VT_INLINE | static_proto; - } - - if (sym->type.ref->f.func_type == FUNC_OLD - && type->ref->f.func_type != FUNC_OLD) { - sym->type.ref = type->ref; - } - - } else { - if ((sym->type.t & VT_ARRAY) && type->ref->c >= 0) { - /* set array size if it was omitted in extern declaration */ - sym->type.ref->c = type->ref->c; - } - if ((type->t ^ sym->type.t) & VT_STATIC) - tcc_warning("storage mismatch for redefinition of '%s'", - get_tok_str(sym->v, NULL)); - } -} - -/* Merge some storage attributes. */ -static void patch_storage(Sym *sym, AttributeDef *ad, CType *type) -{ - if (type) - patch_type(sym, type); - -#ifdef TCC_TARGET_PE - if (sym->a.dllimport != ad->a.dllimport) - tcc_error("incompatible dll linkage for redefinition of '%s'", - get_tok_str(sym->v, NULL)); -#endif - merge_symattr(&sym->a, &ad->a); - if (ad->asm_label) - sym->asm_label = ad->asm_label; - update_storage(sym); -} - -/* copy sym to other stack */ -static Sym *sym_copy(Sym *s0, Sym **ps) -{ - Sym *s; - s = sym_malloc(), *s = *s0; - s->prev = *ps, *ps = s; - if (s->v < SYM_FIRST_ANOM) { - ps = &table_ident[s->v - TOK_IDENT]->sym_identifier; - s->prev_tok = *ps, *ps = s; - } - return s; -} - -/* copy s->type.ref to stack 'ps' for VT_FUNC and VT_PTR */ -static void sym_copy_ref(Sym *s, Sym **ps) -{ - int bt = s->type.t & VT_BTYPE; - if (bt == VT_FUNC || bt == VT_PTR || (bt == VT_STRUCT && s->sym_scope)) { - Sym **sp = &s->type.ref; - for (s = *sp, *sp = NULL; s; s = s->next) { - Sym *s2 = sym_copy(s, ps); - sp = &(*sp = s2)->next; - sym_copy_ref(s2, ps); - } - } -} - -/* define a new external reference to a symbol 'v' */ -static Sym *external_sym(int v, CType *type, int r, AttributeDef *ad) -{ - Sym *s; - - /* look for global symbol */ - s = sym_find(v); - while (s && s->sym_scope) - s = s->prev_tok; - - if (!s) { - /* push forward reference */ - s = global_identifier_push(v, type->t, 0); - s->r |= r; - s->a = ad->a; - s->asm_label = ad->asm_label; - s->type.ref = type->ref; - /* copy type to the global stack */ - if (local_stack) - sym_copy_ref(s, &global_stack); - } else { - patch_storage(s, ad, type); - } - /* push variables on local_stack if any */ - if (local_stack && (s->type.t & VT_BTYPE) != VT_FUNC) - s = sym_copy(s, &local_stack); - return s; -} - -/* save registers up to (vtop - n) stack entry */ -ST_FUNC void save_regs(int n) -{ - SValue *p, *p1; - for(p = vstack, p1 = vtop - n; p <= p1; p++) - save_reg(p->r); -} - -/* save r to the memory stack, and mark it as being free */ -ST_FUNC void save_reg(int r) -{ - save_reg_upstack(r, 0); -} - -/* save r to the memory stack, and mark it as being free, - if seen up to (vtop - n) stack entry */ -ST_FUNC void save_reg_upstack(int r, int n) -{ - int l, size, align, bt; - SValue *p, *p1, sv; - - if ((r &= VT_VALMASK) >= VT_CONST) - return; - if (nocode_wanted) - return; - l = 0; - for(p = vstack, p1 = vtop - n; p <= p1; p++) { - if ((p->r & VT_VALMASK) == r || p->r2 == r) { - /* must save value on stack if not already done */ - if (!l) { - bt = p->type.t & VT_BTYPE; - if (bt == VT_VOID) - continue; - if ((p->r & VT_LVAL) || bt == VT_FUNC) - bt = VT_PTR; - sv.type.t = bt; - size = type_size(&sv.type, &align); - l = get_temp_local_var(size,align); - sv.r = VT_LOCAL | VT_LVAL; - sv.c.i = l; - store(p->r & VT_VALMASK, &sv); -#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) - /* x86 specific: need to pop fp register ST0 if saved */ - if (r == TREG_ST0) { - o(0xd8dd); /* fstp %st(0) */ - } -#endif - /* special long long case */ - if (p->r2 < VT_CONST && USING_TWO_WORDS(bt)) { - sv.c.i += PTR_SIZE; - store(p->r2, &sv); - } - } - /* mark that stack entry as being saved on the stack */ - if (p->r & VT_LVAL) { - /* also clear the bounded flag because the - relocation address of the function was stored in - p->c.i */ - p->r = (p->r & ~(VT_VALMASK | VT_BOUNDED)) | VT_LLOCAL; - } else { - p->r = VT_LVAL | VT_LOCAL; - } - p->sym = NULL; - p->r2 = VT_CONST; - p->c.i = l; - } - } -} - -#ifdef TCC_TARGET_ARM -/* find a register of class 'rc2' with at most one reference on stack. - * If none, call get_reg(rc) */ -ST_FUNC int get_reg_ex(int rc, int rc2) -{ - int r; - SValue *p; - - for(r=0;r<NB_REGS;r++) { - if (reg_classes[r] & rc2) { - int n; - n=0; - for(p = vstack; p <= vtop; p++) { - if ((p->r & VT_VALMASK) == r || - p->r2 == r) - n++; - } - if (n <= 1) - return r; - } - } - return get_reg(rc); -} -#endif - -/* find a free register of class 'rc'. If none, save one register */ -ST_FUNC int get_reg(int rc) -{ - int r; - SValue *p; - - /* find a free register */ - for(r=0;r<NB_REGS;r++) { - if (reg_classes[r] & rc) { - if (nocode_wanted) - return r; - for(p=vstack;p<=vtop;p++) { - if ((p->r & VT_VALMASK) == r || - p->r2 == r) - goto notfound; - } - return r; - } - notfound: ; - } - - /* no register left : free the first one on the stack (VERY - IMPORTANT to start from the bottom to ensure that we don't - spill registers used in gen_opi()) */ - for(p=vstack;p<=vtop;p++) { - /* look at second register (if long long) */ - r = p->r2; - if (r < VT_CONST && (reg_classes[r] & rc)) - goto save_found; - r = p->r & VT_VALMASK; - if (r < VT_CONST && (reg_classes[r] & rc)) { - save_found: - save_reg(r); - return r; - } - } - /* Should never comes here */ - return -1; -} - -/* find a free temporary local variable (return the offset on stack) match the size and align. If none, add new temporary stack variable*/ -static int get_temp_local_var(int size,int align){ - int i; - struct temp_local_variable *temp_var; - int found_var; - SValue *p; - int r; - char free; - char found; - found=0; - for(i=0;i<nb_temp_local_vars;i++){ - temp_var=&arr_temp_local_vars[i]; - if(temp_var->size<size||align!=temp_var->align){ - continue; - } - /*check if temp_var is free*/ - free=1; - for(p=vstack;p<=vtop;p++) { - r=p->r&VT_VALMASK; - if(r==VT_LOCAL||r==VT_LLOCAL){ - if(p->c.i==temp_var->location){ - free=0; - break; - } - } - } - if(free){ - found_var=temp_var->location; - found=1; - break; - } - } - if(!found){ - loc = (loc - size) & -align; - if(nb_temp_local_vars<MAX_TEMP_LOCAL_VARIABLE_NUMBER){ - temp_var=&arr_temp_local_vars[i]; - temp_var->location=loc; - temp_var->size=size; - temp_var->align=align; - nb_temp_local_vars++; - } - found_var=loc; - } - return found_var; -} - -static void clear_temp_local_var_list(){ - nb_temp_local_vars=0; -} - -/* move register 's' (of type 't') to 'r', and flush previous value of r to memory - if needed */ -static void move_reg(int r, int s, int t) -{ - SValue sv; - - if (r != s) { - save_reg(r); - sv.type.t = t; - sv.type.ref = NULL; - sv.r = s; - sv.c.i = 0; - load(r, &sv); - } -} - -/* get address of vtop (vtop MUST BE an lvalue) */ -ST_FUNC void gaddrof(void) -{ - vtop->r &= ~VT_LVAL; - /* tricky: if saved lvalue, then we can go back to lvalue */ - if ((vtop->r & VT_VALMASK) == VT_LLOCAL) - vtop->r = (vtop->r & ~VT_VALMASK) | VT_LOCAL | VT_LVAL; -} - -#ifdef CONFIG_TCC_BCHECK -/* generate a bounded pointer addition */ -static void gen_bounded_ptr_add(void) -{ - int save = (vtop[-1].r & VT_VALMASK) == VT_LOCAL; - if (save) { - vpushv(&vtop[-1]); - vrott(3); - } - vpush_helper_func(TOK___bound_ptr_add); - vrott(3); - gfunc_call(2); - vtop -= save; - vpushi(0); - /* returned pointer is in REG_IRET */ - vtop->r = REG_IRET | VT_BOUNDED; - if (nocode_wanted) - return; - /* relocation offset of the bounding function call point */ - vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(ElfW_Rel)); -} - -/* patch pointer addition in vtop so that pointer dereferencing is - also tested */ -static void gen_bounded_ptr_deref(void) -{ - addr_t func; - int size, align; - ElfW_Rel *rel; - Sym *sym; - - if (nocode_wanted) - return; - - size = type_size(&vtop->type, &align); - switch(size) { - case 1: func = TOK___bound_ptr_indir1; break; - case 2: func = TOK___bound_ptr_indir2; break; - case 4: func = TOK___bound_ptr_indir4; break; - case 8: func = TOK___bound_ptr_indir8; break; - case 12: func = TOK___bound_ptr_indir12; break; - case 16: func = TOK___bound_ptr_indir16; break; - default: - /* may happen with struct member access */ - return; - } - sym = external_helper_sym(func); - if (!sym->c) - put_extern_sym(sym, NULL, 0, 0); - /* patch relocation */ - /* XXX: find a better solution ? */ - rel = (ElfW_Rel *)(cur_text_section->reloc->data + vtop->c.i); - rel->r_info = ELFW(R_INFO)(sym->c, ELFW(R_TYPE)(rel->r_info)); -} - -/* generate lvalue bound code */ -static void gbound(void) -{ - CType type1; - - vtop->r &= ~VT_MUSTBOUND; - /* if lvalue, then use checking code before dereferencing */ - if (vtop->r & VT_LVAL) { - /* if not VT_BOUNDED value, then make one */ - if (!(vtop->r & VT_BOUNDED)) { - /* must save type because we must set it to int to get pointer */ - type1 = vtop->type; - vtop->type.t = VT_PTR; - gaddrof(); - vpushi(0); - gen_bounded_ptr_add(); - vtop->r |= VT_LVAL; - vtop->type = type1; - } - /* then check for dereferencing */ - gen_bounded_ptr_deref(); - } -} - -/* we need to call __bound_ptr_add before we start to load function - args into registers */ -ST_FUNC void gbound_args(int nb_args) -{ - int i, v; - SValue *sv; - - for (i = 1; i <= nb_args; ++i) - if (vtop[1 - i].r & VT_MUSTBOUND) { - vrotb(i); - gbound(); - vrott(i); - } - - sv = vtop - nb_args; - if (sv->r & VT_SYM) { - v = sv->sym->v; - if (v == TOK_setjmp - || v == TOK__setjmp -#ifndef TCC_TARGET_PE - || v == TOK_sigsetjmp - || v == TOK___sigsetjmp -#endif - ) { - vpush_helper_func(TOK___bound_setjmp); - vpushv(sv + 1); - gfunc_call(1); - func_bound_add_epilog = 1; - } -#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 - if (v == TOK_alloca) - func_bound_add_epilog = 1; -#endif -#if TARGETOS_NetBSD - if (v == TOK_longjmp) /* undo rename to __longjmp14 */ - sv->sym->asm_label = TOK___bound_longjmp; -#endif - } -} - -/* Add bounds for local symbols from S to E (via ->prev) */ -static void add_local_bounds(Sym *s, Sym *e) -{ - for (; s != e; s = s->prev) { - if (!s->v || (s->r & VT_VALMASK) != VT_LOCAL) - continue; - /* Add arrays/structs/unions because we always take address */ - if ((s->type.t & VT_ARRAY) - || (s->type.t & VT_BTYPE) == VT_STRUCT - || s->a.addrtaken) { - /* add local bound info */ - int align, size = type_size(&s->type, &align); - addr_t *bounds_ptr = section_ptr_add(lbounds_section, - 2 * sizeof(addr_t)); - bounds_ptr[0] = s->c; - bounds_ptr[1] = size; - } - } -} -#endif - -/* Wrapper around sym_pop, that potentially also registers local bounds. */ -static void pop_local_syms(Sym *b, int keep) -{ -#ifdef CONFIG_TCC_BCHECK - if (tcc_state->do_bounds_check && !keep && (local_scope || !func_var)) - add_local_bounds(local_stack, b); -#endif - if (debug_modes) - tcc_add_debug_info (tcc_state, !local_scope, local_stack, b); - sym_pop(&local_stack, b, keep); -} - -static void incr_bf_adr(int o) -{ - vtop->type = char_pointer_type; - gaddrof(); - vpushs(o); - gen_op('+'); - vtop->type.t = VT_BYTE | VT_UNSIGNED; - vtop->r |= VT_LVAL; -} - -/* single-byte load mode for packed or otherwise unaligned bitfields */ -static void load_packed_bf(CType *type, int bit_pos, int bit_size) -{ - int n, o, bits; - save_reg_upstack(vtop->r, 1); - vpush64(type->t & VT_BTYPE, 0); // B X - bits = 0, o = bit_pos >> 3, bit_pos &= 7; - do { - vswap(); // X B - incr_bf_adr(o); - vdup(); // X B B - n = 8 - bit_pos; - if (n > bit_size) - n = bit_size; - if (bit_pos) - vpushi(bit_pos), gen_op(TOK_SHR), bit_pos = 0; // X B Y - if (n < 8) - vpushi((1 << n) - 1), gen_op('&'); - gen_cast(type); - if (bits) - vpushi(bits), gen_op(TOK_SHL); - vrotb(3); // B Y X - gen_op('|'); // B X - bits += n, bit_size -= n, o = 1; - } while (bit_size); - vswap(), vpop(); - if (!(type->t & VT_UNSIGNED)) { - n = ((type->t & VT_BTYPE) == VT_LLONG ? 64 : 32) - bits; - vpushi(n), gen_op(TOK_SHL); - vpushi(n), gen_op(TOK_SAR); - } -} - -/* single-byte store mode for packed or otherwise unaligned bitfields */ -static void store_packed_bf(int bit_pos, int bit_size) -{ - int bits, n, o, m, c; - c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; - vswap(); // X B - save_reg_upstack(vtop->r, 1); - bits = 0, o = bit_pos >> 3, bit_pos &= 7; - do { - incr_bf_adr(o); // X B - vswap(); //B X - c ? vdup() : gv_dup(); // B V X - vrott(3); // X B V - if (bits) - vpushi(bits), gen_op(TOK_SHR); - if (bit_pos) - vpushi(bit_pos), gen_op(TOK_SHL); - n = 8 - bit_pos; - if (n > bit_size) - n = bit_size; - if (n < 8) { - m = ((1 << n) - 1) << bit_pos; - vpushi(m), gen_op('&'); // X B V1 - vpushv(vtop-1); // X B V1 B - vpushi(m & 0x80 ? ~m & 0x7f : ~m); - gen_op('&'); // X B V1 B1 - gen_op('|'); // X B V2 - } - vdup(), vtop[-1] = vtop[-2]; // X B B V2 - vstore(), vpop(); // X B - bits += n, bit_size -= n, bit_pos = 0, o = 1; - } while (bit_size); - vpop(), vpop(); -} - -static int adjust_bf(SValue *sv, int bit_pos, int bit_size) -{ - int t; - if (0 == sv->type.ref) - return 0; - t = sv->type.ref->auxtype; - if (t != -1 && t != VT_STRUCT) { - sv->type.t = (sv->type.t & ~(VT_BTYPE | VT_LONG)) | t; - sv->r |= VT_LVAL; - } - return t; -} - -/* store vtop a register belonging to class 'rc'. lvalues are - converted to values. Cannot be used if cannot be converted to - register value (such as structures). */ -ST_FUNC int gv(int rc) -{ - int r, r2, r_ok, r2_ok, rc2, bt; - int bit_pos, bit_size, size, align; - - /* NOTE: get_reg can modify vstack[] */ - if (vtop->type.t & VT_BITFIELD) { - CType type; - - bit_pos = BIT_POS(vtop->type.t); - bit_size = BIT_SIZE(vtop->type.t); - /* remove bit field info to avoid loops */ - vtop->type.t &= ~VT_STRUCT_MASK; - - type.ref = NULL; - type.t = vtop->type.t & VT_UNSIGNED; - if ((vtop->type.t & VT_BTYPE) == VT_BOOL) - type.t |= VT_UNSIGNED; - - r = adjust_bf(vtop, bit_pos, bit_size); - - if ((vtop->type.t & VT_BTYPE) == VT_LLONG) - type.t |= VT_LLONG; - else - type.t |= VT_INT; - - if (r == VT_STRUCT) { - load_packed_bf(&type, bit_pos, bit_size); - } else { - int bits = (type.t & VT_BTYPE) == VT_LLONG ? 64 : 32; - /* cast to int to propagate signedness in following ops */ - gen_cast(&type); - /* generate shifts */ - vpushi(bits - (bit_pos + bit_size)); - gen_op(TOK_SHL); - vpushi(bits - bit_size); - /* NOTE: transformed to SHR if unsigned */ - gen_op(TOK_SAR); - } - r = gv(rc); - } else { - if (is_float(vtop->type.t) && - (vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { - /* CPUs usually cannot use float constants, so we store them - generically in data segment */ - init_params p = { rodata_section }; - unsigned long offset; - size = type_size(&vtop->type, &align); - if (NODATA_WANTED) - size = 0, align = 1; - offset = section_add(p.sec, size, align); - vpush_ref(&vtop->type, p.sec, offset, size); - vswap(); - init_putv(&p, &vtop->type, offset); - vtop->r |= VT_LVAL; - } -#ifdef CONFIG_TCC_BCHECK - if (vtop->r & VT_MUSTBOUND) - gbound(); -#endif - - bt = vtop->type.t & VT_BTYPE; - -#ifdef TCC_TARGET_RISCV64 - /* XXX mega hack */ - if (bt == VT_LDOUBLE && rc == RC_FLOAT) - rc = RC_INT; -#endif - rc2 = RC2_TYPE(bt, rc); - - /* need to reload if: - - constant - - lvalue (need to dereference pointer) - - already a register, but not in the right class */ - r = vtop->r & VT_VALMASK; - r_ok = !(vtop->r & VT_LVAL) && (r < VT_CONST) && (reg_classes[r] & rc); - r2_ok = !rc2 || ((vtop->r2 < VT_CONST) && (reg_classes[vtop->r2] & rc2)); - - if (!r_ok || !r2_ok) { - if (!r_ok) - r = get_reg(rc); - if (rc2) { - int load_type = (bt == VT_QFLOAT) ? VT_DOUBLE : VT_PTRDIFF_T; - int original_type = vtop->type.t; - - /* two register type load : - expand to two words temporarily */ - if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { - /* load constant */ - unsigned long long ll = vtop->c.i; - vtop->c.i = ll; /* first word */ - load(r, vtop); - vtop->r = r; /* save register value */ - vpushi(ll >> 32); /* second word */ - } else if (vtop->r & VT_LVAL) { - /* We do not want to modifier the long long pointer here. - So we save any other instances down the stack */ - save_reg_upstack(vtop->r, 1); - /* load from memory */ - vtop->type.t = load_type; - load(r, vtop); - vdup(); - vtop[-1].r = r; /* save register value */ - /* increment pointer to get second word */ - vtop->type.t = VT_PTRDIFF_T; - gaddrof(); - vpushs(PTR_SIZE); - gen_op('+'); - vtop->r |= VT_LVAL; - vtop->type.t = load_type; - } else { - /* move registers */ - if (!r_ok) - load(r, vtop); - if (r2_ok && vtop->r2 < VT_CONST) - goto done; - vdup(); - vtop[-1].r = r; /* save register value */ - vtop->r = vtop[-1].r2; - } - /* Allocate second register. Here we rely on the fact that - get_reg() tries first to free r2 of an SValue. */ - r2 = get_reg(rc2); - load(r2, vtop); - vpop(); - /* write second register */ - vtop->r2 = r2; - done: - vtop->type.t = original_type; - } else { - if (vtop->r == VT_CMP) - vset_VT_JMP(); - /* one register type load */ - load(r, vtop); - } - } - vtop->r = r; -#ifdef TCC_TARGET_C67 - /* uses register pairs for doubles */ - if (bt == VT_DOUBLE) - vtop->r2 = r+1; -#endif - } - return r; -} - -/* generate vtop[-1] and vtop[0] in resp. classes rc1 and rc2 */ -ST_FUNC void gv2(int rc1, int rc2) -{ - /* generate more generic register first. But VT_JMP or VT_CMP - values must be generated first in all cases to avoid possible - reload errors */ - if (vtop->r != VT_CMP && rc1 <= rc2) { - vswap(); - gv(rc1); - vswap(); - gv(rc2); - /* test if reload is needed for first register */ - if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) { - vswap(); - gv(rc1); - vswap(); - } - } else { - gv(rc2); - vswap(); - gv(rc1); - vswap(); - /* test if reload is needed for first register */ - if ((vtop[0].r & VT_VALMASK) >= VT_CONST) { - gv(rc2); - } - } -} - -#if PTR_SIZE == 4 -/* expand 64bit on stack in two ints */ -ST_FUNC void lexpand(void) -{ - int u, v; - u = vtop->type.t & (VT_DEFSIGN | VT_UNSIGNED); - v = vtop->r & (VT_VALMASK | VT_LVAL); - if (v == VT_CONST) { - vdup(); - vtop[0].c.i >>= 32; - } else if (v == (VT_LVAL|VT_CONST) || v == (VT_LVAL|VT_LOCAL)) { - vdup(); - vtop[0].c.i += 4; - } else { - gv(RC_INT); - vdup(); - vtop[0].r = vtop[-1].r2; - vtop[0].r2 = vtop[-1].r2 = VT_CONST; - } - vtop[0].type.t = vtop[-1].type.t = VT_INT | u; -} -#endif - -#if PTR_SIZE == 4 -/* build a long long from two ints */ -static void lbuild(int t) -{ - gv2(RC_INT, RC_INT); - vtop[-1].r2 = vtop[0].r; - vtop[-1].type.t = t; - vpop(); -} -#endif - -/* convert stack entry to register and duplicate its value in another - register */ -static void gv_dup(void) -{ - int t, rc, r; - - t = vtop->type.t; -#if PTR_SIZE == 4 - if ((t & VT_BTYPE) == VT_LLONG) { - if (t & VT_BITFIELD) { - gv(RC_INT); - t = vtop->type.t; - } - lexpand(); - gv_dup(); - vswap(); - vrotb(3); - gv_dup(); - vrotb(4); - /* stack: H L L1 H1 */ - lbuild(t); - vrotb(3); - vrotb(3); - vswap(); - lbuild(t); - vswap(); - return; - } -#endif - /* duplicate value */ - rc = RC_TYPE(t); - gv(rc); - r = get_reg(rc); - vdup(); - load(r, vtop); - vtop->r = r; -} - -#if PTR_SIZE == 4 -/* generate CPU independent (unsigned) long long operations */ -static void gen_opl(int op) -{ - int t, a, b, op1, c, i; - int func; - unsigned short reg_iret = REG_IRET; - unsigned short reg_lret = REG_IRE2; - SValue tmp; - - switch(op) { - case '/': - case TOK_PDIV: - func = TOK___divdi3; - goto gen_func; - case TOK_UDIV: - func = TOK___udivdi3; - goto gen_func; - case '%': - func = TOK___moddi3; - goto gen_mod_func; - case TOK_UMOD: - func = TOK___umoddi3; - gen_mod_func: -#ifdef TCC_ARM_EABI - reg_iret = TREG_R2; - reg_lret = TREG_R3; -#endif - gen_func: - /* call generic long long function */ - vpush_helper_func(func); - vrott(3); - gfunc_call(2); - vpushi(0); - vtop->r = reg_iret; - vtop->r2 = reg_lret; - break; - case '^': - case '&': - case '|': - case '*': - case '+': - case '-': - //pv("gen_opl A",0,2); - t = vtop->type.t; - vswap(); - lexpand(); - vrotb(3); - lexpand(); - /* stack: L1 H1 L2 H2 */ - tmp = vtop[0]; - vtop[0] = vtop[-3]; - vtop[-3] = tmp; - tmp = vtop[-2]; - vtop[-2] = vtop[-3]; - vtop[-3] = tmp; - vswap(); - /* stack: H1 H2 L1 L2 */ - //pv("gen_opl B",0,4); - if (op == '*') { - vpushv(vtop - 1); - vpushv(vtop - 1); - gen_op(TOK_UMULL); - lexpand(); - /* stack: H1 H2 L1 L2 ML MH */ - for(i=0;i<4;i++) - vrotb(6); - /* stack: ML MH H1 H2 L1 L2 */ - tmp = vtop[0]; - vtop[0] = vtop[-2]; - vtop[-2] = tmp; - /* stack: ML MH H1 L2 H2 L1 */ - gen_op('*'); - vrotb(3); - vrotb(3); - gen_op('*'); - /* stack: ML MH M1 M2 */ - gen_op('+'); - gen_op('+'); - } else if (op == '+' || op == '-') { - /* XXX: add non carry method too (for MIPS or alpha) */ - if (op == '+') - op1 = TOK_ADDC1; - else - op1 = TOK_SUBC1; - gen_op(op1); - /* stack: H1 H2 (L1 op L2) */ - vrotb(3); - vrotb(3); - gen_op(op1 + 1); /* TOK_xxxC2 */ - } else { - gen_op(op); - /* stack: H1 H2 (L1 op L2) */ - vrotb(3); - vrotb(3); - /* stack: (L1 op L2) H1 H2 */ - gen_op(op); - /* stack: (L1 op L2) (H1 op H2) */ - } - /* stack: L H */ - lbuild(t); - break; - case TOK_SAR: - case TOK_SHR: - case TOK_SHL: - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { - t = vtop[-1].type.t; - vswap(); - lexpand(); - vrotb(3); - /* stack: L H shift */ - c = (int)vtop->c.i; - /* constant: simpler */ - /* NOTE: all comments are for SHL. the other cases are - done by swapping words */ - vpop(); - if (op != TOK_SHL) - vswap(); - if (c >= 32) { - /* stack: L H */ - vpop(); - if (c > 32) { - vpushi(c - 32); - gen_op(op); - } - if (op != TOK_SAR) { - vpushi(0); - } else { - gv_dup(); - vpushi(31); - gen_op(TOK_SAR); - } - vswap(); - } else { - vswap(); - gv_dup(); - /* stack: H L L */ - vpushi(c); - gen_op(op); - vswap(); - vpushi(32 - c); - if (op == TOK_SHL) - gen_op(TOK_SHR); - else - gen_op(TOK_SHL); - vrotb(3); - /* stack: L L H */ - vpushi(c); - if (op == TOK_SHL) - gen_op(TOK_SHL); - else - gen_op(TOK_SHR); - gen_op('|'); - } - if (op != TOK_SHL) - vswap(); - lbuild(t); - } else { - /* XXX: should provide a faster fallback on x86 ? */ - switch(op) { - case TOK_SAR: - func = TOK___ashrdi3; - goto gen_func; - case TOK_SHR: - func = TOK___lshrdi3; - goto gen_func; - case TOK_SHL: - func = TOK___ashldi3; - goto gen_func; - } - } - break; - default: - /* compare operations */ - t = vtop->type.t; - vswap(); - lexpand(); - vrotb(3); - lexpand(); - /* stack: L1 H1 L2 H2 */ - tmp = vtop[-1]; - vtop[-1] = vtop[-2]; - vtop[-2] = tmp; - /* stack: L1 L2 H1 H2 */ - save_regs(4); - /* compare high */ - op1 = op; - /* when values are equal, we need to compare low words. since - the jump is inverted, we invert the test too. */ - if (op1 == TOK_LT) - op1 = TOK_LE; - else if (op1 == TOK_GT) - op1 = TOK_GE; - else if (op1 == TOK_ULT) - op1 = TOK_ULE; - else if (op1 == TOK_UGT) - op1 = TOK_UGE; - a = 0; - b = 0; - gen_op(op1); - if (op == TOK_NE) { - b = gvtst(0, 0); - } else { - a = gvtst(1, 0); - if (op != TOK_EQ) { - /* generate non equal test */ - vpushi(0); - vset_VT_CMP(TOK_NE); - b = gvtst(0, 0); - } - } - /* compare low. Always unsigned */ - op1 = op; - if (op1 == TOK_LT) - op1 = TOK_ULT; - else if (op1 == TOK_LE) - op1 = TOK_ULE; - else if (op1 == TOK_GT) - op1 = TOK_UGT; - else if (op1 == TOK_GE) - op1 = TOK_UGE; - gen_op(op1); -#if 0//def TCC_TARGET_I386 - if (op == TOK_NE) { gsym(b); break; } - if (op == TOK_EQ) { gsym(a); break; } -#endif - gvtst_set(1, a); - gvtst_set(0, b); - break; - } -} -#endif - -static uint64_t gen_opic_sdiv(uint64_t a, uint64_t b) -{ - uint64_t x = (a >> 63 ? -a : a) / (b >> 63 ? -b : b); - return (a ^ b) >> 63 ? -x : x; -} - -static int gen_opic_lt(uint64_t a, uint64_t b) -{ - return (a ^ (uint64_t)1 << 63) < (b ^ (uint64_t)1 << 63); -} - -/* handle integer constant optimizations and various machine - independent opt */ -static void gen_opic(int op) -{ - SValue *v1 = vtop - 1; - SValue *v2 = vtop; - int t1 = v1->type.t & VT_BTYPE; - int t2 = v2->type.t & VT_BTYPE; - int c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; - int c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; - uint64_t l1 = c1 ? v1->c.i : 0; - uint64_t l2 = c2 ? v2->c.i : 0; - int shm = (t1 == VT_LLONG) ? 63 : 31; - int r; - - if (t1 != VT_LLONG && (PTR_SIZE != 8 || t1 != VT_PTR)) - l1 = ((uint32_t)l1 | - (v1->type.t & VT_UNSIGNED ? 0 : -(l1 & 0x80000000))); - if (t2 != VT_LLONG && (PTR_SIZE != 8 || t2 != VT_PTR)) - l2 = ((uint32_t)l2 | - (v2->type.t & VT_UNSIGNED ? 0 : -(l2 & 0x80000000))); - - if (c1 && c2) { - switch(op) { - case '+': l1 += l2; break; - case '-': l1 -= l2; break; - case '&': l1 &= l2; break; - case '^': l1 ^= l2; break; - case '|': l1 |= l2; break; - case '*': l1 *= l2; break; - - case TOK_PDIV: - case '/': - case '%': - case TOK_UDIV: - case TOK_UMOD: - /* if division by zero, generate explicit division */ - if (l2 == 0) { - if (CONST_WANTED && !NOEVAL_WANTED) - tcc_error("division by zero in constant"); - goto general_case; - } - switch(op) { - default: l1 = gen_opic_sdiv(l1, l2); break; - case '%': l1 = l1 - l2 * gen_opic_sdiv(l1, l2); break; - case TOK_UDIV: l1 = l1 / l2; break; - case TOK_UMOD: l1 = l1 % l2; break; - } - break; - case TOK_SHL: l1 <<= (l2 & shm); break; - case TOK_SHR: l1 >>= (l2 & shm); break; - case TOK_SAR: - l1 = (l1 >> 63) ? ~(~l1 >> (l2 & shm)) : l1 >> (l2 & shm); - break; - /* tests */ - case TOK_ULT: l1 = l1 < l2; break; - case TOK_UGE: l1 = l1 >= l2; break; - case TOK_EQ: l1 = l1 == l2; break; - case TOK_NE: l1 = l1 != l2; break; - case TOK_ULE: l1 = l1 <= l2; break; - case TOK_UGT: l1 = l1 > l2; break; - case TOK_LT: l1 = gen_opic_lt(l1, l2); break; - case TOK_GE: l1 = !gen_opic_lt(l1, l2); break; - case TOK_LE: l1 = !gen_opic_lt(l2, l1); break; - case TOK_GT: l1 = gen_opic_lt(l2, l1); break; - /* logical */ - case TOK_LAND: l1 = l1 && l2; break; - case TOK_LOR: l1 = l1 || l2; break; - default: - goto general_case; - } - if (t1 != VT_LLONG && (PTR_SIZE != 8 || t1 != VT_PTR)) - l1 = ((uint32_t)l1 | - (v1->type.t & VT_UNSIGNED ? 0 : -(l1 & 0x80000000))); - v1->c.i = l1; - v1->r |= v2->r & VT_NONCONST; - vtop--; - } else { - /* if commutative ops, put c2 as constant */ - if (c1 && (op == '+' || op == '&' || op == '^' || - op == '|' || op == '*' || op == TOK_EQ || op == TOK_NE)) { - vswap(); - c2 = c1; //c = c1, c1 = c2, c2 = c; - l2 = l1; //l = l1, l1 = l2, l2 = l; - } - if (c1 && ((l1 == 0 && - (op == TOK_SHL || op == TOK_SHR || op == TOK_SAR)) || - (l1 == -1 && op == TOK_SAR))) { - /* treat (0 << x), (0 >> x) and (-1 >> x) as constant */ - vpop(); - } else if (c2 && ((l2 == 0 && (op == '&' || op == '*')) || - (op == '|' && - (l2 == -1 || (l2 == 0xFFFFFFFF && t2 != VT_LLONG))) || - (l2 == 1 && (op == '%' || op == TOK_UMOD)))) { - /* treat (x & 0), (x * 0), (x | -1) and (x % 1) as constant */ - if (l2 == 1) - vtop->c.i = 0; - vswap(); - vtop--; - } else if (c2 && (((op == '*' || op == '/' || op == TOK_UDIV || - op == TOK_PDIV) && - l2 == 1) || - ((op == '+' || op == '-' || op == '|' || op == '^' || - op == TOK_SHL || op == TOK_SHR || op == TOK_SAR) && - l2 == 0) || - (op == '&' && - (l2 == -1 || (l2 == 0xFFFFFFFF && t2 != VT_LLONG))))) { - /* filter out NOP operations like x*1, x-0, x&-1... */ - vtop--; - } else if (c2 && (op == '*' || op == TOK_PDIV || op == TOK_UDIV)) { - /* try to use shifts instead of muls or divs */ - if (l2 > 0 && (l2 & (l2 - 1)) == 0) { - int n = -1; - while (l2) { - l2 >>= 1; - n++; - } - vtop->c.i = n; - if (op == '*') - op = TOK_SHL; - else if (op == TOK_PDIV) - op = TOK_SAR; - else - op = TOK_SHR; - } - goto general_case; - } else if (c2 && (op == '+' || op == '-') && - (r = vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM), - r == (VT_CONST | VT_SYM) || r == VT_LOCAL)) { - /* symbol + constant case */ - if (op == '-') - l2 = -l2; - l2 += vtop[-1].c.i; - /* The backends can't always deal with addends to symbols - larger than +-1<<31. Don't construct such. */ - if ((int)l2 != l2) - goto general_case; - vtop--; - vtop->c.i = l2; - } else { - general_case: - /* call low level op generator */ - if (t1 == VT_LLONG || t2 == VT_LLONG || - (PTR_SIZE == 8 && (t1 == VT_PTR || t2 == VT_PTR))) - gen_opl(op); - else - gen_opi(op); - } - if (vtop->r == VT_CONST) - vtop->r |= VT_NONCONST; /* is const, but only by optimization */ - } -} - -#if defined TCC_TARGET_X86_64 || defined TCC_TARGET_I386 -# define gen_negf gen_opf -#elif defined TCC_TARGET_ARM -void gen_negf(int op) -{ - /* arm will detect 0-x and replace by vneg */ - vpushi(0), vswap(), gen_op('-'); -} -#else -/* XXX: implement in gen_opf() for other backends too */ -void gen_negf(int op) -{ - /* In IEEE negate(x) isn't subtract(0,x). Without NaNs it's - subtract(-0, x), but with them it's really a sign flip - operation. We implement this with bit manipulation and have - to do some type reinterpretation for this, which TCC can do - only via memory. */ - - int align, size, bt; - - size = type_size(&vtop->type, &align); - bt = vtop->type.t & VT_BTYPE; - save_reg(gv(RC_TYPE(bt))); - vdup(); - incr_bf_adr(size - 1); - vdup(); - vpushi(0x80); /* flip sign */ - gen_op('^'); - vstore(); - vpop(); -} -#endif - -/* generate a floating point operation with constant propagation */ -static void gen_opif(int op) -{ - int c1, c2, cast_int = 0; - SValue *v1, *v2; -#if defined _MSC_VER && defined __x86_64__ - /* avoid bad optimization with f1 -= f2 for f1:-0.0, f2:0.0 */ - volatile -#endif - long double f1, f2; - - v1 = vtop - 1; - v2 = vtop; - if (op == TOK_NEG) - v1 = v2; - - /* currently, we cannot do computations with forward symbols */ - c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; - c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; - if (c1 && c2) { - if (v1->type.t == VT_FLOAT) { - f1 = v1->c.f; - f2 = v2->c.f; - } else if (v1->type.t == VT_DOUBLE) { - f1 = v1->c.d; - f2 = v2->c.d; - } else { - f1 = v1->c.ld; - f2 = v2->c.ld; - } - /* NOTE: we only do constant propagation if finite number (not - NaN or infinity) (ANSI spec) */ - if (!(ieee_finite(f1) || !ieee_finite(f2)) && !CONST_WANTED) - goto general_case; - switch(op) { - case '+': f1 += f2; break; - case '-': f1 -= f2; break; - case '*': f1 *= f2; break; - case '/': - if (f2 == 0.0) { - union { float f; unsigned u; } x1, x2, y; - /* If not in initializer we need to potentially generate - FP exceptions at runtime, otherwise we want to fold. */ - if (!CONST_WANTED) - goto general_case; - /* the run-time result of 0.0/0.0 on x87, also of other compilers - when used to compile the f1 /= f2 below, would be -nan */ - x1.f = f1, x2.f = f2; - if (f1 == 0.0) - y.u = 0x7fc00000; /* nan */ - else - y.u = 0x7f800000; /* infinity */ - y.u |= (x1.u ^ x2.u) & 0x80000000; /* set sign */ - f1 = y.f; - break; - } - f1 /= f2; - break; - case TOK_NEG: - f1 = -f1; - goto unary_result; - case TOK_EQ: - f1 = f1 == f2; - make_int: - cast_int = 1; - break; - case TOK_NE: - f1 = f1 != f2; - goto make_int; - case TOK_LT: - f1 = f1 < f2; - goto make_int; - case TOK_GE: - f1 = f1 >= f2; - goto make_int; - case TOK_LE: - f1 = f1 <= f2; - goto make_int; - case TOK_GT: - f1 = f1 > f2; - goto make_int; - /* XXX: also handles tests ? */ - default: - goto general_case; - } - vtop--; - unary_result: - /* XXX: overflow test ? */ - if (v1->type.t == VT_FLOAT) { - v1->c.f = f1; - } else if (v1->type.t == VT_DOUBLE) { - v1->c.d = f1; - } else { - v1->c.ld = f1; - } - if (cast_int) - gen_cast_s(VT_INT); - } else { - general_case: - if (op == TOK_NEG) { - gen_negf(op); - } else { - gen_opf(op); - } - } -} - -/* print a type. If 'varstr' is not NULL, then the variable is also - printed in the type */ -/* XXX: union */ -/* XXX: add array and function pointers */ -static void type_to_str(char *buf, int buf_size, - CType *type, const char *varstr) -{ - int bt, v, t; - Sym *s, *sa; - char buf1[256]; - const char *tstr; - - t = type->t; - bt = t & VT_BTYPE; - buf[0] = '\0'; - - if (t & VT_EXTERN) - pstrcat(buf, buf_size, "extern "); - if (t & VT_STATIC) - pstrcat(buf, buf_size, "static "); - if (t & VT_TYPEDEF) - pstrcat(buf, buf_size, "typedef "); - if (t & VT_INLINE) - pstrcat(buf, buf_size, "inline "); - if (bt != VT_PTR) { - if (t & VT_VOLATILE) - pstrcat(buf, buf_size, "volatile "); - if (t & VT_CONSTANT) - pstrcat(buf, buf_size, "const "); - } - if (((t & VT_DEFSIGN) && bt == VT_BYTE) - || ((t & VT_UNSIGNED) - && (bt == VT_SHORT || bt == VT_INT || bt == VT_LLONG) - && !IS_ENUM(t) - )) - pstrcat(buf, buf_size, (t & VT_UNSIGNED) ? "unsigned " : "signed "); - - buf_size -= strlen(buf); - buf += strlen(buf); - - switch(bt) { - case VT_VOID: - tstr = "void"; - goto add_tstr; - case VT_BOOL: - tstr = "_Bool"; - goto add_tstr; - case VT_BYTE: - tstr = "char"; - goto add_tstr; - case VT_SHORT: - tstr = "short"; - goto add_tstr; - case VT_INT: - tstr = "int"; - goto maybe_long; - case VT_LLONG: - tstr = "long long"; - maybe_long: - if (t & VT_LONG) - tstr = "long"; - if (!IS_ENUM(t)) - goto add_tstr; - tstr = "enum "; - goto tstruct; - case VT_FLOAT: - tstr = "float"; - goto add_tstr; - case VT_DOUBLE: - tstr = "double"; - if (!(t & VT_LONG)) - goto add_tstr; - case VT_LDOUBLE: - tstr = "long double"; - add_tstr: - pstrcat(buf, buf_size, tstr); - break; - case VT_STRUCT: - tstr = "struct "; - if (IS_UNION(t)) - tstr = "union "; - tstruct: - pstrcat(buf, buf_size, tstr); - v = type->ref->v & ~SYM_STRUCT; - if (v >= SYM_FIRST_ANOM) - pstrcat(buf, buf_size, "<anonymous>"); - else - pstrcat(buf, buf_size, get_tok_str(v, NULL)); - break; - case VT_FUNC: - s = type->ref; - buf1[0]=0; - if (varstr && '*' == *varstr) { - pstrcat(buf1, sizeof(buf1), "("); - pstrcat(buf1, sizeof(buf1), varstr); - pstrcat(buf1, sizeof(buf1), ")"); - } - pstrcat(buf1, buf_size, "("); - sa = s->next; - while (sa != NULL) { - char buf2[256]; - type_to_str(buf2, sizeof(buf2), &sa->type, NULL); - pstrcat(buf1, sizeof(buf1), buf2); - sa = sa->next; - if (sa) - pstrcat(buf1, sizeof(buf1), ", "); - } - if (s->f.func_type == FUNC_ELLIPSIS) - pstrcat(buf1, sizeof(buf1), ", ..."); - pstrcat(buf1, sizeof(buf1), ")"); - type_to_str(buf, buf_size, &s->type, buf1); - goto no_var; - case VT_PTR: - s = type->ref; - if (t & (VT_ARRAY|VT_VLA)) { - if (varstr && '*' == *varstr) - snprintf(buf1, sizeof(buf1), "(%s)[%d]", varstr, s->c); - else - snprintf(buf1, sizeof(buf1), "%s[%d]", varstr ? varstr : "", s->c); - type_to_str(buf, buf_size, &s->type, buf1); - goto no_var; - } - pstrcpy(buf1, sizeof(buf1), "*"); - if (t & VT_CONSTANT) - pstrcat(buf1, buf_size, "const "); - if (t & VT_VOLATILE) - pstrcat(buf1, buf_size, "volatile "); - if (varstr) - pstrcat(buf1, sizeof(buf1), varstr); - type_to_str(buf, buf_size, &s->type, buf1); - goto no_var; - } - if (varstr) { - pstrcat(buf, buf_size, " "); - pstrcat(buf, buf_size, varstr); - } - no_var: ; -} - -static void type_incompatibility_error(CType* st, CType* dt, const char* fmt) -{ - char buf1[256], buf2[256]; - type_to_str(buf1, sizeof(buf1), st, NULL); - type_to_str(buf2, sizeof(buf2), dt, NULL); - tcc_error(fmt, buf1, buf2); -} - -static void type_incompatibility_warning(CType* st, CType* dt, const char* fmt) -{ - char buf1[256], buf2[256]; - type_to_str(buf1, sizeof(buf1), st, NULL); - type_to_str(buf2, sizeof(buf2), dt, NULL); - tcc_warning(fmt, buf1, buf2); -} - -static int pointed_size(CType *type) -{ - int align; - return type_size(pointed_type(type), &align); -} - -static inline int is_null_pointer(SValue *p) -{ - if ((p->r & (VT_VALMASK | VT_LVAL | VT_SYM | VT_NONCONST)) != VT_CONST) - return 0; - return ((p->type.t & VT_BTYPE) == VT_INT && (uint32_t)p->c.i == 0) || - ((p->type.t & VT_BTYPE) == VT_LLONG && p->c.i == 0) || - ((p->type.t & VT_BTYPE) == VT_PTR && - (PTR_SIZE == 4 ? (uint32_t)p->c.i == 0 : p->c.i == 0) && - ((pointed_type(&p->type)->t & VT_BTYPE) == VT_VOID) && - 0 == (pointed_type(&p->type)->t & (VT_CONSTANT | VT_VOLATILE)) - ); -} - -/* compare function types. OLD functions match any new functions */ -static int is_compatible_func(CType *type1, CType *type2) -{ - Sym *s1, *s2; - - s1 = type1->ref; - s2 = type2->ref; - if (s1->f.func_call != s2->f.func_call) - return 0; - if (s1->f.func_type != s2->f.func_type - && s1->f.func_type != FUNC_OLD - && s2->f.func_type != FUNC_OLD) - return 0; - for (;;) { - if (!is_compatible_unqualified_types(&s1->type, &s2->type)) - return 0; - if (s1->f.func_type == FUNC_OLD || s2->f.func_type == FUNC_OLD ) - return 1; - s1 = s1->next; - s2 = s2->next; - if (!s1) - return !s2; - if (!s2) - return 0; - } -} - -/* return true if type1 and type2 are the same. If unqualified is - true, qualifiers on the types are ignored. - */ -static int compare_types(CType *type1, CType *type2, int unqualified) -{ - int bt1, t1, t2; - - t1 = type1->t & VT_TYPE; - t2 = type2->t & VT_TYPE; - if (unqualified) { - /* strip qualifiers before comparing */ - t1 &= ~(VT_CONSTANT | VT_VOLATILE); - t2 &= ~(VT_CONSTANT | VT_VOLATILE); - } - - /* Default Vs explicit signedness only matters for char */ - if ((t1 & VT_BTYPE) != VT_BYTE) { - t1 &= ~VT_DEFSIGN; - t2 &= ~VT_DEFSIGN; - } - /* XXX: bitfields ? */ - if (t1 != t2) - return 0; - - if ((t1 & VT_ARRAY) - && !(type1->ref->c < 0 - || type2->ref->c < 0 - || type1->ref->c == type2->ref->c)) - return 0; - - /* test more complicated cases */ - bt1 = t1 & VT_BTYPE; - if (bt1 == VT_PTR) { - type1 = pointed_type(type1); - type2 = pointed_type(type2); - return is_compatible_types(type1, type2); - } else if (bt1 == VT_STRUCT) { - return (type1->ref == type2->ref); - } else if (bt1 == VT_FUNC) { - return is_compatible_func(type1, type2); - } else if (IS_ENUM(type1->t) && IS_ENUM(type2->t)) { - /* If both are enums then they must be the same, if only one is then - t1 and t2 must be equal, which was checked above already. */ - return type1->ref == type2->ref; - } else { - return 1; - } -} - -/* Check if OP1 and OP2 can be "combined" with operation OP, the combined - type is stored in DEST if non-null (except for pointer plus/minus) . */ -static int combine_types(CType *dest, SValue *op1, SValue *op2, int op) -{ - CType *type1 = &op1->type, *type2 = &op2->type, type; - int t1 = type1->t, t2 = type2->t, bt1 = t1 & VT_BTYPE, bt2 = t2 & VT_BTYPE; - int ret = 1; - - type.t = VT_VOID; - type.ref = NULL; - - if (bt1 == VT_VOID || bt2 == VT_VOID) { - ret = op == '?' ? 1 : 0; - /* NOTE: as an extension, we accept void on only one side */ - type.t = VT_VOID; - } else if (bt1 == VT_PTR || bt2 == VT_PTR) { - if (op == '+') ; /* Handled in caller */ - /* http://port70.net/~nsz/c/c99/n1256.html#6.5.15p6 */ - /* If one is a null ptr constant the result type is the other. */ - else if (is_null_pointer (op2)) type = *type1; - else if (is_null_pointer (op1)) type = *type2; - else if (bt1 != bt2) { - /* accept comparison or cond-expr between pointer and integer - with a warning */ - if ((op == '?' || TOK_ISCOND(op)) - && (is_integer_btype(bt1) || is_integer_btype(bt2))) - tcc_warning("pointer/integer mismatch in %s", - op == '?' ? "conditional expression" : "comparison"); - else if (op != '-' || !is_integer_btype(bt2)) - ret = 0; - type = *(bt1 == VT_PTR ? type1 : type2); - } else { - CType *pt1 = pointed_type(type1); - CType *pt2 = pointed_type(type2); - int pbt1 = pt1->t & VT_BTYPE; - int pbt2 = pt2->t & VT_BTYPE; - int newquals, copied = 0; - if (pbt1 != VT_VOID && pbt2 != VT_VOID - && !compare_types(pt1, pt2, 1/*unqualif*/)) { - if (op != '?' && !TOK_ISCOND(op)) - ret = 0; - else - type_incompatibility_warning(type1, type2, - op == '?' - ? "pointer type mismatch in conditional expression ('%s' and '%s')" - : "pointer type mismatch in comparison('%s' and '%s')"); - } - if (op == '?') { - /* pointers to void get preferred, otherwise the - pointed to types minus qualifs should be compatible */ - type = *((pbt1 == VT_VOID) ? type1 : type2); - /* combine qualifs */ - newquals = ((pt1->t | pt2->t) & (VT_CONSTANT | VT_VOLATILE)); - if ((~pointed_type(&type)->t & (VT_CONSTANT | VT_VOLATILE)) - & newquals) - { - /* copy the pointer target symbol */ - type.ref = sym_push(SYM_FIELD, &type.ref->type, - 0, type.ref->c); - copied = 1; - pointed_type(&type)->t |= newquals; - } - /* pointers to incomplete arrays get converted to - pointers to completed ones if possible */ - if (pt1->t & VT_ARRAY - && pt2->t & VT_ARRAY - && pointed_type(&type)->ref->c < 0 - && (pt1->ref->c > 0 || pt2->ref->c > 0)) - { - if (!copied) - type.ref = sym_push(SYM_FIELD, &type.ref->type, - 0, type.ref->c); - pointed_type(&type)->ref = - sym_push(SYM_FIELD, &pointed_type(&type)->ref->type, - 0, pointed_type(&type)->ref->c); - pointed_type(&type)->ref->c = - 0 < pt1->ref->c ? pt1->ref->c : pt2->ref->c; - } - } - } - if (TOK_ISCOND(op)) - type.t = VT_SIZE_T; - } else if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) { - if (op != '?' || !compare_types(type1, type2, 1)) - ret = 0; - type = *type1; - } else if (is_float(bt1) || is_float(bt2)) { - if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) { - type.t = VT_LDOUBLE; - } else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) { - type.t = VT_DOUBLE; - } else { - type.t = VT_FLOAT; - } - } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) { - /* cast to biggest op */ - type.t = VT_LLONG | VT_LONG; - if (bt1 == VT_LLONG) - type.t &= t1; - if (bt2 == VT_LLONG) - type.t &= t2; - /* convert to unsigned if it does not fit in a long long */ - if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) || - (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED)) - type.t |= VT_UNSIGNED; - } else { - /* integer operations */ - type.t = VT_INT | (VT_LONG & (t1 | t2)); - /* convert to unsigned if it does not fit in an integer */ - if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) || - (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED)) - type.t |= VT_UNSIGNED; - } - if (dest) - *dest = type; - return ret; -} - -/* generic gen_op: handles types problems */ -ST_FUNC void gen_op(int op) -{ - int t1, t2, bt1, bt2, t; - CType type1, combtype; - -redo: - t1 = vtop[-1].type.t; - t2 = vtop[0].type.t; - bt1 = t1 & VT_BTYPE; - bt2 = t2 & VT_BTYPE; - - if (bt1 == VT_FUNC || bt2 == VT_FUNC) { - if (bt2 == VT_FUNC) { - mk_pointer(&vtop->type); - gaddrof(); - } - if (bt1 == VT_FUNC) { - vswap(); - mk_pointer(&vtop->type); - gaddrof(); - vswap(); - } - goto redo; - } else if (!combine_types(&combtype, vtop - 1, vtop, op)) { - tcc_error("invalid operand types for binary operation"); - } else if (bt1 == VT_PTR || bt2 == VT_PTR) { - /* at least one operand is a pointer */ - /* relational op: must be both pointers */ - int align; - if (TOK_ISCOND(op)) - goto std_op; - /* if both pointers, then it must be the '-' op */ - if (bt1 == VT_PTR && bt2 == VT_PTR) { - if (op != '-') - tcc_error("cannot use pointers here"); - vpush_type_size(pointed_type(&vtop[-1].type), &align); - vrott(3); - gen_opic(op); - vtop->type.t = VT_PTRDIFF_T; - vswap(); - gen_op(TOK_PDIV); - } else { - /* exactly one pointer : must be '+' or '-'. */ - if (op != '-' && op != '+') - tcc_error("cannot use pointers here"); - /* Put pointer as first operand */ - if (bt2 == VT_PTR) { - vswap(); - t = t1, t1 = t2, t2 = t; - } -#if PTR_SIZE == 4 - if ((vtop[0].type.t & VT_BTYPE) == VT_LLONG) - /* XXX: truncate here because gen_opl can't handle ptr + long long */ - gen_cast_s(VT_INT); -#endif - type1 = vtop[-1].type; - vpush_type_size(pointed_type(&vtop[-1].type), &align); - gen_op('*'); -#ifdef CONFIG_TCC_BCHECK - if (tcc_state->do_bounds_check && !CONST_WANTED) { - /* if bounded pointers, we generate a special code to - test bounds */ - if (op == '-') { - vpushi(0); - vswap(); - gen_op('-'); - } - gen_bounded_ptr_add(); - } else -#endif - { - gen_opic(op); - } - type1.t &= ~(VT_ARRAY|VT_VLA); - /* put again type if gen_opic() swaped operands */ - vtop->type = type1; - } - } else { - /* floats can only be used for a few operations */ - if (is_float(combtype.t) - && op != '+' && op != '-' && op != '*' && op != '/' - && !TOK_ISCOND(op)) - tcc_error("invalid operands for binary operation"); - else if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL) { - t = bt1 == VT_LLONG ? VT_LLONG : VT_INT; - if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (t | VT_UNSIGNED)) - t |= VT_UNSIGNED; - t |= (VT_LONG & t1); - combtype.t = t; - } - std_op: - t = t2 = combtype.t; - /* XXX: currently, some unsigned operations are explicit, so - we modify them here */ - if (t & VT_UNSIGNED) { - if (op == TOK_SAR) - op = TOK_SHR; - else if (op == '/') - op = TOK_UDIV; - else if (op == '%') - op = TOK_UMOD; - else if (op == TOK_LT) - op = TOK_ULT; - else if (op == TOK_GT) - op = TOK_UGT; - else if (op == TOK_LE) - op = TOK_ULE; - else if (op == TOK_GE) - op = TOK_UGE; - } - vswap(); - gen_cast_s(t); - vswap(); - /* special case for shifts and long long: we keep the shift as - an integer */ - if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL) - t2 = VT_INT; - gen_cast_s(t2); - if (is_float(t)) - gen_opif(op); - else - gen_opic(op); - if (TOK_ISCOND(op)) { - /* relational op: the result is an int */ - vtop->type.t = VT_INT; - } else { - vtop->type.t = t; - } - } - // Make sure that we have converted to an rvalue: - if (vtop->r & VT_LVAL) - gv(is_float(vtop->type.t & VT_BTYPE) ? RC_FLOAT : RC_INT); -} - -#if defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64 || defined TCC_TARGET_ARM -#define gen_cvt_itof1 gen_cvt_itof -#else -/* generic itof for unsigned long long case */ -static void gen_cvt_itof1(int t) -{ - if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == - (VT_LLONG | VT_UNSIGNED)) { - - if (t == VT_FLOAT) - vpush_helper_func(TOK___floatundisf); -#if LDOUBLE_SIZE != 8 - else if (t == VT_LDOUBLE) - vpush_helper_func(TOK___floatundixf); -#endif - else - vpush_helper_func(TOK___floatundidf); - vrott(2); - gfunc_call(1); - vpushi(0); - PUT_R_RET(vtop, t); - } else { - gen_cvt_itof(t); - } -} -#endif - -#if defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64 -#define gen_cvt_ftoi1 gen_cvt_ftoi -#else -/* generic ftoi for unsigned long long case */ -static void gen_cvt_ftoi1(int t) -{ - int st; - if (t == (VT_LLONG | VT_UNSIGNED)) { - /* not handled natively */ - st = vtop->type.t & VT_BTYPE; - if (st == VT_FLOAT) - vpush_helper_func(TOK___fixunssfdi); -#if LDOUBLE_SIZE != 8 - else if (st == VT_LDOUBLE) - vpush_helper_func(TOK___fixunsxfdi); -#endif - else - vpush_helper_func(TOK___fixunsdfdi); - vrott(2); - gfunc_call(1); - vpushi(0); - PUT_R_RET(vtop, t); - } else { - gen_cvt_ftoi(t); - } -} -#endif - -/* special delayed cast for char/short */ -static void force_charshort_cast(void) -{ - int sbt = BFGET(vtop->r, VT_MUSTCAST) == 2 ? VT_LLONG : VT_INT; - int dbt = vtop->type.t; - vtop->r &= ~VT_MUSTCAST; - vtop->type.t = sbt; - gen_cast_s(dbt == VT_BOOL ? VT_BYTE|VT_UNSIGNED : dbt); - vtop->type.t = dbt; -} - -static void gen_cast_s(int t) -{ - CType type; - type.t = t; - type.ref = NULL; - gen_cast(&type); -} - -/* cast 'vtop' to 'type'. Casting to bitfields is forbidden. */ -static void gen_cast(CType *type) -{ - int sbt, dbt, sf, df, c; - int dbt_bt, sbt_bt, ds, ss, bits, trunc; - - /* special delayed cast for char/short */ - if (vtop->r & VT_MUSTCAST) - force_charshort_cast(); - - /* bitfields first get cast to ints */ - if (vtop->type.t & VT_BITFIELD) - gv(RC_INT); - - dbt = type->t & (VT_BTYPE | VT_UNSIGNED); - sbt = vtop->type.t & (VT_BTYPE | VT_UNSIGNED); - if (sbt == VT_FUNC) - sbt = VT_PTR; - -again: - if (sbt != dbt) { - sf = is_float(sbt); - df = is_float(dbt); - dbt_bt = dbt & VT_BTYPE; - sbt_bt = sbt & VT_BTYPE; - if (dbt_bt == VT_VOID) - goto done; - if (sbt_bt == VT_VOID) { -error: - cast_error(&vtop->type, type); - } - - c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; -#if !defined TCC_IS_NATIVE && !defined TCC_IS_NATIVE_387 - /* don't try to convert to ldouble when cross-compiling - (except when it's '0' which is needed for arm:gen_negf()) */ - if (dbt_bt == VT_LDOUBLE && !nocode_wanted && (sf || vtop->c.i != 0)) - c = 0; -#endif - if (c) { - /* constant case: we can do it now */ - /* XXX: in ISOC, cannot do it if error in convert */ - if (sbt == VT_FLOAT) - vtop->c.ld = vtop->c.f; - else if (sbt == VT_DOUBLE) - vtop->c.ld = vtop->c.d; - - if (df) { - if (sbt_bt == VT_LLONG) { - if ((sbt & VT_UNSIGNED) || !(vtop->c.i >> 63)) - vtop->c.ld = vtop->c.i; - else - vtop->c.ld = -(long double)-vtop->c.i; - } else if(!sf) { - if ((sbt & VT_UNSIGNED) || !(vtop->c.i >> 31)) - vtop->c.ld = (uint32_t)vtop->c.i; - else - vtop->c.ld = -(long double)-(uint32_t)vtop->c.i; - } - - if (dbt == VT_FLOAT) - vtop->c.f = (float)vtop->c.ld; - else if (dbt == VT_DOUBLE) - vtop->c.d = (double)vtop->c.ld; - } else if (sf && dbt == VT_BOOL) { - vtop->c.i = (vtop->c.ld != 0); - } else { - if(sf) - vtop->c.i = vtop->c.ld; - else if (sbt_bt == VT_LLONG || (PTR_SIZE == 8 && sbt == VT_PTR)) - ; - else if (sbt & VT_UNSIGNED) - vtop->c.i = (uint32_t)vtop->c.i; - else - vtop->c.i = ((uint32_t)vtop->c.i | -(vtop->c.i & 0x80000000)); - - if (dbt_bt == VT_LLONG || (PTR_SIZE == 8 && dbt == VT_PTR)) - ; - else if (dbt == VT_BOOL) - vtop->c.i = (vtop->c.i != 0); - else { - uint32_t m = dbt_bt == VT_BYTE ? 0xff : - dbt_bt == VT_SHORT ? 0xffff : - 0xffffffff; - vtop->c.i &= m; - if (!(dbt & VT_UNSIGNED)) - vtop->c.i |= -(vtop->c.i & ((m >> 1) + 1)); - } - } - goto done; - - } else if (dbt == VT_BOOL - && (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) - == (VT_CONST | VT_SYM)) { - /* addresses are considered non-zero (see tcctest.c:sinit23) */ - vtop->r = VT_CONST; - vtop->c.i = 1; - goto done; - } - - /* cannot generate code for global or static initializers */ - if (nocode_wanted & DATA_ONLY_WANTED) - goto done; - - /* non constant case: generate code */ - if (dbt == VT_BOOL) { - gen_test_zero(TOK_NE); - goto done; - } - - if (sf || df) { - if (sf && df) { - /* convert from fp to fp */ - gen_cvt_ftof(dbt); - } else if (df) { - /* convert int to fp */ - gen_cvt_itof1(dbt); - } else { - /* convert fp to int */ - sbt = dbt; - if (dbt_bt != VT_LLONG && dbt_bt != VT_INT) - sbt = VT_INT; - gen_cvt_ftoi1(sbt); - goto again; /* may need char/short cast */ - } - goto done; - } - - ds = btype_size(dbt_bt); - ss = btype_size(sbt_bt); - if (ds == 0 || ss == 0) - goto error; - - if (IS_ENUM(type->t) && type->ref->c < 0) - tcc_error("cast to incomplete type"); - - /* same size and no sign conversion needed */ - if (ds == ss && ds >= 4) - goto done; - if (dbt_bt == VT_PTR || sbt_bt == VT_PTR) { - tcc_warning("cast between pointer and integer of different size"); - if (sbt_bt == VT_PTR) { - /* put integer type to allow logical operations below */ - vtop->type.t = (PTR_SIZE == 8 ? VT_LLONG : VT_INT); - } - } - - /* processor allows { int a = 0, b = *(char*)&a; } - That means that if we cast to less width, we can just - change the type and read it still later. */ - #define ALLOW_SUBTYPE_ACCESS 1 - - if (ALLOW_SUBTYPE_ACCESS && (vtop->r & VT_LVAL)) { - /* value still in memory */ - if (ds <= ss) - goto done; - /* ss <= 4 here */ - if (ds <= 4 && !(dbt == (VT_SHORT | VT_UNSIGNED) && sbt == VT_BYTE)) { - gv(RC_INT); - goto done; /* no 64bit envolved */ - } - } - gv(RC_INT); - - trunc = 0; -#if PTR_SIZE == 4 - if (ds == 8) { - /* generate high word */ - if (sbt & VT_UNSIGNED) { - vpushi(0); - gv(RC_INT); - } else { - gv_dup(); - vpushi(31); - gen_op(TOK_SAR); - } - lbuild(dbt); - } else if (ss == 8) { - /* from long long: just take low order word */ - lexpand(); - vpop(); - } - ss = 4; - -#elif PTR_SIZE == 8 - if (ds == 8) { - /* need to convert from 32bit to 64bit */ - if (sbt & VT_UNSIGNED) { -#if defined(TCC_TARGET_RISCV64) - /* RISC-V keeps 32bit vals in registers sign-extended. - So here we need a zero-extension. */ - trunc = 32; -#else - goto done; -#endif - } else { - gen_cvt_sxtw(); - goto done; - } - ss = ds, ds = 4, dbt = sbt; - } else if (ss == 8) { - /* RISC-V keeps 32bit vals in registers sign-extended. - So here we need a sign-extension for signed types and - zero-extension. for unsigned types. */ -#if !defined(TCC_TARGET_RISCV64) - trunc = 32; /* zero upper 32 bits for non RISC-V targets */ -#endif - } else { - ss = 4; - } -#endif - - if (ds >= ss) - goto done; -#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 || defined TCC_TARGET_ARM64 - if (ss == 4) { - gen_cvt_csti(dbt); - goto done; - } -#endif - bits = (ss - ds) * 8; - /* for unsigned, gen_op will convert SAR to SHR */ - vtop->type.t = (ss == 8 ? VT_LLONG : VT_INT) | (dbt & VT_UNSIGNED); - vpushi(bits); - gen_op(TOK_SHL); - vpushi(bits - trunc); - gen_op(TOK_SAR); - vpushi(trunc); - gen_op(TOK_SHR); - } -done: - vtop->type = *type; - vtop->type.t &= ~ ( VT_CONSTANT | VT_VOLATILE | VT_ARRAY ); -} - -/* return type size as known at compile time. Put alignment at 'a' */ -ST_FUNC int type_size(CType *type, int *a) -{ - Sym *s; - int bt; - - bt = type->t & VT_BTYPE; - if (bt == VT_STRUCT) { - /* struct/union */ - s = type->ref; - *a = s->r; - return s->c; - } else if (bt == VT_PTR) { - if (type->t & VT_ARRAY) { - int ts; - - s = type->ref; - ts = type_size(&s->type, a); - - if (ts < 0 && s->c < 0) - ts = -ts; - - return ts * s->c; - } else { - *a = PTR_SIZE; - return PTR_SIZE; - } - } else if (IS_ENUM(type->t) && type->ref->c < 0) { - *a = 0; - return -1; /* incomplete enum */ - } else if (bt == VT_LDOUBLE) { - *a = LDOUBLE_ALIGN; - return LDOUBLE_SIZE; - } else if (bt == VT_DOUBLE || bt == VT_LLONG) { -#ifdef TCC_TARGET_I386 -#ifdef TCC_TARGET_PE - *a = 8; -#else - *a = 4; -#endif -#elif defined(TCC_TARGET_ARM) -#ifdef TCC_ARM_EABI - *a = 8; -#else - *a = 4; -#endif -#else - *a = 8; -#endif - return 8; - } else if (bt == VT_INT || bt == VT_FLOAT) { - *a = 4; - return 4; - } else if (bt == VT_SHORT) { - *a = 2; - return 2; - } else if (bt == VT_QLONG || bt == VT_QFLOAT) { - *a = 8; - return 16; - } else { - /* char, void, function, _Bool */ - *a = 1; - return 1; - } -} - -/* push type size as known at runtime time on top of value stack. Put - alignment at 'a' */ -static void vpush_type_size(CType *type, int *a) -{ - if (type->t & VT_VLA) { - type_size(&type->ref->type, a); - vset(&int_type, VT_LOCAL|VT_LVAL, type->ref->c); - } else { - int size = type_size(type, a); - if (size < 0) - tcc_error("unknown type size"); -#if PTR_SIZE == 8 - vpushll(size); -#else - vpushi(size); -#endif - } -} - -/* return the pointed type of t */ -static inline CType *pointed_type(CType *type) -{ - return &type->ref->type; -} - -/* modify type so that its it is a pointer to type. */ -ST_FUNC void mk_pointer(CType *type) -{ - Sym *s; - s = sym_push(SYM_FIELD, type, 0, -1); - type->t = VT_PTR | (type->t & VT_STORAGE); - type->ref = s; -} - -/* return true if type1 and type2 are exactly the same (including - qualifiers). -*/ -static int is_compatible_types(CType *type1, CType *type2) -{ - return compare_types(type1,type2,0); -} - -/* return true if type1 and type2 are the same (ignoring qualifiers). -*/ -static int is_compatible_unqualified_types(CType *type1, CType *type2) -{ - return compare_types(type1,type2,1); -} - -static void cast_error(CType *st, CType *dt) -{ - type_incompatibility_error(st, dt, "cannot convert '%s' to '%s'"); -} - -/* verify type compatibility to store vtop in 'dt' type */ -static void verify_assign_cast(CType *dt) -{ - CType *st, *type1, *type2; - int dbt, sbt, qualwarn, lvl; - - st = &vtop->type; /* source type */ - dbt = dt->t & VT_BTYPE; - sbt = st->t & VT_BTYPE; - if (dt->t & VT_CONSTANT) - tcc_warning("assignment of read-only location"); - switch(dbt) { - case VT_VOID: - if (sbt != dbt) - tcc_error("assignment to void expression"); - break; - case VT_PTR: - /* special cases for pointers */ - /* '0' can also be a pointer */ - if (is_null_pointer(vtop)) - break; - /* accept implicit pointer to integer cast with warning */ - if (is_integer_btype(sbt)) { - tcc_warning("assignment makes pointer from integer without a cast"); - break; - } - type1 = pointed_type(dt); - if (sbt == VT_PTR) - type2 = pointed_type(st); - else if (sbt == VT_FUNC) - type2 = st; /* a function is implicitly a function pointer */ - else - goto error; - if (is_compatible_types(type1, type2)) - break; - for (qualwarn = lvl = 0;; ++lvl) { - if (((type2->t & VT_CONSTANT) && !(type1->t & VT_CONSTANT)) || - ((type2->t & VT_VOLATILE) && !(type1->t & VT_VOLATILE))) - qualwarn = 1; - dbt = type1->t & (VT_BTYPE|VT_LONG); - sbt = type2->t & (VT_BTYPE|VT_LONG); - if (dbt != VT_PTR || sbt != VT_PTR) - break; - type1 = pointed_type(type1); - type2 = pointed_type(type2); - } - if (!is_compatible_unqualified_types(type1, type2)) { - if ((dbt == VT_VOID || sbt == VT_VOID) && lvl == 0) { - /* void * can match anything */ - } else if (dbt == sbt - && is_integer_btype(sbt & VT_BTYPE) - && IS_ENUM(type1->t) + IS_ENUM(type2->t) - + !!((type1->t ^ type2->t) & VT_UNSIGNED) < 2) { - /* Like GCC don't warn by default for merely changes - in pointer target signedness. Do warn for different - base types, though, in particular for unsigned enums - and signed int targets. */ - } else { - tcc_warning("assignment from incompatible pointer type"); - break; - } - } - if (qualwarn) - tcc_warning_c(warn_discarded_qualifiers)("assignment discards qualifiers from pointer target type"); - break; - case VT_BYTE: - case VT_SHORT: - case VT_INT: - case VT_LLONG: - if (sbt == VT_PTR || sbt == VT_FUNC) { - tcc_warning("assignment makes integer from pointer without a cast"); - } else if (sbt == VT_STRUCT) { - goto case_VT_STRUCT; - } - /* XXX: more tests */ - break; - case VT_STRUCT: - case_VT_STRUCT: - if (!is_compatible_unqualified_types(dt, st)) { - error: - cast_error(st, dt); - } - break; - } -} - -static void gen_assign_cast(CType *dt) -{ - verify_assign_cast(dt); - gen_cast(dt); -} - -/* store vtop in lvalue pushed on stack */ -ST_FUNC void vstore(void) -{ - int sbt, dbt, ft, r, size, align, bit_size, bit_pos, delayed_cast; - - ft = vtop[-1].type.t; - sbt = vtop->type.t & VT_BTYPE; - dbt = ft & VT_BTYPE; - verify_assign_cast(&vtop[-1].type); - - if (sbt == VT_STRUCT) { - /* if structure, only generate pointer */ - /* structure assignment : generate memcpy */ - size = type_size(&vtop->type, &align); - /* destination, keep on stack() as result */ - vpushv(vtop - 1); -#ifdef CONFIG_TCC_BCHECK - if (vtop->r & VT_MUSTBOUND) - gbound(); /* check would be wrong after gaddrof() */ -#endif - vtop->type.t = VT_PTR; - gaddrof(); - /* source */ - vswap(); -#ifdef CONFIG_TCC_BCHECK - if (vtop->r & VT_MUSTBOUND) - gbound(); -#endif - vtop->type.t = VT_PTR; - gaddrof(); - -#ifdef TCC_TARGET_NATIVE_STRUCT_COPY - if (1 -#ifdef CONFIG_TCC_BCHECK - && !tcc_state->do_bounds_check -#endif - ) { - gen_struct_copy(size); - } else -#endif - { - /* type size */ - vpushi(size); - /* Use memmove, rather than memcpy, as dest and src may be same: */ -#ifdef TCC_ARM_EABI - if(!(align & 7)) - vpush_helper_func(TOK_memmove8); - else if(!(align & 3)) - vpush_helper_func(TOK_memmove4); - else -#endif - vpush_helper_func(TOK_memmove); - vrott(4); - gfunc_call(3); - } - - } else if (ft & VT_BITFIELD) { - /* bitfield store handling */ - - /* save lvalue as expression result (example: s.b = s.a = n;) */ - vdup(), vtop[-1] = vtop[-2]; - - bit_pos = BIT_POS(ft); - bit_size = BIT_SIZE(ft); - /* remove bit field info to avoid loops */ - vtop[-1].type.t = ft & ~VT_STRUCT_MASK; - - if (dbt == VT_BOOL) { - gen_cast(&vtop[-1].type); - vtop[-1].type.t = (vtop[-1].type.t & ~VT_BTYPE) | (VT_BYTE | VT_UNSIGNED); - } - r = adjust_bf(vtop - 1, bit_pos, bit_size); - if (dbt != VT_BOOL) { - gen_cast(&vtop[-1].type); - dbt = vtop[-1].type.t & VT_BTYPE; - } - if (r == VT_STRUCT) { - store_packed_bf(bit_pos, bit_size); - } else { - unsigned long long mask = (1ULL << bit_size) - 1; - if (dbt != VT_BOOL) { - /* mask source */ - if (dbt == VT_LLONG) - vpushll(mask); - else - vpushi((unsigned)mask); - gen_op('&'); - } - /* shift source */ - vpushi(bit_pos); - gen_op(TOK_SHL); - vswap(); - /* duplicate destination */ - vdup(); - vrott(3); - /* load destination, mask and or with source */ - if (dbt == VT_LLONG) - vpushll(~(mask << bit_pos)); - else - vpushi(~((unsigned)mask << bit_pos)); - gen_op('&'); - gen_op('|'); - /* store result */ - vstore(); - /* ... and discard */ - vpop(); - } - } else if (dbt == VT_VOID) { - --vtop; - } else { - /* optimize char/short casts */ - delayed_cast = 0; - if ((dbt == VT_BYTE || dbt == VT_SHORT) - && is_integer_btype(sbt) - ) { - if ((vtop->r & VT_MUSTCAST) - && btype_size(dbt) > btype_size(sbt) - ) - force_charshort_cast(); - delayed_cast = 1; - } else { - gen_cast(&vtop[-1].type); - } - -#ifdef CONFIG_TCC_BCHECK - /* bound check case */ - if (vtop[-1].r & VT_MUSTBOUND) { - vswap(); - gbound(); - vswap(); - } -#endif - gv(RC_TYPE(dbt)); /* generate value */ - - if (delayed_cast) { - vtop->r |= BFVAL(VT_MUSTCAST, (sbt == VT_LLONG) + 1); - //tcc_warning("deley cast %x -> %x", sbt, dbt); - vtop->type.t = ft & VT_TYPE; - } - - /* if lvalue was saved on stack, must read it */ - if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) { - SValue sv; - r = get_reg(RC_INT); - sv.type.t = VT_PTRDIFF_T; - sv.r = VT_LOCAL | VT_LVAL; - sv.c.i = vtop[-1].c.i; - load(r, &sv); - vtop[-1].r = r | VT_LVAL; - } - - r = vtop->r & VT_VALMASK; - /* two word case handling : - store second register at word + 4 (or +8 for x86-64) */ - if (USING_TWO_WORDS(dbt)) { - int load_type = (dbt == VT_QFLOAT) ? VT_DOUBLE : VT_PTRDIFF_T; - vtop[-1].type.t = load_type; - store(r, vtop - 1); - vswap(); - /* convert to int to increment easily */ - vtop->type.t = VT_PTRDIFF_T; - gaddrof(); - vpushs(PTR_SIZE); - gen_op('+'); - vtop->r |= VT_LVAL; - vswap(); - vtop[-1].type.t = load_type; - /* XXX: it works because r2 is spilled last ! */ - store(vtop->r2, vtop - 1); - } else { - /* single word */ - store(r, vtop - 1); - } - vswap(); - vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ - } -} - -/* post defines POST/PRE add. c is the token ++ or -- */ -ST_FUNC void inc(int post, int c) -{ - test_lvalue(); - vdup(); /* save lvalue */ - if (post) { - gv_dup(); /* duplicate value */ - vrotb(3); - vrotb(3); - } - /* add constant */ - vpushi(c - TOK_MID); - gen_op('+'); - vstore(); /* store value */ - if (post) - vpop(); /* if post op, return saved value */ -} - -ST_FUNC CString* parse_mult_str (const char *msg) -{ - /* read the string */ - if (tok != TOK_STR) - expect(msg); - cstr_reset(&initstr); - while (tok == TOK_STR) { - /* XXX: add \0 handling too ? */ - cstr_cat(&initstr, tokc.str.data, -1); - next(); - } - cstr_ccat(&initstr, '\0'); - return &initstr; -} - -/* If I is >= 1 and a power of two, returns log2(i)+1. - If I is 0 returns 0. */ -ST_FUNC int exact_log2p1(int i) -{ - int ret; - if (!i) - return 0; - for (ret = 1; i >= 1 << 8; ret += 8) - i >>= 8; - if (i >= 1 << 4) - ret += 4, i >>= 4; - if (i >= 1 << 2) - ret += 2, i >>= 2; - if (i >= 1 << 1) - ret++; - return ret; -} - -/* Parse __attribute__((...)) GNUC extension. */ -static void parse_attribute(AttributeDef *ad) -{ - int t, n; - char *astr; - -redo: - if (tok != TOK_ATTRIBUTE1 && tok != TOK_ATTRIBUTE2) - return; - next(); - skip('('); - skip('('); - while (tok != ')') { - if (tok < TOK_IDENT) - expect("attribute name"); - t = tok; - next(); - switch(t) { - case TOK_CLEANUP1: - case TOK_CLEANUP2: - { - Sym *s; - - skip('('); - s = sym_find(tok); - if (!s) { - tcc_warning_c(warn_implicit_function_declaration)( - "implicit declaration of function '%s'", get_tok_str(tok, &tokc)); - s = external_global_sym(tok, &func_old_type); - } else if ((s->type.t & VT_BTYPE) != VT_FUNC) - tcc_error("'%s' is not declared as function", get_tok_str(tok, &tokc)); - ad->cleanup_func = s; - next(); - skip(')'); - break; - } - case TOK_CONSTRUCTOR1: - case TOK_CONSTRUCTOR2: - ad->f.func_ctor = 1; - break; - case TOK_DESTRUCTOR1: - case TOK_DESTRUCTOR2: - ad->f.func_dtor = 1; - break; - case TOK_ALWAYS_INLINE1: - case TOK_ALWAYS_INLINE2: - ad->f.func_alwinl = 1; - break; - case TOK_SECTION1: - case TOK_SECTION2: - skip('('); - astr = parse_mult_str("section name")->data; - ad->section = find_section(tcc_state, astr); - skip(')'); - break; - case TOK_ALIAS1: - case TOK_ALIAS2: - skip('('); - astr = parse_mult_str("alias(\"target\")")->data; - /* save string as token, for later */ - ad->alias_target = tok_alloc_const(astr); - skip(')'); - break; - case TOK_VISIBILITY1: - case TOK_VISIBILITY2: - skip('('); - astr = parse_mult_str("visibility(\"default|hidden|internal|protected\")")->data; - if (!strcmp (astr, "default")) - ad->a.visibility = STV_DEFAULT; - else if (!strcmp (astr, "hidden")) - ad->a.visibility = STV_HIDDEN; - else if (!strcmp (astr, "internal")) - ad->a.visibility = STV_INTERNAL; - else if (!strcmp (astr, "protected")) - ad->a.visibility = STV_PROTECTED; - else - expect("visibility(\"default|hidden|internal|protected\")"); - skip(')'); - break; - case TOK_ALIGNED1: - case TOK_ALIGNED2: - if (tok == '(') { - next(); - n = expr_const(); - if (n <= 0 || (n & (n - 1)) != 0) - tcc_error("alignment must be a positive power of two"); - skip(')'); - } else { - n = MAX_ALIGN; - } - ad->a.aligned = exact_log2p1(n); - if (n != 1 << (ad->a.aligned - 1)) - tcc_error("alignment of %d is larger than implemented", n); - break; - case TOK_PACKED1: - case TOK_PACKED2: - ad->a.packed = 1; - break; - case TOK_WEAK1: - case TOK_WEAK2: - ad->a.weak = 1; - break; - case TOK_NODEBUG1: - case TOK_NODEBUG2: - ad->a.nodebug = 1; - break; - case TOK_UNUSED1: - case TOK_UNUSED2: - /* currently, no need to handle it because tcc does not - track unused objects */ - break; - case TOK_NORETURN1: - case TOK_NORETURN2: - ad->f.func_noreturn = 1; - break; - case TOK_CDECL1: - case TOK_CDECL2: - case TOK_CDECL3: - ad->f.func_call = FUNC_CDECL; - break; - case TOK_STDCALL1: - case TOK_STDCALL2: - case TOK_STDCALL3: - ad->f.func_call = FUNC_STDCALL; - break; -#ifdef TCC_TARGET_I386 - case TOK_REGPARM1: - case TOK_REGPARM2: - skip('('); - n = expr_const(); - if (n > 3) - n = 3; - else if (n < 0) - n = 0; - if (n > 0) - ad->f.func_call = FUNC_FASTCALL1 + n - 1; - skip(')'); - break; - case TOK_FASTCALL1: - case TOK_FASTCALL2: - case TOK_FASTCALL3: - ad->f.func_call = FUNC_FASTCALLW; - break; -#endif - case TOK_MODE: - skip('('); - switch(tok) { - case TOK_MODE_DI: - ad->attr_mode = VT_LLONG + 1; - break; - case TOK_MODE_QI: - ad->attr_mode = VT_BYTE + 1; - break; - case TOK_MODE_HI: - ad->attr_mode = VT_SHORT + 1; - break; - case TOK_MODE_SI: - case TOK_MODE_word: - ad->attr_mode = VT_INT + 1; - break; - default: - tcc_warning("__mode__(%s) not supported\n", get_tok_str(tok, NULL)); - break; - } - next(); - skip(')'); - break; - case TOK_DLLEXPORT: - ad->a.dllexport = 1; - break; - case TOK_NODECORATE: - ad->a.nodecorate = 1; - break; - case TOK_DLLIMPORT: - ad->a.dllimport = 1; - break; - default: - tcc_warning_c(warn_unsupported)("'%s' attribute ignored", get_tok_str(t, NULL)); - /* skip parameters */ - if (tok == '(') { - int parenthesis = 0; - do { - if (tok == '(') - parenthesis++; - else if (tok == ')') - parenthesis--; - next(); - } while (parenthesis && tok != -1); - } - break; - } - if (tok != ',') - break; - next(); - } - skip(')'); - skip(')'); - goto redo; -} - -static Sym * find_field (CType *type, int v, int *cumofs) -{ - Sym *s = type->ref; - int v1 = v | SYM_FIELD; - - while ((s = s->next) != NULL) { - if (s->v == v1) { - *cumofs += s->c; - return s; - } - if ((s->type.t & VT_BTYPE) == VT_STRUCT - && s->v >= (SYM_FIRST_ANOM | SYM_FIELD)) { - /* try to find field in anonymous sub-struct/union */ - Sym *ret = find_field (&s->type, v1, cumofs); - if (ret) { - *cumofs += s->c; - return ret; - } - } - } - - if (!(v & SYM_FIELD)) { /* top-level call */ - s = type->ref; - if (s->c < 0) - tcc_error("dereferencing incomplete type '%s'", - get_tok_str(s->v & ~SYM_STRUCT, 0)); - else - tcc_error("field not found: %s", - get_tok_str(v, &tokc)); - } - return NULL; -} - -static void check_fields (CType *type, int check) -{ - Sym *s = type->ref; - - while ((s = s->next) != NULL) { - int v = s->v & ~SYM_FIELD; - if (v < SYM_FIRST_ANOM) { - TokenSym *ts = table_ident[v - TOK_IDENT]; - if (check && (ts->tok & SYM_FIELD)) - tcc_error("duplicate member '%s'", get_tok_str(v, NULL)); - ts->tok ^= SYM_FIELD; - } else if ((s->type.t & VT_BTYPE) == VT_STRUCT) - check_fields (&s->type, check); - } -} - -static void struct_layout(CType *type, AttributeDef *ad) -{ - int size, align, maxalign, offset, c, bit_pos, bit_size; - int packed, a, bt, prevbt, prev_bit_size; - int pcc = !tcc_state->ms_bitfields; - int pragma_pack = *tcc_state->pack_stack_ptr; - Sym *f; - - maxalign = 1; - offset = 0; - c = 0; - bit_pos = 0; - prevbt = VT_STRUCT; /* make it never match */ - prev_bit_size = 0; - -//#define BF_DEBUG - - for (f = type->ref->next; f; f = f->next) { - if (f->type.t & VT_BITFIELD) - bit_size = BIT_SIZE(f->type.t); - else - bit_size = -1; - size = type_size(&f->type, &align); - a = f->a.aligned ? 1 << (f->a.aligned - 1) : 0; - packed = 0; - - if (pcc && bit_size == 0) { - /* in pcc mode, packing does not affect zero-width bitfields */ - - } else { - /* in pcc mode, attribute packed overrides if set. */ - if (pcc && (f->a.packed || ad->a.packed)) - align = packed = 1; - - /* pragma pack overrides align if lesser and packs bitfields always */ - if (pragma_pack) { - packed = 1; - if (pragma_pack < align) - align = pragma_pack; - /* in pcc mode pragma pack also overrides individual align */ - if (pcc && pragma_pack < a) - a = 0; - } - } - /* some individual align was specified */ - if (a) - align = a; - - if (type->ref->type.t == VT_UNION) { - if (pcc && bit_size >= 0) - size = (bit_size + 7) >> 3; - offset = 0; - if (size > c) - c = size; - - } else if (bit_size < 0) { - if (pcc) - c += (bit_pos + 7) >> 3; - c = (c + align - 1) & -align; - offset = c; - if (size > 0) - c += size; - bit_pos = 0; - prevbt = VT_STRUCT; - prev_bit_size = 0; - - } else { - /* A bit-field. Layout is more complicated. There are two - options: PCC (GCC) compatible and MS compatible */ - if (pcc) { - /* In PCC layout a bit-field is placed adjacent to the - preceding bit-fields, except if: - - it has zero-width - - an individual alignment was given - - it would overflow its base type container and - there is no packing */ - if (bit_size == 0) { - new_field: - c = (c + ((bit_pos + 7) >> 3) + align - 1) & -align; - bit_pos = 0; - } else if (f->a.aligned) { - goto new_field; - } else if (!packed) { - int a8 = align * 8; - int ofs = ((c * 8 + bit_pos) % a8 + bit_size + a8 - 1) / a8; - if (ofs > size / align) - goto new_field; - } - - /* in pcc mode, long long bitfields have type int if they fit */ - if (size == 8 && bit_size <= 32) - f->type.t = (f->type.t & ~VT_BTYPE) | VT_INT, size = 4; - - while (bit_pos >= align * 8) - c += align, bit_pos -= align * 8; - offset = c; - - /* In PCC layout named bit-fields influence the alignment - of the containing struct using the base types alignment, - except for packed fields (which here have correct align). */ - if (f->v & SYM_FIRST_ANOM - // && bit_size // ??? gcc on ARM/rpi does that - ) - align = 1; - - } else { - bt = f->type.t & VT_BTYPE; - if ((bit_pos + bit_size > size * 8) - || (bit_size > 0) == (bt != prevbt) - ) { - c = (c + align - 1) & -align; - offset = c; - bit_pos = 0; - /* In MS bitfield mode a bit-field run always uses - at least as many bits as the underlying type. - To start a new run it's also required that this - or the last bit-field had non-zero width. */ - if (bit_size || prev_bit_size) - c += size; - } - /* In MS layout the records alignment is normally - influenced by the field, except for a zero-width - field at the start of a run (but by further zero-width - fields it is again). */ - if (bit_size == 0 && prevbt != bt) - align = 1; - prevbt = bt; - prev_bit_size = bit_size; - } - - f->type.t = (f->type.t & ~(0x3f << VT_STRUCT_SHIFT)) - | (bit_pos << VT_STRUCT_SHIFT); - bit_pos += bit_size; - } - if (align > maxalign) - maxalign = align; - -#ifdef BF_DEBUG - printf("set field %s offset %-2d size %-2d align %-2d", - get_tok_str(f->v & ~SYM_FIELD, NULL), offset, size, align); - if (f->type.t & VT_BITFIELD) { - printf(" pos %-2d bits %-2d", - BIT_POS(f->type.t), - BIT_SIZE(f->type.t) - ); - } - printf("\n"); -#endif - - f->c = offset; - f->r = 0; - } - - if (pcc) - c += (bit_pos + 7) >> 3; - - /* store size and alignment */ - a = bt = ad->a.aligned ? 1 << (ad->a.aligned - 1) : 1; - if (a < maxalign) - a = maxalign; - type->ref->r = a; - if (pragma_pack && pragma_pack < maxalign && 0 == pcc) { - /* can happen if individual align for some member was given. In - this case MSVC ignores maxalign when aligning the size */ - a = pragma_pack; - if (a < bt) - a = bt; - } - c = (c + a - 1) & -a; - type->ref->c = c; - -#ifdef BF_DEBUG - printf("struct size %-2d align %-2d\n\n", c, a), fflush(stdout); -#endif - - /* check whether we can access bitfields by their type */ - for (f = type->ref->next; f; f = f->next) { - int s, px, cx, c0; - CType t; - - if (0 == (f->type.t & VT_BITFIELD)) - continue; - f->type.ref = f; - f->auxtype = -1; - bit_size = BIT_SIZE(f->type.t); - if (bit_size == 0) - continue; - bit_pos = BIT_POS(f->type.t); - size = type_size(&f->type, &align); - - if (bit_pos + bit_size <= size * 8 && f->c + size <= c -#ifdef TCC_TARGET_ARM - && !(f->c & (align - 1)) -#endif - ) - continue; - - /* try to access the field using a different type */ - c0 = -1, s = align = 1; - t.t = VT_BYTE; - for (;;) { - px = f->c * 8 + bit_pos; - cx = (px >> 3) & -align; - px = px - (cx << 3); - if (c0 == cx) - break; - s = (px + bit_size + 7) >> 3; - if (s > 4) { - t.t = VT_LLONG; - } else if (s > 2) { - t.t = VT_INT; - } else if (s > 1) { - t.t = VT_SHORT; - } else { - t.t = VT_BYTE; - } - s = type_size(&t, &align); - c0 = cx; - } - - if (px + bit_size <= s * 8 && cx + s <= c -#ifdef TCC_TARGET_ARM - && !(cx & (align - 1)) -#endif - ) { - /* update offset and bit position */ - f->c = cx; - bit_pos = px; - f->type.t = (f->type.t & ~(0x3f << VT_STRUCT_SHIFT)) - | (bit_pos << VT_STRUCT_SHIFT); - if (s != size) - f->auxtype = t.t; -#ifdef BF_DEBUG - printf("FIX field %s offset %-2d size %-2d align %-2d " - "pos %-2d bits %-2d\n", - get_tok_str(f->v & ~SYM_FIELD, NULL), - cx, s, align, px, bit_size); -#endif - } else { - /* fall back to load/store single-byte wise */ - f->auxtype = VT_STRUCT; -#ifdef BF_DEBUG - printf("FIX field %s : load byte-wise\n", - get_tok_str(f->v & ~SYM_FIELD, NULL)); -#endif - } - } -} - -static void do_Static_assert(void); - -/* enum/struct/union declaration. u is VT_ENUM/VT_STRUCT/VT_UNION */ -static void struct_decl(CType *type, int u) -{ - int v, c, size, align, flexible; - int bit_size, bsize, bt; - Sym *s, *ss, **ps; - AttributeDef ad, ad1; - CType type1, btype; - - memset(&ad, 0, sizeof ad); - next(); - parse_attribute(&ad); - if (tok != '{') { - v = tok; - next(); - /* struct already defined ? return it */ - if (v < TOK_IDENT) - expect("struct/union/enum name"); - s = struct_find(v); - if (s && (s->sym_scope == local_scope || tok != '{')) { - if (u == s->type.t) - goto do_decl; - if (u == VT_ENUM && IS_ENUM(s->type.t)) - goto do_decl; - tcc_error("redefinition of '%s'", get_tok_str(v, NULL)); - } - } else { - v = anon_sym++; - } - /* Record the original enum/struct/union token. */ - type1.t = u == VT_ENUM ? u | VT_INT | VT_UNSIGNED : u; - type1.ref = NULL; - /* we put an undefined size for struct/union */ - s = sym_push(v | SYM_STRUCT, &type1, 0, -1); - s->r = 0; /* default alignment is zero as gcc */ -do_decl: - type->t = s->type.t; - type->ref = s; - - if (tok == '{') { - next(); - if (s->c != -1) - tcc_error("struct/union/enum already defined"); - s->c = -2; - /* cannot be empty */ - /* non empty enums are not allowed */ - ps = &s->next; - if (u == VT_ENUM) { - long long ll = 0, pl = 0, nl = 0; - CType t; - t.ref = s; - /* enum symbols have static storage */ - t.t = VT_INT|VT_STATIC|VT_ENUM_VAL; - for(;;) { - v = tok; - if (v < TOK_UIDENT) - expect("identifier"); - ss = sym_find(v); - if (ss && !local_stack) - tcc_error("redefinition of enumerator '%s'", - get_tok_str(v, NULL)); - next(); - if (tok == '=') { - next(); - ll = expr_const64(); - } - ss = sym_push(v, &t, VT_CONST, 0); - ss->enum_val = ll; - *ps = ss, ps = &ss->next; - if (ll < nl) - nl = ll; - if (ll > pl) - pl = ll; - if (tok != ',') - break; - next(); - ll++; - /* NOTE: we accept a trailing comma */ - if (tok == '}') - break; - } - skip('}'); - /* set integral type of the enum */ - t.t = VT_INT; - if (nl >= 0) { - if (pl != (unsigned)pl) - t.t = (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG); - t.t |= VT_UNSIGNED; - } else if (pl != (int)pl || nl != (int)nl) - t.t = (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG); - s->type.t = type->t = t.t | VT_ENUM; - s->c = 0; - /* set type for enum members */ - for (ss = s->next; ss; ss = ss->next) { - ll = ss->enum_val; - if (ll == (int)ll) /* default is int if it fits */ - continue; - if (t.t & VT_UNSIGNED) { - ss->type.t |= VT_UNSIGNED; - if (ll == (unsigned)ll) - continue; - } - ss->type.t = (ss->type.t & ~VT_BTYPE) - | (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG); - } - } else { - c = 0; - flexible = 0; - while (tok != '}') { - if (tok == TOK_STATIC_ASSERT) { - do_Static_assert(); - continue; - } - if (!parse_btype(&btype, &ad1, 0)) { - skip(';'); - continue; - } - while (1) { - if (flexible) - tcc_error("flexible array member '%s' not at the end of struct", - get_tok_str(v, NULL)); - bit_size = -1; - v = 0; - type1 = btype; - if (tok != ':') { - if (tok != ';') - type_decl(&type1, &ad1, &v, TYPE_DIRECT); - if (v == 0) { - if ((type1.t & VT_BTYPE) != VT_STRUCT) - expect("identifier"); - else { - int v = btype.ref->v; - if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { - if (tcc_state->ms_extensions == 0) - expect("identifier"); - } - } - } - if (type_size(&type1, &align) < 0) { - if ((u == VT_STRUCT) && (type1.t & VT_ARRAY) && c) - flexible = 1; - else - tcc_error("field '%s' has incomplete type", - get_tok_str(v, NULL)); - } - if ((type1.t & VT_BTYPE) == VT_FUNC || - (type1.t & VT_BTYPE) == VT_VOID || - (type1.t & VT_STORAGE)) - tcc_error("invalid type for '%s'", - get_tok_str(v, NULL)); - } - if (tok == ':') { - next(); - bit_size = expr_const(); - /* XXX: handle v = 0 case for messages */ - if (bit_size < 0) - tcc_error("negative width in bit-field '%s'", - get_tok_str(v, NULL)); - if (v && bit_size == 0) - tcc_error("zero width for bit-field '%s'", - get_tok_str(v, NULL)); - parse_attribute(&ad1); - } - size = type_size(&type1, &align); - if (bit_size >= 0) { - bt = type1.t & VT_BTYPE; - if (bt != VT_INT && - bt != VT_BYTE && - bt != VT_SHORT && - bt != VT_BOOL && - bt != VT_LLONG) - tcc_error("bitfields must have scalar type"); - bsize = size * 8; - if (bit_size > bsize) { - tcc_error("width of '%s' exceeds its type", - get_tok_str(v, NULL)); - } else if (bit_size == bsize - && !ad.a.packed && !ad1.a.packed) { - /* no need for bit fields */ - ; - } else if (bit_size == 64) { - tcc_error("field width 64 not implemented"); - } else { - type1.t = (type1.t & ~VT_STRUCT_MASK) - | VT_BITFIELD - | (bit_size << (VT_STRUCT_SHIFT + 6)); - } - } - if (v != 0 || (type1.t & VT_BTYPE) == VT_STRUCT) { - /* Remember we've seen a real field to check - for placement of flexible array member. */ - c = 1; - } - /* If member is a struct or bit-field, enforce - placing into the struct (as anonymous). */ - if (v == 0 && - ((type1.t & VT_BTYPE) == VT_STRUCT || - bit_size >= 0)) { - v = anon_sym++; - } - if (v) { - ss = sym_push(v | SYM_FIELD, &type1, 0, 0); - ss->a = ad1.a; - *ps = ss; - ps = &ss->next; - } - if (tok == ';' || tok == TOK_EOF) - break; - skip(','); - } - skip(';'); - } - skip('}'); - parse_attribute(&ad); - if (ad.cleanup_func) { - tcc_warning("attribute '__cleanup__' ignored on type"); - } - check_fields(type, 1); - check_fields(type, 0); - struct_layout(type, &ad); - if (debug_modes) - tcc_debug_fix_anon(tcc_state, type); - } - } -} - -static void sym_to_attr(AttributeDef *ad, Sym *s) -{ - merge_symattr(&ad->a, &s->a); - merge_funcattr(&ad->f, &s->f); -} - -/* Add type qualifiers to a type. If the type is an array then the qualifiers - are added to the element type, copied because it could be a typedef. */ -static void parse_btype_qualify(CType *type, int qualifiers) -{ - while (type->t & VT_ARRAY) { - type->ref = sym_push(SYM_FIELD, &type->ref->type, 0, type->ref->c); - type = &type->ref->type; - } - type->t |= qualifiers; -} - -/* return 0 if no type declaration. otherwise, return the basic type - and skip it. - */ -static int parse_btype(CType *type, AttributeDef *ad, int ignore_label) -{ - int t, u, bt, st, type_found, typespec_found, g, n; - Sym *s; - CType type1; - - memset(ad, 0, sizeof(AttributeDef)); - type_found = 0; - typespec_found = 0; - t = VT_INT; - bt = st = -1; - type->ref = NULL; - - while(1) { - switch(tok) { - case TOK_EXTENSION: - /* currently, we really ignore extension */ - next(); - continue; - - /* basic types */ - case TOK_CHAR: - u = VT_BYTE; - basic_type: - next(); - basic_type1: - if (u == VT_SHORT || u == VT_LONG) { - if (st != -1 || (bt != -1 && bt != VT_INT)) - tmbt: tcc_error("too many basic types"); - st = u; - } else { - if (bt != -1 || (st != -1 && u != VT_INT)) - goto tmbt; - bt = u; - } - if (u != VT_INT) - t = (t & ~(VT_BTYPE|VT_LONG)) | u; - typespec_found = 1; - break; - case TOK_VOID: - u = VT_VOID; - goto basic_type; - case TOK_SHORT: - u = VT_SHORT; - goto basic_type; - case TOK_INT: - u = VT_INT; - goto basic_type; - case TOK_ALIGNAS: - { int n; - AttributeDef ad1; - next(); - skip('('); - memset(&ad1, 0, sizeof(AttributeDef)); - if (parse_btype(&type1, &ad1, 0)) { - type_decl(&type1, &ad1, &n, TYPE_ABSTRACT); - if (ad1.a.aligned) - n = 1 << (ad1.a.aligned - 1); - else - type_size(&type1, &n); - } else { - n = expr_const(); - if (n < 0 || (n & (n - 1)) != 0) - tcc_error("alignment must be a positive power of two"); - } - skip(')'); - ad->a.aligned = exact_log2p1(n); - } - continue; - case TOK_LONG: - if ((t & VT_BTYPE) == VT_DOUBLE) { - t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LDOUBLE; - } else if ((t & (VT_BTYPE|VT_LONG)) == VT_LONG) { - t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LLONG; - } else { - u = VT_LONG; - goto basic_type; - } - next(); - break; -#ifdef TCC_TARGET_ARM64 - case TOK_UINT128: - /* GCC's __uint128_t appears in some Linux header files. Make it a - synonym for long double to get the size and alignment right. */ - u = VT_LDOUBLE; - goto basic_type; -#endif - case TOK_BOOL: - u = VT_BOOL; - goto basic_type; - case TOK_COMPLEX: - tcc_error("_Complex is not yet supported"); - case TOK_FLOAT: - u = VT_FLOAT; - goto basic_type; - case TOK_DOUBLE: - if ((t & (VT_BTYPE|VT_LONG)) == VT_LONG) { - t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LDOUBLE; - } else { - u = VT_DOUBLE; - goto basic_type; - } - next(); - break; - case TOK_ENUM: - struct_decl(&type1, VT_ENUM); - basic_type2: - u = type1.t; - type->ref = type1.ref; - goto basic_type1; - case TOK_STRUCT: - struct_decl(&type1, VT_STRUCT); - goto basic_type2; - case TOK_UNION: - struct_decl(&type1, VT_UNION); - goto basic_type2; - - /* type modifiers */ - case TOK__Atomic: - next(); - type->t = t; - parse_btype_qualify(type, VT_ATOMIC); - t = type->t; - if (tok == '(') { - parse_expr_type(&type1); - /* remove all storage modifiers except typedef */ - type1.t &= ~(VT_STORAGE&~VT_TYPEDEF); - if (type1.ref) - sym_to_attr(ad, type1.ref); - goto basic_type2; - } - break; - case TOK_CONST1: - case TOK_CONST2: - case TOK_CONST3: - type->t = t; - parse_btype_qualify(type, VT_CONSTANT); - t = type->t; - next(); - break; - case TOK_VOLATILE1: - case TOK_VOLATILE2: - case TOK_VOLATILE3: - type->t = t; - parse_btype_qualify(type, VT_VOLATILE); - t = type->t; - next(); - break; - case TOK_SIGNED1: - case TOK_SIGNED2: - case TOK_SIGNED3: - if ((t & (VT_DEFSIGN|VT_UNSIGNED)) == (VT_DEFSIGN|VT_UNSIGNED)) - tcc_error("signed and unsigned modifier"); - t |= VT_DEFSIGN; - next(); - typespec_found = 1; - break; - case TOK_REGISTER: - case TOK_AUTO: - case TOK_RESTRICT1: - case TOK_RESTRICT2: - case TOK_RESTRICT3: - next(); - break; - case TOK_UNSIGNED: - if ((t & (VT_DEFSIGN|VT_UNSIGNED)) == VT_DEFSIGN) - tcc_error("signed and unsigned modifier"); - t |= VT_DEFSIGN | VT_UNSIGNED; - next(); - typespec_found = 1; - break; - - /* storage */ - case TOK_EXTERN: - g = VT_EXTERN; - goto storage; - case TOK_STATIC: - g = VT_STATIC; - goto storage; - case TOK_TYPEDEF: - g = VT_TYPEDEF; - goto storage; - storage: - if (t & (VT_EXTERN|VT_STATIC|VT_TYPEDEF) & ~g) - tcc_error("multiple storage classes"); - t |= g; - next(); - break; - case TOK_INLINE1: - case TOK_INLINE2: - case TOK_INLINE3: - t |= VT_INLINE; - next(); - break; - case TOK_NORETURN3: - next(); - ad->f.func_noreturn = 1; - break; - /* GNUC attribute */ - case TOK_ATTRIBUTE1: - case TOK_ATTRIBUTE2: - parse_attribute(ad); - if (ad->attr_mode) { - u = ad->attr_mode -1; - t = (t & ~(VT_BTYPE|VT_LONG)) | u; - } - continue; - /* GNUC typeof */ - case TOK_TYPEOF1: - case TOK_TYPEOF2: - case TOK_TYPEOF3: - next(); - parse_expr_type(&type1); - /* remove all storage modifiers except typedef */ - type1.t &= ~(VT_STORAGE&~VT_TYPEDEF); - if (type1.ref) - sym_to_attr(ad, type1.ref); - goto basic_type2; - case TOK_THREAD_LOCAL: - tcc_error("_Thread_local is not implemented"); - default: - if (typespec_found) - goto the_end; - s = sym_find(tok); - if (!s || !(s->type.t & VT_TYPEDEF)) - goto the_end; - - n = tok, next(); - if (tok == ':' && ignore_label) { - /* ignore if it's a label */ - unget_tok(n); - goto the_end; - } - - t &= ~(VT_BTYPE|VT_LONG); - u = t & ~(VT_CONSTANT | VT_VOLATILE), t ^= u; - type->t = (s->type.t & ~VT_TYPEDEF) | u; - type->ref = s->type.ref; - if (t) - parse_btype_qualify(type, t); - t = type->t; - /* get attributes from typedef */ - sym_to_attr(ad, s); - typespec_found = 1; - st = bt = -2; - break; - } - type_found = 1; - } -the_end: - if (tcc_state->char_is_unsigned) { - if ((t & (VT_DEFSIGN|VT_BTYPE)) == VT_BYTE) - t |= VT_UNSIGNED; - } - /* VT_LONG is used just as a modifier for VT_INT / VT_LLONG */ - bt = t & (VT_BTYPE|VT_LONG); - if (bt == VT_LONG) - t |= LONG_SIZE == 8 ? VT_LLONG : VT_INT; -#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE - if (bt == VT_LDOUBLE) - t = (t & ~(VT_BTYPE|VT_LONG)) | (VT_DOUBLE|VT_LONG); -#endif - type->t = t; - return type_found; -} - -/* convert a function parameter type (array to pointer and function to - function pointer) */ -static inline void convert_parameter_type(CType *pt) -{ - /* remove const and volatile qualifiers (XXX: const could be used - to indicate a const function parameter */ - pt->t &= ~(VT_CONSTANT | VT_VOLATILE); - /* array must be transformed to pointer according to ANSI C */ - pt->t &= ~VT_ARRAY; - if ((pt->t & VT_BTYPE) == VT_FUNC) { - mk_pointer(pt); - } -} - -ST_FUNC CString* parse_asm_str(void) -{ - skip('('); - return parse_mult_str("string constant"); -} - -/* Parse an asm label and return the token */ -static int asm_label_instr(void) -{ - int v; - char *astr; - - next(); - astr = parse_asm_str()->data; - skip(')'); -#ifdef ASM_DEBUG - printf("asm_alias: \"%s\"\n", astr); -#endif - v = tok_alloc_const(astr); - return v; -} - -static int post_type(CType *type, AttributeDef *ad, int storage, int td) -{ - int n, l, t1, arg_size, align; - Sym **plast, *s, *first; - AttributeDef ad1; - CType pt; - TokenString *vla_array_tok = NULL; - int *vla_array_str = NULL; - - if (tok == '(') { - /* function type, or recursive declarator (return if so) */ - next(); - if (TYPE_DIRECT == (td & (TYPE_DIRECT|TYPE_ABSTRACT))) - return 0; - if (tok == ')') - l = 0; - else if (parse_btype(&pt, &ad1, 0)) - l = FUNC_NEW; - else if (td & (TYPE_DIRECT|TYPE_ABSTRACT)) { - merge_attr (ad, &ad1); - return 0; - } else - l = FUNC_OLD; - - first = NULL; - plast = &first; - arg_size = 0; - ++local_scope; - if (l) { - for(;;) { - /* read param name and compute offset */ - if (l != FUNC_OLD) { - if ((pt.t & VT_BTYPE) == VT_VOID && tok == ')') - break; - type_decl(&pt, &ad1, &n, TYPE_DIRECT | TYPE_ABSTRACT | TYPE_PARAM); - if ((pt.t & VT_BTYPE) == VT_VOID) - tcc_error("parameter declared as void"); - if (n == 0) - n = SYM_FIELD; - } else { - n = tok; - pt.t = VT_VOID; /* invalid type */ - pt.ref = NULL; - next(); - } - if (n < TOK_UIDENT) - expect("identifier"); - convert_parameter_type(&pt); - arg_size += (type_size(&pt, &align) + PTR_SIZE - 1) / PTR_SIZE; - /* these symbols may be evaluated for VLArrays (see below, under - nocode_wanted) which is why we push them here as normal symbols - temporarily. Example: int func(int a, int b[++a]); */ - s = sym_push(n, &pt, VT_LOCAL|VT_LVAL, 0); - *plast = s; - plast = &s->next; - if (tok == ')') - break; - skip(','); - if (l == FUNC_NEW && tok == TOK_DOTS) { - l = FUNC_ELLIPSIS; - next(); - break; - } - if (l == FUNC_NEW && !parse_btype(&pt, &ad1, 0)) - tcc_error("invalid type"); - } - } else - /* if no parameters, then old type prototype */ - l = FUNC_OLD; - skip(')'); - /* remove parameter symbols from token table, keep on stack */ - if (first) { - sym_pop(local_stack ? &local_stack : &global_stack, first->prev, 1); - for (s = first; s; s = s->next) - s->v |= SYM_FIELD; - } - --local_scope; - /* NOTE: const is ignored in returned type as it has a special - meaning in gcc / C++ */ - type->t &= ~VT_CONSTANT; - /* some ancient pre-K&R C allows a function to return an array - and the array brackets to be put after the arguments, such - that "int c()[]" means something like "int[] c()" */ - if (tok == '[') { - next(); - skip(']'); /* only handle simple "[]" */ - mk_pointer(type); - } - /* we push a anonymous symbol which will contain the function prototype */ - ad->f.func_args = arg_size; - ad->f.func_type = l; - s = sym_push(SYM_FIELD, type, 0, 0); - s->a = ad->a; - s->f = ad->f; - s->next = first; - type->t = VT_FUNC; - type->ref = s; - } else if (tok == '[') { - int saved_nocode_wanted = nocode_wanted; - /* array definition */ - next(); - n = -1; - t1 = 0; - if (td & TYPE_PARAM) while (1) { - /* XXX The optional type-quals and static should only be accepted - in parameter decls. The '*' as well, and then even only - in prototypes (not function defs). */ - switch (tok) { - case TOK_RESTRICT1: case TOK_RESTRICT2: case TOK_RESTRICT3: - case TOK_CONST1: - case TOK_VOLATILE1: - case TOK_STATIC: - case '*': - next(); - continue; - default: - break; - } - if (tok != ']') { - /* Code generation is not done now but has to be done - at start of function. Save code here for later use. */ - nocode_wanted = 1; - skip_or_save_block(&vla_array_tok); - unget_tok(0); - vla_array_str = vla_array_tok->str; - begin_macro(vla_array_tok, 2); - next(); - gexpr(); - end_macro(); - next(); - goto check; - } - break; - - } else if (tok != ']') { - if (!local_stack || (storage & VT_STATIC)) - vpushi(expr_const()); - else { - /* VLAs (which can only happen with local_stack && !VT_STATIC) - length must always be evaluated, even under nocode_wanted, - so that its size slot is initialized (e.g. under sizeof - or typeof). */ - nocode_wanted = 0; - gexpr(); - } -check: - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { - n = vtop->c.i; - if (n < 0) - tcc_error("invalid array size"); - } else { - if (!is_integer_btype(vtop->type.t & VT_BTYPE)) - tcc_error("size of variable length array should be an integer"); - n = 0; - t1 = VT_VLA; - } - } - skip(']'); - /* parse next post type */ - post_type(type, ad, storage, (td & ~(TYPE_DIRECT|TYPE_ABSTRACT)) | TYPE_NEST); - - if ((type->t & VT_BTYPE) == VT_FUNC) - tcc_error("declaration of an array of functions"); - if ((type->t & VT_BTYPE) == VT_VOID - || type_size(type, &align) < 0) - tcc_error("declaration of an array of incomplete type elements"); - - t1 |= type->t & VT_VLA; - - if (t1 & VT_VLA) { - if (n < 0) { - if (td & TYPE_NEST) - tcc_error("need explicit inner array size in VLAs"); - } - else { - loc -= type_size(&int_type, &align); - loc &= -align; - n = loc; - - vpush_type_size(type, &align); - gen_op('*'); - vset(&int_type, VT_LOCAL|VT_LVAL, n); - vswap(); - vstore(); - } - } - if (n != -1) - vpop(); - nocode_wanted = saved_nocode_wanted; - - /* we push an anonymous symbol which will contain the array - element type */ - s = sym_push(SYM_FIELD, type, 0, n); - type->t = (t1 ? VT_VLA : VT_ARRAY) | VT_PTR; - type->ref = s; - - if (vla_array_str) { - if (t1 & VT_VLA) - s->vla_array_str = vla_array_str; - else - tok_str_free_str(vla_array_str); - } - } - return 1; -} - -/* Parse a type declarator (except basic type), and return the type - in 'type'. 'td' is a bitmask indicating which kind of type decl is - expected. 'type' should contain the basic type. 'ad' is the - attribute definition of the basic type. It can be modified by - type_decl(). If this (possibly abstract) declarator is a pointer chain - it returns the innermost pointed to type (equals *type, but is a different - pointer), otherwise returns type itself, that's used for recursive calls. */ -static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td) -{ - CType *post, *ret; - int qualifiers, storage; - - /* recursive type, remove storage bits first, apply them later again */ - storage = type->t & VT_STORAGE; - type->t &= ~VT_STORAGE; - post = ret = type; - - while (tok == '*') { - qualifiers = 0; - redo: - next(); - switch(tok) { - case TOK__Atomic: - qualifiers |= VT_ATOMIC; - goto redo; - case TOK_CONST1: - case TOK_CONST2: - case TOK_CONST3: - qualifiers |= VT_CONSTANT; - goto redo; - case TOK_VOLATILE1: - case TOK_VOLATILE2: - case TOK_VOLATILE3: - qualifiers |= VT_VOLATILE; - goto redo; - case TOK_RESTRICT1: - case TOK_RESTRICT2: - case TOK_RESTRICT3: - goto redo; - /* XXX: clarify attribute handling */ - case TOK_ATTRIBUTE1: - case TOK_ATTRIBUTE2: - parse_attribute(ad); - break; - } - mk_pointer(type); - type->t |= qualifiers; - if (ret == type) - /* innermost pointed to type is the one for the first derivation */ - ret = pointed_type(type); - } - - if (tok == '(') { - /* This is possibly a parameter type list for abstract declarators - ('int ()'), use post_type for testing this. */ - if (!post_type(type, ad, 0, td)) { - /* It's not, so it's a nested declarator, and the post operations - apply to the innermost pointed to type (if any). */ - /* XXX: this is not correct to modify 'ad' at this point, but - the syntax is not clear */ - parse_attribute(ad); - post = type_decl(type, ad, v, td); - skip(')'); - } else - goto abstract; - } else if (tok >= TOK_IDENT && (td & TYPE_DIRECT)) { - /* type identifier */ - *v = tok; - next(); - } else { - abstract: - if (!(td & TYPE_ABSTRACT)) - expect("identifier"); - *v = 0; - } - post_type(post, ad, post != ret ? 0 : storage, - td & ~(TYPE_DIRECT|TYPE_ABSTRACT)); - parse_attribute(ad); - type->t |= storage; - return ret; -} - -/* indirection with full error checking and bound check */ -ST_FUNC void indir(void) -{ - if ((vtop->type.t & VT_BTYPE) != VT_PTR) { - if ((vtop->type.t & VT_BTYPE) == VT_FUNC) - return; - expect("pointer"); - } - if (vtop->r & VT_LVAL) - gv(RC_INT); - vtop->type = *pointed_type(&vtop->type); - /* Arrays and functions are never lvalues */ - if (!(vtop->type.t & (VT_ARRAY | VT_VLA)) - && (vtop->type.t & VT_BTYPE) != VT_FUNC) { - vtop->r |= VT_LVAL; - /* if bound checking, the referenced pointer must be checked */ -#ifdef CONFIG_TCC_BCHECK - if (tcc_state->do_bounds_check) - vtop->r |= VT_MUSTBOUND; -#endif - } -} - -/* pass a parameter to a function and do type checking and casting */ -static void gfunc_param_typed(Sym *func, Sym *arg) -{ - int func_type; - CType type; - - func_type = func->f.func_type; - if (func_type == FUNC_OLD || - (func_type == FUNC_ELLIPSIS && arg == NULL)) { - /* default casting : only need to convert float to double */ - if ((vtop->type.t & VT_BTYPE) == VT_FLOAT) { - gen_cast_s(VT_DOUBLE); - } else if (vtop->type.t & VT_BITFIELD) { - type.t = vtop->type.t & (VT_BTYPE | VT_UNSIGNED); - type.ref = vtop->type.ref; - gen_cast(&type); - } else if (vtop->r & VT_MUSTCAST) { - force_charshort_cast(); - } - } else if (arg == NULL) { - tcc_error("too many arguments to function"); - } else { - type = arg->type; - type.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */ - gen_assign_cast(&type); - } -} - -/* parse an expression and return its type without any side effect. */ -static void expr_type(CType *type, void (*expr_fn)(void)) -{ - nocode_wanted++; - expr_fn(); - *type = vtop->type; - vpop(); - nocode_wanted--; -} - -/* parse an expression of the form '(type)' or '(expr)' and return its - type */ -static void parse_expr_type(CType *type) -{ - int n; - AttributeDef ad; - - skip('('); - if (parse_btype(type, &ad, 0)) { - type_decl(type, &ad, &n, TYPE_ABSTRACT); - } else { - expr_type(type, gexpr); - } - skip(')'); -} - -static void parse_type(CType *type) -{ - AttributeDef ad; - int n; - - if (!parse_btype(type, &ad, 0)) { - expect("type"); - } - type_decl(type, &ad, &n, TYPE_ABSTRACT); -} - -static void parse_builtin_params(int nc, const char *args) -{ - char c, sep = '('; - CType type; - if (nc) - nocode_wanted++; - next(); - if (*args == 0) - skip(sep); - while ((c = *args++)) { - skip(sep); - sep = ','; - if (c == 't') { - parse_type(&type); - vpush(&type); - continue; - } - expr_eq(); - type.ref = NULL; - type.t = 0; - switch (c) { - case 'e': - continue; - case 'V': - type.t = VT_CONSTANT; - case 'v': - type.t |= VT_VOID; - mk_pointer (&type); - break; - case 'S': - type.t = VT_CONSTANT; - case 's': - type.t |= char_type.t; - mk_pointer (&type); - break; - case 'i': - type.t = VT_INT; - break; - case 'l': - type.t = VT_SIZE_T; - break; - default: - break; - } - gen_assign_cast(&type); - } - skip(')'); - if (nc) - nocode_wanted--; -} - -static void parse_atomic(int atok) -{ - int size, align, arg, t, save = 0; - CType *atom, *atom_ptr, ct = {0}; - SValue store; - char buf[40]; - static const char *const templates[] = { - /* - * Each entry consists of callback and function template. - * The template represents argument types and return type. - * - * ? void (return-only) - * b bool - * a atomic - * A read-only atomic - * p pointer to memory - * v value - * l load pointer - * s save pointer - * m memory model - */ - - /* keep in order of appearance in tcctok.h: */ - /* __atomic_store */ "alm.?", - /* __atomic_load */ "Asm.v", - /* __atomic_exchange */ "alsm.v", - /* __atomic_compare_exchange */ "aplbmm.b", - /* __atomic_fetch_add */ "avm.v", - /* __atomic_fetch_sub */ "avm.v", - /* __atomic_fetch_or */ "avm.v", - /* __atomic_fetch_xor */ "avm.v", - /* __atomic_fetch_and */ "avm.v", - /* __atomic_fetch_nand */ "avm.v", - /* __atomic_and_fetch */ "avm.v", - /* __atomic_sub_fetch */ "avm.v", - /* __atomic_or_fetch */ "avm.v", - /* __atomic_xor_fetch */ "avm.v", - /* __atomic_and_fetch */ "avm.v", - /* __atomic_nand_fetch */ "avm.v" - }; - const char *template = templates[(atok - TOK___atomic_store)]; - - atom = atom_ptr = NULL; - size = 0; /* pacify compiler */ - next(); - skip('('); - for (arg = 0;;) { - expr_eq(); - switch (template[arg]) { - case 'a': - case 'A': - atom_ptr = &vtop->type; - if ((atom_ptr->t & VT_BTYPE) != VT_PTR) - expect("pointer"); - atom = pointed_type(atom_ptr); - size = type_size(atom, &align); - if (size > 8 - || (size & (size - 1)) - || (atok > TOK___atomic_compare_exchange - && (0 == btype_size(atom->t & VT_BTYPE) - || (atom->t & VT_BTYPE) == VT_PTR))) - expect("integral or integer-sized pointer target type"); - /* GCC does not care either: */ - /* if (!(atom->t & VT_ATOMIC)) - tcc_warning("pointer target declaration is missing '_Atomic'"); */ - break; - - case 'p': - if ((vtop->type.t & VT_BTYPE) != VT_PTR - || type_size(pointed_type(&vtop->type), &align) != size) - tcc_error("pointer target type mismatch in argument %d", arg + 1); - gen_assign_cast(atom_ptr); - break; - case 'v': - gen_assign_cast(atom); - break; - case 'l': - indir(); - gen_assign_cast(atom); - break; - case 's': - save = 1; - indir(); - store = *vtop; - vpop(); - break; - case 'm': - gen_assign_cast(&int_type); - break; - case 'b': - ct.t = VT_BOOL; - gen_assign_cast(&ct); - break; - } - if ('.' == template[++arg]) - break; - skip(','); - } - skip(')'); - - ct.t = VT_VOID; - switch (template[arg + 1]) { - case 'b': - ct.t = VT_BOOL; - break; - case 'v': - ct = *atom; - break; - } - - sprintf(buf, "%s_%d", get_tok_str(atok, 0), size); - vpush_helper_func(tok_alloc_const(buf)); - vrott(arg - save + 1); - gfunc_call(arg - save); - - vpush(&ct); - PUT_R_RET(vtop, ct.t); - t = ct.t & VT_BTYPE; - if (t == VT_BYTE || t == VT_SHORT || t == VT_BOOL) { -#ifdef PROMOTE_RET - vtop->r |= BFVAL(VT_MUSTCAST, 1); -#else - vtop->type.t = VT_INT; -#endif - } - gen_cast(&ct); - if (save) { - vpush(&ct); - *vtop = store; - vswap(); - vstore(); - } -} - -ST_FUNC void unary(void) -{ - int n, t, align, size, r, sizeof_caller; - CType type; - Sym *s; - AttributeDef ad; - - /* generate line number info */ - if (debug_modes) - tcc_debug_line(tcc_state), tcc_tcov_check_line (tcc_state, 1); - - sizeof_caller = in_sizeof; - in_sizeof = 0; - type.ref = NULL; - /* XXX: GCC 2.95.3 does not generate a table although it should be - better here */ - tok_next: - switch(tok) { - case TOK_EXTENSION: - next(); - goto tok_next; - case TOK_LCHAR: -#ifdef TCC_TARGET_PE - t = VT_SHORT|VT_UNSIGNED; - goto push_tokc; -#endif - case TOK_CINT: - case TOK_CCHAR: - t = VT_INT; - push_tokc: - type.t = t; - vsetc(&type, VT_CONST, &tokc); - next(); - break; - case TOK_CUINT: - t = VT_INT | VT_UNSIGNED; - goto push_tokc; - case TOK_CLLONG: - t = VT_LLONG; - goto push_tokc; - case TOK_CULLONG: - t = VT_LLONG | VT_UNSIGNED; - goto push_tokc; - case TOK_CFLOAT: - t = VT_FLOAT; - goto push_tokc; - case TOK_CDOUBLE: - t = VT_DOUBLE; - goto push_tokc; - case TOK_CLDOUBLE: -#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE - t = VT_DOUBLE | VT_LONG; -#else - t = VT_LDOUBLE; -#endif - goto push_tokc; - case TOK_CLONG: - t = (LONG_SIZE == 8 ? VT_LLONG : VT_INT) | VT_LONG; - goto push_tokc; - case TOK_CULONG: - t = (LONG_SIZE == 8 ? VT_LLONG : VT_INT) | VT_LONG | VT_UNSIGNED; - goto push_tokc; - case TOK___FUNCTION__: - if (!gnu_ext) - goto tok_identifier; - /* fall thru */ - case TOK___FUNC__: - { - Section *sec; - int len; - /* special function name identifier */ - len = strlen(funcname) + 1; - /* generate char[len] type */ - type.t = char_type.t; - if (tcc_state->warn_write_strings & WARN_ON) - type.t |= VT_CONSTANT; - mk_pointer(&type); - type.t |= VT_ARRAY; - type.ref->c = len; - sec = rodata_section; - vpush_ref(&type, sec, sec->data_offset, len); - if (!NODATA_WANTED) - memcpy(section_ptr_add(sec, len), funcname, len); - next(); - } - break; - case TOK_LSTR: -#ifdef TCC_TARGET_PE - t = VT_SHORT | VT_UNSIGNED; -#else - t = VT_INT; -#endif - goto str_init; - case TOK_STR: - /* string parsing */ - t = char_type.t; - str_init: - if (tcc_state->warn_write_strings & WARN_ON) - t |= VT_CONSTANT; - type.t = t; - mk_pointer(&type); - type.t |= VT_ARRAY; - memset(&ad, 0, sizeof(AttributeDef)); - ad.section = rodata_section; - decl_initializer_alloc(&type, &ad, VT_CONST, 2, 0, 0); - break; - case '(': - next(); - /* cast ? */ - if (parse_btype(&type, &ad, 0)) { - type_decl(&type, &ad, &n, TYPE_ABSTRACT); - skip(')'); - /* check ISOC99 compound literal */ - if (tok == '{') { - /* data is allocated locally by default */ - if (global_expr) - r = VT_CONST; - else - r = VT_LOCAL; - /* all except arrays are lvalues */ - if (!(type.t & VT_ARRAY)) - r |= VT_LVAL; - memset(&ad, 0, sizeof(AttributeDef)); - decl_initializer_alloc(&type, &ad, r, 1, 0, 0); - } else { - if (sizeof_caller) { - vpush(&type); - return; - } - unary(); - gen_cast(&type); - } - } else if (tok == '{') { - int saved_nocode_wanted = nocode_wanted; - if (CONST_WANTED && !NOEVAL_WANTED) - expect("constant"); - if (0 == local_scope) - tcc_error("statement expression outside of function"); - /* save all registers */ - save_regs(0); - /* statement expression : we do not accept break/continue - inside as GCC does. We do retain the nocode_wanted state, - as statement expressions can't ever be entered from the - outside, so any reactivation of code emission (from labels - or loop heads) can be disabled again after the end of it. */ - block(1); - /* If the statement expr can be entered, then we retain the current - nocode_wanted state (from e.g. a 'return 0;' in the stmt-expr). - If it can't be entered then the state is that from before the - statement expression. */ - if (saved_nocode_wanted) - nocode_wanted = saved_nocode_wanted; - skip(')'); - } else { - gexpr(); - skip(')'); - } - break; - case '*': - next(); - unary(); - indir(); - break; - case '&': - next(); - unary(); - /* functions names must be treated as function pointers, - except for unary '&' and sizeof. Since we consider that - functions are not lvalues, we only have to handle it - there and in function calls. */ - /* arrays can also be used although they are not lvalues */ - if ((vtop->type.t & VT_BTYPE) != VT_FUNC && - !(vtop->type.t & (VT_ARRAY | VT_VLA))) - test_lvalue(); - if (vtop->sym) - vtop->sym->a.addrtaken = 1; - mk_pointer(&vtop->type); - gaddrof(); - break; - case '!': - next(); - unary(); - gen_test_zero(TOK_EQ); - break; - case '~': - next(); - unary(); - vpushi(-1); - gen_op('^'); - break; - case '+': - next(); - unary(); - if ((vtop->type.t & VT_BTYPE) == VT_PTR) - tcc_error("pointer not accepted for unary plus"); - /* In order to force cast, we add zero, except for floating point - where we really need an noop (otherwise -0.0 will be transformed - into +0.0). */ - if (!is_float(vtop->type.t)) { - vpushi(0); - gen_op('+'); - } - break; - case TOK_SIZEOF: - case TOK_ALIGNOF1: - case TOK_ALIGNOF2: - case TOK_ALIGNOF3: - t = tok; - next(); - in_sizeof++; - expr_type(&type, unary); /* Perform a in_sizeof = 0; */ - if (t == TOK_SIZEOF) { - vpush_type_size(&type, &align); - gen_cast_s(VT_SIZE_T); - } else { - type_size(&type, &align); - s = NULL; - if (vtop[1].r & VT_SYM) - s = vtop[1].sym; /* hack: accessing previous vtop */ - if (s && s->a.aligned) - align = 1 << (s->a.aligned - 1); - vpushs(align); - } - break; - - case TOK_builtin_expect: - /* __builtin_expect is a no-op for now */ - parse_builtin_params(0, "ee"); - vpop(); - break; - case TOK_builtin_types_compatible_p: - parse_builtin_params(0, "tt"); - vtop[-1].type.t &= ~(VT_CONSTANT | VT_VOLATILE); - vtop[0].type.t &= ~(VT_CONSTANT | VT_VOLATILE); - n = is_compatible_types(&vtop[-1].type, &vtop[0].type); - vtop -= 2; - vpushi(n); - break; - case TOK_builtin_choose_expr: - { - int64_t c; - next(); - skip('('); - c = expr_const64(); - skip(','); - if (!c) { - nocode_wanted++; - } - expr_eq(); - if (!c) { - vpop(); - nocode_wanted--; - } - skip(','); - if (c) { - nocode_wanted++; - } - expr_eq(); - if (c) { - vpop(); - nocode_wanted--; - } - skip(')'); - } - break; - case TOK_builtin_constant_p: - constant_p = 1; - parse_builtin_params(1, "e"); - n = constant_p && - (vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST && - !((vtop->r & VT_SYM) && vtop->sym->a.addrtaken); - vtop--; - vpushi(n); - break; - case TOK_builtin_frame_address: - case TOK_builtin_return_address: - { - int tok1 = tok; - int64_t level; - next(); - skip('('); - level = expr_const64(); - if (level < 0) { - tcc_error("%s only takes positive integers", - tok1 == TOK_builtin_return_address ? - "__builtin_return_address" : - "__builtin_frame_address"); - } - skip(')'); - type.t = VT_VOID; - mk_pointer(&type); - vset(&type, VT_LOCAL, 0); /* local frame */ - while (level--) { -#ifdef TCC_TARGET_RISCV64 - vpushi(2*PTR_SIZE); - gen_op('-'); -#endif - mk_pointer(&vtop->type); - indir(); /* -> parent frame */ - } - if (tok1 == TOK_builtin_return_address) { - // assume return address is just above frame pointer on stack -#ifdef TCC_TARGET_ARM - vpushi(2*PTR_SIZE); - gen_op('+'); -#elif defined TCC_TARGET_RISCV64 - vpushi(PTR_SIZE); - gen_op('-'); -#else - vpushi(PTR_SIZE); - gen_op('+'); -#endif - mk_pointer(&vtop->type); - indir(); - } - } - break; -#ifdef TCC_TARGET_RISCV64 - case TOK_builtin_va_start: - parse_builtin_params(0, "ee"); - r = vtop->r & VT_VALMASK; - if (r == VT_LLOCAL) - r = VT_LOCAL; - if (r != VT_LOCAL) - tcc_error("__builtin_va_start expects a local variable"); - gen_va_start(); - vstore(); - break; -#endif -#ifdef TCC_TARGET_X86_64 -#ifdef TCC_TARGET_PE - case TOK_builtin_va_start: - parse_builtin_params(0, "ee"); - r = vtop->r & VT_VALMASK; - if (r == VT_LLOCAL) - r = VT_LOCAL; - if (r != VT_LOCAL) - tcc_error("__builtin_va_start expects a local variable"); - vtop->r = r; - vtop->type = char_pointer_type; - vtop->c.i += 8; - vstore(); - break; -#else - case TOK_builtin_va_arg_types: - parse_builtin_params(0, "t"); - vpushi(classify_x86_64_va_arg(&vtop->type)); - vswap(); - vpop(); - break; -#endif -#endif - -#ifdef TCC_TARGET_ARM64 - case TOK_builtin_va_start: { - parse_builtin_params(0, "ee"); - //xx check types - gen_va_start(); - vpushi(0); - vtop->type.t = VT_VOID; - break; - } - case TOK_builtin_va_arg: { - parse_builtin_params(0, "et"); - type = vtop->type; - vpop(); - //xx check types - gen_va_arg(&type); - vtop->type = type; - break; - } - case TOK___arm64_clear_cache: { - parse_builtin_params(0, "ee"); - gen_clear_cache(); - vpushi(0); - vtop->type.t = VT_VOID; - break; - } -#endif - - /* atomic operations */ - case TOK___atomic_store: - case TOK___atomic_load: - case TOK___atomic_exchange: - case TOK___atomic_compare_exchange: - case TOK___atomic_fetch_add: - case TOK___atomic_fetch_sub: - case TOK___atomic_fetch_or: - case TOK___atomic_fetch_xor: - case TOK___atomic_fetch_and: - case TOK___atomic_fetch_nand: - case TOK___atomic_add_fetch: - case TOK___atomic_sub_fetch: - case TOK___atomic_or_fetch: - case TOK___atomic_xor_fetch: - case TOK___atomic_and_fetch: - case TOK___atomic_nand_fetch: - parse_atomic(tok); - break; - - /* pre operations */ - case TOK_INC: - case TOK_DEC: - t = tok; - next(); - unary(); - inc(0, t); - break; - case '-': - next(); - unary(); - if (is_float(vtop->type.t)) { - gen_opif(TOK_NEG); - } else { - vpushi(0); - vswap(); - gen_op('-'); - } - break; - case TOK_LAND: - if (!gnu_ext) - goto tok_identifier; - next(); - /* allow to take the address of a label */ - if (tok < TOK_UIDENT) - expect("label identifier"); - s = label_find(tok); - if (!s) { - s = label_push(&global_label_stack, tok, LABEL_FORWARD); - } else { - if (s->r == LABEL_DECLARED) - s->r = LABEL_FORWARD; - } - if ((s->type.t & VT_BTYPE) != VT_PTR) { - s->type.t = VT_VOID; - mk_pointer(&s->type); - s->type.t |= VT_STATIC; - } - vpushsym(&s->type, s); - next(); - break; - - case TOK_GENERIC: - { - CType controlling_type; - int has_default = 0; - int has_match = 0; - int learn = 0; - TokenString *str = NULL; - int saved_nocode_wanted = nocode_wanted; - nocode_wanted &= ~CONST_WANTED_MASK; - - next(); - skip('('); - expr_type(&controlling_type, expr_eq); - controlling_type.t &= ~(VT_CONSTANT | VT_VOLATILE | VT_ARRAY); - if ((controlling_type.t & VT_BTYPE) == VT_FUNC) - mk_pointer(&controlling_type); - - nocode_wanted = saved_nocode_wanted; - - for (;;) { - learn = 0; - skip(','); - if (tok == TOK_DEFAULT) { - if (has_default) - tcc_error("too many 'default'"); - has_default = 1; - if (!has_match) - learn = 1; - next(); - } else { - AttributeDef ad_tmp; - int itmp; - CType cur_type; - - parse_btype(&cur_type, &ad_tmp, 0); - type_decl(&cur_type, &ad_tmp, &itmp, TYPE_ABSTRACT); - if (compare_types(&controlling_type, &cur_type, 0)) { - if (has_match) { - tcc_error("type match twice"); - } - has_match = 1; - learn = 1; - } - } - skip(':'); - if (learn) { - if (str) - tok_str_free(str); - skip_or_save_block(&str); - } else { - skip_or_save_block(NULL); - } - if (tok == ')') - break; - } - if (!str) { - char buf[60]; - type_to_str(buf, sizeof buf, &controlling_type, NULL); - tcc_error("type '%s' does not match any association", buf); - } - begin_macro(str, 1); - next(); - expr_eq(); - if (tok != TOK_EOF) - expect(","); - end_macro(); - next(); - break; - } - // special qnan , snan and infinity values - case TOK___NAN__: - n = 0x7fc00000; -special_math_val: - vpushi(n); - vtop->type.t = VT_FLOAT; - next(); - break; - case TOK___SNAN__: - n = 0x7f800001; - goto special_math_val; - case TOK___INF__: - n = 0x7f800000; - goto special_math_val; - - default: - tok_identifier: - t = tok; - next(); - if (t < TOK_UIDENT) - expect("identifier"); - s = sym_find(t); - if (!s || IS_ASM_SYM(s)) { - const char *name = get_tok_str(t, NULL); - if (tok != '(') - tcc_error("'%s' undeclared", name); - /* for simple function calls, we tolerate undeclared - external reference to int() function */ - tcc_warning_c(warn_implicit_function_declaration)( - "implicit declaration of function '%s'", name); - s = external_global_sym(t, &func_old_type); - } - - r = s->r; - /* A symbol that has a register is a local register variable, - which starts out as VT_LOCAL value. */ - if ((r & VT_VALMASK) < VT_CONST) - r = (r & ~VT_VALMASK) | VT_LOCAL; - - vset(&s->type, r, s->c); - /* Point to s as backpointer (even without r&VT_SYM). - Will be used by at least the x86 inline asm parser for - regvars. */ - vtop->sym = s; - - if (r & VT_SYM) { - vtop->c.i = 0; - } else if (r == VT_CONST && IS_ENUM_VAL(s->type.t)) { - vtop->c.i = s->enum_val; - } - break; - } - - /* post operations */ - while (1) { - if (tok == TOK_INC || tok == TOK_DEC) { - inc(1, tok); - next(); - } else if (tok == '.' || tok == TOK_ARROW || tok == TOK_CDOUBLE) { - int qualifiers, cumofs = 0; - /* field */ - if (tok == TOK_ARROW) - indir(); - qualifiers = vtop->type.t & (VT_CONSTANT | VT_VOLATILE); - test_lvalue(); - gaddrof(); - /* expect pointer on structure */ - if ((vtop->type.t & VT_BTYPE) != VT_STRUCT) - expect("struct or union"); - if (tok == TOK_CDOUBLE) - expect("field name"); - next(); - if (tok == TOK_CINT || tok == TOK_CUINT) - expect("field name"); - s = find_field(&vtop->type, tok, &cumofs); - /* add field offset to pointer */ - vtop->type = char_pointer_type; /* change type to 'char *' */ - vpushi(cumofs); - gen_op('+'); - /* change type to field type, and set to lvalue */ - vtop->type = s->type; - vtop->type.t |= qualifiers; - /* an array is never an lvalue */ - if (!(vtop->type.t & VT_ARRAY)) { - vtop->r |= VT_LVAL; -#ifdef CONFIG_TCC_BCHECK - /* if bound checking, the referenced pointer must be checked */ - if (tcc_state->do_bounds_check) - vtop->r |= VT_MUSTBOUND; -#endif - } - next(); - } else if (tok == '[') { - next(); - gexpr(); - gen_op('+'); - indir(); - skip(']'); - } else if (tok == '(') { - SValue ret; - Sym *sa; - int nb_args, ret_nregs, ret_align, regsize, variadic; - - /* function call */ - if ((vtop->type.t & VT_BTYPE) != VT_FUNC) { - /* pointer test (no array accepted) */ - if ((vtop->type.t & (VT_BTYPE | VT_ARRAY)) == VT_PTR) { - vtop->type = *pointed_type(&vtop->type); - if ((vtop->type.t & VT_BTYPE) != VT_FUNC) - goto error_func; - } else { - error_func: - expect("function pointer"); - } - } else { - vtop->r &= ~VT_LVAL; /* no lvalue */ - } - /* get return type */ - s = vtop->type.ref; - next(); - sa = s->next; /* first parameter */ - nb_args = regsize = 0; - ret.r2 = VT_CONST; - /* compute first implicit argument if a structure is returned */ - if ((s->type.t & VT_BTYPE) == VT_STRUCT) { - variadic = (s->f.func_type == FUNC_ELLIPSIS); - ret_nregs = gfunc_sret(&s->type, variadic, &ret.type, - &ret_align, ®size); - if (ret_nregs <= 0) { - /* get some space for the returned structure */ - size = type_size(&s->type, &align); -#ifdef TCC_TARGET_ARM64 - /* On arm64, a small struct is return in registers. - It is much easier to write it to memory if we know - that we are allowed to write some extra bytes, so - round the allocated space up to a power of 2: */ - if (size < 16) - while (size & (size - 1)) - size = (size | (size - 1)) + 1; -#endif - loc = (loc - size) & -align; - ret.type = s->type; - ret.r = VT_LOCAL | VT_LVAL; - /* pass it as 'int' to avoid structure arg passing - problems */ - vseti(VT_LOCAL, loc); -#ifdef CONFIG_TCC_BCHECK - if (tcc_state->do_bounds_check) - --loc; -#endif - ret.c = vtop->c; - if (ret_nregs < 0) - vtop--; - else - nb_args++; - } - } else { - ret_nregs = 1; - ret.type = s->type; - } - - if (ret_nregs > 0) { - /* return in register */ - ret.c.i = 0; - PUT_R_RET(&ret, ret.type.t); - } - if (tok != ')') { - for(;;) { - expr_eq(); - gfunc_param_typed(s, sa); - nb_args++; - if (sa) - sa = sa->next; - if (tok == ')') - break; - skip(','); - } - } - if (sa) - tcc_error("too few arguments to function"); - skip(')'); - gfunc_call(nb_args); - - if (ret_nregs < 0) { - vsetc(&ret.type, ret.r, &ret.c); -#ifdef TCC_TARGET_RISCV64 - arch_transfer_ret_regs(1); -#endif - } else { - /* return value */ - for (r = ret.r + ret_nregs + !ret_nregs; r-- > ret.r;) { - vsetc(&ret.type, r, &ret.c); - vtop->r2 = ret.r2; /* Loop only happens when r2 is VT_CONST */ - } - - /* handle packed struct return */ - if (((s->type.t & VT_BTYPE) == VT_STRUCT) && ret_nregs) { - int addr, offset; - - size = type_size(&s->type, &align); - /* We're writing whole regs often, make sure there's enough - space. Assume register size is power of 2. */ - if (regsize > align) - align = regsize; - loc = (loc - size) & -align; - addr = loc; - offset = 0; - for (;;) { - vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset); - vswap(); - vstore(); - vtop--; - if (--ret_nregs == 0) - break; - offset += regsize; - } - vset(&s->type, VT_LOCAL | VT_LVAL, addr); - } - - /* Promote char/short return values. This is matters only - for calling function that were not compiled by TCC and - only on some architectures. For those where it doesn't - matter we expect things to be already promoted to int, - but not larger. */ - t = s->type.t & VT_BTYPE; - if (t == VT_BYTE || t == VT_SHORT || t == VT_BOOL) { -#ifdef PROMOTE_RET - vtop->r |= BFVAL(VT_MUSTCAST, 1); -#else - vtop->type.t = VT_INT; -#endif - } - } - if (s->f.func_noreturn) { - if (debug_modes) - tcc_tcov_block_end(tcc_state, -1); - CODE_OFF(); - } - } else { - break; - } - } -} - -#ifndef precedence_parser /* original top-down parser */ - -static void expr_prod(void) -{ - int t; - - unary(); - while ((t = tok) == '*' || t == '/' || t == '%') { - next(); - unary(); - gen_op(t); - } -} - -static void expr_sum(void) -{ - int t; - - expr_prod(); - while ((t = tok) == '+' || t == '-') { - next(); - expr_prod(); - gen_op(t); - } -} - -static void expr_shift(void) -{ - int t; - - expr_sum(); - while ((t = tok) == TOK_SHL || t == TOK_SAR) { - next(); - expr_sum(); - gen_op(t); - } -} - -static void expr_cmp(void) -{ - int t; - - expr_shift(); - while (((t = tok) >= TOK_ULE && t <= TOK_GT) || - t == TOK_ULT || t == TOK_UGE) { - next(); - expr_shift(); - gen_op(t); - } -} - -static void expr_cmpeq(void) -{ - int t; - - expr_cmp(); - while ((t = tok) == TOK_EQ || t == TOK_NE) { - next(); - expr_cmp(); - gen_op(t); - } -} - -static void expr_and(void) -{ - expr_cmpeq(); - while (tok == '&') { - next(); - expr_cmpeq(); - gen_op('&'); - } -} - -static void expr_xor(void) -{ - expr_and(); - while (tok == '^') { - next(); - expr_and(); - gen_op('^'); - } -} - -static void expr_or(void) -{ - expr_xor(); - while (tok == '|') { - next(); - expr_xor(); - gen_op('|'); - } -} - -static void expr_landor(int op); - -static void expr_land(void) -{ - expr_or(); - if (tok == TOK_LAND) - expr_landor(tok); -} - -static void expr_lor(void) -{ - expr_land(); - if (tok == TOK_LOR) - expr_landor(tok); -} - -# define expr_landor_next(op) op == TOK_LAND ? expr_or() : expr_land() -#else /* defined precedence_parser */ -# define expr_landor_next(op) unary(), expr_infix(precedence(op) + 1) -# define expr_lor() unary(), expr_infix(1) - -static int precedence(int tok) -{ - switch (tok) { - case TOK_LOR: return 1; - case TOK_LAND: return 2; - case '|': return 3; - case '^': return 4; - case '&': return 5; - case TOK_EQ: case TOK_NE: return 6; - relat: case TOK_ULT: case TOK_UGE: return 7; - case TOK_SHL: case TOK_SAR: return 8; - case '+': case '-': return 9; - case '*': case '/': case '%': return 10; - default: - if (tok >= TOK_ULE && tok <= TOK_GT) - goto relat; - return 0; - } -} -static unsigned char prec[256]; -static void init_prec(void) -{ - int i; - for (i = 0; i < 256; i++) - prec[i] = precedence(i); -} -#define precedence(i) ((unsigned)i < 256 ? prec[i] : 0) - -static void expr_landor(int op); - -static void expr_infix(int p) -{ - int t = tok, p2; - while ((p2 = precedence(t)) >= p) { - if (t == TOK_LOR || t == TOK_LAND) { - expr_landor(t); - } else { - next(); - unary(); - if (precedence(tok) > p2) - expr_infix(p2 + 1); - gen_op(t); - } - t = tok; - } -} -#endif - -/* Assuming vtop is a value used in a conditional context - (i.e. compared with zero) return 0 if it's false, 1 if - true and -1 if it can't be statically determined. */ -static int condition_3way(void) -{ - int c = -1; - if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST && - (!(vtop->r & VT_SYM) || !vtop->sym->a.weak)) { - vdup(); - gen_cast_s(VT_BOOL); - c = vtop->c.i; - vpop(); - } - return c; -} - -static void expr_landor(int op) -{ - int t = 0, cc = 1, f = 0, i = op == TOK_LAND, c; - for(;;) { - c = f ? i : condition_3way(); - if (c < 0) - save_regs(1), cc = 0; - else if (c != i) - nocode_wanted++, f = 1; - if (tok != op) - break; - if (c < 0) - t = gvtst(i, t); - else - vpop(); - next(); - expr_landor_next(op); - } - if (cc || f) { - vpop(); - vpushi(i ^ f); - gsym(t); - nocode_wanted -= f; - } else { - gvtst_set(i, t); - } -} - -static int is_cond_bool(SValue *sv) -{ - if ((sv->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST - && (sv->type.t & VT_BTYPE) == VT_INT) - return (unsigned)sv->c.i < 2; - if (sv->r == VT_CMP) - return 1; - return 0; -} - -static void expr_cond(void) -{ - int tt, u, r1, r2, rc, t1, t2, islv, c, g; - SValue sv; - CType type; - - expr_lor(); - if (tok == '?') { - next(); - c = condition_3way(); - g = (tok == ':' && gnu_ext); - tt = 0; - if (!g) { - if (c < 0) { - save_regs(1); - tt = gvtst(1, 0); - } else { - vpop(); - } - } else if (c < 0) { - /* needed to avoid having different registers saved in - each branch */ - save_regs(1); - gv_dup(); - tt = gvtst(0, 0); - } - - if (c == 0) - nocode_wanted++; - if (!g) - gexpr(); - - if ((vtop->type.t & VT_BTYPE) == VT_FUNC) - mk_pointer(&vtop->type); - sv = *vtop; /* save value to handle it later */ - vtop--; /* no vpop so that FP stack is not flushed */ - - if (g) { - u = tt; - } else if (c < 0) { - u = gjmp(0); - gsym(tt); - } else - u = 0; - - if (c == 0) - nocode_wanted--; - if (c == 1) - nocode_wanted++; - skip(':'); - expr_cond(); - - if ((vtop->type.t & VT_BTYPE) == VT_FUNC) - mk_pointer(&vtop->type); - - /* cast operands to correct type according to ISOC rules */ - if (!combine_types(&type, &sv, vtop, '?')) - type_incompatibility_error(&sv.type, &vtop->type, - "type mismatch in conditional expression (have '%s' and '%s')"); - - if (c < 0 && is_cond_bool(vtop) && is_cond_bool(&sv)) { - /* optimize "if (f ? a > b : c || d) ..." for example, where normally - "a < b" and "c || d" would be forced to "(int)0/1" first, whereas - this code jumps directly to the if's then/else branches. */ - t1 = gvtst(0, 0); - t2 = gjmp(0); - gsym(u); - vpushv(&sv); - /* combine jump targets of 2nd op with VT_CMP of 1st op */ - gvtst_set(0, t1); - gvtst_set(1, t2); - gen_cast(&type); - // tcc_warning("two conditions expr_cond"); - return; - } - - /* keep structs lvalue by transforming `(expr ? a : b)` to `*(expr ? &a : &b)` so - that `(expr ? a : b).mem` does not error with "lvalue expected" */ - islv = (vtop->r & VT_LVAL) && (sv.r & VT_LVAL) && VT_STRUCT == (type.t & VT_BTYPE); - - /* now we convert second operand */ - if (c != 1) { - gen_cast(&type); - if (islv) { - mk_pointer(&vtop->type); - gaddrof(); - } else if (VT_STRUCT == (vtop->type.t & VT_BTYPE)) - gaddrof(); - } - - rc = RC_TYPE(type.t); - /* for long longs, we use fixed registers to avoid having - to handle a complicated move */ - if (USING_TWO_WORDS(type.t)) - rc = RC_RET(type.t); - - tt = r2 = 0; - if (c < 0) { - r2 = gv(rc); - tt = gjmp(0); - } - gsym(u); - if (c == 1) - nocode_wanted--; - - /* this is horrible, but we must also convert first - operand */ - if (c != 0) { - *vtop = sv; - gen_cast(&type); - if (islv) { - mk_pointer(&vtop->type); - gaddrof(); - } else if (VT_STRUCT == (vtop->type.t & VT_BTYPE)) - gaddrof(); - } - - if (c < 0) { - r1 = gv(rc); - move_reg(r2, r1, islv ? VT_PTR : type.t); - vtop->r = r2; - gsym(tt); - } - - if (islv) - indir(); - } -} - -static void expr_eq(void) -{ - int t; - - expr_cond(); - if ((t = tok) == '=' || TOK_ASSIGN(t)) { - test_lvalue(); - next(); - if (t == '=') { - expr_eq(); - } else { - vdup(); - expr_eq(); - gen_op(TOK_ASSIGN_OP(t)); - } - vstore(); - } -} - -ST_FUNC void gexpr(void) -{ - while (1) { - expr_eq(); - if (tok != ',') - break; - constant_p &= (vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST && - !((vtop->r & VT_SYM) && vtop->sym->a.addrtaken); - vpop(); - next(); - } -} - -/* parse a constant expression and return value in vtop. */ -static void expr_const1(void) -{ - nocode_wanted += CONST_WANTED_BIT; - expr_cond(); - nocode_wanted -= CONST_WANTED_BIT; -} - -/* parse an integer constant and return its value. */ -static inline int64_t expr_const64(void) -{ - int64_t c; - expr_const1(); - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM | VT_NONCONST)) != VT_CONST) - expect("constant expression"); - c = vtop->c.i; - vpop(); - return c; -} - -/* parse an integer constant and return its value. - Complain if it doesn't fit 32bit (signed or unsigned). */ -ST_FUNC int expr_const(void) -{ - int c; - int64_t wc = expr_const64(); - c = wc; - if (c != wc && (unsigned)c != wc) - tcc_error("constant exceeds 32 bit"); - return c; -} - -/* ------------------------------------------------------------------------- */ -/* return from function */ - -#ifndef TCC_TARGET_ARM64 -static void gfunc_return(CType *func_type) -{ - if ((func_type->t & VT_BTYPE) == VT_STRUCT) { - CType type, ret_type; - int ret_align, ret_nregs, regsize; - ret_nregs = gfunc_sret(func_type, func_var, &ret_type, - &ret_align, ®size); - if (ret_nregs < 0) { -#ifdef TCC_TARGET_RISCV64 - arch_transfer_ret_regs(0); -#endif - } else if (0 == ret_nregs) { - /* if returning structure, must copy it to implicit - first pointer arg location */ - type = *func_type; - mk_pointer(&type); - vset(&type, VT_LOCAL | VT_LVAL, func_vc); - indir(); - vswap(); - /* copy structure value to pointer */ - vstore(); - } else { - /* returning structure packed into registers */ - int size, addr, align, rc; - size = type_size(func_type,&align); - if ((vtop->r != (VT_LOCAL | VT_LVAL) || - (vtop->c.i & (ret_align-1))) - && (align & (ret_align-1))) { - loc = (loc - size) & -ret_align; - addr = loc; - type = *func_type; - vset(&type, VT_LOCAL | VT_LVAL, addr); - vswap(); - vstore(); - vpop(); - vset(&ret_type, VT_LOCAL | VT_LVAL, addr); - } - vtop->type = ret_type; - rc = RC_RET(ret_type.t); - if (ret_nregs == 1) - gv(rc); - else { - for (;;) { - vdup(); - gv(rc); - vpop(); - if (--ret_nregs == 0) - break; - /* We assume that when a structure is returned in multiple - registers, their classes are consecutive values of the - suite s(n) = 2^n */ - rc <<= 1; - vtop->c.i += regsize; - } - } - } - } else { - gv(RC_RET(func_type->t)); - } - vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ -} -#endif - -static void check_func_return(void) -{ - if ((func_vt.t & VT_BTYPE) == VT_VOID) - return; - if (!strcmp (funcname, "main") - && (func_vt.t & VT_BTYPE) == VT_INT) { - /* main returns 0 by default */ - vpushi(0); - gen_assign_cast(&func_vt); - gfunc_return(&func_vt); - } else { - tcc_warning("function might return no value: '%s'", funcname); - } -} - -/* ------------------------------------------------------------------------- */ -/* switch/case */ - -static int case_cmpi(const void *pa, const void *pb) -{ - int64_t a = (*(struct case_t**) pa)->v1; - int64_t b = (*(struct case_t**) pb)->v1; - return a < b ? -1 : a > b; -} - -static int case_cmpu(const void *pa, const void *pb) -{ - uint64_t a = (uint64_t)(*(struct case_t**) pa)->v1; - uint64_t b = (uint64_t)(*(struct case_t**) pb)->v1; - return a < b ? -1 : a > b; -} - -static void gtst_addr(int t, int a) -{ - gsym_addr(gvtst(0, t), a); -} - -static void gcase(struct case_t **base, int len, int *bsym) -{ - struct case_t *p; - int e; - int ll = (vtop->type.t & VT_BTYPE) == VT_LLONG; - while (len > 8) { - /* binary search */ - p = base[len/2]; - vdup(); - if (ll) - vpushll(p->v2); - else - vpushi(p->v2); - gen_op(TOK_LE); - e = gvtst(1, 0); - vdup(); - if (ll) - vpushll(p->v1); - else - vpushi(p->v1); - gen_op(TOK_GE); - gtst_addr(0, p->sym); /* v1 <= x <= v2 */ - /* x < v1 */ - gcase(base, len/2, bsym); - /* x > v2 */ - gsym(e); - e = len/2 + 1; - base += e; len -= e; - } - /* linear scan */ - while (len--) { - p = *base++; - vdup(); - if (ll) - vpushll(p->v2); - else - vpushi(p->v2); - if (p->v1 == p->v2) { - gen_op(TOK_EQ); - gtst_addr(0, p->sym); - } else { - gen_op(TOK_LE); - e = gvtst(1, 0); - vdup(); - if (ll) - vpushll(p->v1); - else - vpushi(p->v1); - gen_op(TOK_GE); - gtst_addr(0, p->sym); - gsym(e); - } - } - *bsym = gjmp(*bsym); -} - -/* ------------------------------------------------------------------------- */ -/* __attribute__((cleanup(fn))) */ - -static void try_call_scope_cleanup(Sym *stop) -{ - Sym *cls = cur_scope->cl.s; - - for (; cls != stop; cls = cls->ncl) { - Sym *fs = cls->next; - Sym *vs = cls->prev_tok; - - vpushsym(&fs->type, fs); - vset(&vs->type, vs->r, vs->c); - vtop->sym = vs; - mk_pointer(&vtop->type); - gaddrof(); - gfunc_call(1); - } -} - -static void try_call_cleanup_goto(Sym *cleanupstate) -{ - Sym *oc, *cc; - int ocd, ccd; - - if (!cur_scope->cl.s) - return; - - /* search NCA of both cleanup chains given parents and initial depth */ - ocd = cleanupstate ? cleanupstate->v & ~SYM_FIELD : 0; - for (ccd = cur_scope->cl.n, oc = cleanupstate; ocd > ccd; --ocd, oc = oc->ncl) - ; - for (cc = cur_scope->cl.s; ccd > ocd; --ccd, cc = cc->ncl) - ; - for (; cc != oc; cc = cc->ncl, oc = oc->ncl, --ccd) - ; - - try_call_scope_cleanup(cc); -} - -/* call 'func' for each __attribute__((cleanup(func))) */ -static void block_cleanup(struct scope *o) -{ - int jmp = 0; - Sym *g, **pg; - for (pg = &pending_gotos; (g = *pg) && g->c > o->cl.n;) { - if (g->prev_tok->r & LABEL_FORWARD) { - Sym *pcl = g->next; - if (!jmp) - jmp = gjmp(0); - gsym(pcl->jnext); - try_call_scope_cleanup(o->cl.s); - pcl->jnext = gjmp(0); - if (!o->cl.n) - goto remove_pending; - g->c = o->cl.n; - pg = &g->prev; - } else { - remove_pending: - *pg = g->prev; - sym_free(g); - } - } - gsym(jmp); - try_call_scope_cleanup(o->cl.s); -} - -/* ------------------------------------------------------------------------- */ -/* VLA */ - -static void vla_restore(int loc) -{ - if (loc) - gen_vla_sp_restore(loc); -} - -static void vla_leave(struct scope *o) -{ - struct scope *c = cur_scope, *v = NULL; - for (; c != o && c; c = c->prev) - if (c->vla.num) - v = c; - if (v) - vla_restore(v->vla.locorig); -} - -/* ------------------------------------------------------------------------- */ -/* local scopes */ - -static void new_scope(struct scope *o) -{ - /* copy and link previous scope */ - *o = *cur_scope; - o->prev = cur_scope; - cur_scope = o; - cur_scope->vla.num = 0; - - /* record local declaration stack position */ - o->lstk = local_stack; - o->llstk = local_label_stack; - ++local_scope; -} - -static void prev_scope(struct scope *o, int is_expr) -{ - vla_leave(o->prev); - - if (o->cl.s != o->prev->cl.s) - block_cleanup(o->prev); - - /* pop locally defined labels */ - label_pop(&local_label_stack, o->llstk, is_expr); - - /* In the is_expr case (a statement expression is finished here), - vtop might refer to symbols on the local_stack. Either via the - type or via vtop->sym. We can't pop those nor any that in turn - might be referred to. To make it easier we don't roll back - any symbols in that case; some upper level call to block() will - do that. We do have to remove such symbols from the lookup - tables, though. sym_pop will do that. */ - - /* pop locally defined symbols */ - pop_local_syms(o->lstk, is_expr); - cur_scope = o->prev; - --local_scope; -} - -/* leave a scope via break/continue(/goto) */ -static void leave_scope(struct scope *o) -{ - if (!o) - return; - try_call_scope_cleanup(o->cl.s); - vla_leave(o); -} - -/* short versiona for scopes with 'if/do/while/switch' which can - declare only types (of struct/union/enum) */ -static void new_scope_s(struct scope *o) -{ - o->lstk = local_stack; - ++local_scope; -} - -static void prev_scope_s(struct scope *o) -{ - sym_pop(&local_stack, o->lstk, 0); - --local_scope; -} - -/* ------------------------------------------------------------------------- */ -/* call block from 'for do while' loops */ - -static void lblock(int *bsym, int *csym) -{ - struct scope *lo = loop_scope, *co = cur_scope; - int *b = co->bsym, *c = co->csym; - if (csym) { - co->csym = csym; - loop_scope = co; - } - co->bsym = bsym; - block(0); - co->bsym = b; - if (csym) { - co->csym = c; - loop_scope = lo; - } -} - -static void block(int is_expr) -{ - int a, b, c, d, e, t; - struct scope o; - Sym *s; - - if (is_expr) { - /* default return value is (void) */ - vpushi(0); - vtop->type.t = VT_VOID; - } - -again: - t = tok; - /* If the token carries a value, next() might destroy it. Only with - invalid code such as f(){"123"4;} */ - if (TOK_HAS_VALUE(t)) - goto expr; - next(); - - if (debug_modes) - tcc_tcov_check_line (tcc_state, 0), tcc_tcov_block_begin (tcc_state); - - if (t == TOK_IF) { - new_scope_s(&o); - skip('('); - gexpr(); - skip(')'); - a = gvtst(1, 0); - block(0); - if (tok == TOK_ELSE) { - d = gjmp(0); - gsym(a); - next(); - block(0); - gsym(d); /* patch else jmp */ - } else { - gsym(a); - } - prev_scope_s(&o); - - } else if (t == TOK_WHILE) { - new_scope_s(&o); - d = gind(); - skip('('); - gexpr(); - skip(')'); - a = gvtst(1, 0); - b = 0; - lblock(&a, &b); - gjmp_addr(d); - gsym_addr(b, d); - gsym(a); - prev_scope_s(&o); - - } else if (t == '{') { - if (debug_modes) - tcc_debug_stabn(tcc_state, N_LBRAC, ind - func_ind); - new_scope(&o); - - /* handle local labels declarations */ - while (tok == TOK_LABEL) { - do { - next(); - if (tok < TOK_UIDENT) - expect("label identifier"); - label_push(&local_label_stack, tok, LABEL_DECLARED); - next(); - } while (tok == ','); - skip(';'); - } - - while (tok != '}') { - decl(VT_LOCAL); - if (tok != '}') { - if (is_expr) - vpop(); - block(is_expr); - } - } - - prev_scope(&o, is_expr); - if (debug_modes) - tcc_debug_stabn(tcc_state, N_RBRAC, ind - func_ind); - if (local_scope) - next(); - else if (!nocode_wanted) - check_func_return(); - - } else if (t == TOK_RETURN) { - b = (func_vt.t & VT_BTYPE) != VT_VOID; - if (tok != ';') { - gexpr(); - if (b) { - gen_assign_cast(&func_vt); - } else { - if (vtop->type.t != VT_VOID) - tcc_warning("void function returns a value"); - vtop--; - } - } else if (b) { - tcc_warning("'return' with no value"); - b = 0; - } - leave_scope(root_scope); - if (b) - gfunc_return(&func_vt); - skip(';'); - /* jump unless last stmt in top-level block */ - if (tok != '}' || local_scope != 1) - rsym = gjmp(rsym); - if (debug_modes) - tcc_tcov_block_end (tcc_state, -1); - CODE_OFF(); - - } else if (t == TOK_BREAK) { - /* compute jump */ - if (!cur_scope->bsym) - tcc_error("cannot break"); - if (cur_switch && cur_scope->bsym == cur_switch->bsym) - leave_scope(cur_switch->scope); - else - leave_scope(loop_scope); - *cur_scope->bsym = gjmp(*cur_scope->bsym); - skip(';'); - - } else if (t == TOK_CONTINUE) { - /* compute jump */ - if (!cur_scope->csym) - tcc_error("cannot continue"); - leave_scope(loop_scope); - *cur_scope->csym = gjmp(*cur_scope->csym); - skip(';'); - - } else if (t == TOK_FOR) { - new_scope(&o); - - skip('('); - if (tok != ';') { - /* c99 for-loop init decl? */ - if (!decl(VT_JMP)) { - /* no, regular for-loop init expr */ - gexpr(); - vpop(); - } - } - skip(';'); - a = b = 0; - c = d = gind(); - if (tok != ';') { - gexpr(); - a = gvtst(1, 0); - } - skip(';'); - if (tok != ')') { - e = gjmp(0); - d = gind(); - gexpr(); - vpop(); - gjmp_addr(c); - gsym(e); - } - skip(')'); - lblock(&a, &b); - gjmp_addr(d); - gsym_addr(b, d); - gsym(a); - prev_scope(&o, 0); - - } else if (t == TOK_DO) { - new_scope_s(&o); - a = b = 0; - d = gind(); - lblock(&a, &b); - gsym(b); - skip(TOK_WHILE); - skip('('); - gexpr(); - skip(')'); - skip(';'); - c = gvtst(0, 0); - gsym_addr(c, d); - gsym(a); - prev_scope_s(&o); - - } else if (t == TOK_SWITCH) { - struct switch_t *sw; - - sw = tcc_mallocz(sizeof *sw); - sw->bsym = &a; - sw->scope = cur_scope; - sw->prev = cur_switch; - sw->nocode_wanted = nocode_wanted; - cur_switch = sw; - - new_scope_s(&o); - skip('('); - gexpr(); - skip(')'); - sw->sv = *vtop--; /* save switch value */ - a = 0; - b = gjmp(0); /* jump to first case */ - lblock(&a, NULL); - a = gjmp(a); /* add implicit break */ - /* case lookup */ - gsym(b); - prev_scope_s(&o); - - if (sw->nocode_wanted) - goto skip_switch; - if (sw->sv.type.t & VT_UNSIGNED) - qsort(sw->p, sw->n, sizeof(void*), case_cmpu); - else - qsort(sw->p, sw->n, sizeof(void*), case_cmpi); - for (b = 1; b < sw->n; b++) - if (sw->sv.type.t & VT_UNSIGNED - ? (uint64_t)sw->p[b - 1]->v2 >= (uint64_t)sw->p[b]->v1 - : sw->p[b - 1]->v2 >= sw->p[b]->v1) - tcc_error("duplicate case value"); - vpushv(&sw->sv); - gv(RC_INT); - d = 0, gcase(sw->p, sw->n, &d); - vpop(); - if (sw->def_sym) - gsym_addr(d, sw->def_sym); - else - gsym(d); - skip_switch: - /* break label */ - gsym(a); - - dynarray_reset(&sw->p, &sw->n); - cur_switch = sw->prev; - tcc_free(sw); - - } else if (t == TOK_CASE) { - struct case_t *cr = tcc_malloc(sizeof(struct case_t)); - if (!cur_switch) - expect("switch"); - cr->v1 = cr->v2 = expr_const64(); - if (gnu_ext && tok == TOK_DOTS) { - next(); - cr->v2 = expr_const64(); - if ((!(cur_switch->sv.type.t & VT_UNSIGNED) && cr->v2 < cr->v1) - || (cur_switch->sv.type.t & VT_UNSIGNED && (uint64_t)cr->v2 < (uint64_t)cr->v1)) - tcc_warning("empty case range"); - } - /* case and default are unreachable from a switch under nocode_wanted */ - if (!cur_switch->nocode_wanted) - cr->sym = gind(); - dynarray_add(&cur_switch->p, &cur_switch->n, cr); - skip(':'); - is_expr = 0; - goto block_after_label; - - } else if (t == TOK_DEFAULT) { - if (!cur_switch) - expect("switch"); - if (cur_switch->def_sym) - tcc_error("too many 'default'"); - cur_switch->def_sym = cur_switch->nocode_wanted ? 1 : gind(); - skip(':'); - is_expr = 0; - goto block_after_label; - - } else if (t == TOK_GOTO) { - vla_restore(cur_scope->vla.locorig); - if (tok == '*' && gnu_ext) { - /* computed goto */ - next(); - gexpr(); - if ((vtop->type.t & VT_BTYPE) != VT_PTR) - expect("pointer"); - ggoto(); - - } else if (tok >= TOK_UIDENT) { - s = label_find(tok); - /* put forward definition if needed */ - if (!s) - s = label_push(&global_label_stack, tok, LABEL_FORWARD); - else if (s->r == LABEL_DECLARED) - s->r = LABEL_FORWARD; - - if (s->r & LABEL_FORWARD) { - /* start new goto chain for cleanups, linked via label->next */ - if (cur_scope->cl.s && !nocode_wanted) { - sym_push2(&pending_gotos, SYM_FIELD, 0, cur_scope->cl.n); - pending_gotos->prev_tok = s; - s = sym_push2(&s->next, SYM_FIELD, 0, 0); - pending_gotos->next = s; - } - s->jnext = gjmp(s->jnext); - } else { - try_call_cleanup_goto(s->cleanupstate); - gjmp_addr(s->jnext); - } - next(); - - } else { - expect("label identifier"); - } - skip(';'); - - } else if (t == TOK_ASM1 || t == TOK_ASM2 || t == TOK_ASM3) { - asm_instr(); - - } else { - if (tok == ':' && t >= TOK_UIDENT) { - /* label case */ - next(); - s = label_find(t); - if (s) { - if (s->r == LABEL_DEFINED) - tcc_error("duplicate label '%s'", get_tok_str(s->v, NULL)); - s->r = LABEL_DEFINED; - if (s->next) { - Sym *pcl; /* pending cleanup goto */ - for (pcl = s->next; pcl; pcl = pcl->prev) - gsym(pcl->jnext); - sym_pop(&s->next, NULL, 0); - } else - gsym(s->jnext); - } else { - s = label_push(&global_label_stack, t, LABEL_DEFINED); - } - s->jnext = gind(); - s->cleanupstate = cur_scope->cl.s; - - block_after_label: - { - /* Accept attributes after labels (e.g. 'unused') */ - AttributeDef ad_tmp; - parse_attribute(&ad_tmp); - } - if (debug_modes) - tcc_tcov_reset_ind(tcc_state); - vla_restore(cur_scope->vla.loc); - if (tok != '}') - goto again; - /* we accept this, but it is a mistake */ - tcc_warning_c(warn_all)("deprecated use of label at end of compound statement"); - - } else { - /* expression case */ - if (t != ';') { - unget_tok(t); - expr: - if (is_expr) { - vpop(); - gexpr(); - } else { - gexpr(); - vpop(); - } - skip(';'); - } - } - } - - if (debug_modes) - tcc_tcov_check_line (tcc_state, 0), tcc_tcov_block_end (tcc_state, 0); -} - -/* This skips over a stream of tokens containing balanced {} and () - pairs, stopping at outer ',' ';' and '}' (or matching '}' if we started - with a '{'). If STR then allocates and stores the skipped tokens - in *STR. This doesn't check if () and {} are nested correctly, - i.e. "({)}" is accepted. */ -static void skip_or_save_block(TokenString **str) -{ - int braces = tok == '{'; - int level = 0; - if (str) - *str = tok_str_alloc(); - - while (1) { - int t = tok; - if (level == 0 - && (t == ',' - || t == ';' - || t == '}' - || t == ')' - || t == ']')) - break; - if (t == TOK_EOF) { - if (str || level > 0) - tcc_error("unexpected end of file"); - else - break; - } - if (str) - tok_str_add_tok(*str); - next(); - if (t == '{' || t == '(' || t == '[') { - level++; - } else if (t == '}' || t == ')' || t == ']') { - level--; - if (level == 0 && braces && t == '}') - break; - } - } - if (str) { - tok_str_add(*str, -1); - tok_str_add(*str, 0); - } -} - -#define EXPR_CONST 1 -#define EXPR_ANY 2 - -static void parse_init_elem(int expr_type) -{ - int saved_global_expr; - switch(expr_type) { - case EXPR_CONST: - /* compound literals must be allocated globally in this case */ - saved_global_expr = global_expr; - global_expr = 1; - expr_const1(); - global_expr = saved_global_expr; - /* NOTE: symbols are accepted, as well as lvalue for anon symbols - (compound literals). */ - if (((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST - && ((vtop->r & (VT_SYM|VT_LVAL)) != (VT_SYM|VT_LVAL) - || vtop->sym->v < SYM_FIRST_ANOM)) -#ifdef TCC_TARGET_PE - || ((vtop->r & VT_SYM) && vtop->sym->a.dllimport) -#endif - ) - tcc_error("initializer element is not constant"); - break; - case EXPR_ANY: - expr_eq(); - break; - } -} - -#if 1 -static void init_assert(init_params *p, int offset) -{ - if (p->sec ? !NODATA_WANTED && offset > p->sec->data_offset - : !nocode_wanted && offset > p->local_offset) - tcc_internal_error("initializer overflow"); -} -#else -#define init_assert(sec, offset) -#endif - -/* put zeros for variable based init */ -static void init_putz(init_params *p, unsigned long c, int size) -{ - init_assert(p, c + size); - if (p->sec) { - /* nothing to do because globals are already set to zero */ - } else { - vpush_helper_func(TOK_memset); - vseti(VT_LOCAL, c); -#ifdef TCC_TARGET_ARM - vpushs(size); - vpushi(0); -#else - vpushi(0); - vpushs(size); -#endif - gfunc_call(3); - } -} - -#define DIF_FIRST 1 -#define DIF_SIZE_ONLY 2 -#define DIF_HAVE_ELEM 4 -#define DIF_CLEAR 8 - -/* delete relocations for specified range c ... c + size. Unfortunatly - in very special cases, relocations may occur unordered */ -static void decl_design_delrels(Section *sec, int c, int size) -{ - ElfW_Rel *rel, *rel2, *rel_end; - if (!sec || !sec->reloc) - return; - rel = rel2 = (ElfW_Rel*)sec->reloc->data; - rel_end = (ElfW_Rel*)(sec->reloc->data + sec->reloc->data_offset); - while (rel < rel_end) { - if (rel->r_offset >= c && rel->r_offset < c + size) { - sec->reloc->data_offset -= sizeof *rel; - } else { - if (rel2 != rel) - memcpy(rel2, rel, sizeof *rel); - ++rel2; - } - ++rel; - } -} - -static void decl_design_flex(init_params *p, Sym *ref, int index) -{ - if (ref == p->flex_array_ref) { - if (index >= ref->c) - ref->c = index + 1; - } else if (ref->c < 0) - tcc_error("flexible array has zero size in this context"); -} - -/* t is the array or struct type. c is the array or struct - address. cur_field is the pointer to the current - field, for arrays the 'c' member contains the current start - index. 'flags' is as in decl_initializer. - 'al' contains the already initialized length of the - current container (starting at c). This returns the new length of that. */ -static int decl_designator(init_params *p, CType *type, unsigned long c, - Sym **cur_field, int flags, int al) -{ - Sym *s, *f; - int index, index_last, align, l, nb_elems, elem_size; - unsigned long corig = c; - - elem_size = 0; - nb_elems = 1; - - if (flags & DIF_HAVE_ELEM) - goto no_designator; - - if (gnu_ext && tok >= TOK_UIDENT) { - l = tok, next(); - if (tok == ':') - goto struct_field; - unget_tok(l); - } - - /* NOTE: we only support ranges for last designator */ - while (nb_elems == 1 && (tok == '[' || tok == '.')) { - if (tok == '[') { - if (!(type->t & VT_ARRAY)) - expect("array type"); - next(); - index = index_last = expr_const(); - if (tok == TOK_DOTS && gnu_ext) { - next(); - index_last = expr_const(); - } - skip(']'); - s = type->ref; - decl_design_flex(p, s, index_last); - if (index < 0 || index_last >= s->c || index_last < index) - tcc_error("index exceeds array bounds or range is empty"); - if (cur_field) - (*cur_field)->c = index_last; - type = pointed_type(type); - elem_size = type_size(type, &align); - c += index * elem_size; - nb_elems = index_last - index + 1; - } else { - int cumofs; - next(); - l = tok; - struct_field: - next(); - if ((type->t & VT_BTYPE) != VT_STRUCT) - expect("struct/union type"); - cumofs = 0; - f = find_field(type, l, &cumofs); - if (cur_field) - *cur_field = f; - type = &f->type; - c += cumofs; - } - cur_field = NULL; - } - if (!cur_field) { - if (tok == '=') { - next(); - } else if (!gnu_ext) { - expect("="); - } - } else { - no_designator: - if (type->t & VT_ARRAY) { - index = (*cur_field)->c; - s = type->ref; - decl_design_flex(p, s, index); - if (index >= s->c) - tcc_error("too many initializers"); - type = pointed_type(type); - elem_size = type_size(type, &align); - c += index * elem_size; - } else { - f = *cur_field; - /* Skip bitfield padding. Also with size 32 and 64. */ - while (f && (f->v & SYM_FIRST_ANOM) && - is_integer_btype(f->type.t & VT_BTYPE)) - *cur_field = f = f->next; - if (!f) - tcc_error("too many initializers"); - type = &f->type; - c += f->c; - } - } - - if (!elem_size) /* for structs */ - elem_size = type_size(type, &align); - - /* Using designators the same element can be initialized more - than once. In that case we need to delete possibly already - existing relocations. */ - if (!(flags & DIF_SIZE_ONLY) && c - corig < al) { - decl_design_delrels(p->sec, c, elem_size * nb_elems); - flags &= ~DIF_CLEAR; /* mark stack dirty too */ - } - - decl_initializer(p, type, c, flags & ~DIF_FIRST); - - if (!(flags & DIF_SIZE_ONLY) && nb_elems > 1) { - Sym aref = {0}; - CType t1; - int i; - if (p->sec || (type->t & VT_ARRAY)) { - /* make init_putv/vstore believe it were a struct */ - aref.c = elem_size; - t1.t = VT_STRUCT, t1.ref = &aref; - type = &t1; - } - if (p->sec) - vpush_ref(type, p->sec, c, elem_size); - else - vset(type, VT_LOCAL|VT_LVAL, c); - for (i = 1; i < nb_elems; i++) { - vdup(); - init_putv(p, type, c + elem_size * i); - } - vpop(); - } - - c += nb_elems * elem_size; - if (c - corig > al) - al = c - corig; - return al; -} - -/* store a value or an expression directly in global data or in local array */ -static void init_putv(init_params *p, CType *type, unsigned long c) -{ - int bt; - void *ptr; - CType dtype; - int size, align; - Section *sec = p->sec; - uint64_t val; - - dtype = *type; - dtype.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */ - - size = type_size(type, &align); - if (type->t & VT_BITFIELD) - size = (BIT_POS(type->t) + BIT_SIZE(type->t) + 7) / 8; - init_assert(p, c + size); - - if (sec) { - /* XXX: not portable */ - /* XXX: generate error if incorrect relocation */ - gen_assign_cast(&dtype); - bt = type->t & VT_BTYPE; - - if ((vtop->r & VT_SYM) - && bt != VT_PTR - && (bt != (PTR_SIZE == 8 ? VT_LLONG : VT_INT) - || (type->t & VT_BITFIELD)) - && !((vtop->r & VT_CONST) && vtop->sym->v >= SYM_FIRST_ANOM) - ) - tcc_error("initializer element is not computable at load time"); - - if (NODATA_WANTED) { - vtop--; - return; - } - - ptr = sec->data + c; - val = vtop->c.i; - - /* XXX: make code faster ? */ - if ((vtop->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST) && - vtop->sym->v >= SYM_FIRST_ANOM && - /* XXX This rejects compound literals like - '(void *){ptr}'. The problem is that '&sym' is - represented the same way, which would be ruled out - by the SYM_FIRST_ANOM check above, but also '"string"' - in 'char *p = "string"' is represented the same - with the type being VT_PTR and the symbol being an - anonymous one. That is, there's no difference in vtop - between '(void *){x}' and '&(void *){x}'. Ignore - pointer typed entities here. Hopefully no real code - will ever use compound literals with scalar type. */ - (vtop->type.t & VT_BTYPE) != VT_PTR) { - /* These come from compound literals, memcpy stuff over. */ - Section *ssec; - ElfSym *esym; - ElfW_Rel *rel; - esym = elfsym(vtop->sym); - ssec = tcc_state->sections[esym->st_shndx]; - memmove (ptr, ssec->data + esym->st_value + (int)vtop->c.i, size); - if (ssec->reloc) { - /* We need to copy over all memory contents, and that - includes relocations. Use the fact that relocs are - created it order, so look from the end of relocs - until we hit one before the copied region. */ - unsigned long relofs = ssec->reloc->data_offset; - while (relofs >= sizeof(*rel)) { - relofs -= sizeof(*rel); - rel = (ElfW_Rel*)(ssec->reloc->data + relofs); - if (rel->r_offset >= esym->st_value + size) - continue; - if (rel->r_offset < esym->st_value) - break; - put_elf_reloca(symtab_section, sec, - c + rel->r_offset - esym->st_value, - ELFW(R_TYPE)(rel->r_info), - ELFW(R_SYM)(rel->r_info), -#if PTR_SIZE == 8 - rel->r_addend -#else - 0 -#endif - ); - } - } - } else { - if (type->t & VT_BITFIELD) { - int bit_pos, bit_size, bits, n; - unsigned char *p, v, m; - bit_pos = BIT_POS(vtop->type.t); - bit_size = BIT_SIZE(vtop->type.t); - p = (unsigned char*)ptr + (bit_pos >> 3); - bit_pos &= 7, bits = 0; - while (bit_size) { - n = 8 - bit_pos; - if (n > bit_size) - n = bit_size; - v = val >> bits << bit_pos; - m = ((1 << n) - 1) << bit_pos; - *p = (*p & ~m) | (v & m); - bits += n, bit_size -= n, bit_pos = 0, ++p; - } - } else - switch(bt) { - case VT_BOOL: - *(char *)ptr = val != 0; - break; - case VT_BYTE: - *(char *)ptr = val; - break; - case VT_SHORT: - write16le(ptr, val); - break; - case VT_FLOAT: - write32le(ptr, val); - break; - case VT_DOUBLE: - write64le(ptr, val); - break; - case VT_LDOUBLE: -#if defined TCC_IS_NATIVE_387 - /* Host and target platform may be different but both have x87. - On windows, tcc does not use VT_LDOUBLE, except when it is a - cross compiler. In this case a mingw gcc as host compiler - comes here with 10-byte long doubles, while msvc or tcc won't. - tcc itself can still translate by asm. - In any case we avoid possibly random bytes 11 and 12. - */ - if (sizeof (long double) >= 10) - memcpy(ptr, &vtop->c.ld, 10); -#ifdef __TINYC__ - else if (sizeof (long double) == sizeof (double)) - __asm__("fldl %1\nfstpt %0\n" : "=m" (*ptr) : "m" (vtop->c.ld)); -#endif - else -#endif - /* For other platforms it should work natively, but may not work - for cross compilers */ - if (sizeof(long double) == LDOUBLE_SIZE) - memcpy(ptr, &vtop->c.ld, LDOUBLE_SIZE); - else if (sizeof(double) == LDOUBLE_SIZE) - *(double*)ptr = (double)vtop->c.ld; - else if (0 == memcmp(ptr, &vtop->c.ld, LDOUBLE_SIZE)) - ; /* nothing to do for 0.0 */ -#ifndef TCC_CROSS_TEST - else - tcc_error("can't cross compile long double constants"); -#endif - break; - -#if PTR_SIZE == 8 - /* intptr_t may need a reloc too, see tcctest.c:relocation_test() */ - case VT_LLONG: - case VT_PTR: - if (vtop->r & VT_SYM) - greloca(sec, vtop->sym, c, R_DATA_PTR, val); - else - write64le(ptr, val); - break; - case VT_INT: - write32le(ptr, val); - break; -#else - case VT_LLONG: - write64le(ptr, val); - break; - case VT_PTR: - case VT_INT: - if (vtop->r & VT_SYM) - greloc(sec, vtop->sym, c, R_DATA_PTR); - write32le(ptr, val); - break; -#endif - default: - //tcc_internal_error("unexpected type"); - break; - } - } - vtop--; - } else { - vset(&dtype, VT_LOCAL|VT_LVAL, c); - vswap(); - vstore(); - vpop(); - } -} - -/* 't' contains the type and storage info. 'c' is the offset of the - object in section 'sec'. If 'sec' is NULL, it means stack based - allocation. 'flags & DIF_FIRST' is true if array '{' must be read (multi - dimension implicit array init handling). 'flags & DIF_SIZE_ONLY' is true if - size only evaluation is wanted (only for arrays). */ -static void decl_initializer(init_params *p, CType *type, unsigned long c, int flags) -{ - int len, n, no_oblock, i; - int size1, align1; - Sym *s, *f; - Sym indexsym; - CType *t1; - - /* generate line number info */ - if (debug_modes && !p->sec) - tcc_debug_line(tcc_state), tcc_tcov_check_line (tcc_state, 1); - - if (!(flags & DIF_HAVE_ELEM) && tok != '{' && - /* In case of strings we have special handling for arrays, so - don't consume them as initializer value (which would commit them - to some anonymous symbol). */ - tok != TOK_LSTR && tok != TOK_STR && - (!(flags & DIF_SIZE_ONLY) - /* a struct may be initialized from a struct of same type, as in - struct {int x,y;} a = {1,2}, b = {3,4}, c[] = {a,b}; - In that case we need to parse the element in order to check - it for compatibility below */ - || (type->t & VT_BTYPE) == VT_STRUCT) - ) { - int ncw_prev = nocode_wanted; - if ((flags & DIF_SIZE_ONLY) && !p->sec) - ++nocode_wanted; - parse_init_elem(!p->sec ? EXPR_ANY : EXPR_CONST); - nocode_wanted = ncw_prev; - flags |= DIF_HAVE_ELEM; - } - - if (type->t & VT_ARRAY) { - no_oblock = 1; - if (((flags & DIF_FIRST) && tok != TOK_LSTR && tok != TOK_STR) || - tok == '{') { - skip('{'); - no_oblock = 0; - } - - s = type->ref; - n = s->c; - t1 = pointed_type(type); - size1 = type_size(t1, &align1); - - /* only parse strings here if correct type (otherwise: handle - them as ((w)char *) expressions */ - if ((tok == TOK_LSTR && -#ifdef TCC_TARGET_PE - (t1->t & VT_BTYPE) == VT_SHORT && (t1->t & VT_UNSIGNED) -#else - (t1->t & VT_BTYPE) == VT_INT -#endif - ) || (tok == TOK_STR && (t1->t & VT_BTYPE) == VT_BYTE)) { - len = 0; - cstr_reset(&initstr); - if (size1 != (tok == TOK_STR ? 1 : sizeof(nwchar_t))) - tcc_error("unhandled string literal merging"); - while (tok == TOK_STR || tok == TOK_LSTR) { - if (initstr.size) - initstr.size -= size1; - if (tok == TOK_STR) - len += tokc.str.size; - else - len += tokc.str.size / sizeof(nwchar_t); - len--; - cstr_cat(&initstr, tokc.str.data, tokc.str.size); - next(); - } - if (tok != ')' && tok != '}' && tok != ',' && tok != ';' - && tok != TOK_EOF) { - /* Not a lone literal but part of a bigger expression. */ - unget_tok(size1 == 1 ? TOK_STR : TOK_LSTR); - tokc.str.size = initstr.size; - tokc.str.data = initstr.data; - goto do_init_array; - } - - decl_design_flex(p, s, len); - if (!(flags & DIF_SIZE_ONLY)) { - int nb = n, ch; - if (len < nb) - nb = len; - if (len > nb) - tcc_warning("initializer-string for array is too long"); - /* in order to go faster for common case (char - string in global variable, we handle it - specifically */ - if (p->sec && size1 == 1) { - init_assert(p, c + nb); - if (!NODATA_WANTED) - memcpy(p->sec->data + c, initstr.data, nb); - } else { - for(i=0;i<n;i++) { - if (i >= nb) { - /* only add trailing zero if enough storage (no - warning in this case since it is standard) */ - if (flags & DIF_CLEAR) - break; - if (n - i >= 4) { - init_putz(p, c + i * size1, (n - i) * size1); - break; - } - ch = 0; - } else if (size1 == 1) - ch = ((unsigned char *)initstr.data)[i]; - else - ch = ((nwchar_t *)initstr.data)[i]; - vpushi(ch); - init_putv(p, t1, c + i * size1); - } - } - } - } else { - - do_init_array: - indexsym.c = 0; - f = &indexsym; - - do_init_list: - /* zero memory once in advance */ - if (!(flags & (DIF_CLEAR | DIF_SIZE_ONLY))) { - init_putz(p, c, n*size1); - flags |= DIF_CLEAR; - } - - len = 0; - /* GNU extension: if the initializer is empty for a flex array, - it's size is zero. We won't enter the loop, so set the size - now. */ - decl_design_flex(p, s, len); - while (tok != '}' || (flags & DIF_HAVE_ELEM)) { - len = decl_designator(p, type, c, &f, flags, len); - flags &= ~DIF_HAVE_ELEM; - if (type->t & VT_ARRAY) { - ++indexsym.c; - /* special test for multi dimensional arrays (may not - be strictly correct if designators are used at the - same time) */ - if (no_oblock && len >= n*size1) - break; - } else { - if (s->type.t == VT_UNION) - f = NULL; - else - f = f->next; - if (no_oblock && f == NULL) - break; - } - - if (tok == '}') - break; - skip(','); - } - } - if (!no_oblock) - skip('}'); - - } else if ((flags & DIF_HAVE_ELEM) - /* Use i_c_parameter_t, to strip toplevel qualifiers. - The source type might have VT_CONSTANT set, which is - of course assignable to non-const elements. */ - && is_compatible_unqualified_types(type, &vtop->type)) { - goto one_elem; - - } else if ((type->t & VT_BTYPE) == VT_STRUCT) { - no_oblock = 1; - if ((flags & DIF_FIRST) || tok == '{') { - skip('{'); - no_oblock = 0; - } - s = type->ref; - f = s->next; - n = s->c; - size1 = 1; - goto do_init_list; - - } else if (tok == '{') { - if (flags & DIF_HAVE_ELEM) - skip(';'); - next(); - decl_initializer(p, type, c, flags & ~DIF_HAVE_ELEM); - skip('}'); - - } else one_elem: if ((flags & DIF_SIZE_ONLY)) { - /* If we supported only ISO C we wouldn't have to accept calling - this on anything than an array if DIF_SIZE_ONLY (and even then - only on the outermost level, so no recursion would be needed), - because initializing a flex array member isn't supported. - But GNU C supports it, so we need to recurse even into - subfields of structs and arrays when DIF_SIZE_ONLY is set. */ - /* just skip expression */ - if (flags & DIF_HAVE_ELEM) - vpop(); - else - skip_or_save_block(NULL); - - } else { - if (!(flags & DIF_HAVE_ELEM)) { - /* This should happen only when we haven't parsed - the init element above for fear of committing a - string constant to memory too early. */ - if (tok != TOK_STR && tok != TOK_LSTR) - expect("string constant"); - parse_init_elem(!p->sec ? EXPR_ANY : EXPR_CONST); - } - if (!p->sec && (flags & DIF_CLEAR) /* container was already zero'd */ - && (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST - && vtop->c.i == 0 - && btype_size(type->t & VT_BTYPE) /* not for fp constants */ - ) - vpop(); - else - init_putv(p, type, c); - } -} - -/* parse an initializer for type 't' if 'has_init' is non zero, and - allocate space in local or global data space ('r' is either - VT_LOCAL or VT_CONST). If 'v' is non zero, then an associated - variable 'v' of scope 'scope' is declared before initializers - are parsed. If 'v' is zero, then a reference to the new object - is put in the value stack. If 'has_init' is 2, a special parsing - is done to handle string constants. */ -static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, - int has_init, int v, int global) -{ - int size, align, addr; - TokenString *init_str = NULL; - - Section *sec; - Sym *flexible_array; - Sym *sym; - int saved_nocode_wanted = nocode_wanted; -#ifdef CONFIG_TCC_BCHECK - int bcheck = tcc_state->do_bounds_check && !NODATA_WANTED; -#endif - init_params p = {0}; - - /* Always allocate static or global variables */ - if (v && (r & VT_VALMASK) == VT_CONST) - nocode_wanted |= DATA_ONLY_WANTED; - - flexible_array = NULL; - size = type_size(type, &align); - - /* exactly one flexible array may be initialized, either the - toplevel array or the last member of the toplevel struct */ - - if (size < 0) { - /* If the base type itself was an array type of unspecified size - (like in 'typedef int arr[]; arr x = {1};') then we will - overwrite the unknown size by the real one for this decl. - We need to unshare the ref symbol holding that size. */ - type->ref = sym_push(SYM_FIELD, &type->ref->type, 0, type->ref->c); - p.flex_array_ref = type->ref; - - } else if (has_init && (type->t & VT_BTYPE) == VT_STRUCT) { - Sym *field = type->ref->next; - if (field) { - while (field->next) - field = field->next; - if (field->type.t & VT_ARRAY && field->type.ref->c < 0) { - flexible_array = field; - p.flex_array_ref = field->type.ref; - size = -1; - } - } - } - - if (size < 0) { - /* If unknown size, do a dry-run 1st pass */ - if (!has_init) - tcc_error("unknown type size"); - if (has_init == 2) { - /* only get strings */ - init_str = tok_str_alloc(); - while (tok == TOK_STR || tok == TOK_LSTR) { - tok_str_add_tok(init_str); - next(); - } - tok_str_add(init_str, -1); - tok_str_add(init_str, 0); - } else - skip_or_save_block(&init_str); - unget_tok(0); - - /* compute size */ - begin_macro(init_str, 1); - next(); - decl_initializer(&p, type, 0, DIF_FIRST | DIF_SIZE_ONLY); - /* prepare second initializer parsing */ - macro_ptr = init_str->str; - next(); - - /* if still unknown size, error */ - size = type_size(type, &align); - if (size < 0) - tcc_error("unknown type size"); - - /* If there's a flex member and it was used in the initializer - adjust size. */ - if (flexible_array && flexible_array->type.ref->c > 0) - size += flexible_array->type.ref->c - * pointed_size(&flexible_array->type); - } - - /* take into account specified alignment if bigger */ - if (ad->a.aligned) { - int speca = 1 << (ad->a.aligned - 1); - if (speca > align) - align = speca; - } else if (ad->a.packed) { - align = 1; - } - - if (!v && NODATA_WANTED) - size = 0, align = 1; - - if ((r & VT_VALMASK) == VT_LOCAL) { - sec = NULL; -#ifdef CONFIG_TCC_BCHECK - if (bcheck && v) { - /* add padding between stack variables for bound checking */ - loc -= align; - } -#endif - loc = (loc - size) & -align; - addr = loc; - p.local_offset = addr + size; -#ifdef CONFIG_TCC_BCHECK - if (bcheck && v) { - /* add padding between stack variables for bound checking */ - loc -= align; - } -#endif - if (v) { - /* local variable */ -#ifdef CONFIG_TCC_ASM - if (ad->asm_label) { - int reg = asm_parse_regvar(ad->asm_label); - if (reg >= 0) - r = (r & ~VT_VALMASK) | reg; - } -#endif - sym = sym_push(v, type, r, addr); - if (ad->cleanup_func) { - Sym *cls = sym_push2(&all_cleanups, - SYM_FIELD | ++cur_scope->cl.n, 0, 0); - cls->prev_tok = sym; - cls->next = ad->cleanup_func; - cls->ncl = cur_scope->cl.s; - cur_scope->cl.s = cls; - } - - sym->a = ad->a; - } else { - /* push local reference */ - vset(type, r, addr); - } - } else { - sym = NULL; - if (v && global) { - /* see if the symbol was already defined */ - sym = sym_find(v); - if (sym) { - if (p.flex_array_ref && (sym->type.t & type->t & VT_ARRAY) - && sym->type.ref->c > type->ref->c) { - /* flex array was already declared with explicit size - extern int arr[10]; - int arr[] = { 1,2,3 }; */ - type->ref->c = sym->type.ref->c; - size = type_size(type, &align); - } - patch_storage(sym, ad, type); - /* we accept several definitions of the same global variable. */ - if (!has_init && sym->c && elfsym(sym)->st_shndx != SHN_UNDEF) - goto no_alloc; - } - } - - /* allocate symbol in corresponding section */ - sec = ad->section; - if (!sec) { - CType *tp = type; - while ((tp->t & (VT_BTYPE|VT_ARRAY)) == (VT_PTR|VT_ARRAY)) - tp = &tp->ref->type; - if (tp->t & VT_CONSTANT) { - sec = rodata_section; - } else if (has_init) { - sec = data_section; - /*if (tcc_state->g_debug & 4) - tcc_warning("rw data: %s", get_tok_str(v, 0));*/ - } else if (tcc_state->nocommon) - sec = bss_section; - } - - if (sec) { - addr = section_add(sec, size, align); -#ifdef CONFIG_TCC_BCHECK - /* add padding if bound check */ - if (bcheck) - section_add(sec, 1, 1); -#endif - } else { - addr = align; /* SHN_COMMON is special, symbol value is align */ - sec = common_section; - } - - if (v) { - if (!sym) { - sym = sym_push(v, type, r | VT_SYM, 0); - patch_storage(sym, ad, NULL); - } - /* update symbol definition */ - put_extern_sym(sym, sec, addr, size); - } else { - /* push global reference */ - vpush_ref(type, sec, addr, size); - sym = vtop->sym; - vtop->r |= r; - } - -#ifdef CONFIG_TCC_BCHECK - /* handles bounds now because the symbol must be defined - before for the relocation */ - if (bcheck) { - addr_t *bounds_ptr; - - greloca(bounds_section, sym, bounds_section->data_offset, R_DATA_PTR, 0); - /* then add global bound info */ - bounds_ptr = section_ptr_add(bounds_section, 2 * sizeof(addr_t)); - bounds_ptr[0] = 0; /* relocated */ - bounds_ptr[1] = size; - } -#endif - } - - if (type->t & VT_VLA) { - int a; - - if (NODATA_WANTED) - goto no_alloc; - - /* save before-VLA stack pointer if needed */ - if (cur_scope->vla.num == 0) { - if (cur_scope->prev && cur_scope->prev->vla.num) { - cur_scope->vla.locorig = cur_scope->prev->vla.loc; - } else { - gen_vla_sp_save(loc -= PTR_SIZE); - cur_scope->vla.locorig = loc; - } - } - - vpush_type_size(type, &a); - gen_vla_alloc(type, a); -#if defined TCC_TARGET_PE && defined TCC_TARGET_X86_64 - /* on _WIN64, because of the function args scratch area, the - result of alloca differs from RSP and is returned in RAX. */ - gen_vla_result(addr), addr = (loc -= PTR_SIZE); -#endif - gen_vla_sp_save(addr); - cur_scope->vla.loc = addr; - cur_scope->vla.num++; - } else if (has_init) { - p.sec = sec; - decl_initializer(&p, type, addr, DIF_FIRST); - /* patch flexible array member size back to -1, */ - /* for possible subsequent similar declarations */ - if (flexible_array) - flexible_array->type.ref->c = -1; - } - - no_alloc: - /* restore parse state if needed */ - if (init_str) { - end_macro(); - next(); - } - - nocode_wanted = saved_nocode_wanted; -} - -/* generate vla code saved in post_type() */ -static void func_vla_arg_code(Sym *arg) -{ - int align; - TokenString *vla_array_tok = NULL; - - if (arg->type.ref) - func_vla_arg_code(arg->type.ref); - - if ((arg->type.t & VT_VLA) && arg->type.ref->vla_array_str) { - loc -= type_size(&int_type, &align); - loc &= -align; - arg->type.ref->c = loc; - - unget_tok(0); - vla_array_tok = tok_str_alloc(); - vla_array_tok->str = arg->type.ref->vla_array_str; - begin_macro(vla_array_tok, 1); - next(); - gexpr(); - end_macro(); - next(); - vpush_type_size(&arg->type.ref->type, &align); - gen_op('*'); - vset(&int_type, VT_LOCAL|VT_LVAL, arg->type.ref->c); - vswap(); - vstore(); - vpop(); - } -} - -static void func_vla_arg(Sym *sym) -{ - Sym *arg; - - for (arg = sym->type.ref->next; arg; arg = arg->next) - if (arg->type.t & VT_VLA) - func_vla_arg_code(arg); -} - -/* parse a function defined by symbol 'sym' and generate its code in - 'cur_text_section' */ -static void gen_function(Sym *sym) -{ - struct scope f = { 0 }; - cur_scope = root_scope = &f; - nocode_wanted = 0; - ind = cur_text_section->data_offset; - if (sym->a.aligned) { - size_t newoff = section_add(cur_text_section, 0, - 1 << (sym->a.aligned - 1)); - gen_fill_nops(newoff - ind); - } - /* NOTE: we patch the symbol size later */ - put_extern_sym(sym, cur_text_section, ind, 0); - if (sym->type.ref->f.func_ctor) - add_array (tcc_state, ".init_array", sym->c); - if (sym->type.ref->f.func_dtor) - add_array (tcc_state, ".fini_array", sym->c); - - funcname = get_tok_str(sym->v, NULL); - func_ind = ind; - func_vt = sym->type.ref->type; - func_var = sym->type.ref->f.func_type == FUNC_ELLIPSIS; - - /* put debug symbol */ - tcc_debug_funcstart(tcc_state, sym); - /* push a dummy symbol to enable local sym storage */ - sym_push2(&local_stack, SYM_FIELD, 0, 0); - local_scope = 1; /* for function parameters */ - gfunc_prolog(sym); - tcc_debug_prolog_epilog(tcc_state, 0); - local_scope = 0; - rsym = 0; - clear_temp_local_var_list(); - func_vla_arg(sym); - block(0); - gsym(rsym); - nocode_wanted = 0; - /* reset local stack */ - pop_local_syms(NULL, 0); - tcc_debug_prolog_epilog(tcc_state, 1); - gfunc_epilog(); - cur_text_section->data_offset = ind; - local_scope = 0; - label_pop(&global_label_stack, NULL, 0); - sym_pop(&all_cleanups, NULL, 0); - /* patch symbol size */ - elfsym(sym)->st_size = ind - func_ind; - /* end of function */ - tcc_debug_funcend(tcc_state, ind - func_ind); - /* It's better to crash than to generate wrong code */ - cur_text_section = NULL; - funcname = ""; /* for safety */ - func_vt.t = VT_VOID; /* for safety */ - func_var = 0; /* for safety */ - ind = 0; /* for safety */ - func_ind = -1; - nocode_wanted = DATA_ONLY_WANTED; - check_vstack(); - /* do this after funcend debug info */ - next(); -} - -static void gen_inline_functions(TCCState *s) -{ - Sym *sym; - int inline_generated, i; - struct InlineFunc *fn; - - tcc_open_bf(s, ":inline:", 0); - /* iterate while inline function are referenced */ - do { - inline_generated = 0; - for (i = 0; i < s->nb_inline_fns; ++i) { - fn = s->inline_fns[i]; - sym = fn->sym; - if (sym && (sym->c || !(sym->type.t & VT_INLINE))) { - /* the function was used or forced (and then not internal): - generate its code and convert it to a normal function */ - fn->sym = NULL; - tcc_debug_putfile(s, fn->filename); - begin_macro(fn->func_str, 1); - next(); - cur_text_section = text_section; - gen_function(sym); - end_macro(); - - inline_generated = 1; - } - } - } while (inline_generated); - tcc_close(); -} - -static void free_inline_functions(TCCState *s) -{ - int i; - /* free tokens of unused inline functions */ - for (i = 0; i < s->nb_inline_fns; ++i) { - struct InlineFunc *fn = s->inline_fns[i]; - if (fn->sym) - tok_str_free(fn->func_str); - } - dynarray_reset(&s->inline_fns, &s->nb_inline_fns); -} - -static void do_Static_assert(void) -{ - int c; - const char *msg; - - next(); - skip('('); - c = expr_const(); - msg = "_Static_assert fail"; - if (tok == ',') { - next(); - msg = parse_mult_str("string constant")->data; - } - skip(')'); - if (c == 0) - tcc_error("%s", msg); - skip(';'); -} - -/* 'l' is VT_LOCAL or VT_CONST to define default storage type - or VT_CMP if parsing old style parameter list - or VT_JMP if parsing c99 for decl: for (int i = 0, ...) */ -static int decl(int l) -{ - int v, has_init, r, oldint; - CType type, btype; - Sym *sym; - AttributeDef ad, adbase; - - while (1) { - - if (tok == TOK_STATIC_ASSERT) { - do_Static_assert(); - continue; - } - - oldint = 0; - if (!parse_btype(&btype, &adbase, l == VT_LOCAL)) { - if (l == VT_JMP) - return 0; - /* skip redundant ';' if not in old parameter decl scope */ - if (tok == ';' && l != VT_CMP) { - next(); - continue; - } - if (l != VT_CONST) - break; - if (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3) { - /* global asm block */ - asm_global_instr(); - continue; - } - if (tok >= TOK_UIDENT) { - /* special test for old K&R protos without explicit int - type. Only accepted when defining global data */ - btype.t = VT_INT; - oldint = 1; - } else { - if (tok != TOK_EOF) - expect("declaration"); - break; - } - } - - if (tok == ';') { - if ((btype.t & VT_BTYPE) == VT_STRUCT) { - v = btype.ref->v; - if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) >= SYM_FIRST_ANOM) - tcc_warning("unnamed struct/union that defines no instances"); - next(); - continue; - } - if (IS_ENUM(btype.t)) { - next(); - continue; - } - } - - while (1) { /* iterate thru each declaration */ - type = btype; - ad = adbase; - type_decl(&type, &ad, &v, TYPE_DIRECT); -#if 0 - { - char buf[500]; - type_to_str(buf, sizeof(buf), &type, get_tok_str(v, NULL)); - printf("type = '%s'\n", buf); - } -#endif - if ((type.t & VT_BTYPE) == VT_FUNC) { - if ((type.t & VT_STATIC) && (l != VT_CONST)) - tcc_error("function without file scope cannot be static"); - /* if old style function prototype, we accept a - declaration list */ - sym = type.ref; - if (sym->f.func_type == FUNC_OLD && l == VT_CONST) { - func_vt = type; - decl(VT_CMP); - } -#if defined TCC_TARGET_MACHO || defined TARGETOS_ANDROID - if (sym->f.func_alwinl - && ((type.t & (VT_EXTERN | VT_INLINE)) - == (VT_EXTERN | VT_INLINE))) { - /* always_inline functions must be handled as if they - don't generate multiple global defs, even if extern - inline, i.e. GNU inline semantics for those. Rewrite - them into static inline. */ - type.t &= ~VT_EXTERN; - type.t |= VT_STATIC; - } -#endif - /* always compile 'extern inline' */ - if (type.t & VT_EXTERN) - type.t &= ~VT_INLINE; - - } else if (oldint) { - tcc_warning("type defaults to int"); - } - - if (gnu_ext && (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) { - ad.asm_label = asm_label_instr(); - /* parse one last attribute list, after asm label */ - parse_attribute(&ad); - #if 0 - /* gcc does not allow __asm__("label") with function definition, - but why not ... */ - if (tok == '{') - expect(";"); - #endif - } - -#ifdef TCC_TARGET_PE - if (ad.a.dllimport || ad.a.dllexport) { - if (type.t & VT_STATIC) - tcc_error("cannot have dll linkage with static"); - if (type.t & VT_TYPEDEF) { - tcc_warning("'%s' attribute ignored for typedef", - ad.a.dllimport ? (ad.a.dllimport = 0, "dllimport") : - (ad.a.dllexport = 0, "dllexport")); - } else if (ad.a.dllimport) { - if ((type.t & VT_BTYPE) == VT_FUNC) - ad.a.dllimport = 0; - else - type.t |= VT_EXTERN; - } - } -#endif - if (tok == '{') { - if (l != VT_CONST) - tcc_error("cannot use local functions"); - if ((type.t & VT_BTYPE) != VT_FUNC) - expect("function definition"); - - /* reject abstract declarators in function definition - make old style params without decl have int type */ - sym = type.ref; - while ((sym = sym->next) != NULL) { - if (!(sym->v & ~SYM_FIELD)) - expect("identifier"); - if (sym->type.t == VT_VOID) - sym->type = int_type; - } - - /* apply post-declaraton attributes */ - merge_funcattr(&type.ref->f, &ad.f); - - /* put function symbol */ - type.t &= ~VT_EXTERN; - sym = external_sym(v, &type, 0, &ad); - - /* static inline functions are just recorded as a kind - of macro. Their code will be emitted at the end of - the compilation unit only if they are used */ - if (sym->type.t & VT_INLINE) { - struct InlineFunc *fn; - fn = tcc_malloc(sizeof *fn + strlen(file->filename)); - strcpy(fn->filename, file->filename); - fn->sym = sym; - skip_or_save_block(&fn->func_str); - dynarray_add(&tcc_state->inline_fns, - &tcc_state->nb_inline_fns, fn); - } else { - /* compute text section */ - cur_text_section = ad.section; - if (!cur_text_section) - cur_text_section = text_section; - gen_function(sym); - } - break; - } else { - if (l == VT_CMP) { - /* find parameter in function parameter list */ - for (sym = func_vt.ref->next; sym; sym = sym->next) - if ((sym->v & ~SYM_FIELD) == v) - goto found; - tcc_error("declaration for parameter '%s' but no such parameter", - get_tok_str(v, NULL)); - found: - if (type.t & VT_STORAGE) /* 'register' is okay */ - tcc_error("storage class specified for '%s'", - get_tok_str(v, NULL)); - if (sym->type.t != VT_VOID) - tcc_error("redefinition of parameter '%s'", - get_tok_str(v, NULL)); - convert_parameter_type(&type); - sym->type = type; - } else if (type.t & VT_TYPEDEF) { - /* save typedefed type */ - /* XXX: test storage specifiers ? */ - sym = sym_find(v); - if (sym && sym->sym_scope == local_scope) { - if (!is_compatible_types(&sym->type, &type) - || !(sym->type.t & VT_TYPEDEF)) - tcc_error("incompatible redefinition of '%s'", - get_tok_str(v, NULL)); - sym->type = type; - } else { - sym = sym_push(v, &type, 0, 0); - } - sym->a = ad.a; - if ((type.t & VT_BTYPE) == VT_FUNC) - merge_funcattr(&sym->type.ref->f, &ad.f); - if (debug_modes) - tcc_debug_typedef (tcc_state, sym); - } else if ((type.t & VT_BTYPE) == VT_VOID - && !(type.t & VT_EXTERN)) { - tcc_error("declaration of void object"); - } else { - r = 0; - if ((type.t & VT_BTYPE) == VT_FUNC) { - /* external function definition */ - /* specific case for func_call attribute */ - merge_funcattr(&type.ref->f, &ad.f); - } else if (!(type.t & VT_ARRAY)) { - /* not lvalue if array */ - r |= VT_LVAL; - } - has_init = (tok == '='); - if (has_init && (type.t & VT_VLA)) - tcc_error("variable length array cannot be initialized"); - if (((type.t & VT_EXTERN) && (!has_init || l != VT_CONST)) - || (type.t & VT_BTYPE) == VT_FUNC - /* as with GCC, uninitialized global arrays with no size - are considered extern: */ - || ((type.t & VT_ARRAY) && !has_init - && l == VT_CONST && type.ref->c < 0) - ) { - /* external variable or function */ - type.t |= VT_EXTERN; - sym = external_sym(v, &type, r, &ad); - if (ad.alias_target) { - /* Aliases need to be emitted when their target - symbol is emitted, even if perhaps unreferenced. - We only support the case where the base is - already defined, otherwise we would need - deferring to emit the aliases until the end of - the compile unit. */ - Sym *alias_target = sym_find(ad.alias_target); - ElfSym *esym = elfsym(alias_target); - if (!esym) - tcc_error("unsupported forward __alias__ attribute"); - put_extern_sym2(sym, esym->st_shndx, - esym->st_value, esym->st_size, 1); - } - } else { - if (l == VT_CONST || (type.t & VT_STATIC)) - r |= VT_CONST; - else - r |= VT_LOCAL; - if (has_init) - next(); - else if (l == VT_CONST) - /* uninitialized global variables may be overridden */ - type.t |= VT_EXTERN; - decl_initializer_alloc(&type, &ad, r, has_init, v, l == VT_CONST); - } - } - if (tok != ',') { - if (l == VT_JMP) - return 1; - skip(';'); - break; - } - next(); - } - } - } - return 0; -} - -/* ------------------------------------------------------------------------- */ -#undef gjmp_addr -#undef gjmp -/* ------------------------------------------------------------------------- */ diff --git a/tinycc/tcclib.h b/tinycc/tcclib.h deleted file mode 100644 index 8d59e4c..0000000 --- a/tinycc/tcclib.h +++ /dev/null @@ -1,80 +0,0 @@ -/* Simple libc header for TCC - * - * Add any function you want from the libc there. This file is here - * only for your convenience so that you do not need to put the whole - * glibc include files on your floppy disk - */ -#ifndef _TCCLIB_H -#define _TCCLIB_H - -#include <stddef.h> -#include <stdarg.h> - -/* stdlib.h */ -void *calloc(size_t nmemb, size_t size); -void *malloc(size_t size); -void free(void *ptr); -void *realloc(void *ptr, size_t size); -int atoi(const char *nptr); -long int strtol(const char *nptr, char **endptr, int base); -unsigned long int strtoul(const char *nptr, char **endptr, int base); -void exit(int); - -/* stdio.h */ -typedef struct __FILE FILE; -#define EOF (-1) -extern FILE *stdin; -extern FILE *stdout; -extern FILE *stderr; -FILE *fopen(const char *path, const char *mode); -FILE *fdopen(int fildes, const char *mode); -FILE *freopen(const char *path, const char *mode, FILE *stream); -int fclose(FILE *stream); -size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); -size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream); -int fgetc(FILE *stream); -char *fgets(char *s, int size, FILE *stream); -int getc(FILE *stream); -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, ...); -int sprintf(char *str, const char *format, ...); -int snprintf(char *str, size_t size, const char *format, ...); -int asprintf(char **strp, const char *format, ...); -int dprintf(int fd, const char *format, ...); -int vprintf(const char *format, va_list ap); -int vfprintf(FILE *stream, const char *format, va_list ap); -int vsprintf(char *str, const char *format, va_list ap); -int vsnprintf(char *str, size_t size, const char *format, va_list ap); -int vasprintf(char **strp, const char *format, va_list ap); -int vdprintf(int fd, const char *format, va_list ap); - -void perror(const char *s); - -/* string.h */ -char *strcat(char *dest, const char *src); -char *strchr(const char *s, int c); -char *strrchr(const char *s, int c); -char *strcpy(char *dest, const char *src); -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 -#define RTLD_NOW 0x002 -#define RTLD_GLOBAL 0x100 - -void *dlopen(const char *filename, int flag); -const char *dlerror(void); -void *dlsym(void *handle, char *symbol); -int dlclose(void *handle); - -#endif /* _TCCLIB_H */ diff --git a/tinycc/tccmacho.c b/tinycc/tccmacho.c deleted file mode 100644 index 4d282dd..0000000 --- a/tinycc/tccmacho.c +++ /dev/null @@ -1,2480 +0,0 @@ -/* - * Mach-O file handling for TCC - * - * 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 - */ -#include "tcc.h" - -/* In order to make life easy for us we are generating Mach-O files which - don't make use of some modern features, but which aren't entirely classic - either in that they do use some modern features. We're also only - generating 64bit Mach-O files, and only native endian at that. - - In particular we're generating executables that don't make use of - DYLD_INFO for dynamic linking info, as that requires us building a - trie of exported names. We're simply using classic symbol tables which - are still supported by modern dyld. - - But we do use LC_MAIN, which is a "modern" feature in order to not have - to setup our own crt code. We're not using lazy linking, so even function - calls are resolved at startup. */ - -#if !defined TCC_TARGET_X86_64 && !defined TCC_TARGET_ARM64 -#error Platform not supported -#endif - -/* XXX: this file uses tcc_error() to the effect of exit(1) */ -#undef _tcc_error - -#define DEBUG_MACHO 0 -#define dprintf if (DEBUG_MACHO) printf - -#define MH_EXECUTE (0x2) -#define MH_DYLDLINK (0x4) -#define MH_DYLIB (0x6) -#define MH_PIE (0x200000) - -#define CPU_SUBTYPE_LIB64 (0x80000000) -#define CPU_SUBTYPE_X86_ALL (3) -#define CPU_SUBTYPE_ARM64_ALL (0) - -#define CPU_ARCH_ABI64 (0x01000000) - -#define CPU_TYPE_X86 (7) -#define CPU_TYPE_X86_64 (CPU_TYPE_X86 | CPU_ARCH_ABI64) -#define CPU_TYPE_ARM (12) -#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) - -struct fat_header { - uint32_t magic; /* FAT_MAGIC or FAT_MAGIC_64 */ - uint32_t nfat_arch; /* number of structs that follow */ -}; - -struct fat_arch { - int cputype; /* cpu specifier (int) */ - int cpusubtype; /* machine specifier (int) */ - uint32_t offset; /* file offset to this object file */ - uint32_t size; /* size of this object file */ - uint32_t align; /* alignment as a power of 2 */ -}; - -#define FAT_MAGIC 0xcafebabe -#define FAT_CIGAM 0xbebafeca -#define FAT_MAGIC_64 0xcafebabf -#define FAT_CIGAM_64 0xbfbafeca - -struct mach_header { - uint32_t magic; /* mach magic number identifier */ - int cputype; /* cpu specifier */ - int cpusubtype; /* machine specifier */ - uint32_t filetype; /* type of file */ - uint32_t ncmds; /* number of load commands */ - uint32_t sizeofcmds; /* the size of all the load commands */ - uint32_t flags; /* flags */ -}; - -struct mach_header_64 { - struct mach_header mh; - uint32_t reserved; /* reserved, pad to 64bit */ -}; - -/* Constant for the magic field of the mach_header (32-bit architectures) */ -#define MH_MAGIC 0xfeedface /* the mach magic number */ -#define MH_CIGAM 0xcefaedfe /* NXSwapInt(MH_MAGIC) */ -#define MH_MAGIC_64 0xfeedfacf /* the 64-bit mach magic number */ -#define MH_CIGAM_64 0xcffaedfe /* NXSwapInt(MH_MAGIC_64) */ - -struct load_command { - uint32_t cmd; /* type of load command */ - uint32_t cmdsize; /* total size of command in bytes */ -}; - -#define LC_REQ_DYLD 0x80000000 -#define LC_SYMTAB 0x2 -#define LC_DYSYMTAB 0xb -#define LC_LOAD_DYLIB 0xc -#define LC_ID_DYLIB 0xd -#define LC_LOAD_DYLINKER 0xe -#define LC_SEGMENT_64 0x19 -#define LC_RPATH (0x1c | LC_REQ_DYLD) -#define LC_REEXPORT_DYLIB (0x1f | LC_REQ_DYLD) -#define LC_DYLD_INFO_ONLY (0x22|LC_REQ_DYLD) -#define LC_MAIN (0x28|LC_REQ_DYLD) -#define LC_SOURCE_VERSION 0x2A -#define LC_BUILD_VERSION 0x32 -#define LC_DYLD_EXPORTS_TRIE (0x33 | LC_REQ_DYLD) -#define LC_DYLD_CHAINED_FIXUPS (0x34 | LC_REQ_DYLD) - -#define SG_READ_ONLY 0x10 /* This segment is made read-only after fixups */ - -typedef int vm_prot_t; - -struct segment_command_64 { /* for 64-bit architectures */ - uint32_t cmd; /* LC_SEGMENT_64 */ - uint32_t cmdsize; /* includes sizeof section_64 structs */ - char segname[16]; /* segment name */ - uint64_t vmaddr; /* memory address of this segment */ - uint64_t vmsize; /* memory size of this segment */ - uint64_t fileoff; /* file offset of this segment */ - uint64_t filesize; /* amount to map from the file */ - vm_prot_t maxprot; /* maximum VM protection */ - vm_prot_t initprot; /* initial VM protection */ - uint32_t nsects; /* number of sections in segment */ - uint32_t flags; /* flags */ -}; - -struct section_64 { /* for 64-bit architectures */ - char sectname[16]; /* name of this section */ - char segname[16]; /* segment this section goes in */ - uint64_t addr; /* memory address of this section */ - uint64_t size; /* size in bytes of this section */ - uint32_t offset; /* file offset of this section */ - uint32_t align; /* section alignment (power of 2) */ - uint32_t reloff; /* file offset of relocation entries */ - uint32_t nreloc; /* number of relocation entries */ - uint32_t flags; /* flags (section type and attributes)*/ - uint32_t reserved1; /* reserved (for offset or index) */ - uint32_t reserved2; /* reserved (for count or sizeof) */ - uint32_t reserved3; /* reserved */ -}; - -enum { - DYLD_CHAINED_IMPORT = 1, -}; - -struct dyld_chained_fixups_header { - uint32_t fixups_version; ///< 0 - uint32_t starts_offset; ///< Offset of dyld_chained_starts_in_image. - uint32_t imports_offset; ///< Offset of imports table in chain_data. - uint32_t symbols_offset; ///< Offset of symbol strings in chain_data. - uint32_t imports_count; ///< Number of imported symbol names. - uint32_t imports_format; ///< DYLD_CHAINED_IMPORT* - uint32_t symbols_format; ///< 0 => uncompressed, 1 => zlib compressed -}; - -struct dyld_chained_starts_in_image -{ - uint32_t seg_count; - uint32_t seg_info_offset[1]; // each entry is offset into this struct for that segment - // followed by pool of dyld_chain_starts_in_segment data -}; - -enum { - DYLD_CHAINED_PTR_64 = 2, // target is vmaddr - DYLD_CHAINED_PTR_64_OFFSET = 6, // target is vm offset -}; - -enum { - DYLD_CHAINED_PTR_START_NONE = 0xFFFF, // used in page_start[] to denote a page with no fixups -}; - -#define SEG_PAGE_SIZE 16384 - -struct dyld_chained_starts_in_segment -{ - uint32_t size; // size of this (amount kernel needs to copy) - uint16_t page_size; // 0x1000 or 0x4000 - uint16_t pointer_format; // DYLD_CHAINED_PTR_* - uint64_t segment_offset; // offset in memory to start of segment - uint32_t max_valid_pointer; // for 32-bit OS, any value beyond this is not a pointer - uint16_t page_count; // how many pages are in array - uint16_t page_start[1]; // each entry is offset in each page of first element in chain - // or DYLD_CHAINED_PTR_START_NONE if no fixups on page -}; - -enum BindSpecialDylib { - BIND_SPECIAL_DYLIB_FLAT_LOOKUP = -2, -}; - -struct dyld_chained_import -{ - uint32_t lib_ordinal : 8, - weak_import : 1, - name_offset : 23; -}; - -struct dyld_chained_ptr_64_rebase -{ - uint64_t target : 36, // vmaddr, 64GB max image size - high8 : 8, // top 8 bits set to this after slide added - reserved : 7, // all zeros - next : 12, // 4-byte stride - bind : 1; // == 0 -}; - -struct dyld_chained_ptr_64_bind -{ - uint64_t ordinal : 24, - addend : 8, // 0 thru 255 - reserved : 19, // all zeros - next : 12, // 4-byte stride - bind : 1; // == 1 -}; - -#define S_REGULAR 0x0 -#define S_ZEROFILL 0x1 -#define S_NON_LAZY_SYMBOL_POINTERS 0x6 -#define S_LAZY_SYMBOL_POINTERS 0x7 -#define S_SYMBOL_STUBS 0x8 -#define S_MOD_INIT_FUNC_POINTERS 0x9 -#define S_MOD_TERM_FUNC_POINTERS 0xa - -#define S_ATTR_PURE_INSTRUCTIONS 0x80000000 -#define S_ATTR_SOME_INSTRUCTIONS 0x00000400 -#define S_ATTR_DEBUG 0x02000000 - - -typedef uint32_t lc_str; - -struct dylib_command { - uint32_t cmd; /* LC_ID_DYLIB, LC_LOAD_{,WEAK_}DYLIB, - LC_REEXPORT_DYLIB */ - uint32_t cmdsize; /* includes pathname string */ - lc_str name; /* library's path name */ - uint32_t timestamp; /* library's build time stamp */ - uint32_t current_version; /* library's current version number */ - uint32_t compatibility_version; /* library's compatibility vers number*/ -}; - -struct rpath_command { - uint32_t cmd; /* LC_RPATH */ - uint32_t cmdsize; /* includes string */ - lc_str path; /* path to add to run path */ -}; - -struct dylinker_command { - uint32_t cmd; /* LC_ID_DYLINKER, LC_LOAD_DYLINKER or - LC_DYLD_ENVIRONMENT */ - uint32_t cmdsize; /* includes pathname string */ - lc_str name; /* dynamic linker's path name */ -}; - -struct linkedit_data_command { - uint32_t cmd; /* LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, - LC_FUNCTION_STARTS, LC_DATA_IN_CODE, - LC_DYLIB_CODE_SIGN_DRS, - LC_LINKER_OPTIMIZATION_HINT, - LC_DYLD_EXPORTS_TRIE, or - LC_DYLD_CHAINED_FIXUPS. */ - uint32_t cmdsize; /* sizeof(struct linkedit_data_command) */ - uint32_t dataoff; /* file offset of data in __LINKEDIT segment */ - uint32_t datasize; /* file size of data in __LINKEDIT segment */ -}; - -#define PLATFORM_MACOS 1 - -struct build_version_command { - uint32_t cmd; /* LC_BUILD_VERSION */ - uint32_t cmdsize; /* sizeof(struct build_version_command) plus */ - /* ntools * sizeof(struct build_tool_version) */ - uint32_t platform; /* platform */ - uint32_t minos; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */ - uint32_t sdk; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */ - uint32_t ntools; /* number of tool entries following this */ -}; - -struct source_version_command { - uint32_t cmd; /* LC_SOURCE_VERSION */ - uint32_t cmdsize; /* 16 */ - uint64_t version; /* A.B.C.D.E packed as a24.b10.c10.d10.e10 */ -}; - -struct symtab_command { - uint32_t cmd; /* LC_SYMTAB */ - uint32_t cmdsize; /* sizeof(struct symtab_command) */ - uint32_t symoff; /* symbol table offset */ - uint32_t nsyms; /* number of symbol table entries */ - uint32_t stroff; /* string table offset */ - uint32_t strsize; /* string table size in bytes */ -}; - -struct dysymtab_command { - uint32_t cmd; /* LC_DYSYMTAB */ - uint32_t cmdsize; /* sizeof(struct dysymtab_command) */ - - uint32_t ilocalsym; /* index to local symbols */ - uint32_t nlocalsym; /* number of local symbols */ - - uint32_t iextdefsym;/* index to externally defined symbols */ - uint32_t nextdefsym;/* number of externally defined symbols */ - - uint32_t iundefsym; /* index to undefined symbols */ - uint32_t nundefsym; /* number of undefined symbols */ - - uint32_t tocoff; /* file offset to table of contents */ - uint32_t ntoc; /* number of entries in table of contents */ - - uint32_t modtaboff; /* file offset to module table */ - uint32_t nmodtab; /* number of module table entries */ - - uint32_t extrefsymoff; /* offset to referenced symbol table */ - uint32_t nextrefsyms; /* number of referenced symbol table entries */ - - uint32_t indirectsymoff;/* file offset to the indirect symbol table */ - uint32_t nindirectsyms; /* number of indirect symbol table entries */ - - uint32_t extreloff; /* offset to external relocation entries */ - uint32_t nextrel; /* number of external relocation entries */ - uint32_t locreloff; /* offset to local relocation entries */ - uint32_t nlocrel; /* number of local relocation entries */ -}; - -#define BIND_OPCODE_DONE 0x00 -#define BIND_OPCODE_SET_DYLIB_SPECIAL_IMM 0x30 -#define BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM 0x40 -#define BIND_OPCODE_SET_TYPE_IMM 0x50 -#define BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB 0x70 -#define BIND_OPCODE_DO_BIND 0x90 - -#define BIND_SYMBOL_FLAGS_WEAK_IMPORT 0x1 - -#define BIND_TYPE_POINTER 1 -#define BIND_SPECIAL_DYLIB_FLAT_LOOKUP -2 - -#define REBASE_OPCODE_DONE 0x00 -#define REBASE_OPCODE_SET_TYPE_IMM 0x10 -#define REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB 0x20 -#define REBASE_OPCODE_DO_REBASE_IMM_TIMES 0x50 - -#define REBASE_TYPE_POINTER 1 - -#define EXPORT_SYMBOL_FLAGS_KIND_REGULAR 0x00 -#define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02 -#define EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION 0x04 - -struct dyld_info_command { - uint32_t cmd; /* LC_DYLD_INFO or LC_DYLD_INFO_ONLY */ - uint32_t cmdsize; /* sizeof(struct dyld_info_command) */ - uint32_t rebase_off; /* file offset to rebase info */ - uint32_t rebase_size; /* size of rebase info */ - uint32_t bind_off; /* file offset to binding info */ - uint32_t bind_size; /* size of binding info */ - uint32_t weak_bind_off; /* file offset to weak binding info */ - uint32_t weak_bind_size; /* size of weak binding info */ - uint32_t lazy_bind_off; /* file offset to lazy binding info */ - uint32_t lazy_bind_size; /* size of lazy binding infs */ - uint32_t export_off; /* file offset to lazy binding info */ - uint32_t export_size; /* size of lazy binding infs */ -}; - -#define INDIRECT_SYMBOL_LOCAL 0x80000000 - -struct entry_point_command { - uint32_t cmd; /* LC_MAIN only used in MH_EXECUTE filetypes */ - uint32_t cmdsize; /* 24 */ - uint64_t entryoff; /* file (__TEXT) offset of main() */ - uint64_t stacksize;/* if not zero, initial stack size */ -}; - -enum skind { - sk_unknown = 0, - sk_discard, - sk_text, - sk_stubs, - sk_stub_helper, - sk_ro_data, - sk_uw_info, - sk_nl_ptr, // non-lazy pointers, aka GOT - sk_debug_info, - sk_debug_abbrev, - sk_debug_line, - sk_debug_aranges, - sk_debug_str, - sk_debug_line_str, - sk_stab, - sk_stab_str, - sk_la_ptr, // lazy pointers - sk_init, - sk_fini, - sk_rw_data, - sk_bss, - sk_linkedit, - sk_last -}; - -struct nlist_64 { - uint32_t n_strx; /* index into the string table */ - uint8_t n_type; /* type flag, see below */ - uint8_t n_sect; /* section number or NO_SECT */ - uint16_t n_desc; /* see <mach-o/stab.h> */ - uint64_t n_value; /* value of this symbol (or stab offset) */ -}; - -#define N_UNDF 0x0 -#define N_ABS 0x2 -#define N_EXT 0x1 -#define N_SECT 0xe - -#define N_WEAK_REF 0x0040 -#define N_WEAK_DEF 0x0080 - -struct macho { - struct mach_header_64 mh; - int *seg2lc, nseg; - struct load_command **lc; - struct entry_point_command *ep; - int nlc; - struct { - Section *s; - int machosect; - } sk_to_sect[sk_last]; - int *elfsectomacho; - int *e2msym; - Section *symtab, *strtab, *indirsyms, *stubs, *exports; - uint32_t ilocal, iextdef, iundef; - int stubsym, n_got, nr_plt; - int segment[sk_last]; -#ifdef CONFIG_NEW_MACHO - Section *chained_fixups; - int n_bind; - int n_bind_rebase; - struct bind_rebase { - int section; - int bind; - ElfW_Rel rel; - } *bind_rebase; -#else - Section *rebase, *binding, *weak_binding, *lazy_binding; - Section *stub_helper, *la_symbol_ptr; - struct dyld_info_command *dyldinfo; - int helpsym, lasym, dyld_private, dyld_stub_binder; - int n_lazy_bind; - struct s_lazy_bind { - int section; - int bind_offset; - int la_symbol_offset; - ElfW_Rel rel; - } *s_lazy_bind; - int n_rebase; - struct s_rebase { - int section; - ElfW_Rel rel; - } *s_rebase; - int n_bind; - struct bind { - int section; - ElfW_Rel rel; - } *bind; -#endif -}; - -#define SHT_LINKEDIT (SHT_LOOS + 42) -#define SHN_FROMDLL (SHN_LOOS + 2) /* Symbol is undefined, comes from a DLL */ - -static void * add_lc(struct macho *mo, uint32_t cmd, uint32_t cmdsize) -{ - struct load_command *lc = tcc_mallocz(cmdsize); - lc->cmd = cmd; - lc->cmdsize = cmdsize; - mo->lc = tcc_realloc(mo->lc, sizeof(mo->lc[0]) * (mo->nlc + 1)); - mo->lc[mo->nlc++] = lc; - return lc; -} - -static struct segment_command_64 * add_segment(struct macho *mo, const char *name) -{ - struct segment_command_64 *sc = add_lc(mo, LC_SEGMENT_64, sizeof(*sc)); - strncpy(sc->segname, name, 16); - mo->seg2lc = tcc_realloc(mo->seg2lc, sizeof(*mo->seg2lc) * (mo->nseg + 1)); - mo->seg2lc[mo->nseg++] = mo->nlc - 1; - return sc; -} - -static struct segment_command_64 * get_segment(struct macho *mo, int i) -{ - return (struct segment_command_64 *) (mo->lc[mo->seg2lc[i]]); -} - -static int add_section(struct macho *mo, struct segment_command_64 **_seg, const char *name) -{ - struct segment_command_64 *seg = *_seg; - int ret = seg->nsects; - struct section_64 *sec; - seg->nsects++; - seg->cmdsize += sizeof(*sec); - seg = tcc_realloc(seg, sizeof(*seg) + seg->nsects * sizeof(*sec)); - sec = (struct section_64*)((char*)seg + sizeof(*seg)) + ret; - memset(sec, 0, sizeof(*sec)); - strncpy(sec->sectname, name, 16); - strncpy(sec->segname, seg->segname, 16); - *_seg = seg; - return ret; -} - -static struct section_64 *get_section(struct segment_command_64 *seg, int i) -{ - return (struct section_64*)((char*)seg + sizeof(*seg)) + i; -} - -static void * add_dylib(struct macho *mo, char *name) -{ - struct dylib_command *lc; - int sz = (sizeof(*lc) + strlen(name) + 1 + 7) & -8; - lc = add_lc(mo, LC_LOAD_DYLIB, sz); - lc->name = sizeof(*lc); - strcpy((char*)lc + lc->name, name); - lc->timestamp = 2; - lc->current_version = 1 << 16; - lc->compatibility_version = 1 << 16; - return lc; -} - -static int uleb128_size (unsigned long long value) -{ - int size = 0; - - do { - value >>= 7; - size++; - } while (value != 0); - return size; -} - -static void write_uleb128(Section *section, uint64_t value) -{ - do { - unsigned char byte = value & 0x7f; - uint8_t *ptr = section_ptr_add(section, 1); - - value >>= 7; - *ptr = byte | (value ? 0x80 : 0); - } while (value != 0); -} - -static void tcc_macho_add_destructor(TCCState *s1) -{ - int init_sym, mh_execute_header, at_exit_sym; - Section *s; - ElfW_Rel *rel; - uint8_t *ptr; - - mh_execute_header = put_elf_sym(s1->symtab, -4096, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT), 0, - text_section->sh_num, "__mh_execute_header"); - s = find_section(s1, ".fini_array"); - if (s->data_offset == 0) - return; - init_sym = put_elf_sym(s1->symtab, text_section->data_offset, 0, - ELFW(ST_INFO)(STB_LOCAL, STT_FUNC), 0, - text_section->sh_num, "___GLOBAL_init_65535"); - at_exit_sym = put_elf_sym(s1->symtab, 0, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_FUNC), 0, - SHN_UNDEF, "___cxa_atexit"); -#ifdef TCC_TARGET_X86_64 - ptr = section_ptr_add(text_section, 4); - ptr[0] = 0x55; // pushq %rbp - ptr[1] = 0x48; // movq %rsp, %rbp - ptr[2] = 0x89; - ptr[3] = 0xe5; - for_each_elem(s->reloc, 0, rel, ElfW_Rel) { - int sym_index = ELFW(R_SYM)(rel->r_info); - - ptr = section_ptr_add(text_section, 26); - ptr[0] = 0x48; // lea destructor(%rip),%rax - ptr[1] = 0x8d; - ptr[2] = 0x05; - put_elf_reloca(s1->symtab, text_section, - text_section->data_offset - 23, - R_X86_64_PC32, sym_index, -4); - ptr[7] = 0x48; // mov %rax,%rdi - ptr[8] = 0x89; - ptr[9] = 0xc7; - ptr[10] = 0x31; // xorl %ecx, %ecx - ptr[11] = 0xc9; - ptr[12] = 0x89; // movl %ecx, %esi - ptr[13] = 0xce; - ptr[14] = 0x48; // lea mh_execute_header(%rip),%rdx - ptr[15] = 0x8d; - ptr[16] = 0x15; - put_elf_reloca(s1->symtab, text_section, - text_section->data_offset - 9, - R_X86_64_PC32, mh_execute_header, -4); - ptr[21] = 0xe8; // call __cxa_atexit - put_elf_reloca(s1->symtab, text_section, - text_section->data_offset - 4, - R_X86_64_PLT32, at_exit_sym, -4); - } - ptr = section_ptr_add(text_section, 2); - ptr[0] = 0x5d; // pop %rbp - ptr[1] = 0xc3; // ret -#elif defined TCC_TARGET_ARM64 - ptr = section_ptr_add(text_section, 8); - write32le(ptr, 0xa9bf7bfd); // stp x29, x30, [sp, #-16]! - write32le(ptr + 4, 0x910003fd); // mov x29, sp - for_each_elem(s->reloc, 0, rel, ElfW_Rel) { - int sym_index = ELFW(R_SYM)(rel->r_info); - - ptr = section_ptr_add(text_section, 24); - put_elf_reloc(s1->symtab, text_section, - text_section->data_offset - 24, - R_AARCH64_ADR_PREL_PG_HI21, sym_index); - write32le(ptr, 0x90000000); // adrp x0, destructor@page - put_elf_reloc(s1->symtab, text_section, - text_section->data_offset - 20, - R_AARCH64_LDST8_ABS_LO12_NC, sym_index); - write32le(ptr + 4, 0x91000000); // add x0,x0,destructor@pageoff - write32le(ptr + 8, 0xd2800001); // mov x1, #0 - put_elf_reloc(s1->symtab, text_section, - text_section->data_offset - 12, - R_AARCH64_ADR_PREL_PG_HI21, mh_execute_header); - write32le(ptr + 12, 0x90000002); // adrp x2, mh_execute_header@page - put_elf_reloc(s1->symtab, text_section, - text_section->data_offset - 8, - R_AARCH64_LDST8_ABS_LO12_NC, mh_execute_header); - write32le(ptr + 16, 0x91000042); // add x2,x2,mh_execute_header@pageoff - put_elf_reloc(s1->symtab, text_section, - text_section->data_offset - 4, - R_AARCH64_CALL26, at_exit_sym); - write32le(ptr + 20, 0x94000000); // bl __cxa_atexit - } - ptr = section_ptr_add(text_section, 8); - write32le(ptr, 0xa8c17bfd); // ldp x29, x30, [sp], #16 - write32le(ptr + 4, 0xd65f03c0); // ret -#endif - s->reloc->data_offset = s->data_offset = 0; - s->sh_flags &= ~SHF_ALLOC; - add_array (s1, ".init_array", init_sym); -} - -#ifdef CONFIG_NEW_MACHO -static void bind_rebase_add(struct macho *mo, int bind, int sh_info, - ElfW_Rel *rel, struct sym_attr *attr) -{ - mo->bind_rebase = tcc_realloc(mo->bind_rebase, (mo->n_bind_rebase + 1) * - sizeof(struct bind_rebase)); - mo->bind_rebase[mo->n_bind_rebase].section = sh_info; - mo->bind_rebase[mo->n_bind_rebase].bind = bind; - mo->bind_rebase[mo->n_bind_rebase].rel = *rel; - if (attr) - mo->bind_rebase[mo->n_bind_rebase].rel.r_offset = attr->got_offset; - mo->n_bind_rebase++; - mo->n_bind += bind; -} - -static void check_relocs(TCCState *s1, struct macho *mo) -{ - Section *s; - ElfW_Rel *rel, save_rel; - ElfW(Sym) *sym; - int i, j, type, gotplt_entry, sym_index, for_code; - uint32_t *pi, *goti; - struct sym_attr *attr; - - goti = NULL; - mo->nr_plt = mo->n_got = 0; - for (i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - if (s->sh_type != SHT_RELX || - !strncmp(s1->sections[s->sh_info]->name, ".debug_", 7)) - continue; - for_each_elem(s, 0, rel, ElfW_Rel) { - save_rel = *rel; - type = ELFW(R_TYPE)(rel->r_info); - gotplt_entry = gotplt_entry_type(type); - for_code = code_reloc(type); - /* We generate a non-lazy pointer for used undefined symbols - and for defined symbols that must have a place for their - address due to codegen (i.e. a reloc requiring a got slot). */ - sym_index = ELFW(R_SYM)(rel->r_info); - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - if (sym->st_shndx == SHN_UNDEF - || gotplt_entry == ALWAYS_GOTPLT_ENTRY) { - attr = get_sym_attr(s1, sym_index, 1); - if (!attr->dyn_index) { - attr->got_offset = s1->got->data_offset; - attr->plt_offset = -1; - attr->dyn_index = 1; /* used as flag */ - section_ptr_add(s1->got, PTR_SIZE); - put_elf_reloc(s1->symtab, s1->got, attr->got_offset, - R_JMP_SLOT, sym_index); - goti = tcc_realloc(goti, (mo->n_got + 1) * sizeof(*goti)); - if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) { - if (sym->st_shndx == SHN_UNDEF) - tcc_error("undefined local symbo: '%s'", - (char *) symtab_section->link->data + sym->st_name); - goti[mo->n_got++] = INDIRECT_SYMBOL_LOCAL; - } else { - goti[mo->n_got++] = mo->e2msym[sym_index]; - if (sym->st_shndx == SHN_UNDEF -#ifdef TCC_TARGET_X86_64 - && type == R_X86_64_GOTPCREL -#elif defined TCC_TARGET_ARM64 - && type == R_AARCH64_ADR_GOT_PAGE -#endif - ) { - attr->plt_offset = -mo->n_bind_rebase - 2; - bind_rebase_add(mo, 1, s1->got->reloc->sh_info, &save_rel, attr); - s1->got->reloc->data_offset -= sizeof (ElfW_Rel); - } - if (for_code && sym->st_shndx == SHN_UNDEF) - s1->got->reloc->data_offset -= sizeof (ElfW_Rel); - } - } - if (for_code && sym->st_shndx == SHN_UNDEF) { - if ((int)attr->plt_offset < -1) { - /* remove above bind and replace with plt */ - mo->bind_rebase[-attr->plt_offset - 2].bind = 2; - attr->plt_offset = -1; - } - if (attr->plt_offset == -1) { - uint8_t *jmp; - - attr->plt_offset = mo->stubs->data_offset; -#ifdef TCC_TARGET_X86_64 - if (type != R_X86_64_PLT32) - continue; - jmp = section_ptr_add(mo->stubs, 6); - jmp[0] = 0xff; /* jmpq *ofs(%rip) */ - jmp[1] = 0x25; - put_elf_reloc(s1->symtab, mo->stubs, - attr->plt_offset + 2, - R_X86_64_GOTPCREL, sym_index); -#elif defined TCC_TARGET_ARM64 - if (type != R_AARCH64_CALL26) - continue; - jmp = section_ptr_add(mo->stubs, 12); - put_elf_reloc(s1->symtab, mo->stubs, - attr->plt_offset, - R_AARCH64_ADR_GOT_PAGE, sym_index); - write32le(jmp, // adrp x16, #sym - 0x90000010); - put_elf_reloc(s1->symtab, mo->stubs, - attr->plt_offset + 4, - R_AARCH64_LD64_GOT_LO12_NC, sym_index); - write32le(jmp + 4, // ld x16,[x16, #sym] - 0xf9400210); - write32le(jmp + 8, // br x16 - 0xd61f0200); -#endif - bind_rebase_add(mo, 1, s1->got->reloc->sh_info, &save_rel, attr); - pi = section_ptr_add(mo->indirsyms, sizeof(*pi)); - *pi = mo->e2msym[sym_index]; - mo->nr_plt++; - } - rel->r_info = ELFW(R_INFO)(mo->stubsym, type); - rel->r_addend += attr->plt_offset; - } - } - if (type == R_DATA_PTR || type == R_JMP_SLOT) - bind_rebase_add(mo, sym->st_shndx == SHN_UNDEF ? 1 : 0, - s->sh_info, &save_rel, NULL); - } - } - /* remove deleted binds */ - for (i = 0, j = 0; i < mo->n_bind_rebase; i++) - if (mo->bind_rebase[i].bind == 2) - mo->n_bind--; - else - mo->bind_rebase[j++] = mo->bind_rebase[i]; - mo->n_bind_rebase = j; - pi = section_ptr_add(mo->indirsyms, mo->n_got * sizeof(*pi)); - memcpy(pi, goti, mo->n_got * sizeof(*pi)); - tcc_free(goti); -} - -#else - -static void check_relocs(TCCState *s1, struct macho *mo) -{ - uint8_t *jmp; - Section *s; - ElfW_Rel *rel, save_rel; - ElfW(Sym) *sym; - int i, type, gotplt_entry, sym_index, for_code; - int bind_offset, la_symbol_offset; - uint32_t *pi, *goti; - struct sym_attr *attr; - -#ifdef TCC_TARGET_X86_64 - jmp = section_ptr_add(mo->stub_helper, 16); - jmp[0] = 0x4c; /* leaq _dyld_private(%rip), %r11 */ - jmp[1] = 0x8d; - jmp[2] = 0x1d; - put_elf_reloca(s1->symtab, mo->stub_helper, 3, - R_X86_64_PC32, mo->dyld_private, -4); - jmp[7] = 0x41; /* pushq %r11 */ - jmp[8] = 0x53; - jmp[9] = 0xff; /* jmpq *dyld_stub_binder@GOT(%rip) */ - jmp[10] = 0x25; - put_elf_reloca(s1->symtab, mo->stub_helper, 11, - R_X86_64_GOTPCREL, mo->dyld_stub_binder, -4); - jmp[15] = 0x90; /* nop */ -#elif defined TCC_TARGET_ARM64 - jmp = section_ptr_add(mo->stub_helper, 24); - put_elf_reloc(s1->symtab, mo->stub_helper, 0, - R_AARCH64_ADR_PREL_PG_HI21, mo->dyld_private); - write32le(jmp, 0x90000011); // adrp x17, _dyld_private@page - put_elf_reloc(s1->symtab, mo->stub_helper, 4, - R_AARCH64_LDST64_ABS_LO12_NC, mo->dyld_private); - write32le(jmp + 4, 0x91000231); // add x17,x17,_dyld_private@pageoff - write32le(jmp + 8, 0xa9bf47f0); // stp x16/x17, [sp, #-16]! - put_elf_reloc(s1->symtab, mo->stub_helper, 12, - R_AARCH64_ADR_GOT_PAGE, mo->dyld_stub_binder); - write32le(jmp + 12, 0x90000010); // adrp x16, dyld_stub_binder@page - put_elf_reloc(s1->symtab, mo->stub_helper, 16, - R_AARCH64_LD64_GOT_LO12_NC, mo->dyld_stub_binder); - write32le(jmp + 16, 0xf9400210); // ldr x16,[x16,dyld_stub_binder@pageoff] - write32le(jmp + 20, 0xd61f0200); // br x16 -#endif - - goti = NULL; - mo->nr_plt = mo->n_got = 0; - for (i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - if (s->sh_type != SHT_RELX || - !strncmp(s1->sections[s->sh_info]->name, ".debug_", 7)) - continue; - for_each_elem(s, 0, rel, ElfW_Rel) { - save_rel = *rel; - type = ELFW(R_TYPE)(rel->r_info); - gotplt_entry = gotplt_entry_type(type); - for_code = code_reloc(type); - /* We generate a non-lazy pointer for used undefined symbols - and for defined symbols that must have a place for their - address due to codegen (i.e. a reloc requiring a got slot). */ - sym_index = ELFW(R_SYM)(rel->r_info); - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - if (sym->st_shndx == SHN_UNDEF - || gotplt_entry == ALWAYS_GOTPLT_ENTRY) { - attr = get_sym_attr(s1, sym_index, 1); - if (!attr->dyn_index) { - attr->got_offset = s1->got->data_offset; - attr->plt_offset = -1; - attr->dyn_index = 1; /* used as flag */ - section_ptr_add(s1->got, PTR_SIZE); - put_elf_reloc(s1->symtab, s1->got, attr->got_offset, - R_JMP_SLOT, sym_index); - goti = tcc_realloc(goti, (mo->n_got + 1) * sizeof(*goti)); - if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) { - if (sym->st_shndx == SHN_UNDEF) - tcc_error("undefined local symbo: '%s'", - (char *) symtab_section->link->data + sym->st_name); - goti[mo->n_got++] = INDIRECT_SYMBOL_LOCAL; - } else { - goti[mo->n_got++] = mo->e2msym[sym_index]; - if (sym->st_shndx == SHN_UNDEF -#ifdef TCC_TARGET_X86_64 - && type == R_X86_64_GOTPCREL -#elif defined TCC_TARGET_ARM64 - && type == R_AARCH64_ADR_GOT_PAGE -#endif - ) { - mo->bind = - tcc_realloc(mo->bind, - (mo->n_bind + 1) * - sizeof(struct bind)); - mo->bind[mo->n_bind].section = s1->got->reloc->sh_info; - mo->bind[mo->n_bind].rel = save_rel; - mo->bind[mo->n_bind].rel.r_offset = attr->got_offset; - mo->n_bind++; - s1->got->reloc->data_offset -= sizeof (ElfW_Rel); - } - } - } - if (for_code && sym->st_shndx == SHN_UNDEF) { - if (attr->plt_offset == -1) { - attr->plt_offset = mo->stubs->data_offset; -#ifdef TCC_TARGET_X86_64 - if (type != R_X86_64_PLT32) - continue; - /* __stubs */ - jmp = section_ptr_add(mo->stubs, 6); - jmp[0] = 0xff; /* jmpq *__la_symbol_ptr(%rip) */ - jmp[1] = 0x25; - put_elf_reloca(s1->symtab, mo->stubs, - mo->stubs->data_offset - 4, - R_X86_64_PC32, mo->lasym, - mo->la_symbol_ptr->data_offset - 4); - - /* __stub_helper */ - bind_offset = mo->stub_helper->data_offset + 1; - jmp = section_ptr_add(mo->stub_helper, 10); - jmp[0] = 0x68; /* pushq $bind_offset */ - jmp[5] = 0xe9; /* jmpq __stub_helper */ - write32le(jmp + 6, -mo->stub_helper->data_offset); - - /* __la_symbol_ptr */ - la_symbol_offset = mo->la_symbol_ptr->data_offset; - put_elf_reloca(s1->symtab, mo->la_symbol_ptr, - mo->la_symbol_ptr->data_offset, - R_DATA_PTR, mo->helpsym, - mo->stub_helper->data_offset - 10); - section_ptr_add(mo->la_symbol_ptr, PTR_SIZE); -#elif defined TCC_TARGET_ARM64 - if (type != R_AARCH64_CALL26) - continue; - /* __stubs */ - jmp = section_ptr_add(mo->stubs, 12); - put_elf_reloca(s1->symtab, mo->stubs, - mo->stubs->data_offset - 12, - R_AARCH64_ADR_PREL_PG_HI21, mo->lasym, - mo->la_symbol_ptr->data_offset); - write32le(jmp, // adrp x16, __la_symbol_ptr@page - 0x90000010); - put_elf_reloca(s1->symtab, mo->stubs, - mo->stubs->data_offset - 8, - R_AARCH64_LDST64_ABS_LO12_NC, mo->lasym, - mo->la_symbol_ptr->data_offset); - write32le(jmp + 4, // ldr x16,[x16, __la_symbol_ptr@pageoff] - 0xf9400210); - write32le(jmp + 8, // br x16 - 0xd61f0200); - - /* __stub_helper */ - bind_offset = mo->stub_helper->data_offset + 8; - jmp = section_ptr_add(mo->stub_helper, 12); - write32le(jmp + 0, // ldr w16, l0 - 0x18000050); - write32le(jmp + 4, // b stubHelperHeader - 0x14000000 + - ((-(mo->stub_helper->data_offset - 8) / 4) & - 0x3ffffff)); - write32le(jmp + 8, 0); // l0: .long bind_offset - - /* __la_symbol_ptr */ - la_symbol_offset = mo->la_symbol_ptr->data_offset; - put_elf_reloca(s1->symtab, mo->la_symbol_ptr, - mo->la_symbol_ptr->data_offset, - R_DATA_PTR, mo->helpsym, - mo->stub_helper->data_offset - 12); - section_ptr_add(mo->la_symbol_ptr, PTR_SIZE); -#endif - mo->s_lazy_bind = - tcc_realloc(mo->s_lazy_bind, (mo->n_lazy_bind + 1) * - sizeof(struct s_lazy_bind)); - mo->s_lazy_bind[mo->n_lazy_bind].section = - mo->stub_helper->reloc->sh_info; - mo->s_lazy_bind[mo->n_lazy_bind].bind_offset = - bind_offset; - mo->s_lazy_bind[mo->n_lazy_bind].la_symbol_offset = - la_symbol_offset; - mo->s_lazy_bind[mo->n_lazy_bind].rel = save_rel; - mo->s_lazy_bind[mo->n_lazy_bind].rel.r_offset = - attr->plt_offset; - mo->n_lazy_bind++; - pi = section_ptr_add(mo->indirsyms, sizeof(*pi)); - *pi = mo->e2msym[sym_index]; - mo->nr_plt++; - } - rel->r_info = ELFW(R_INFO)(mo->stubsym, type); - rel->r_addend += attr->plt_offset; - } - } - if (type == R_DATA_PTR || type == R_JMP_SLOT) { - if (sym->st_shndx == SHN_UNDEF) { - mo->bind = tcc_realloc(mo->bind, - (mo->n_bind + 1) * - sizeof(struct bind)); - mo->bind[mo->n_bind].section = s->sh_info; - mo->bind[mo->n_bind].rel = save_rel; - mo->n_bind++; - } - else { - mo->s_rebase = - tcc_realloc(mo->s_rebase, (mo->n_rebase + 1) * - sizeof(struct s_rebase)); - mo->s_rebase[mo->n_rebase].section = s->sh_info; - mo->s_rebase[mo->n_rebase].rel = save_rel; - mo->n_rebase++; - } - } - } - } - pi = section_ptr_add(mo->indirsyms, mo->n_got * sizeof(*pi)); - memcpy(pi, goti, mo->n_got * sizeof(*pi)); - pi = section_ptr_add(mo->indirsyms, mo->nr_plt * sizeof(*pi)); - memcpy(pi, mo->indirsyms->data, mo->nr_plt * sizeof(*pi)); - tcc_free(goti); -} -#endif - -static int check_symbols(TCCState *s1, struct macho *mo) -{ - int sym_index, sym_end; - int ret = 0; - - mo->ilocal = mo->iextdef = mo->iundef = -1; - sym_end = symtab_section->data_offset / sizeof(ElfW(Sym)); - for (sym_index = 1; sym_index < sym_end; ++sym_index) { - int elf_index = ((struct nlist_64 *)mo->symtab->data + sym_index - 1)->n_value; - ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + elf_index; - const char *name = (char*)symtab_section->link->data + sym->st_name; - unsigned type = ELFW(ST_TYPE)(sym->st_info); - unsigned bind = ELFW(ST_BIND)(sym->st_info); - unsigned vis = ELFW(ST_VISIBILITY)(sym->st_other); - - dprintf("%4d (%4d): %09lx %4d %4d %4d %3d %s\n", - sym_index, elf_index, (long)sym->st_value, - type, bind, vis, sym->st_shndx, name); - if (bind == STB_LOCAL) { - if (mo->ilocal == -1) - mo->ilocal = sym_index - 1; - if (mo->iextdef != -1 || mo->iundef != -1) - tcc_error("local syms after global ones"); - } else if (sym->st_shndx != SHN_UNDEF) { - if (mo->iextdef == -1) - mo->iextdef = sym_index - 1; - if (mo->iundef != -1) - tcc_error("external defined symbol after undefined"); - } else if (sym->st_shndx == SHN_UNDEF) { - if (mo->iundef == -1) - mo->iundef = sym_index - 1; - if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK - || s1->output_type != TCC_OUTPUT_EXE - || find_elf_sym(s1->dynsymtab_section, name)) { - /* Mark the symbol as coming from a dylib so that - relocate_syms doesn't complain. Normally bind_exe_dynsyms - would do this check, and place the symbol into dynsym - which is checked by relocate_syms. But Mach-O doesn't use - bind_exe_dynsyms. */ - sym->st_shndx = SHN_FROMDLL; - continue; - } - tcc_error_noabort("undefined symbol '%s'", name); - ret = -1; - } - } - return ret; -} - -static void convert_symbol(TCCState *s1, struct macho *mo, struct nlist_64 *pn) -{ - struct nlist_64 n = *pn; - ElfSym *sym = (ElfW(Sym) *)symtab_section->data + pn->n_value; - const char *name = (char*)symtab_section->link->data + sym->st_name; - switch(ELFW(ST_TYPE)(sym->st_info)) { - case STT_NOTYPE: - case STT_OBJECT: - case STT_FUNC: - case STT_SECTION: - n.n_type = N_SECT; - break; - case STT_FILE: - n.n_type = N_ABS; - break; - default: - tcc_error("unhandled ELF symbol type %d %s", - ELFW(ST_TYPE)(sym->st_info), name); - } - if (sym->st_shndx == SHN_UNDEF) - tcc_error("should have been rewritten to SHN_FROMDLL: %s", name); - else if (sym->st_shndx == SHN_FROMDLL) - n.n_type = N_UNDF, n.n_sect = 0; - else if (sym->st_shndx == SHN_ABS) - n.n_type = N_ABS, n.n_sect = 0; - else if (sym->st_shndx >= SHN_LORESERVE) - tcc_error("unhandled ELF symbol section %d %s", sym->st_shndx, name); - else if (!mo->elfsectomacho[sym->st_shndx]) { - if (strncmp(s1->sections[sym->st_shndx]->name, ".debug_", 7)) - tcc_error("ELF section %d(%s) not mapped into Mach-O for symbol %s", - sym->st_shndx, s1->sections[sym->st_shndx]->name, name); - } - else - n.n_sect = mo->elfsectomacho[sym->st_shndx]; - if (ELFW(ST_BIND)(sym->st_info) == STB_GLOBAL) - n.n_type |= N_EXT; - else if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK) - n.n_desc |= N_WEAK_REF | (n.n_type != N_UNDF ? N_WEAK_DEF : 0); - n.n_strx = pn->n_strx; - n.n_value = sym->st_value; - *pn = n; -} - -static void convert_symbols(TCCState *s1, struct macho *mo) -{ - struct nlist_64 *pn; - for_each_elem(mo->symtab, 0, pn, struct nlist_64) - convert_symbol(s1, mo, pn); -} - -static int machosymcmp(const void *_a, const void *_b, void *arg) -{ - TCCState *s1 = arg; - int ea = ((struct nlist_64 *)_a)->n_value; - int eb = ((struct nlist_64 *)_b)->n_value; - ElfSym *sa = (ElfSym *)symtab_section->data + ea; - ElfSym *sb = (ElfSym *)symtab_section->data + eb; - int r; - /* locals, then defined externals, then undefined externals, the - last two sections also by name, otherwise stable sort */ - r = (ELFW(ST_BIND)(sb->st_info) == STB_LOCAL) - - (ELFW(ST_BIND)(sa->st_info) == STB_LOCAL); - if (r) - return r; - r = (sa->st_shndx == SHN_UNDEF) - (sb->st_shndx == SHN_UNDEF); - if (r) - return r; - if (ELFW(ST_BIND)(sa->st_info) != STB_LOCAL) { - const char * na = (char*)symtab_section->link->data + sa->st_name; - const char * nb = (char*)symtab_section->link->data + sb->st_name; - r = strcmp(na, nb); - if (r) - return r; - } - return ea - eb; -} - -/* cannot use qsort because code has to be reentrant */ -static void tcc_qsort (void *base, size_t nel, size_t width, - int (*comp)(const void *, const void *, void *), void *arg) -{ - size_t wnel, gap, wgap, i, j, k; - char *a, *b, tmp; - - wnel = width * nel; - for (gap = 0; ++gap < nel;) - gap *= 3; - while ( gap /= 3 ) { - wgap = width * gap; - for (i = wgap; i < wnel; i += width) { - for (j = i - wgap; ;j -= wgap) { - a = j + (char *)base; - b = a + wgap; - if ( (*comp)(a, b, arg) <= 0 ) - break; - k = width; - do { - tmp = *a; - *a++ = *b; - *b++ = tmp; - } while ( --k ); - if (j < wgap) - break; - } - } - } -} - -static void create_symtab(TCCState *s1, struct macho *mo) -{ - int sym_index, sym_end; - struct nlist_64 *pn; - - /* Stub creation belongs to check_relocs, but we need to create - the symbol now, so its included in the sorting. */ - mo->stubs = new_section(s1, "__stubs", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); - s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); - mo->stubsym = put_elf_sym(s1->symtab, 0, 0, - ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0, - mo->stubs->sh_num, ".__stubs"); -#ifdef CONFIG_NEW_MACHO - mo->chained_fixups = new_section(s1, "CHAINED_FIXUPS", - SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); -#else - mo->stub_helper = new_section(s1, "__stub_helper", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); - mo->la_symbol_ptr = new_section(s1, "__la_symbol_ptr", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); - mo->helpsym = put_elf_sym(s1->symtab, 0, 0, - ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0, - mo->stub_helper->sh_num, ".__stub_helper"); - mo->lasym = put_elf_sym(s1->symtab, 0, 0, - ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0, - mo->la_symbol_ptr->sh_num, ".__la_symbol_ptr"); - section_ptr_add(data_section, -data_section->data_offset & (PTR_SIZE - 1)); - mo->dyld_private = put_elf_sym(s1->symtab, data_section->data_offset, PTR_SIZE, - ELFW(ST_INFO)(STB_LOCAL, STT_OBJECT), 0, - data_section->sh_num, ".__dyld_private"); - section_ptr_add(data_section, PTR_SIZE); - mo->dyld_stub_binder = put_elf_sym(s1->symtab, 0, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT), 0, - SHN_UNDEF, "dyld_stub_binder"); - mo->rebase = new_section(s1, "REBASE", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); - mo->binding = new_section(s1, "BINDING", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); - mo->weak_binding = new_section(s1, "WEAK_BINDING", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); - mo->lazy_binding = new_section(s1, "LAZY_BINDING", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); -#endif - mo->exports = new_section(s1, "EXPORT", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); - mo->indirsyms = new_section(s1, "LEINDIR", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); - - mo->symtab = new_section(s1, "LESYMTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); - mo->strtab = new_section(s1, "LESTRTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); - put_elf_str(mo->strtab, " "); /* Mach-O starts strtab with a space */ - sym_end = symtab_section->data_offset / sizeof(ElfW(Sym)); - pn = section_ptr_add(mo->symtab, sizeof(*pn) * (sym_end - 1)); - for (sym_index = 1; sym_index < sym_end; ++sym_index) { - ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index; - const char *name = (char*)symtab_section->link->data + sym->st_name; - pn[sym_index - 1].n_strx = put_elf_str(mo->strtab, name); - pn[sym_index - 1].n_value = sym_index; - } - section_ptr_add(mo->strtab, -mo->strtab->data_offset & (PTR_SIZE - 1)); - tcc_qsort(pn, sym_end - 1, sizeof(*pn), machosymcmp, s1); - mo->e2msym = tcc_malloc(sym_end * sizeof(*mo->e2msym)); - mo->e2msym[0] = -1; - for (sym_index = 1; sym_index < sym_end; ++sym_index) { - mo->e2msym[pn[sym_index - 1].n_value] = sym_index - 1; - } -} - -const struct { - int seg_initial; - uint32_t flags; - const char *name; -} skinfo[sk_last] = { - /*[sk_unknown] =*/ { 0 }, - /*[sk_discard] =*/ { 0 }, - /*[sk_text] =*/ { 1, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS - | S_ATTR_SOME_INSTRUCTIONS, "__text" }, - /*[sk_stubs] =*/ { 1, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS | S_SYMBOL_STUBS - | S_ATTR_SOME_INSTRUCTIONS , "__stubs" }, - /*[sk_stub_helper] =*/ { 1, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS - | S_ATTR_SOME_INSTRUCTIONS , "__stub_helper" }, - /*[sk_ro_data] =*/ { 2, S_REGULAR, "__rodata" }, - /*[sk_uw_info] =*/ { 0 }, - /*[sk_nl_ptr] =*/ { 2, S_NON_LAZY_SYMBOL_POINTERS, "__got" }, - /*[sk_debug_info] =*/ { 3, S_REGULAR | S_ATTR_DEBUG, "__debug_info" }, - /*[sk_debug_abbrev] =*/ { 3, S_REGULAR | S_ATTR_DEBUG, "__debug_abbrev" }, - /*[sk_debug_line] =*/ { 3, S_REGULAR | S_ATTR_DEBUG, "__debug_line" }, - /*[sk_debug_aranges] =*/ { 3, S_REGULAR | S_ATTR_DEBUG, "__debug_aranges" }, - /*[sk_debug_str] =*/ { 3, S_REGULAR | S_ATTR_DEBUG, "__debug_str" }, - /*[sk_debug_line_str] =*/ { 3, S_REGULAR | S_ATTR_DEBUG, "__debug_line_str" }, - /*[sk_stab] =*/ { 4, S_REGULAR, "__stab" }, - /*[sk_stab_str] =*/ { 4, S_REGULAR, "__stab_str" }, - /*[sk_la_ptr] =*/ { 4, S_LAZY_SYMBOL_POINTERS, "__la_symbol_ptr" }, - /*[sk_init] =*/ { 4, S_MOD_INIT_FUNC_POINTERS, "__mod_init_func" }, - /*[sk_fini] =*/ { 4, S_MOD_TERM_FUNC_POINTERS, "__mod_term_func" }, - /*[sk_rw_data] =*/ { 4, S_REGULAR, "__data" }, - /*[sk_bss] =*/ { 4, S_ZEROFILL, "__bss" }, - /*[sk_linkedit] =*/ { 5, S_REGULAR, NULL }, -}; - -#define START ((uint64_t)1 << 32) - -const struct { - int used; - const char *name; - uint64_t vmaddr; - uint64_t vmsize; - vm_prot_t maxprot; - vm_prot_t initprot; - uint32_t flags; -} all_segment[] = { - { 1, "__PAGEZERO", 0, START, 0, 0, 0 }, - { 0, "__TEXT", START, 0, 5, 5, 0 }, - { 0, "__DATA_CONST", -1, 0, 3, 3, SG_READ_ONLY }, - { 0, "__DWARF", -1, 0, 7, 3, 0 }, - { 0, "__DATA", -1, 0, 3, 3, 0 }, - { 1, "__LINKEDIT", -1, 0, 1, 1, 0 }, -}; - -#define N_SEGMENT (sizeof(all_segment)/sizeof(all_segment[0])) - -#ifdef CONFIG_NEW_MACHO -static void calc_fixup_size(TCCState *s1, struct macho *mo) -{ - int i, size; - - size = (sizeof(struct dyld_chained_fixups_header) + 7) & -8; - size += (sizeof(struct dyld_chained_starts_in_image) + (mo->nseg - 1) * sizeof(uint32_t) + 7) & -8; - for (i = (s1->output_type == TCC_OUTPUT_EXE); i < mo->nseg - 1; i++) { - int page_count = (get_segment(mo, i)->vmsize + SEG_PAGE_SIZE - 1) / SEG_PAGE_SIZE; - size += (sizeof(struct dyld_chained_starts_in_segment) + (page_count - 1) * sizeof(uint16_t) + 7) & -8; - } - size += mo->n_bind * sizeof (struct dyld_chained_import) + 1; - for (i = 0; i < mo->n_bind_rebase; i++) { - if (mo->bind_rebase[i].bind) { - int sym_index = ELFW(R_SYM)(mo->bind_rebase[i].rel.r_info); - ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - const char *name = (char *) symtab_section->link->data + sym->st_name; - size += strlen(name) + 1; - } - } - size = (size + 7) & -8; - section_ptr_add(mo->chained_fixups, size); -} - -#else - -static void set_segment_and_offset(TCCState *s1, struct macho *mo, addr_t addr, - uint8_t *ptr, int opcode, - Section *sec, addr_t offset) -{ - int i; - struct segment_command_64 *seg = NULL; - - for (i = (s1->output_type == TCC_OUTPUT_EXE); i < mo->nseg - 1; i++) { - seg = get_segment(mo, i); - if (addr >= seg->vmaddr && addr < (seg->vmaddr + seg->vmsize)) - break; - } - *ptr = opcode | i; - write_uleb128(sec, offset - seg->vmaddr); -} - -static void bind_rebase(TCCState *s1, struct macho *mo) -{ - int i; - uint8_t *ptr; - ElfW(Sym) *sym; - const char *name; - - for (i = 0; i < mo->n_lazy_bind; i++) { - int sym_index = ELFW(R_SYM)(mo->s_lazy_bind[i].rel.r_info); - - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - name = (char *) symtab_section->link->data + sym->st_name; - write32le(mo->stub_helper->data + - mo->s_lazy_bind[i].bind_offset, - mo->lazy_binding->data_offset); - ptr = section_ptr_add(mo->lazy_binding, 1); - set_segment_and_offset(s1, mo, mo->la_symbol_ptr->sh_addr, ptr, - BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, - mo->lazy_binding, - mo->s_lazy_bind[i].la_symbol_offset + - mo->la_symbol_ptr->sh_addr); - ptr = section_ptr_add(mo->lazy_binding, 5 + strlen(name)); - *ptr++ = BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | - (BIND_SPECIAL_DYLIB_FLAT_LOOKUP & 0xf); - *ptr++ = BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | 0; - strcpy((char *)ptr, name); - ptr += strlen(name) + 1; - *ptr++ = BIND_OPCODE_DO_BIND; - *ptr = BIND_OPCODE_DONE; - } - for (i = 0; i < mo->n_rebase; i++) { - Section *s = s1->sections[mo->s_rebase[i].section]; - - ptr = section_ptr_add(mo->rebase, 2); - *ptr++ = REBASE_OPCODE_SET_TYPE_IMM | REBASE_TYPE_POINTER; - set_segment_and_offset(s1, mo, s->sh_addr, ptr, - REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, - mo->rebase, - mo->s_rebase[i].rel.r_offset + - s->sh_addr); - ptr = section_ptr_add(mo->rebase, 1); - *ptr = REBASE_OPCODE_DO_REBASE_IMM_TIMES | 1; - } - for (i = 0; i < mo->n_bind; i++) { - int sym_index = ELFW(R_SYM)(mo->bind[i].rel.r_info); - Section *s = s1->sections[mo->bind[i].section]; - Section *binding; - - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - name = (char *) symtab_section->link->data + sym->st_name; - binding = ELFW(ST_BIND)(sym->st_info) == STB_WEAK - ? mo->weak_binding : mo->binding; - ptr = section_ptr_add(binding, 4 + (binding == mo->binding) + - strlen(name)); - if (binding == mo->binding) - *ptr++ = BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | - (BIND_SPECIAL_DYLIB_FLAT_LOOKUP & 0xf); - *ptr++ = BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | - (binding == mo->weak_binding - ? BIND_SYMBOL_FLAGS_WEAK_IMPORT : 0); - strcpy((char *)ptr, name); - ptr += strlen(name) + 1; - *ptr++ = BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER; - set_segment_and_offset(s1, mo, s->sh_addr, ptr, - BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, - binding, - mo->bind[i].rel.r_offset + s->sh_addr); - ptr = section_ptr_add(binding, 1); - *ptr++ = BIND_OPCODE_DO_BIND; - } - if (mo->rebase->data_offset) { - ptr = section_ptr_add(mo->rebase, 1); - *ptr = REBASE_OPCODE_DONE; - } - if (mo->binding->data_offset) { - ptr = section_ptr_add(mo->binding, 1); - *ptr = BIND_OPCODE_DONE; - } - if (mo->weak_binding->data_offset) { - ptr = section_ptr_add(mo->weak_binding, 1); - *ptr = BIND_OPCODE_DONE; - } - tcc_free(mo->s_lazy_bind); - tcc_free(mo->s_rebase); - tcc_free(mo->bind); -} -#endif - -struct trie_info { - const char *name; - int flag; - addr_t addr; - int str_size; - int term_size; -}; - -struct trie_node { - int start; - int end; - int index_start; - int index_end; - int n_child; - struct trie_node *child; -}; - -struct trie_seq { - int n_child; - struct trie_node *node; - int offset; - int nest_offset; -}; - -static void create_trie(struct trie_node *node, - int from, int to, int index_start, - int n_trie, struct trie_info *trie) -{ - int i; - int start, end, index_end; - char cur; - struct trie_node *child; - - for (i = from; i < to; i = end) { - cur = trie[i].name[index_start]; - start = i++; - for (; i < to; i++) - if (cur != trie[i].name[index_start]) - break; - end = i; - if (start == end - 1 || - (trie[start].name[index_start] && - trie[start].name[index_start + 1] == 0)) - index_end = trie[start].str_size - 1; - else { - index_end = index_start + 1; - for (;;) { - cur = trie[start].name[index_end]; - for (i = start + 1; i < end; i++) - if (cur != trie[i].name[index_end]) - break; - if (trie[start].name[index_end] && - trie[start].name[index_end + 1] == 0) { - end = start + 1; - index_end = trie[start].str_size - 1; - break; - } - if (i != end) - break; - index_end++; - } - } - node->child = tcc_realloc(node->child, - (node->n_child + 1) * - sizeof(struct trie_node)); - child = &node->child[node->n_child]; - child->start = start; - child->end = end; - child->index_start = index_start; - child->index_end = index_end; - child->n_child = 0; - child->child = NULL; - node->n_child++; - if (start != end - 1) - create_trie(child, start, end, index_end, n_trie, trie); - } -} - -static int create_seq(int *offset, int *n_seq, struct trie_seq **seq, - struct trie_node *node, - int n_trie, struct trie_info *trie) -{ - int i, nest_offset, last_seq = *n_seq, retval = *offset; - struct trie_seq *p_seq; - struct trie_node *p_nest; - - for (i = 0; i < node->n_child; i++) { - p_nest = &node->child[i]; - *seq = tcc_realloc(*seq, (*n_seq + 1) * sizeof(struct trie_seq)); - p_seq = &(*seq)[(*n_seq)++]; - p_seq->n_child = i == 0 ? node->n_child : -1; - p_seq->node = p_nest; - p_seq->offset = *offset; - p_seq->nest_offset = 0; - *offset += (i == 0 ? 1 + 1 : 0) + - p_nest->index_end - p_nest->index_start + 1 + 3; - } - for (i = 0; i < node->n_child; i++) { - nest_offset = - create_seq(offset, n_seq, seq, &node->child[i], n_trie, trie); - p_seq = &(*seq)[last_seq + i]; - p_seq->nest_offset = nest_offset; - } - return retval; -} - -static void node_free(struct trie_node *node) -{ - int i; - - for (i = 0; i < node->n_child; i++) - node_free(&node->child[i]); - tcc_free(node->child); -} - -static int triecmp(const void *_a, const void *_b, void *arg) -{ - struct trie_info *a = (struct trie_info *) _a; - struct trie_info *b = (struct trie_info *) _b; - int len_a = strlen(a->name); - int len_b = strlen(b->name); - - /* strange sorting needed. Name 'xx' should be after 'xx1' */ - if (!strncmp(a->name, b->name, len_a < len_b ? len_a : len_b)) - return len_a < len_b ? 1 : (len_a > len_b ? -1 : 0); - return strcmp(a->name, b->name); -} - -static void export_trie(TCCState *s1, struct macho *mo) -{ - int i, size, offset = 0, save_offset; - uint8_t *ptr; - int sym_index; - int sym_end = symtab_section->data_offset / sizeof(ElfW(Sym)); - int n_trie = 0, n_seq = 0; - struct trie_info *trie = NULL, *p_trie; - struct trie_node node, *p_node; - struct trie_seq *seq = NULL; - addr_t vm_addr = get_segment(mo, s1->output_type == TCC_OUTPUT_EXE)->vmaddr; - - for (sym_index = 1; sym_index < sym_end; ++sym_index) { - ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index; - const char *name = (char*)symtab_section->link->data + sym->st_name; - - if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE && - (ELFW(ST_BIND)(sym->st_info) == STB_GLOBAL || - ELFW(ST_BIND)(sym->st_info) == STB_WEAK)) { - int flag = EXPORT_SYMBOL_FLAGS_KIND_REGULAR; - addr_t addr = - sym->st_value + s1->sections[sym->st_shndx]->sh_addr - vm_addr; - - if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK) - flag |= EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION; - dprintf ("%s %d %llx\n", name, flag, (long long)addr + vm_addr); - trie = tcc_realloc(trie, (n_trie + 1) * sizeof(struct trie_info)); - trie[n_trie].name = name; - trie[n_trie].flag = flag; - trie[n_trie].addr = addr; - trie[n_trie].str_size = strlen(name) + 1; - trie[n_trie].term_size = uleb128_size(flag) + uleb128_size(addr); - n_trie++; - } - } - if (n_trie) { - tcc_qsort(trie, n_trie, sizeof(struct trie_info), triecmp, NULL); - memset(&node, 0, sizeof(node)); - create_trie(&node, 0, n_trie, 0, n_trie, trie); - create_seq(&offset, &n_seq, &seq, &node, n_trie, trie); - save_offset = offset; - for (i = 0; i < n_seq; i++) { - p_node = seq[i].node; - if (p_node->n_child == 0) { - p_trie = &trie[p_node->start]; - seq[i].nest_offset = offset; - offset += 1 + p_trie->term_size + 1; - } - } - for (i = 0; i < n_seq; i++) { - p_node = seq[i].node; - p_trie = &trie[p_node->start]; - if (seq[i].n_child >= 0) { - section_ptr_add(mo->exports, - seq[i].offset - mo->exports->data_offset); - ptr = section_ptr_add(mo->exports, 2); - *ptr++ = 0; - *ptr = seq[i].n_child; - } - size = p_node->index_end - p_node->index_start; - ptr = section_ptr_add(mo->exports, size + 1); - memcpy(ptr, &p_trie->name[p_node->index_start], size); - ptr[size] = 0; - write_uleb128(mo->exports, seq[i].nest_offset); - } - section_ptr_add(mo->exports, save_offset - mo->exports->data_offset); - for (i = 0; i < n_seq; i++) { - p_node = seq[i].node; - if (p_node->n_child == 0) { - p_trie = &trie[p_node->start]; - write_uleb128(mo->exports, p_trie->term_size); - write_uleb128(mo->exports, p_trie->flag); - write_uleb128(mo->exports, p_trie->addr); - ptr = section_ptr_add(mo->exports, 1); - *ptr = 0; - } - } - section_ptr_add(mo->exports, -mo->exports->data_offset & 7); - node_free(&node); - tcc_free(seq); - } - tcc_free(trie); -} - -static void collect_sections(TCCState *s1, struct macho *mo, const char *filename) -{ - int i, sk, numsec; - int used_segment[N_SEGMENT]; - uint64_t curaddr, fileofs; - Section *s; - struct segment_command_64 *seg; - struct dylib_command *dylib; -#ifdef CONFIG_NEW_MACHO - struct linkedit_data_command *chained_fixups_lc; - struct linkedit_data_command *export_trie_lc; -#endif - struct build_version_command *dyldbv; - struct source_version_command *dyldsv; - struct rpath_command *rpath; - struct dylinker_command *dyldlc; - struct symtab_command *symlc; - struct dysymtab_command *dysymlc; - char *str; - - for (i = 0; i < N_SEGMENT; i++) - used_segment[i] = all_segment[i].used; - - memset (mo->sk_to_sect, 0, sizeof(mo->sk_to_sect)); - for (i = s1->nb_sections; i-- > 1;) { - int type, flags; - s = s1->sections[i]; - type = s->sh_type; - flags = s->sh_flags; - sk = sk_unknown; - /* debug sections have sometimes no SHF_ALLOC */ - if ((flags & SHF_ALLOC) || !strncmp(s->name, ".debug_", 7)) { - switch (type) { - default: sk = sk_unknown; break; - case SHT_INIT_ARRAY: sk = sk_init; break; - case SHT_FINI_ARRAY: sk = sk_fini; break; - case SHT_NOBITS: sk = sk_bss; break; - case SHT_SYMTAB: sk = sk_discard; break; - case SHT_STRTAB: - if (s == stabstr_section) - sk = sk_stab_str; - else - sk = sk_discard; - break; - case SHT_RELX: sk = sk_discard; break; - case SHT_LINKEDIT: sk = sk_linkedit; break; - case SHT_PROGBITS: - if (s == mo->stubs) - sk = sk_stubs; -#ifndef CONFIG_NEW_MACHO - else if (s == mo->stub_helper) - sk = sk_stub_helper; - else if (s == mo->la_symbol_ptr) - sk = sk_la_ptr; -#endif - else if (s == rodata_section) - sk = sk_ro_data; - else if (s == s1->got) - sk = sk_nl_ptr; - else if (s == stab_section) - sk = sk_stab; - else if (s == dwarf_info_section) - sk = sk_debug_info; - else if (s == dwarf_abbrev_section) - sk = sk_debug_abbrev; - else if (s == dwarf_line_section) - sk = sk_debug_line; - else if (s == dwarf_aranges_section) - sk = sk_debug_aranges; - else if (s == dwarf_str_section) - sk = sk_debug_str; - else if (s == dwarf_line_str_section) - sk = sk_debug_line_str; - else if (flags & SHF_EXECINSTR) - sk = sk_text; - else if (flags & SHF_WRITE) - sk = sk_rw_data; - else - sk = sk_ro_data; - break; - } - } else - sk = sk_discard; - s->prev = mo->sk_to_sect[sk].s; - mo->sk_to_sect[sk].s = s; - used_segment[skinfo[sk].seg_initial] = 1; - } - - if (s1->output_type != TCC_OUTPUT_EXE) - used_segment[0] = 0; - - for (i = 0; i < N_SEGMENT; i++) - if (used_segment[i]) { - seg = add_segment(mo, all_segment[i].name); - if (i == 1 && s1->output_type != TCC_OUTPUT_EXE) - seg->vmaddr = 0; - else - seg->vmaddr = all_segment[i].vmaddr; - seg->vmsize = all_segment[i].vmsize; - seg->maxprot = all_segment[i].maxprot; - seg->initprot = all_segment[i].initprot; - seg->flags = all_segment[i].flags; - for (sk = sk_unknown; sk < sk_last; sk++) - if (skinfo[sk].seg_initial == i) - mo->segment[sk] = mo->nseg - 1; - } - - if (s1->output_type != TCC_OUTPUT_EXE) { - const char *name = s1->install_name ? s1->install_name : filename; - i = (sizeof(*dylib) + strlen(name) + 1 + 7) &-8; - dylib = add_lc(mo, LC_ID_DYLIB, i); - dylib->name = sizeof(*dylib); - dylib->timestamp = 1; - dylib->current_version = - s1->current_version ? s1->current_version : 1 << 16; - dylib->compatibility_version = - s1->compatibility_version ? s1->compatibility_version : 1 << 16; - str = (char*)dylib + dylib->name; - strcpy(str, name); - } - -#ifdef CONFIG_NEW_MACHO - chained_fixups_lc = add_lc(mo, LC_DYLD_CHAINED_FIXUPS, - sizeof(struct linkedit_data_command)); - export_trie_lc = add_lc(mo, LC_DYLD_EXPORTS_TRIE, - sizeof(struct linkedit_data_command)); -#else - mo->dyldinfo = add_lc(mo, LC_DYLD_INFO_ONLY, sizeof(*mo->dyldinfo)); -#endif - - symlc = add_lc(mo, LC_SYMTAB, sizeof(*symlc)); - dysymlc = add_lc(mo, LC_DYSYMTAB, sizeof(*dysymlc)); - - if (s1->output_type == TCC_OUTPUT_EXE) { - i = (sizeof(*dyldlc) + strlen("/usr/lib/dyld") + 1 + 7) &-8; - dyldlc = add_lc(mo, LC_LOAD_DYLINKER, i); - dyldlc->name = sizeof(*dyldlc); - str = (char*)dyldlc + dyldlc->name; - strcpy(str, "/usr/lib/dyld"); - } - - dyldbv = add_lc(mo, LC_BUILD_VERSION, sizeof(*dyldbv)); - dyldbv->platform = PLATFORM_MACOS; - dyldbv->minos = (10 << 16) + (6 << 8); - dyldbv->sdk = (10 << 16) + (6 << 8); - dyldbv->ntools = 0; - - dyldsv = add_lc(mo, LC_SOURCE_VERSION, sizeof(*dyldsv)); - dyldsv->version = 0; - - if (s1->output_type == TCC_OUTPUT_EXE) { - mo->ep = add_lc(mo, LC_MAIN, sizeof(*mo->ep)); - mo->ep->entryoff = 4096; - } - - for(i = 0; i < s1->nb_loaded_dlls; i++) { - DLLReference *dllref = s1->loaded_dlls[i]; - if (dllref->level == 0) - add_dylib(mo, dllref->name); - } - - if (s1->rpath) { - char *path = s1->rpath, *end; - do { - end = strchr(path, ':'); - if (!end) - end = strchr(path, 0); - i = (sizeof(*rpath) + (end - path) + 1 + 7) &-8; - rpath = add_lc(mo, LC_RPATH, i); - rpath->path = sizeof(*rpath); - str = (char*)rpath + rpath->path; - memcpy(str, path, end - path); - str[end - path] = 0; - path = end + 1; - } while (*end); - } - - fileofs = 4096; /* leave space for mach-o headers */ - curaddr = get_segment(mo, s1->output_type == TCC_OUTPUT_EXE)->vmaddr; - curaddr += 4096; - seg = NULL; - numsec = 0; - mo->elfsectomacho = tcc_mallocz(sizeof(*mo->elfsectomacho) * s1->nb_sections); - for (sk = sk_unknown; sk < sk_last; sk++) { - struct section_64 *sec = NULL; - if (seg) { - seg->vmsize = curaddr - seg->vmaddr; - seg->filesize = fileofs - seg->fileoff; - } -#ifdef CONFIG_NEW_MACHO - if (sk == sk_linkedit) { - calc_fixup_size(s1, mo); - export_trie(s1, mo); - } -#else - if (sk == sk_linkedit) { - bind_rebase(s1, mo); - export_trie(s1, mo); - } -#endif - if (skinfo[sk].seg_initial && - (s1->output_type != TCC_OUTPUT_EXE || mo->segment[sk]) && - mo->sk_to_sect[sk].s) { - uint64_t al = 0; - int si; - seg = get_segment(mo, mo->segment[sk]); - if (skinfo[sk].name) { - si = add_section(mo, &seg, skinfo[sk].name); - numsec++; - mo->lc[mo->seg2lc[mo->segment[sk]]] = (struct load_command*)seg; - mo->sk_to_sect[sk].machosect = si; - sec = get_section(seg, si); - sec->flags = skinfo[sk].flags; - if (sk == sk_stubs) -#ifdef TCC_TARGET_X86_64 - sec->reserved2 = 6; -#elif defined TCC_TARGET_ARM64 - sec->reserved2 = 12; -#endif - if (sk == sk_nl_ptr) - sec->reserved1 = mo->nr_plt; -#ifndef CONFIG_NEW_MACHO - if (sk == sk_la_ptr) - sec->reserved1 = mo->nr_plt + mo->n_got; -#endif - } - if (seg->vmaddr == -1) { - curaddr = (curaddr + SEG_PAGE_SIZE - 1) & -SEG_PAGE_SIZE; - seg->vmaddr = curaddr; - fileofs = (fileofs + SEG_PAGE_SIZE - 1) & -SEG_PAGE_SIZE; - seg->fileoff = fileofs; - } - - for (s = mo->sk_to_sect[sk].s; s; s = s->prev) { - int a = exact_log2p1(s->sh_addralign); - if (a && al < (a - 1)) - al = a - 1; - s->sh_size = s->data_offset; - } - if (sec) - sec->align = al; - al = 1ULL << al; - if (al > 4096) - tcc_warning("alignment > 4096"), sec->align = 12, al = 4096; - curaddr = (curaddr + al - 1) & -al; - fileofs = (fileofs + al - 1) & -al; - if (sec) { - sec->addr = curaddr; - sec->offset = fileofs; - } - for (s = mo->sk_to_sect[sk].s; s; s = s->prev) { - al = s->sh_addralign; - curaddr = (curaddr + al - 1) & -al; - dprintf("%s: curaddr now 0x%lx\n", s->name, (long)curaddr); - s->sh_addr = curaddr; - curaddr += s->sh_size; - if (s->sh_type != SHT_NOBITS) { - fileofs = (fileofs + al - 1) & -al; - s->sh_offset = fileofs; - fileofs += s->sh_size; - dprintf("%s: fileofs now %ld\n", s->name, (long)fileofs); - } - if (sec) - mo->elfsectomacho[s->sh_num] = numsec; - } - if (sec) - sec->size = curaddr - sec->addr; - } - if (DEBUG_MACHO) - for (s = mo->sk_to_sect[sk].s; s; s = s->prev) { - int type = s->sh_type; - int flags = s->sh_flags; - printf("%d section %-16s %-10s %09lx %04x %02d %s,%s,%s\n", - sk, - s->name, - type == SHT_PROGBITS ? "progbits" : - type == SHT_NOBITS ? "nobits" : - type == SHT_SYMTAB ? "symtab" : - type == SHT_STRTAB ? "strtab" : - type == SHT_INIT_ARRAY ? "init" : - type == SHT_FINI_ARRAY ? "fini" : - type == SHT_RELX ? "rel" : "???", - (long)s->sh_addr, - (unsigned)s->data_offset, - s->sh_addralign, - flags & SHF_ALLOC ? "alloc" : "", - flags & SHF_WRITE ? "write" : "", - flags & SHF_EXECINSTR ? "exec" : "" - ); - } - } - if (seg) { - seg->vmsize = curaddr - seg->vmaddr; - seg->filesize = fileofs - seg->fileoff; - } - - /* Fill symtab info */ - symlc->symoff = mo->symtab->sh_offset; - symlc->nsyms = mo->symtab->data_offset / sizeof(struct nlist_64); - symlc->stroff = mo->strtab->sh_offset; - symlc->strsize = mo->strtab->data_offset; - - dysymlc->iundefsym = mo->iundef == -1 ? symlc->nsyms : mo->iundef; - dysymlc->iextdefsym = mo->iextdef == -1 ? dysymlc->iundefsym : mo->iextdef; - dysymlc->ilocalsym = mo->ilocal == -1 ? dysymlc->iextdefsym : mo->ilocal; - dysymlc->nlocalsym = dysymlc->iextdefsym - dysymlc->ilocalsym; - dysymlc->nextdefsym = dysymlc->iundefsym - dysymlc->iextdefsym; - dysymlc->nundefsym = symlc->nsyms - dysymlc->iundefsym; - dysymlc->indirectsymoff = mo->indirsyms->sh_offset; - dysymlc->nindirectsyms = mo->indirsyms->data_offset / sizeof(uint32_t); - -#ifdef CONFIG_NEW_MACHO - if (mo->chained_fixups->data_offset) { - chained_fixups_lc->dataoff = mo->chained_fixups->sh_offset; - chained_fixups_lc->datasize = mo->chained_fixups->data_offset; - } - if (mo->exports->data_offset) { - export_trie_lc->dataoff = mo->exports->sh_offset; - export_trie_lc->datasize = mo->exports->data_offset; - } -#else - if (mo->rebase->data_offset) { - mo->dyldinfo->rebase_off = mo->rebase->sh_offset; - mo->dyldinfo->rebase_size = mo->rebase->data_offset; - } - if (mo->binding->data_offset) { - mo->dyldinfo->bind_off = mo->binding->sh_offset; - mo->dyldinfo->bind_size = mo->binding->data_offset; - } - if (mo->weak_binding->data_offset) { - mo->dyldinfo->weak_bind_off = mo->weak_binding->sh_offset; - mo->dyldinfo->weak_bind_size = mo->weak_binding->data_offset; - } - if (mo->lazy_binding->data_offset) { - mo->dyldinfo->lazy_bind_off = mo->lazy_binding->sh_offset; - mo->dyldinfo->lazy_bind_size = mo->lazy_binding->data_offset; - } - if (mo->exports->data_offset) { - mo->dyldinfo->export_off = mo->exports->sh_offset; - mo->dyldinfo->export_size = mo->exports->data_offset; - } -#endif -} - -static void macho_write(TCCState *s1, struct macho *mo, FILE *fp) -{ - int i, sk; - uint64_t fileofs = 0; - Section *s; - mo->mh.mh.magic = MH_MAGIC_64; -#ifdef TCC_TARGET_X86_64 - mo->mh.mh.cputype = CPU_TYPE_X86_64; - mo->mh.mh.cpusubtype = CPU_SUBTYPE_LIB64 | CPU_SUBTYPE_X86_ALL; -#elif defined TCC_TARGET_ARM64 - mo->mh.mh.cputype = CPU_TYPE_ARM64; - mo->mh.mh.cpusubtype = CPU_SUBTYPE_ARM64_ALL; -#endif - if (s1->output_type == TCC_OUTPUT_EXE) { - mo->mh.mh.filetype = MH_EXECUTE; - mo->mh.mh.flags = MH_DYLDLINK | MH_PIE; - } - else { - mo->mh.mh.filetype = MH_DYLIB; - mo->mh.mh.flags = MH_DYLDLINK; - } - mo->mh.mh.ncmds = mo->nlc; - mo->mh.mh.sizeofcmds = 0; - for (i = 0; i < mo->nlc; i++) - mo->mh.mh.sizeofcmds += mo->lc[i]->cmdsize; - - fwrite(&mo->mh, 1, sizeof(mo->mh), fp); - fileofs += sizeof(mo->mh); - for (i = 0; i < mo->nlc; i++) { - fwrite(mo->lc[i], 1, mo->lc[i]->cmdsize, fp); - fileofs += mo->lc[i]->cmdsize; - } - - for (sk = sk_unknown; sk < sk_last; sk++) { - //struct segment_command_64 *seg; - if (skinfo[sk].seg_initial == 0 || - (s1->output_type == TCC_OUTPUT_EXE && !mo->segment[sk]) || - !mo->sk_to_sect[sk].s) - continue; - /*seg =*/ get_segment(mo, mo->segment[sk]); - for (s = mo->sk_to_sect[sk].s; s; s = s->prev) { - if (s->sh_type != SHT_NOBITS) { - while (fileofs < s->sh_offset) - fputc(0, fp), fileofs++; - if (s->sh_size) { - fwrite(s->data, 1, s->sh_size, fp); - fileofs += s->sh_size; - } - } - } - } -} - -#ifdef CONFIG_NEW_MACHO -static int bind_rebase_cmp(const void *_a, const void *_b, void *arg) -{ - TCCState *s1 = arg; - struct bind_rebase *a = (struct bind_rebase *) _a; - struct bind_rebase *b = (struct bind_rebase *) _b; - addr_t aa = s1->sections[a->section]->sh_addr + a->rel.r_offset; - addr_t ab = s1->sections[b->section]->sh_addr + b->rel.r_offset; - - return aa > ab ? 1 : aa < ab ? -1 : 0; -} - -ST_FUNC void bind_rebase_import(TCCState *s1, struct macho *mo) -{ - int i, j, k, bind_index, size, page_count, sym_index; - const char *name; - ElfW(Sym) *sym; - unsigned char *data = mo->chained_fixups->data; - struct segment_command_64 *seg; - struct dyld_chained_fixups_header *header; - struct dyld_chained_starts_in_image *image; - struct dyld_chained_starts_in_segment *segment; - struct dyld_chained_import *import; - - tcc_qsort(mo->bind_rebase, mo->n_bind_rebase, sizeof(struct bind_rebase), - bind_rebase_cmp, s1); - for (i = 0; i < mo->n_bind_rebase - 1; i++) - if (mo->bind_rebase[i].section == mo->bind_rebase[i + 1].section && - mo->bind_rebase[i].rel.r_offset == mo->bind_rebase[i + 1].rel.r_offset) { - sym_index = ELFW(R_SYM)(mo->bind_rebase[i].rel.r_info); - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - name = (char *) symtab_section->link->data + sym->st_name; - tcc_error("Overlap %s/%s %s:%s", - mo->bind_rebase[i].bind ? "bind" : "rebase", - mo->bind_rebase[i + 1].bind ? "bind" : "rebase", - s1->sections[mo->bind_rebase[i].section]->name, name); - } - header = (struct dyld_chained_fixups_header *) data; - data += (sizeof(struct dyld_chained_fixups_header) + 7) & -8; - header->starts_offset = data - mo->chained_fixups->data; - header->imports_count = mo->n_bind; - header->imports_format = DYLD_CHAINED_IMPORT; - header->symbols_format = 0; - size = sizeof(struct dyld_chained_starts_in_image) + - (mo->nseg - 1) * sizeof(uint32_t); - image = (struct dyld_chained_starts_in_image *) data; - data += (size + 7) & -8; - image->seg_count = mo->nseg; - for (i = (s1->output_type == TCC_OUTPUT_EXE); i < mo->nseg - 1; i++) { - image->seg_info_offset[i] = (data - mo->chained_fixups->data) - - header->starts_offset; - seg = get_segment(mo, i); - page_count = (seg->vmsize + SEG_PAGE_SIZE - 1) / SEG_PAGE_SIZE; - size = sizeof(struct dyld_chained_starts_in_segment) + - (page_count - 1) * sizeof(uint16_t); - segment = (struct dyld_chained_starts_in_segment *) data; - data += (size + 7) & -8; - segment->size = size; - segment->page_size = SEG_PAGE_SIZE; -#if 1 -#define PTR_64_OFFSET 0 -#define PTR_64_MASK 0x7FFFFFFFFFFULL - segment->pointer_format = DYLD_CHAINED_PTR_64; -#else -#define PTR_64_OFFSET 0x100000000ULL -#define PTR_64_MASK 0xFFFFFFFFFFFFFFULL - segment->pointer_format = DYLD_CHAINED_PTR_64_OFFSET; -#endif - segment->segment_offset = seg->fileoff; - segment->max_valid_pointer = 0; - segment->page_count = page_count; - // add bind/rebase - bind_index = 0; - k = 0; - for (j = 0; j < page_count; j++) { - addr_t start = seg->vmaddr + j * SEG_PAGE_SIZE; - addr_t end = start + SEG_PAGE_SIZE; - void *last = NULL; - addr_t last_o = 0; - addr_t cur_o, cur; - struct dyld_chained_ptr_64_rebase *rebase; - struct dyld_chained_ptr_64_bind *bind; - - segment->page_start[j] = DYLD_CHAINED_PTR_START_NONE; - for (; k < mo->n_bind_rebase; k++) { - Section *s = s1->sections[mo->bind_rebase[k].section]; - addr_t r_offset = mo->bind_rebase[k].rel.r_offset; - addr_t addr = s->sh_addr + r_offset; - - if ((addr & 3) || - (addr & (SEG_PAGE_SIZE - 1)) > SEG_PAGE_SIZE - PTR_SIZE) - tcc_error("Illegal rel_offset %s %lld", - s->name, (long long)r_offset); - if (addr >= end) - break; - if (addr >= start) { - cur_o = addr - start; - if (mo->bind_rebase[k].bind) { - if (segment->page_start[j] == DYLD_CHAINED_PTR_START_NONE) - segment->page_start[j] = cur_o; - else { - bind = (struct dyld_chained_ptr_64_bind *) last; - bind->next = (cur_o - last_o) / 4; - } - bind = (struct dyld_chained_ptr_64_bind *) - (s->data + r_offset); - last = bind; - last_o = cur_o; - bind->ordinal = bind_index; - bind->addend = 0; - bind->reserved = 0; - bind->next = 0; - bind->bind = 1; - } - else { - if (segment->page_start[j] == DYLD_CHAINED_PTR_START_NONE) - segment->page_start[j] = cur_o; - else { - rebase = (struct dyld_chained_ptr_64_rebase *) last; - rebase->next = (cur_o - last_o) / 4; - } - rebase = (struct dyld_chained_ptr_64_rebase *) - (s->data + r_offset); - last = rebase; - last_o = cur_o; - cur = (*(uint64_t *) (s->data + r_offset)) - - PTR_64_OFFSET; - rebase->target = cur & PTR_64_MASK; - rebase->high8 = cur >> (64 - 8); - if (cur != ((uint64_t)rebase->high8 << (64 - 8)) + rebase->target) - tcc_error("rebase error"); - rebase->reserved = 0; - rebase->next = 0; - rebase->bind = 0; - } - } - bind_index += mo->bind_rebase[k].bind; - } - } - } - // add imports - header->imports_offset = data - mo->chained_fixups->data; - import = (struct dyld_chained_import *) data; - data += mo->n_bind * sizeof (struct dyld_chained_import); - header->symbols_offset = data - mo->chained_fixups->data; - data++; - for (i = 0, bind_index = 0; i < mo->n_bind_rebase; i++) { - if (mo->bind_rebase[i].bind) { - import[bind_index].lib_ordinal = - BIND_SPECIAL_DYLIB_FLAT_LOOKUP & 0xffu; - import[bind_index].name_offset = - (data - mo->chained_fixups->data) - header->symbols_offset; - sym_index = ELFW(R_SYM)(mo->bind_rebase[i].rel.r_info); - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - import[bind_index].weak_import = - ELFW(ST_BIND)(sym->st_info) == STB_WEAK; - name = (char *) symtab_section->link->data + sym->st_name; - strcpy((char *) data, name); - data += strlen(name) + 1; - bind_index++; - } - } - tcc_free(mo->bind_rebase); -} -#endif - -ST_FUNC int macho_output_file(TCCState *s1, const char *filename) -{ - int fd, mode, file_type; - FILE *fp; - int i, ret = -1; - struct macho mo; - - (void)memset(&mo, 0, sizeof(mo)); - - file_type = s1->output_type; - if (file_type == TCC_OUTPUT_OBJ) - mode = 0666; - else - mode = 0777; - unlink(filename); - fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode); - if (fd < 0 || (fp = fdopen(fd, "wb")) == NULL) { - tcc_error_noabort("could not write '%s: %s'", filename, strerror(errno)); - return -1; - } - if (s1->verbose) - printf("<- %s\n", filename); - - tcc_add_runtime(s1); - tcc_macho_add_destructor(s1); - resolve_common_syms(s1); - create_symtab(s1, &mo); - check_relocs(s1, &mo); - ret = check_symbols(s1, &mo); - if (!ret) { - int save_output = s1->output_type; - - collect_sections(s1, &mo, filename); - relocate_syms(s1, s1->symtab, 0); - if (s1->output_type == TCC_OUTPUT_EXE) - mo.ep->entryoff = get_sym_addr(s1, "main", 1, 1) - - get_segment(&mo, 1)->vmaddr; - if (s1->nb_errors) - goto do_ret; - // Macho uses bind/rebase instead of dynsym - s1->output_type = TCC_OUTPUT_EXE; - relocate_sections(s1); - s1->output_type = save_output; -#ifdef CONFIG_NEW_MACHO - bind_rebase_import(s1, &mo); -#endif - convert_symbols(s1, &mo); - macho_write(s1, &mo, fp); - } - - do_ret: - for (i = 0; i < mo.nlc; i++) - tcc_free(mo.lc[i]); - tcc_free(mo.seg2lc); - tcc_free(mo.lc); - tcc_free(mo.elfsectomacho); - tcc_free(mo.e2msym); - - fclose(fp); -#ifdef CONFIG_CODESIGN - { - char command[1024]; - int retval; - - snprintf(command, sizeof(command), "codesign -f -s - %s", filename); - retval = system (command); - if (retval == -1 || !(WIFEXITED(retval) && WEXITSTATUS(retval) == 0)) - tcc_error ("command failed '%s'", command); - } -#endif - return ret; -} - -static uint32_t macho_swap32(uint32_t x) -{ - return (x >> 24) | (x << 24) | ((x >> 8) & 0xff00) | ((x & 0xff00) << 8); -} -#define SWAP(x) (swap ? macho_swap32(x) : (x)) -#define tbd_parse_movepast(s) \ - (pos = (pos = strstr(pos, s)) ? pos + strlen(s) : NULL) -#define tbd_parse_movetoany(cs) (pos = strpbrk(pos, cs)) -#define tbd_parse_skipws while (*pos && (*pos==' '||*pos=='\n')) ++pos -#define tbd_parse_tramplequote if(*pos=='\''||*pos=='"') tbd_parse_trample -#define tbd_parse_tramplespace if(*pos==' ') tbd_parse_trample -#define tbd_parse_trample *pos++=0 - -#ifdef TCC_IS_NATIVE -/* Looks for the active developer SDK set by xcode-select (or the default - one set during installation.) */ -ST_FUNC void tcc_add_macos_sdkpath(TCCState* s) -{ - char *sdkroot = NULL, *pos = NULL; - void* xcs = dlopen("libxcselect.dylib", RTLD_GLOBAL | RTLD_LAZY); - CString path; - int (*f)(unsigned int, char**) = dlsym(xcs, "xcselect_host_sdk_path"); - cstr_new(&path); - if (f) f(1, &sdkroot); - if (sdkroot) - pos = strstr(sdkroot,"SDKs/MacOSX"); - if (pos) - cstr_printf(&path, "%.*s.sdk/usr/lib", (int)(pos - sdkroot + 11), sdkroot); - /* must use free from libc directly */ -#pragma push_macro("free") -#undef free - free(sdkroot); -#pragma pop_macro("free") - if (path.size) - tcc_add_library_path(s, (char*)path.data); - else - tcc_add_library_path(s, - "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib" - ":" "/Applications/Xcode.app/Developer/SDKs/MacOSX.sdk/usr/lib" - ); - cstr_free(&path); -} - -ST_FUNC const char* macho_tbd_soname(const char* filename) { - char *soname, *data, *pos; - const char *ret = filename; - - int fd = open(filename,O_RDONLY); - if (fd<0) return ret; - pos = data = tcc_load_text(fd); - if (!tbd_parse_movepast("install-name: ")) goto the_end; - tbd_parse_skipws; - tbd_parse_tramplequote; - soname = pos; - if (!tbd_parse_movetoany("\n \"'")) goto the_end; - tbd_parse_trample; - ret = tcc_strdup(soname); -the_end: - tcc_free(data); - return ret; -} -#endif /* TCC_IS_NATIVE */ - -ST_FUNC int macho_load_tbd(TCCState* s1, int fd, const char* filename, int lev) -{ - char *soname, *data, *pos; - int ret = -1; - - pos = data = tcc_load_text(fd); - if (!tbd_parse_movepast("install-name: ")) goto the_end; - tbd_parse_skipws; - tbd_parse_tramplequote; - soname = pos; - if (!tbd_parse_movetoany("\n \"'")) goto the_end; - tbd_parse_trample; - ret = 0; - if (tcc_add_dllref(s1, soname, lev)->found) - goto the_end; - while(pos) { - char* sym = NULL; - int cont = 1; - if (!tbd_parse_movepast("symbols: ")) break; - if (!tbd_parse_movepast("[")) break; - while (cont) { - tbd_parse_skipws; - tbd_parse_tramplequote; - sym = pos; - if (!tbd_parse_movetoany(",] \"'")) break; - tbd_parse_tramplequote; - tbd_parse_tramplespace; - tbd_parse_skipws; - if (*pos==0||*pos==']') cont=0; - tbd_parse_trample; - set_elf_sym(s1->dynsymtab_section, 0, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, SHN_UNDEF, sym); - } - } - -the_end: - tcc_free(data); - return ret; -} - -ST_FUNC int macho_load_dll(TCCState * s1, int fd, const char* filename, int lev) -{ - unsigned char buf[sizeof(struct mach_header_64)]; - void *buf2; - uint32_t machofs = 0; - struct fat_header fh; - struct mach_header mh; - struct load_command *lc; - int i, swap = 0; - const char *soname = filename; - struct nlist_64 *symtab = 0; - uint32_t nsyms = 0; - char *strtab = 0; - uint32_t strsize = 0; - uint32_t iextdef = 0; - uint32_t nextdef = 0; - - again: - if (full_read(fd, buf, sizeof(buf)) != sizeof(buf)) - return -1; - memcpy(&fh, buf, sizeof(fh)); - if (fh.magic == FAT_MAGIC || fh.magic == FAT_CIGAM) { - struct fat_arch *fa = load_data(fd, sizeof(fh), - fh.nfat_arch * sizeof(*fa)); - swap = fh.magic == FAT_CIGAM; - for (i = 0; i < SWAP(fh.nfat_arch); i++) -#ifdef TCC_TARGET_X86_64 - if (SWAP(fa[i].cputype) == CPU_TYPE_X86_64 - && SWAP(fa[i].cpusubtype) == CPU_SUBTYPE_X86_ALL) -#elif defined TCC_TARGET_ARM64 - if (SWAP(fa[i].cputype) == CPU_TYPE_ARM64 - && SWAP(fa[i].cpusubtype) == CPU_SUBTYPE_ARM64_ALL) -#endif - break; - if (i == SWAP(fh.nfat_arch)) { - tcc_free(fa); - return -1; - } - machofs = SWAP(fa[i].offset); - tcc_free(fa); - lseek(fd, machofs, SEEK_SET); - goto again; - } else if (fh.magic == FAT_MAGIC_64 || fh.magic == FAT_CIGAM_64) { - tcc_warning("%s: Mach-O fat 64bit files of type 0x%x not handled", - filename, fh.magic); - return -1; - } - - memcpy(&mh, buf, sizeof(mh)); - if (mh.magic != MH_MAGIC_64) - return -1; - dprintf("found Mach-O at %d\n", machofs); - buf2 = load_data(fd, machofs + sizeof(struct mach_header_64), mh.sizeofcmds); - for (i = 0, lc = buf2; i < mh.ncmds; i++) { - dprintf("lc %2d: 0x%08x\n", i, lc->cmd); - switch (lc->cmd) { - case LC_SYMTAB: - { - struct symtab_command *sc = (struct symtab_command*)lc; - nsyms = sc->nsyms; - symtab = load_data(fd, machofs + sc->symoff, nsyms * sizeof(*symtab)); - strsize = sc->strsize; - strtab = load_data(fd, machofs + sc->stroff, strsize); - break; - } - case LC_ID_DYLIB: - { - struct dylib_command *dc = (struct dylib_command*)lc; - soname = (char*)lc + dc->name; - dprintf(" ID_DYLIB %d 0x%x 0x%x %s\n", - dc->timestamp, dc->current_version, - dc->compatibility_version, soname); - break; - } - case LC_REEXPORT_DYLIB: - { - struct dylib_command *dc = (struct dylib_command*)lc; - char *name = (char*)lc + dc->name; - int subfd = open(name, O_RDONLY | O_BINARY); - dprintf(" REEXPORT %s\n", name); - if (subfd < 0) - tcc_warning("can't open %s (reexported from %s)", name, filename); - else { - /* Hopefully the REEXPORTs never form a cycle, we don't check - for that! */ - macho_load_dll(s1, subfd, name, lev + 1); - close(subfd); - } - break; - } - case LC_DYSYMTAB: - { - struct dysymtab_command *dc = (struct dysymtab_command*)lc; - iextdef = dc->iextdefsym; - nextdef = dc->nextdefsym; - break; - } - } - lc = (struct load_command*) ((char*)lc + lc->cmdsize); - } - - if (tcc_add_dllref(s1, soname, lev)->found) - goto the_end; - - if (!nsyms || !nextdef) - tcc_warning("%s doesn't export any symbols?", filename); - - //dprintf("symbols (all):\n"); - dprintf("symbols (exported):\n"); - dprintf(" n: typ sec desc value name\n"); - //for (i = 0; i < nsyms; i++) { - for (i = iextdef; i < iextdef + nextdef; i++) { - struct nlist_64 *sym = symtab + i; - dprintf("%5d: %3d %3d 0x%04x 0x%016lx %s\n", - i, sym->n_type, sym->n_sect, sym->n_desc, (long)sym->n_value, - strtab + sym->n_strx); - set_elf_sym(s1->dynsymtab_section, 0, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), - 0, SHN_UNDEF, strtab + sym->n_strx); - } - - the_end: - tcc_free(strtab); - tcc_free(symtab); - tcc_free(buf2); - return 0; -} diff --git a/tinycc/tccpe.c b/tinycc/tccpe.c deleted file mode 100644 index ab610af..0000000 --- a/tinycc/tccpe.c +++ /dev/null @@ -1,2036 +0,0 @@ -/* - * TCCPE.C - PE file output for the Tiny C Compiler - * - * Copyright (c) 2005-2007 grischka - * - * 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 - */ - -#include "tcc.h" - -#define PE_MERGE_DATA 1 -#define PE_PRINT_SECTIONS 0 - -#ifndef _WIN32 -#define stricmp strcasecmp -#define strnicmp strncasecmp -#include <sys/stat.h> /* chmod() */ -#endif - -#ifdef TCC_TARGET_X86_64 -# define ADDR3264 ULONGLONG -# define PE_IMAGE_REL IMAGE_REL_BASED_DIR64 -# 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 R_XXX_FUNCCALL R_X86_64_PC32 -# define IMAGE_FILE_MACHINE 0x8664 -# define RSRC_RELTYPE 3 - -#elif defined TCC_TARGET_ARM -# define ADDR3264 DWORD -# define PE_IMAGE_REL IMAGE_REL_BASED_HIGHLOW -# define REL_TYPE_DIRECT R_ARM_ABS32 -# define R_XXX_THUNKFIX R_ARM_ABS32 -# define R_XXX_RELATIVE R_ARM_RELATIVE -# define R_XXX_FUNCCALL R_ARM_PC24 -# define R_XXX_FUNCCALL2 R_ARM_ABS32 -# define IMAGE_FILE_MACHINE 0x01C0 -# define RSRC_RELTYPE 7 /* ??? (not tested) */ - -#elif defined TCC_TARGET_I386 -# define ADDR3264 DWORD -# define PE_IMAGE_REL IMAGE_REL_BASED_HIGHLOW -# define REL_TYPE_DIRECT R_386_32 -# define R_XXX_THUNKFIX R_386_32 -# define R_XXX_RELATIVE R_386_RELATIVE -# define R_XXX_FUNCCALL R_386_PC32 -# define IMAGE_FILE_MACHINE 0x014C -# define RSRC_RELTYPE 7 /* DIR32NB */ - -#endif - -#ifndef IMAGE_NT_SIGNATURE -/* ----------------------------------------------------------- */ -/* definitions below are from winnt.h */ - -typedef unsigned char BYTE; -typedef unsigned short WORD; -typedef unsigned int DWORD; -typedef unsigned long long ULONGLONG; -#pragma pack(push, 1) - -typedef struct _IMAGE_DOS_HEADER { /* DOS .EXE header */ - WORD e_magic; /* Magic number */ - WORD e_cblp; /* Bytes on last page of file */ - WORD e_cp; /* Pages in file */ - WORD e_crlc; /* Relocations */ - WORD e_cparhdr; /* Size of header in paragraphs */ - WORD e_minalloc; /* Minimum extra paragraphs needed */ - WORD e_maxalloc; /* Maximum extra paragraphs needed */ - WORD e_ss; /* Initial (relative) SS value */ - WORD e_sp; /* Initial SP value */ - WORD e_csum; /* Checksum */ - WORD e_ip; /* Initial IP value */ - WORD e_cs; /* Initial (relative) CS value */ - WORD e_lfarlc; /* File address of relocation table */ - WORD e_ovno; /* Overlay number */ - WORD e_res[4]; /* Reserved words */ - WORD e_oemid; /* OEM identifier (for e_oeminfo) */ - WORD e_oeminfo; /* OEM information; e_oemid specific */ - WORD e_res2[10]; /* Reserved words */ - DWORD e_lfanew; /* File address of new exe header */ -} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; - -#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */ -#define SIZE_OF_NT_SIGNATURE 4 - -typedef struct _IMAGE_FILE_HEADER { - WORD Machine; - WORD NumberOfSections; - DWORD TimeDateStamp; - DWORD PointerToSymbolTable; - DWORD NumberOfSymbols; - WORD SizeOfOptionalHeader; - WORD Characteristics; -} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; - - -#define IMAGE_SIZEOF_FILE_HEADER 20 - -typedef struct _IMAGE_DATA_DIRECTORY { - DWORD VirtualAddress; - DWORD Size; -} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; - - -typedef struct _IMAGE_OPTIONAL_HEADER { - /* Standard fields. */ - WORD Magic; - BYTE MajorLinkerVersion; - BYTE MinorLinkerVersion; - DWORD SizeOfCode; - DWORD SizeOfInitializedData; - DWORD SizeOfUninitializedData; - DWORD AddressOfEntryPoint; - DWORD BaseOfCode; -#ifndef TCC_TARGET_X86_64 - DWORD BaseOfData; -#endif - /* NT additional fields. */ - ADDR3264 ImageBase; - DWORD SectionAlignment; - DWORD FileAlignment; - WORD MajorOperatingSystemVersion; - WORD MinorOperatingSystemVersion; - WORD MajorImageVersion; - WORD MinorImageVersion; - WORD MajorSubsystemVersion; - WORD MinorSubsystemVersion; - DWORD Win32VersionValue; - DWORD SizeOfImage; - DWORD SizeOfHeaders; - DWORD CheckSum; - WORD Subsystem; - WORD DllCharacteristics; - ADDR3264 SizeOfStackReserve; - ADDR3264 SizeOfStackCommit; - ADDR3264 SizeOfHeapReserve; - ADDR3264 SizeOfHeapCommit; - DWORD LoaderFlags; - DWORD NumberOfRvaAndSizes; - IMAGE_DATA_DIRECTORY DataDirectory[16]; -} IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, IMAGE_OPTIONAL_HEADER; - -#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 /* Export Directory */ -#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 /* Import Directory */ -#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 /* Resource Directory */ -#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 /* Exception Directory */ -#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 /* Security Directory */ -#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 /* Base Relocation Table */ -#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 /* Debug Directory */ -/* IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 (X86 usage) */ -#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 /* Architecture Specific Data */ -#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 /* RVA of GP */ -#define IMAGE_DIRECTORY_ENTRY_TLS 9 /* TLS Directory */ -#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 /* Load Configuration Directory */ -#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 /* Bound Import Directory in headers */ -#define IMAGE_DIRECTORY_ENTRY_IAT 12 /* Import Address Table */ -#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 /* Delay Load Import Descriptors */ -#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 /* COM Runtime descriptor */ - -/* Section header format. */ -#define IMAGE_SIZEOF_SHORT_NAME 8 - -typedef struct _IMAGE_SECTION_HEADER { - BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; - union { - DWORD PhysicalAddress; - DWORD VirtualSize; - } Misc; - DWORD VirtualAddress; - DWORD SizeOfRawData; - DWORD PointerToRawData; - DWORD PointerToRelocations; - DWORD PointerToLinenumbers; - WORD NumberOfRelocations; - WORD NumberOfLinenumbers; - DWORD Characteristics; -} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; - -#define IMAGE_SIZEOF_SECTION_HEADER 40 - -typedef struct _IMAGE_EXPORT_DIRECTORY { - DWORD Characteristics; - DWORD TimeDateStamp; - WORD MajorVersion; - WORD MinorVersion; - DWORD Name; - DWORD Base; - DWORD NumberOfFunctions; - DWORD NumberOfNames; - DWORD AddressOfFunctions; - DWORD AddressOfNames; - DWORD AddressOfNameOrdinals; -} IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY; - -typedef struct _IMAGE_IMPORT_DESCRIPTOR { - union { - DWORD Characteristics; - DWORD OriginalFirstThunk; - }; - DWORD TimeDateStamp; - DWORD ForwarderChain; - DWORD Name; - DWORD FirstThunk; -} IMAGE_IMPORT_DESCRIPTOR; - -typedef struct _IMAGE_BASE_RELOCATION { - DWORD VirtualAddress; - DWORD SizeOfBlock; -// WORD TypeOffset[1]; -} IMAGE_BASE_RELOCATION; - -#define IMAGE_SIZEOF_BASE_RELOCATION 8 - -#define IMAGE_REL_BASED_ABSOLUTE 0 -#define IMAGE_REL_BASED_HIGH 1 -#define IMAGE_REL_BASED_LOW 2 -#define IMAGE_REL_BASED_HIGHLOW 3 -#define IMAGE_REL_BASED_HIGHADJ 4 -#define IMAGE_REL_BASED_MIPS_JMPADDR 5 -#define IMAGE_REL_BASED_SECTION 6 -#define IMAGE_REL_BASED_REL32 7 -#define IMAGE_REL_BASED_DIR64 10 - -#define IMAGE_SCN_CNT_CODE 0x00000020 -#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 -#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 -#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 -#define IMAGE_SCN_MEM_SHARED 0x10000000 -#define IMAGE_SCN_MEM_EXECUTE 0x20000000 -#define IMAGE_SCN_MEM_READ 0x40000000 -#define IMAGE_SCN_MEM_WRITE 0x80000000 - -#pragma pack(pop) - -/* ----------------------------------------------------------- */ -#endif /* ndef IMAGE_NT_SIGNATURE */ -/* ----------------------------------------------------------- */ - -#ifndef IMAGE_REL_BASED_DIR64 -# define IMAGE_REL_BASED_DIR64 10 -#endif - -#pragma pack(push, 1) -struct pe_header -{ - IMAGE_DOS_HEADER doshdr; - BYTE dosstub[0x40]; - DWORD nt_sig; - IMAGE_FILE_HEADER filehdr; -#ifdef TCC_TARGET_X86_64 - IMAGE_OPTIONAL_HEADER64 opthdr; -#else -#ifdef _WIN64 - IMAGE_OPTIONAL_HEADER32 opthdr; -#else - IMAGE_OPTIONAL_HEADER opthdr; -#endif -#endif -}; - -struct pe_reloc_header { - DWORD offset; - DWORD size; -}; - -struct pe_rsrc_header { - struct _IMAGE_FILE_HEADER filehdr; - struct _IMAGE_SECTION_HEADER sectionhdr; -}; - -struct pe_rsrc_reloc { - DWORD offset; - DWORD size; - WORD type; -}; -#pragma pack(pop) - -/* ------------------------------------------------------------- */ -/* internal temporary structures */ - -enum { - sec_text = 0, - sec_rdata , - sec_data , - sec_bss , - sec_idata , - sec_pdata , - sec_other , - sec_rsrc , - sec_stab , - sec_stabstr , - sec_reloc , - sec_last -}; - -#if 0 -static const DWORD pe_sec_flags[] = { - 0x60000020, /* ".text" , */ - 0xC0000040, /* ".data" , */ - 0xC0000080, /* ".bss" , */ - 0x40000040, /* ".idata" , */ - 0x40000040, /* ".pdata" , */ - 0xE0000060, /* < other > , */ - 0x40000040, /* ".rsrc" , */ - 0x42000802, /* ".stab" , */ - 0x42000040, /* ".reloc" , */ -}; -#endif - -struct section_info { - int cls; - char name[32]; - ADDR3264 sh_addr; - DWORD sh_size; - DWORD pe_flags; - Section *sec; - DWORD data_size; - IMAGE_SECTION_HEADER ish; -}; - -struct import_symbol { - int sym_index; - int iat_index; - int thk_offset; -}; - -struct pe_import_info { - int dll_index; - int sym_count; - struct import_symbol **symbols; -}; - -struct pe_info { - TCCState *s1; - Section *reloc; - Section *thunk; - const char *filename; - int type; - DWORD sizeofheaders; - ADDR3264 imagebase; - const char *start_symbol; - DWORD start_addr; - DWORD imp_offs; - DWORD imp_size; - DWORD iat_offs; - DWORD iat_size; - DWORD exp_offs; - DWORD exp_size; - int subsystem; - DWORD section_align; - DWORD file_align; - struct section_info **sec_info; - int sec_count; - struct pe_import_info **imp_info; - int imp_count; -}; - -#define PE_NUL 0 -#define PE_DLL 1 -#define PE_GUI 2 -#define PE_EXE 3 -#define PE_RUN 4 - -/* --------------------------------------------*/ - -static const char *pe_export_name(TCCState *s1, ElfW(Sym) *sym) -{ - const char *name = (char*)symtab_section->link->data + sym->st_name; - if (s1->leading_underscore && name[0] == '_' && !(sym->st_other & ST_PE_STDCALL)) - return name + 1; - return name; -} - -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 & ST_PE_STDCALL) { - /* try w/0 stdcall deco (windows API convention) */ - p = strrchr(s, '@'); - if (!p || s[0] != '_') - break; - 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_", 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 { - 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 n == 2 ? err : sym_index; -} - -/*----------------------------------------------------------------------------*/ - -static int dynarray_assoc(void **pp, int n, int key) -{ - int i; - for (i = 0; i < n; ++i, ++pp) - if (key == **(int **) pp) - return i; - return -1; -} - -static DWORD umin(DWORD a, DWORD b) -{ - return a < b ? a : b; -} - -static DWORD umax(DWORD a, DWORD b) -{ - return a < b ? b : a; -} - -static DWORD pe_file_align(struct pe_info *pe, DWORD n) -{ - return (n + (pe->file_align - 1)) & ~(pe->file_align - 1); -} - -static ADDR3264 pe_virtual_align(struct pe_info *pe, ADDR3264 n) -{ - return (n + (pe->section_align - 1)) & ~(ADDR3264)(pe->section_align - 1); -} - -static void pe_align_section(Section *s, int a) -{ - int i = s->data_offset & (a-1); - if (i) - section_ptr_add(s, a - i); -} - -static void pe_set_datadir(struct pe_header *hdr, int dir, DWORD addr, DWORD size) -{ - hdr->opthdr.DataDirectory[dir].VirtualAddress = addr; - hdr->opthdr.DataDirectory[dir].Size = size; -} - -struct pe_file { - FILE *op; - DWORD sum; - unsigned pos; -}; - -static int pe_fwrite(void *data, int len, struct pe_file *pf) -{ - WORD *p = data; - DWORD sum; - int ret, i; - pf->pos += (ret = fwrite(data, 1, len, pf->op)); - sum = pf->sum; - for (i = len; i > 0; i -= 2) { - sum += (i >= 2) ? *p++ : *(BYTE*)p; - sum = (sum + (sum >> 16)) & 0xFFFF; - } - pf->sum = sum; - return len == ret ? 0 : -1; -} - -static void pe_fpad(struct pe_file *pf, DWORD new_pos) -{ - char buf[256]; - int n, diff = new_pos - pf->pos; - memset(buf, 0, sizeof buf); - while (diff > 0) { - diff -= n = umin(diff, sizeof buf); - fwrite(buf, n, 1, pf->op); - } - pf->pos = new_pos; -} - -/*----------------------------------------------------------------------------*/ -static int pe_write(struct pe_info *pe) -{ - static const struct pe_header pe_template = { - { - /* IMAGE_DOS_HEADER doshdr */ - 0x5A4D, /*WORD e_magic; Magic number */ - 0x0090, /*WORD e_cblp; Bytes on last page of file */ - 0x0003, /*WORD e_cp; Pages in file */ - 0x0000, /*WORD e_crlc; Relocations */ - - 0x0004, /*WORD e_cparhdr; Size of header in paragraphs */ - 0x0000, /*WORD e_minalloc; Minimum extra paragraphs needed */ - 0xFFFF, /*WORD e_maxalloc; Maximum extra paragraphs needed */ - 0x0000, /*WORD e_ss; Initial (relative) SS value */ - - 0x00B8, /*WORD e_sp; Initial SP value */ - 0x0000, /*WORD e_csum; Checksum */ - 0x0000, /*WORD e_ip; Initial IP value */ - 0x0000, /*WORD e_cs; Initial (relative) CS value */ - 0x0040, /*WORD e_lfarlc; File address of relocation table */ - 0x0000, /*WORD e_ovno; Overlay number */ - {0,0,0,0}, /*WORD e_res[4]; Reserved words */ - 0x0000, /*WORD e_oemid; OEM identifier (for e_oeminfo) */ - 0x0000, /*WORD e_oeminfo; OEM information; e_oemid specific */ - {0,0,0,0,0,0,0,0,0,0}, /*WORD e_res2[10]; Reserved words */ - 0x00000080 /*DWORD e_lfanew; File address of new exe header */ - },{ - /* BYTE dosstub[0x40] */ - /* 14 code bytes + "This program cannot be run in DOS mode.\r\r\n$" + 6 * 0x00 */ - 0x0e,0x1f,0xba,0x0e,0x00,0xb4,0x09,0xcd,0x21,0xb8,0x01,0x4c,0xcd,0x21,0x54,0x68, - 0x69,0x73,0x20,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x20,0x63,0x61,0x6e,0x6e,0x6f, - 0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6e,0x20,0x69,0x6e,0x20,0x44,0x4f,0x53,0x20, - 0x6d,0x6f,0x64,0x65,0x2e,0x0d,0x0d,0x0a,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - }, - 0x00004550, /* DWORD nt_sig = IMAGE_NT_SIGNATURE */ - { - /* IMAGE_FILE_HEADER filehdr */ - IMAGE_FILE_MACHINE, /*WORD Machine; */ - 0x0003, /*WORD NumberOfSections; */ - 0x00000000, /*DWORD TimeDateStamp; */ - 0x00000000, /*DWORD PointerToSymbolTable; */ - 0x00000000, /*DWORD NumberOfSymbols; */ -#if defined(TCC_TARGET_X86_64) - 0x00F0, /*WORD SizeOfOptionalHeader; */ - 0x022F /*WORD Characteristics; */ -#define CHARACTERISTICS_DLL 0x222E -#elif defined(TCC_TARGET_I386) - 0x00E0, /*WORD SizeOfOptionalHeader; */ - 0x030F /*WORD Characteristics; */ -#define CHARACTERISTICS_DLL 0x230E -#elif defined(TCC_TARGET_ARM) - 0x00E0, /*WORD SizeOfOptionalHeader; */ - 0x010F, /*WORD Characteristics; */ -#define CHARACTERISTICS_DLL 0x230F -#endif -},{ - /* IMAGE_OPTIONAL_HEADER opthdr */ - /* Standard fields. */ -#ifdef TCC_TARGET_X86_64 - 0x020B, /*WORD Magic; */ -#else - 0x010B, /*WORD Magic; */ -#endif - 0x06, /*BYTE MajorLinkerVersion; */ - 0x00, /*BYTE MinorLinkerVersion; */ - 0x00000000, /*DWORD SizeOfCode; */ - 0x00000000, /*DWORD SizeOfInitializedData; */ - 0x00000000, /*DWORD SizeOfUninitializedData; */ - 0x00000000, /*DWORD AddressOfEntryPoint; */ - 0x00000000, /*DWORD BaseOfCode; */ -#ifndef TCC_TARGET_X86_64 - 0x00000000, /*DWORD BaseOfData; */ -#endif - /* NT additional fields. */ -#if defined(TCC_TARGET_ARM) - 0x00100000, /*DWORD ImageBase; */ -#else - 0x00400000, /*DWORD ImageBase; */ -#endif - 0x00001000, /*DWORD SectionAlignment; */ - 0x00000200, /*DWORD FileAlignment; */ - 0x0004, /*WORD MajorOperatingSystemVersion; */ - 0x0000, /*WORD MinorOperatingSystemVersion; */ - 0x0000, /*WORD MajorImageVersion; */ - 0x0000, /*WORD MinorImageVersion; */ - 0x0004, /*WORD MajorSubsystemVersion; */ - 0x0000, /*WORD MinorSubsystemVersion; */ - 0x00000000, /*DWORD Win32VersionValue; */ - 0x00000000, /*DWORD SizeOfImage; */ - 0x00000200, /*DWORD SizeOfHeaders; */ - 0x00000000, /*DWORD CheckSum; */ - 0x0002, /*WORD Subsystem; */ - 0x0000, /*WORD DllCharacteristics; */ - 0x00100000, /*DWORD SizeOfStackReserve; */ - 0x00001000, /*DWORD SizeOfStackCommit; */ - 0x00100000, /*DWORD SizeOfHeapReserve; */ - 0x00001000, /*DWORD SizeOfHeapCommit; */ - 0x00000000, /*DWORD LoaderFlags; */ - 0x00000010, /*DWORD NumberOfRvaAndSizes; */ - - /* IMAGE_DATA_DIRECTORY DataDirectory[16]; */ - {{0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, - {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}} - }}; - - struct pe_header pe_header = pe_template; - - int i; - struct pe_file pf = {0}; - DWORD file_offset; - struct section_info *si; - IMAGE_SECTION_HEADER *psh; - TCCState *s1 = pe->s1; - - pf.op = fopen(pe->filename, "wb"); - if (NULL == pf.op) - return tcc_error_noabort("could not write '%s': %s", pe->filename, strerror(errno)); - - pe->sizeofheaders = pe_file_align(pe, - sizeof (struct pe_header) - + pe->sec_count * sizeof (IMAGE_SECTION_HEADER) - ); - - file_offset = pe->sizeofheaders; - - if (2 == pe->s1->verbose) - printf("-------------------------------" - "\n virt file size section" "\n"); - for (i = 0; i < pe->sec_count; ++i) { - DWORD addr, size; - const char *sh_name; - - si = pe->sec_info[i]; - sh_name = si->name; - addr = si->sh_addr - pe->imagebase; - size = si->sh_size; - psh = &si->ish; - - if (2 == pe->s1->verbose) - printf("%6x %6x %6x %s\n", - (unsigned)addr, (unsigned)file_offset, (unsigned)size, sh_name); - - switch (si->cls) { - case sec_text: - if (!pe_header.opthdr.BaseOfCode) - pe_header.opthdr.BaseOfCode = addr; - break; - - case sec_data: -#ifndef TCC_TARGET_X86_64 - if (!pe_header.opthdr.BaseOfData) - pe_header.opthdr.BaseOfData = addr; -#endif - break; - - case sec_bss: - break; - - case sec_reloc: - pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_BASERELOC, addr, size); - break; - - case sec_rsrc: - pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_RESOURCE, addr, size); - break; - - case sec_pdata: - pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXCEPTION, addr, size); - break; - } - - if (pe->imp_size) { - pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IMPORT, - pe->imp_offs, pe->imp_size); - pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IAT, - pe->iat_offs, pe->iat_size); - } - if (pe->exp_size) { - pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXPORT, - pe->exp_offs, pe->exp_size); - } - - memcpy(psh->Name, sh_name, umin(strlen(sh_name), sizeof psh->Name)); - - psh->Characteristics = si->pe_flags; - psh->VirtualAddress = addr; - psh->Misc.VirtualSize = size; - pe_header.opthdr.SizeOfImage = - umax(pe_virtual_align(pe, size + addr), pe_header.opthdr.SizeOfImage); - - if (si->data_size) { - 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; - if (pe->s1->pe_stack_size) - 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; - - pe_fwrite(&pe_header, sizeof pe_header, &pf); - for (i = 0; i < pe->sec_count; ++i) - pe_fwrite(&pe->sec_info[i]->ish, sizeof(IMAGE_SECTION_HEADER), &pf); - - file_offset = pe->sizeofheaders; - for (i = 0; i < pe->sec_count; ++i) { - Section *s; - si = pe->sec_info[i]; - if (!si->data_size) - continue; - for (s = si->sec; s; s = s->prev) { - pe_fpad(&pf, file_offset); - pe_fwrite(s->data, s->data_offset, &pf); - if (s->prev) - file_offset += s->prev->sh_addr - s->sh_addr; - } - file_offset = si->ish.PointerToRawData + si->ish.SizeOfRawData; - pe_fpad(&pf, file_offset); - } - - pf.sum += file_offset; - fseek(pf.op, offsetof(struct pe_header, opthdr.CheckSum), SEEK_SET); - pe_fwrite(&pf.sum, sizeof (DWORD), &pf); - - fclose (pf.op); -#ifndef _WIN32 - chmod(pe->filename, 0777); -#endif - - if (2 == pe->s1->verbose) - printf("-------------------------------\n"); - if (pe->s1->verbose) - printf("<- %s (%u bytes)\n", pe->filename, (unsigned)file_offset); - - return 0; -} - -/*----------------------------------------------------------------------------*/ - -static struct import_symbol *pe_add_import(struct pe_info *pe, int sym_index) -{ - int i; - int dll_index; - struct pe_import_info *p; - struct import_symbol *s; - ElfW(Sym) *isym; - - isym = (ElfW(Sym) *)pe->s1->dynsymtab_section->data + sym_index; - dll_index = isym->st_size; - - i = dynarray_assoc ((void**)pe->imp_info, pe->imp_count, dll_index); - if (-1 != i) { - p = pe->imp_info[i]; - goto found_dll; - } - p = tcc_mallocz(sizeof *p); - p->dll_index = dll_index; - dynarray_add(&pe->imp_info, &pe->imp_count, p); - -found_dll: - i = dynarray_assoc ((void**)p->symbols, p->sym_count, sym_index); - if (-1 != i) - return p->symbols[i]; - - s = tcc_mallocz(sizeof *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) -{ - int thk_ptr, ent_ptr, dll_ptr, sym_cnt, i; - DWORD rva_base = pe->thunk->sh_addr - pe->imagebase; - int ndlls = pe->imp_count; - TCCState *s1 = pe->s1; - - for (sym_cnt = i = 0; i < ndlls; ++i) - sym_cnt += pe->imp_info[i]->sym_count; - - if (0 == sym_cnt) - return; - - pe_align_section(pe->thunk, 16); - pe->imp_size = (ndlls + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR); - pe->iat_size = (sym_cnt + ndlls) * sizeof(ADDR3264); - dll_ptr = pe->thunk->data_offset; - thk_ptr = dll_ptr + pe->imp_size; - ent_ptr = thk_ptr + pe->iat_size; - pe->imp_offs = dll_ptr + rva_base; - pe->iat_offs = thk_ptr + rva_base; - section_ptr_add(pe->thunk, pe->imp_size + 2*pe->iat_size); - - for (i = 0; i < pe->imp_count; ++i) { - IMAGE_IMPORT_DESCRIPTOR *hdr; - int k, n, dllindex; - ADDR3264 v; - struct pe_import_info *p = pe->imp_info[i]; - const char *name; - DLLReference *dllref; - - dllindex = p->dll_index; - if (dllindex) - name = tcc_basename((dllref = pe->s1->loaded_dlls[dllindex-1])->name); - else - name = "", dllref = NULL; - - /* put the dll name into the import header */ - v = put_elf_str(pe->thunk, name); - hdr = (IMAGE_IMPORT_DESCRIPTOR*)(pe->thunk->data + dll_ptr); - hdr->FirstThunk = thk_ptr + rva_base; - hdr->OriginalFirstThunk = ent_ptr + rva_base; - hdr->Name = v + rva_base; - - for (k = 0, n = p->sym_count; k <= n; ++k) { - if (k < n) { - int iat_index = p->symbols[k]->iat_index; - int sym_index = p->symbols[k]->sym_index; - 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 = (char*)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; - - 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) { - if (dllref) { - if ( !dllref->handle ) - dllref->handle = LoadLibrary(dllref->name); - v = (ADDR3264)GetProcAddress(dllref->handle, ordinal?(char*)0+ordinal:name); - } - if (!v) - tcc_error_noabort("could not resolve 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); - } -} - -/* ------------------------------------------------------------- */ - -struct pe_sort_sym -{ - int index; - const char *name; -}; - -static int sym_cmp(const void *va, const void *vb) -{ - const char *ca = (*(struct pe_sort_sym**)va)->name; - const char *cb = (*(struct pe_sort_sym**)vb)->name; - return strcmp(ca, cb); -} - -static void pe_build_exports(struct pe_info *pe) -{ - ElfW(Sym) *sym; - int sym_index, sym_end; - DWORD rva_base, base_o, func_o, name_o, ord_o, str_o; - IMAGE_EXPORT_DIRECTORY *hdr; - int sym_count, ord; - struct pe_sort_sym **sorted, *p; - TCCState *s1 = pe->s1; - - FILE *op; - char buf[260]; - const char *dllname; - const char *name; - - rva_base = pe->thunk->sh_addr - pe->imagebase; - sym_count = 0, sorted = NULL, op = NULL; - - sym_end = symtab_section->data_offset / sizeof(ElfW(Sym)); - 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 & ST_PE_EXPORT) { - p = tcc_malloc(sizeof *p); - p->index = sym_index; - p->name = name; - dynarray_add(&sorted, &sym_count, p); - } -#if 0 - if (sym->st_other & ST_PE_EXPORT) - printf("export: %s\n", name); - if (sym->st_other & ST_PE_STDCALL) - printf("stdcall: %s\n", name); -#endif - } - - if (0 == sym_count) - return; - - qsort (sorted, sym_count, sizeof *sorted, sym_cmp); - - pe_align_section(pe->thunk, 16); - dllname = tcc_basename(pe->filename); - - base_o = pe->thunk->data_offset; - func_o = base_o + sizeof(IMAGE_EXPORT_DIRECTORY); - name_o = func_o + sym_count * sizeof (DWORD); - ord_o = name_o + sym_count * sizeof (DWORD); - str_o = ord_o + sym_count * sizeof(WORD); - - hdr = section_ptr_add(pe->thunk, str_o - base_o); - hdr->Characteristics = 0; - hdr->Base = 1; - hdr->NumberOfFunctions = sym_count; - hdr->NumberOfNames = sym_count; - hdr->AddressOfFunctions = func_o + rva_base; - hdr->AddressOfNames = name_o + rva_base; - hdr->AddressOfNameOrdinals = ord_o + rva_base; - hdr->Name = str_o + rva_base; - put_elf_str(pe->thunk, dllname); - -#if 1 - /* automatically write exports to <output-filename>.def */ - pstrcpy(buf, sizeof buf, pe->filename); - strcpy(tcc_fileextension(buf), ".def"); - op = fopen(buf, "wb"); - if (NULL == op) { - tcc_error_noabort("could not create '%s': %s", buf, strerror(errno)); - } else { - fprintf(op, "LIBRARY %s\n\nEXPORTS\n", dllname); - if (pe->s1->verbose) - printf("<- %s (%d symbol%s)\n", buf, sym_count, &"s"[sym_count < 2]); - } -#endif - - for (ord = 0; ord < sym_count; ++ord) - { - p = sorted[ord], sym_index = p->index, name = p->name; - /* insert actual address later in relocate_sections() */ - put_elf_reloc(symtab_section, pe->thunk, - func_o, R_XXX_RELATIVE, sym_index); - *(DWORD*)(pe->thunk->data + name_o) - = pe->thunk->data_offset + rva_base; - *(WORD*)(pe->thunk->data + ord_o) - = ord; - put_elf_str(pe->thunk, name); - func_o += sizeof (DWORD); - name_o += sizeof (DWORD); - ord_o += sizeof (WORD); - if (op) - fprintf(op, "%s\n", name); - } - - pe->exp_offs = base_o + rva_base; - pe->exp_size = pe->thunk->data_offset - base_o; - dynarray_reset(&sorted, &sym_count); - if (op) - fclose(op); -} - -/* ------------------------------------------------------------- */ -static void pe_build_reloc (struct pe_info *pe) -{ - DWORD offset, block_ptr, sh_addr, addr; - int count, i; - ElfW_Rel *rel, *rel_end; - Section *s = NULL, *sr; - struct pe_reloc_header *hdr; - - sh_addr = offset = block_ptr = count = i = 0; - rel = rel_end = NULL; - - for(;;) { - if (rel < rel_end) { - int type = ELFW(R_TYPE)(rel->r_info); - addr = rel->r_offset + sh_addr; - ++ rel; - if (type != REL_TYPE_DIRECT) - continue; - if (count == 0) { /* new block */ - block_ptr = pe->reloc->data_offset; - section_ptr_add(pe->reloc, sizeof(struct pe_reloc_header)); - offset = addr & 0xFFFFFFFF<<12; - } - if ((addr -= offset) < (1<<12)) { /* one block spans 4k addresses */ - WORD *wp = section_ptr_add(pe->reloc, sizeof (WORD)); - *wp = addr | PE_IMAGE_REL<<12; - ++count; - continue; - } - -- rel; - - } else if (s) { - sr = s->reloc; - if (sr) { - rel = (ElfW_Rel *)sr->data; - rel_end = (ElfW_Rel *)(sr->data + sr->data_offset); - sh_addr = s->sh_addr; - } - s = s->prev; - continue; - - } else if (i < pe->sec_count) { - s = pe->sec_info[i]->sec, ++i; - continue; - - } else if (!count) - break; - - /* fill the last block and ready for a new one */ - if (count & 1) /* align for DWORDS */ - section_ptr_add(pe->reloc, sizeof(WORD)), ++count; - hdr = (struct pe_reloc_header *)(pe->reloc->data + block_ptr); - hdr -> offset = offset - pe->imagebase; - hdr -> size = count * sizeof(WORD) + sizeof(struct pe_reloc_header); - count = 0; - } -} - -/* ------------------------------------------------------------- */ -static int pe_section_class(Section *s) -{ - int type, flags; - const char *name; - type = s->sh_type; - flags = s->sh_flags; - name = s->name; - if (0 == memcmp(name, ".stab", 5)) { - if (0 == s->s1->do_debug) - return sec_last; - return name[5] ? sec_stabstr : sec_stab; - } - if (flags & SHF_ALLOC) { - if (type == SHT_PROGBITS - || type == SHT_INIT_ARRAY - || type == SHT_FINI_ARRAY) { - if (flags & SHF_EXECINSTR) - return sec_text; - if (flags & SHF_WRITE) - return sec_data; - if (0 == strcmp(name, ".rsrc")) - return sec_rsrc; - if (0 == strcmp(name, ".iedat")) - return sec_idata; - if (0 == strcmp(name, ".pdata")) - return sec_pdata; - return sec_rdata; - } else if (type == SHT_NOBITS) { - return sec_bss; - } - return sec_other; - } else { - if (0 == strcmp(name, ".reloc")) - return sec_reloc; - } - return sec_last; -} - -static int pe_assign_addresses (struct pe_info *pe) -{ - int i, k, n, c, nbs; - ADDR3264 addr; - int *sec_order, *sec_cls; - struct section_info *si; - Section *s; - TCCState *s1 = pe->s1; - - 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); - - nbs = s1->nb_sections; - sec_order = tcc_mallocz(2 * sizeof (int) * nbs); - sec_cls = sec_order + nbs; - for (i = 1; i < nbs; ++i) { - s = s1->sections[i]; - k = pe_section_class(s); - for (n = i; n > 1 && k < (c = sec_cls[n - 1]); --n) - sec_cls[n] = c, sec_order[n] = sec_order[n - 1]; - sec_cls[n] = k, sec_order[n] = i; - } - si = NULL; - addr = pe->imagebase + 1; - - for (i = 1; (c = sec_cls[i]) < sec_last; ++i) { - s = s1->sections[sec_order[i]]; - - if (PE_MERGE_DATA && c == sec_bss) - c = sec_data; - - if (si && c == si->cls) { - /* merge with previous section */ - s->sh_addr = addr = ((addr - 1) | (16 - 1)) + 1; - } else { - si = NULL; - s->sh_addr = addr = pe_virtual_align(pe, addr); - } - - if (NULL == pe->thunk - && c == (data_section == rodata_section ? sec_data : sec_rdata)) - pe->thunk = s; - - if (s == pe->thunk) { - pe_build_imports(pe); - pe_build_exports(pe); - } - if (s == pe->reloc) - pe_build_reloc (pe); - - if (0 == s->data_offset) - continue; - - if (si) - goto add_section; - - si = tcc_mallocz(sizeof *si); - dynarray_add(&pe->sec_info, &pe->sec_count, si); - - strcpy(si->name, s->name); - si->cls = c; - si->sh_addr = addr; - - si->pe_flags = IMAGE_SCN_MEM_READ; - if (s->sh_flags & SHF_EXECINSTR) - si->pe_flags |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE; - else if (s->sh_type == SHT_NOBITS) - si->pe_flags |= IMAGE_SCN_CNT_UNINITIALIZED_DATA; - else - si->pe_flags |= IMAGE_SCN_CNT_INITIALIZED_DATA; - if (s->sh_flags & SHF_WRITE) - si->pe_flags |= IMAGE_SCN_MEM_WRITE; - if (0 == (s->sh_flags & SHF_ALLOC)) - si->pe_flags |= IMAGE_SCN_MEM_DISCARDABLE; - -add_section: - addr += s->data_offset; - si->sh_size = addr - si->sh_addr; - if (s->sh_type != SHT_NOBITS) { - Section **ps = &si->sec; - while (*ps) - ps = &(*ps)->prev; - *ps = s, s->prev = NULL; - si->data_size = si->sh_size; - } - //printf("%08x %05x %08x %s\n", si->sh_addr, si->sh_size, si->pe_flags, s->name); - } -#if 0 - for (i = 1; i < nbs; ++i) { - Section *s = s1->sections[sec_order[i]]; - int type = s->sh_type; - int flags = s->sh_flags; - printf("section %-16s %-10s %p %04x %s,%s,%s\n", - s->name, - type == SHT_PROGBITS ? "progbits" : - type == SHT_INIT_ARRAY ? "initarr" : - type == SHT_FINI_ARRAY ? "finiarr" : - type == SHT_NOBITS ? "nobits" : - type == SHT_SYMTAB ? "symtab" : - type == SHT_STRTAB ? "strtab" : - type == SHT_RELX ? "rel" : "???", - s->sh_addr, - (unsigned)s->data_offset, - flags & SHF_ALLOC ? "alloc" : "", - flags & SHF_WRITE ? "write" : "", - flags & SHF_EXECINSTR ? "exec" : "" - ); - fflush(stdout); - } - s1->verbose = 2; -#endif - tcc_free(sec_order); - return 0; -} - -/*----------------------------------------------------------------------------*/ - -static int pe_isafunc(TCCState *s1, int sym_index) -{ - Section *sr = text_section->reloc; - ElfW_Rel *rel, *rel_end; - ElfW(Addr)info = ELFW(R_INFO)(sym_index, R_XXX_FUNCCALL); -#ifdef R_XXX_FUNCCALL2 - ElfW(Addr)info2 = ELFW(R_INFO)(sym_index, R_XXX_FUNCCALL2); -#endif - if (!sr) - return 0; - rel_end = (ElfW_Rel *)(sr->data + sr->data_offset); - for (rel = (ElfW_Rel *)sr->data; rel < rel_end; rel++) { - if (rel->r_info == info) - return 1; -#ifdef R_XXX_FUNCCALL2 - if (rel->r_info == info2) - return 1; -#endif - } - return 0; -} - -/*----------------------------------------------------------------------------*/ -static int pe_check_symbols(struct pe_info *pe) -{ - ElfW(Sym) *sym; - int sym_index, sym_end; - int ret = 0; - TCCState *s1 = pe->s1; - - pe_align_section(text_section, 8); - - sym_end = symtab_section->data_offset / sizeof(ElfW(Sym)); - for (sym_index = 1; sym_index < sym_end; ++sym_index) { - - sym = (ElfW(Sym) *)symtab_section->data + sym_index; - if (sym->st_shndx == SHN_UNDEF) { - - const char *name = (char*)symtab_section->link->data + sym->st_name; - unsigned type = ELFW(ST_TYPE)(sym->st_info); - int imp_sym = pe_find_import(pe->s1, sym); - struct import_symbol *is; - - if (imp_sym <= 0) - goto not_found; - - if (type == STT_NOTYPE) { - /* symbols from assembler have no type, find out which */ - if (pe_isafunc(s1, sym_index)) - type = STT_FUNC; - else - type = STT_OBJECT; - } - - is = pe_add_import(pe, imp_sym); - - if (type == STT_FUNC) { - unsigned offset = is->thk_offset; - if (offset) { - /* got aliased symbol, like stricmp and _stricmp */ - } else { - char buffer[100]; - unsigned char *p; - - /* add a helper symbol, will be patched later in - pe_build_imports */ - sprintf(buffer, "IAT.%s", name); - is->iat_index = put_elf_sym( - symtab_section, 0, sizeof(DWORD), - ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT), - 0, SHN_UNDEF, buffer); - - offset = text_section->data_offset; - is->thk_offset = offset; - - /* add the 'jmp IAT[x]' instruction */ -#ifdef TCC_TARGET_ARM - p = section_ptr_add(text_section, 8+4); // room for code and address - write32le(p + 0, 0xE59FC000); // arm code ldr ip, [pc] ; PC+8+0 = 0001xxxx - write32le(p + 4, 0xE59CF000); // arm code ldr pc, [ip] - put_elf_reloc(symtab_section, text_section, - offset + 8, R_XXX_THUNKFIX, is->iat_index); // offset to IAT position -#else - p = section_ptr_add(text_section, 8); - write16le(p, 0x25FF); -#ifdef TCC_TARGET_X86_64 - write32le(p + 2, (DWORD)-4); -#endif - put_elf_reloc(symtab_section, text_section, - offset + 2, R_XXX_THUNKFIX, is->iat_index); -#endif - } - /* tcc_realloc might have altered sym's address */ - sym = (ElfW(Sym) *)symtab_section->data + sym_index; - - /* patch the original symbol */ - sym->st_value = offset; - sym->st_shndx = text_section->sh_num; - sym->st_other &= ~ST_PE_EXPORT; /* do not export */ - continue; - } - - if (type == STT_OBJECT) { /* data, ptr to that should be */ - if (0 == is->iat_index) { - /* original symbol will be patched later in pe_build_imports */ - is->iat_index = sym_index; - continue; - } - } - - not_found: - if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK) - /* STB_WEAK undefined symbols are accepted */ - continue; - ret = tcc_error_noabort("undefined symbol '%s'%s", name, - imp_sym < 0 ? ", missing __declspec(dllimport)?":""); - - } 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 |= ST_PE_EXPORT; - } - } - return ret; -} - -/*----------------------------------------------------------------------------*/ -#if PE_PRINT_SECTIONS -static void pe_print_section(FILE * f, Section * s) -{ - /* just if you're curious */ - BYTE *p, *e, b; - int i, n, l, m; - p = s->data; - e = s->data + s->data_offset; - l = e - p; - - fprintf(f, "section \"%s\"", s->name); - if (s->link) - fprintf(f, "\nlink \"%s\"", s->link->name); - if (s->reloc) - fprintf(f, "\nreloc \"%s\"", s->reloc->name); - fprintf(f, "\nv_addr %08X", (unsigned)s->sh_addr); - fprintf(f, "\ncontents %08X", (unsigned)l); - fprintf(f, "\n\n"); - - if (s->sh_type == SHT_NOBITS) - return; - - if (0 == l) - return; - - if (s->sh_type == SHT_SYMTAB) - m = sizeof(ElfW(Sym)); - else if (s->sh_type == SHT_RELX) - m = sizeof(ElfW_Rel); - else - m = 16; - - fprintf(f, "%-8s", "offset"); - for (i = 0; i < m; ++i) - fprintf(f, " %02x", i); - n = 56; - - if (s->sh_type == SHT_SYMTAB || s->sh_type == SHT_RELX) { - const char *fields1[] = { - "name", - "value", - "size", - "bind", - "type", - "other", - "shndx", - NULL - }; - - const char *fields2[] = { - "offs", - "type", - "symb", - NULL - }; - - const char **p; - - if (s->sh_type == SHT_SYMTAB) - p = fields1, n = 106; - else - p = fields2, n = 58; - - for (i = 0; p[i]; ++i) - fprintf(f, "%6s", p[i]); - fprintf(f, " symbol"); - } - - fprintf(f, "\n"); - for (i = 0; i < n; ++i) - fprintf(f, "-"); - fprintf(f, "\n"); - - for (i = 0; i < l;) - { - fprintf(f, "%08X", i); - for (n = 0; n < m; ++n) { - if (n + i < l) - fprintf(f, " %02X", p[i + n]); - else - fprintf(f, " "); - } - - if (s->sh_type == SHT_SYMTAB) { - ElfW(Sym) *sym = (ElfW(Sym) *) (p + i); - const char *name = s->link->data + sym->st_name; - fprintf(f, " %04X %04X %04X %02X %02X %02X %04X \"%s\"", - (unsigned)sym->st_name, - (unsigned)sym->st_value, - (unsigned)sym->st_size, - (unsigned)ELFW(ST_BIND)(sym->st_info), - (unsigned)ELFW(ST_TYPE)(sym->st_info), - (unsigned)sym->st_other, - (unsigned)sym->st_shndx, - name); - - } else if (s->sh_type == SHT_RELX) { - ElfW_Rel *rel = (ElfW_Rel *) (p + i); - ElfW(Sym) *sym = - (ElfW(Sym) *) s->link->data + ELFW(R_SYM)(rel->r_info); - const char *name = s->link->link->data + sym->st_name; - fprintf(f, " %04X %02X %04X \"%s\"", - (unsigned)rel->r_offset, - (unsigned)ELFW(R_TYPE)(rel->r_info), - (unsigned)ELFW(R_SYM)(rel->r_info), - name); - } else { - fprintf(f, " "); - for (n = 0; n < m; ++n) { - if (n + i < l) { - b = p[i + n]; - if (b < 32 || b >= 127) - b = '.'; - fprintf(f, "%c", b); - } - } - } - i += m; - fprintf(f, "\n"); - } - fprintf(f, "\n\n"); -} - -static void pe_print_sections(TCCState *s1, const char *fname) -{ - Section *s; - FILE *f; - int i; - f = fopen(fname, "w"); - for (i = 1; i < s1->nb_sections; ++i) { - s = s1->sections[i]; - pe_print_section(f, s); - } - pe_print_section(f, s1->dynsymtab_section); - fclose(f); -} -#endif - -/* ------------------------------------------------------------- */ -/* helper function for load/store to insert one more indirection */ - -#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 -ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2) -{ - int r2; - if ((sv->r & (VT_VALMASK|VT_SYM)) != (VT_CONST|VT_SYM) || (sv->r2 != VT_CONST)) - return sv; - if (!sv->sym->a.dllimport) - return sv; - // 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; - v2->sym = sv->sym; - - r2 = get_reg(RC_INT); - load(r2, v2); - v2->r = r2; - if ((uint32_t)sv->c.i) { - vpushv(v2); - 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 set_elf_sym( - s1->dynsymtab_section, - value, - dllindex, /* st_size */ - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), - 0, - value ? SHN_ABS : SHN_UNDEF, - name - ); -} - -static int read_mem(int fd, unsigned offset, void *buffer, unsigned len) -{ - lseek(fd, offset, SEEK_SET); - return len == read(fd, buffer, len); -} - -/* ------------------------------------------------------------- */ - -static int get_dllexports(int fd, char **pp) -{ - int l, i, n, n0, ret; - char *p; - - IMAGE_SECTION_HEADER ish; - IMAGE_EXPORT_DIRECTORY ied; - IMAGE_DOS_HEADER dh; - IMAGE_FILE_HEADER ih; - DWORD sig, ref, addr, ptr, namep; - - int pef_hdroffset, opt_hdroffset, sec_hdroffset; - - n = n0 = 0; - p = NULL; - 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; - opt_hdroffset = pef_hdroffset + sizeof ih; - if (ih.Machine == 0x014C) { - IMAGE_OPTIONAL_HEADER32 oh; - 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; - } else if (ih.Machine == 0x8664) { - IMAGE_OPTIONAL_HEADER64 oh; - 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; - } else - goto the_end; - - //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: - *pp = p; - return ret; -} - -/* ------------------------------------------------------------- - * This is for compiled windows resources in 'coff' format - * as generated by 'windres.exe -O coff ...'. - */ - -static int pe_load_res(TCCState *s1, int fd) -{ - struct pe_rsrc_header hdr; - Section *rsrc_section; - int i, ret = -1, sym_index; - BYTE *ptr; - unsigned offs; - - if (!read_mem(fd, 0, &hdr, sizeof hdr)) - goto quit; - - if (hdr.filehdr.Machine != IMAGE_FILE_MACHINE - || hdr.filehdr.NumberOfSections != 1 - || strcmp((char*)hdr.sectionhdr.Name, ".rsrc") != 0) - goto quit; - - rsrc_section = new_section(s1, ".rsrc", SHT_PROGBITS, SHF_ALLOC); - ptr = section_ptr_add(rsrc_section, hdr.sectionhdr.SizeOfRawData); - offs = hdr.sectionhdr.PointerToRawData; - if (!read_mem(fd, offs, ptr, hdr.sectionhdr.SizeOfRawData)) - goto quit; - offs = hdr.sectionhdr.PointerToRelocations; - sym_index = put_elf_sym(symtab_section, 0, 0, 0, 0, rsrc_section->sh_num, ".rsrc"); - for (i = 0; i < hdr.sectionhdr.NumberOfRelocations; ++i) { - struct pe_rsrc_reloc rel; - 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 != RSRC_RELTYPE) - goto quit; - put_elf_reloc(symtab_section, rsrc_section, - rel.offset, R_XXX_RELATIVE, sym_index); - offs += sizeof rel; - } - ret = 0; -quit: - return ret; -} - -/* ------------------------------------------------------------- */ - -static char *trimfront(char *p) -{ - while ((unsigned char)*p <= ' ' && *p && *p != '\n') - ++p; - return p; -} - -/* -static char *trimback(char *a, char *e) -{ - while (e > a && (unsigned char)e[-1] <= ' ') - --e; - *e = 0;; - return a; -}*/ - -static char *get_token(char **s, char *f) -{ - char *p = *s, *e; - p = e = trimfront(p); - while ((unsigned char)*e > ' ') - ++e; - *s = trimfront(e); - *f = **s; *e = 0; - return p; -} - -static int pe_load_def(TCCState *s1, int fd) -{ - int state = 0, ret = -1, dllindex = 0, ord; - char dllname[80], *buf, *line, *p, *x, next; - - buf = tcc_load_text(fd); - for (line = buf;; ++line) { - p = get_token(&line, &next); - if (!(*p && *p != ';')) - goto skip; - switch (state) { - case 0: - if (0 != stricmp(p, "LIBRARY") || next == '\n') - goto quit; - pstrcpy(dllname, sizeof dllname, get_token(&line, &next)); - ++state; - break; - case 1: - if (0 != stricmp(p, "EXPORTS")) - goto quit; - ++state; - break; - case 2: - dllindex = tcc_add_dllref(s1, dllname, 0)->index; - ++state; - /* fall through */ - default: - /* get ordinal and will store in sym->st_value */ - ord = 0; - if (next == '@') { - x = get_token(&line, &next); - ord = (int)strtol(x + 1, &x, 10); - } - //printf("token %s ; %s : %d\n", dllname, p, ord); - pe_putimport(s1, dllindex, p, ord); - break; - } -skip: - while ((unsigned char)next > ' ') - get_token(&line, &next); - if (next != '\n') - break; - } - ret = 0; -quit: - tcc_free(buf); - return ret; -} - -/* ------------------------------------------------------------- */ - -static int pe_load_dll(TCCState *s1, int fd, const char *filename) -{ - char *p, *q; - int index, ret; - - ret = get_dllexports(fd, &p); - if (ret) { - return -1; - } else if (p) { - index = tcc_add_dllref(s1, filename, 0)->index; - for (q = p; *q; q += 1 + strlen(q)) - pe_putimport(s1, index, q, 0); - tcc_free(p); - } - return 0; -} - -ST_FUNC int pe_load_file(struct TCCState *s1, int fd, const char *filename) -{ - int ret = -1; - char buf[10]; - if (0 == strcmp(tcc_fileextension(filename), ".def")) - ret = pe_load_def(s1, fd); - else if (pe_load_res(s1, fd) == 0) - ret = 0; - else if (read_mem(fd, 0, buf, 4) && 0 == memcmp(buf, "MZ", 2)) - ret = pe_load_dll(s1, fd, filename); - return ret; -} - -PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp) -{ - int ret, fd = open(filename, O_RDONLY | O_BINARY); - if (fd < 0) - return -1; - ret = get_dllexports(fd, pp); - close(fd); - return ret; -} - -/* ------------------------------------------------------------- */ -#ifdef TCC_TARGET_X86_64 -static unsigned pe_add_uwwind_info(TCCState *s1) -{ - if (NULL == s1->uw_pdata) { - s1->uw_pdata = find_section(s1, ".pdata"); - s1->uw_pdata->sh_addralign = 4; - } - if (0 == s1->uw_sym) - s1->uw_sym = put_elf_sym(symtab_section, 0, 0, 0, 0, text_section->sh_num, ".uw_base"); - if (0 == s1->uw_offs) { - /* As our functions all have the same stackframe, we use one entry for all */ - static const unsigned char uw_info[] = { - 0x01, // UBYTE: 3 Version , UBYTE: 5 Flags - 0x04, // UBYTE Size of prolog - 0x02, // UBYTE Count of unwind codes - 0x05, // UBYTE: 4 Frame Register (rbp), UBYTE: 4 Frame Register offset (scaled) - // USHORT * n Unwind codes array - // 0x0b, 0x01, 0xff, 0xff, // stack size - 0x04, 0x03, // set frame ptr (mov rsp -> rbp) - 0x01, 0x50 // push reg (rbp) - }; - - Section *s = text_section; - unsigned char *p; - - section_ptr_add(s, -s->data_offset & 3); /* align */ - s1->uw_offs = s->data_offset; - p = section_ptr_add(s, sizeof uw_info); - memcpy(p, uw_info, sizeof uw_info); - } - - return s1->uw_offs; -} - -ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack) -{ - TCCState *s1 = tcc_state; - Section *pd; - unsigned o, n, d; - struct /* _RUNTIME_FUNCTION */ { - DWORD BeginAddress; - DWORD EndAddress; - DWORD UnwindData; - } *p; - - d = pe_add_uwwind_info(s1); - pd = s1->uw_pdata; - o = pd->data_offset; - p = section_ptr_add(pd, sizeof *p); - - /* record this function */ - p->BeginAddress = start; - p->EndAddress = end; - p->UnwindData = d; - - /* put relocations on it */ - for (n = o + sizeof *p; o < n; o += sizeof p->BeginAddress) - put_elf_reloc(symtab_section, pd, o, R_XXX_RELATIVE, s1->uw_sym); -} -#endif -/* ------------------------------------------------------------- */ -#ifdef TCC_TARGET_X86_64 -#define PE_STDSYM(n,s) n -#else -#define PE_STDSYM(n,s) "_" n s -#endif - -static void pe_add_runtime(TCCState *s1, struct pe_info *pe) -{ - const char *start_symbol; - int pe_type; - - if (TCC_OUTPUT_DLL == s1->output_type) { - pe_type = PE_DLL; - start_symbol = PE_STDSYM("__dllstart","@12"); - } else { - const char *run_symbol; - if (find_elf_sym(symtab_section, PE_STDSYM("WinMain","@16"))) { - start_symbol = "__winstart"; - run_symbol = "__runwinmain"; - pe_type = PE_GUI; - } else if (find_elf_sym(symtab_section, PE_STDSYM("wWinMain","@16"))) { - start_symbol = "__wwinstart"; - run_symbol = "__runwwinmain"; - pe_type = PE_GUI; - } else if (find_elf_sym(symtab_section, "wmain")) { - start_symbol = "__wstart"; - run_symbol = "__runwmain"; - pe_type = PE_EXE; - } else { - start_symbol = "__start"; - run_symbol = "__runmain"; - pe_type = PE_EXE; - - } - if (TCC_OUTPUT_MEMORY == s1->output_type) - start_symbol = run_symbol; - } - - pe->start_symbol = start_symbol + 1; - if (!s1->leading_underscore || strchr(start_symbol, '@')) - ++start_symbol; - -#ifdef CONFIG_TCC_BACKTRACE - if (s1->do_backtrace) { -#ifdef CONFIG_TCC_BCHECK - if (s1->do_bounds_check && s1->output_type != TCC_OUTPUT_DLL) - tcc_add_support(s1, "bcheck.o"); -#endif - if (s1->output_type == TCC_OUTPUT_EXE) - tcc_add_support(s1, "bt-exe.o"); - if (s1->output_type == TCC_OUTPUT_DLL) - tcc_add_support(s1, "bt-dll.o"); - if (s1->output_type != TCC_OUTPUT_DLL) - tcc_add_support(s1, "bt-log.o"); - if (s1->output_type != TCC_OUTPUT_MEMORY) - tcc_add_btstub(s1); - } -#endif - - /* grab the startup code from libtcc1.a */ -#ifdef TCC_IS_NATIVE - if (TCC_OUTPUT_MEMORY != s1->output_type || s1->runtime_main) -#endif - set_global_sym(s1, start_symbol, NULL, 0); - - if (0 == s1->nostdlib) { - static const char * const libs[] = { - "msvcrt", "kernel32", "", "user32", "gdi32", NULL - }; - const char * const *pp, *p; - if (TCC_LIBTCC1[0]) - tcc_add_support(s1, TCC_LIBTCC1); - for (pp = libs; 0 != (p = *pp); ++pp) { - if (*p) - tcc_add_library_err(s1, p); - else if (PE_DLL != pe_type && PE_GUI != pe_type) - break; - } - } - - /* need this for 'tccelf.c:relocate_sections()' */ - if (TCC_OUTPUT_DLL == s1->output_type) - s1->output_type = TCC_OUTPUT_EXE; - if (TCC_OUTPUT_MEMORY == s1->output_type) - pe_type = PE_RUN; - pe->type = pe_type; -} - -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) -{ - struct pe_info pe; - - memset(&pe, 0, sizeof pe); - pe.filename = filename; - pe.s1 = s1; - s1->filetype = 0; - -#ifdef CONFIG_TCC_BCHECK - tcc_add_bcheck(s1); -#endif - tcc_add_pragma_libs(s1); - pe_add_runtime(s1, &pe); - resolve_common_syms(s1); - pe_set_options(s1, &pe); - pe_check_symbols(&pe); - - if (s1->nb_errors) - ; - else if (filename) { - pe_assign_addresses(&pe); - relocate_syms(s1, s1->symtab, 0); - s1->pe_imagebase = pe.imagebase; - relocate_sections(s1); - pe.start_addr = (DWORD) - (get_sym_addr(s1, pe.start_symbol, 1, 1) - pe.imagebase); - if (0 == s1->nb_errors) - pe_write(&pe); - dynarray_reset(&pe.sec_info, &pe.sec_count); - } else { -#ifdef TCC_IS_NATIVE - pe.thunk = data_section; - pe_build_imports(&pe); - s1->runtime_main = pe.start_symbol; -#ifdef TCC_TARGET_X86_64 - s1->uw_pdata = find_section(s1, ".pdata"); -#endif -#endif - } - pe_free_imports(&pe); -#if PE_PRINT_SECTIONS - if (s1->g_debug & 8) - pe_print_sections(s1, "tcc.log"); -#endif - return s1->nb_errors ? -1 : 0; -} - -/* ------------------------------------------------------------- */ diff --git a/tinycc/tccpp.c b/tinycc/tccpp.c deleted file mode 100644 index 717ab48..0000000 --- a/tinycc/tccpp.c +++ /dev/null @@ -1,3999 +0,0 @@ -/* - * 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 - */ - -#define USING_GLOBALS -#include "tcc.h" - -/* #define to 1 to enable (see parse_pp_string()) */ -#define ACCEPT_LF_IN_STRINGS 0 - -/********************************************************/ -/* global variables */ - -ST_DATA int tok_flags; -ST_DATA int parse_flags; - -ST_DATA struct BufferedFile *file; -ST_DATA int tok; -ST_DATA CValue tokc; -ST_DATA const int *macro_ptr; -ST_DATA CString tokcstr; /* current parsed string, if any */ - -/* display benchmark infos */ -ST_DATA int tok_ident; -ST_DATA TokenSym **table_ident; - -/* ------------------------------------------------------------------------- */ - -static TokenSym *hash_ident[TOK_HASH_SIZE]; -static char token_buf[STRING_MAX_SIZE + 1]; -static CString cstr_buf; -static TokenString tokstr_buf; -static unsigned char isidnum_table[256 - CH_EOF]; -static int pp_debug_tok, pp_debug_symv; -static int pp_once; -static int pp_expr; -static int pp_counter; -static void tok_print(const char *msg, const int *str); - -static struct TinyAlloc *toksym_alloc; -static struct TinyAlloc *tokstr_alloc; - -static TokenString *macro_stack; - -static const char tcc_keywords[] = -#define DEF(id, str) str "\0" -#include "tcctok.h" -#undef DEF -; - -/* WARNING: the content of this string encodes token numbers */ -static const unsigned char tok_two_chars[] = -/* outdated -- gr - "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253" - "-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\313..\250##\266"; -*/{ - '<','=', TOK_LE, - '>','=', TOK_GE, - '!','=', TOK_NE, - '&','&', TOK_LAND, - '|','|', TOK_LOR, - '+','+', TOK_INC, - '-','-', TOK_DEC, - '=','=', TOK_EQ, - '<','<', TOK_SHL, - '>','>', TOK_SAR, - '+','=', TOK_A_ADD, - '-','=', TOK_A_SUB, - '*','=', TOK_A_MUL, - '/','=', TOK_A_DIV, - '%','=', TOK_A_MOD, - '&','=', TOK_A_AND, - '^','=', TOK_A_XOR, - '|','=', TOK_A_OR, - '-','>', TOK_ARROW, - '.','.', TOK_TWODOTS, - '#','#', TOK_TWOSHARPS, - '#','#', TOK_PPJOIN, - 0 -}; - -static void next_nomacro(void); - -ST_FUNC void skip(int c) -{ - if (tok != c) - tcc_error("'%c' expected (got \"%s\")", c, get_tok_str(tok, &tokc)); - next(); -} - -ST_FUNC void expect(const char *msg) -{ - tcc_error("%s expected", msg); -} - -/* ------------------------------------------------------------------------- */ -/* Custom allocator for tiny objects */ - -#define USE_TAL - -#ifndef USE_TAL -#define tal_free(al, p) tcc_free(p) -#define tal_realloc(al, p, size) tcc_realloc(p, size) -#define tal_new(a,b,c) -#define tal_delete(a) -#else -#if !defined(MEM_DEBUG) -#define tal_free(al, p) tal_free_impl(al, p) -#define tal_realloc(al, p, size) tal_realloc_impl(&al, p, size) -#define TAL_DEBUG_PARAMS -#else -#define TAL_DEBUG 1 -//#define TAL_INFO 1 /* collect and dump allocators stats */ -#define tal_free(al, p) tal_free_impl(al, p, __FILE__, __LINE__) -#define tal_realloc(al, p, size) tal_realloc_impl(&al, p, size, __FILE__, __LINE__) -#define TAL_DEBUG_PARAMS , const char *file, int line -#define TAL_DEBUG_FILE_LEN 40 -#endif - -#define TOKSYM_TAL_SIZE (768 * 1024) /* allocator for tiny TokenSym in table_ident */ -#define TOKSTR_TAL_SIZE (768 * 1024) /* allocator for tiny TokenString instances */ -#define CSTR_TAL_SIZE (256 * 1024) /* allocator for tiny CString instances */ -#define TOKSYM_TAL_LIMIT 256 /* prefer unique limits to distinguish allocators debug msgs */ -#define TOKSTR_TAL_LIMIT 128 /* 32 * sizeof(int) */ -#define CSTR_TAL_LIMIT 1024 - -typedef struct TinyAlloc { - unsigned limit; - unsigned size; - uint8_t *buffer; - uint8_t *p; - unsigned nb_allocs; - struct TinyAlloc *next, *top; -#ifdef TAL_INFO - unsigned nb_peak; - unsigned nb_total; - unsigned nb_missed; - uint8_t *peak_p; -#endif -} TinyAlloc; - -typedef struct tal_header_t { - unsigned size; -#ifdef TAL_DEBUG - int line_num; /* negative line_num used for double free check */ - char file_name[TAL_DEBUG_FILE_LEN + 1]; -#endif -} tal_header_t; - -/* ------------------------------------------------------------------------- */ - -static TinyAlloc *tal_new(TinyAlloc **pal, unsigned limit, unsigned size) -{ - TinyAlloc *al = tcc_mallocz(sizeof(TinyAlloc)); - al->p = al->buffer = tcc_malloc(size); - al->limit = limit; - al->size = size; - if (pal) *pal = al; - return al; -} - -static void tal_delete(TinyAlloc *al) -{ - TinyAlloc *next; - -tail_call: - if (!al) - return; -#ifdef TAL_INFO - fprintf(stderr, "limit=%5d, size=%5g MB, nb_peak=%6d, nb_total=%8d, nb_missed=%6d, usage=%5.1f%%\n", - al->limit, al->size / 1024.0 / 1024.0, al->nb_peak, al->nb_total, al->nb_missed, - (al->peak_p - al->buffer) * 100.0 / al->size); -#endif -#ifdef TAL_DEBUG - if (al->nb_allocs > 0) { - uint8_t *p; - fprintf(stderr, "TAL_DEBUG: memory leak %d chunk(s) (limit= %d)\n", - al->nb_allocs, al->limit); - p = al->buffer; - while (p < al->p) { - tal_header_t *header = (tal_header_t *)p; - if (header->line_num > 0) { - fprintf(stderr, "%s:%d: chunk of %d bytes leaked\n", - header->file_name, header->line_num, header->size); - } - p += header->size + sizeof(tal_header_t); - } -#if MEM_DEBUG-0 == 2 - exit(2); -#endif - } -#endif - next = al->next; - tcc_free(al->buffer); - tcc_free(al); - al = next; - goto tail_call; -} - -static void tal_free_impl(TinyAlloc *al, void *p TAL_DEBUG_PARAMS) -{ - if (!p) - return; -tail_call: - if (al->buffer <= (uint8_t *)p && (uint8_t *)p < al->buffer + al->size) { -#ifdef TAL_DEBUG - tal_header_t *header = (((tal_header_t *)p) - 1); - if (header->line_num < 0) { - fprintf(stderr, "%s:%d: TAL_DEBUG: double frees chunk from\n", - file, line); - fprintf(stderr, "%s:%d: %d bytes\n", - header->file_name, (int)-header->line_num, (int)header->size); - } else - header->line_num = -header->line_num; -#endif - al->nb_allocs--; - if (!al->nb_allocs) - al->p = al->buffer; - } else if (al->next) { - al = al->next; - goto tail_call; - } - else - tcc_free(p); -} - -static void *tal_realloc_impl(TinyAlloc **pal, void *p, unsigned size TAL_DEBUG_PARAMS) -{ - tal_header_t *header; - void *ret; - int is_own; - unsigned adj_size = (size + 3) & -4; - TinyAlloc *al = *pal; - -tail_call: - is_own = (al->buffer <= (uint8_t *)p && (uint8_t *)p < al->buffer + al->size); - if ((!p || is_own) && size <= al->limit) { - if (al->p - al->buffer + adj_size + sizeof(tal_header_t) < al->size) { - header = (tal_header_t *)al->p; - header->size = adj_size; -#ifdef TAL_DEBUG - { int ofs = strlen(file) - TAL_DEBUG_FILE_LEN; - strncpy(header->file_name, file + (ofs > 0 ? ofs : 0), TAL_DEBUG_FILE_LEN); - header->file_name[TAL_DEBUG_FILE_LEN] = 0; - header->line_num = line; } -#endif - ret = al->p + sizeof(tal_header_t); - al->p += adj_size + sizeof(tal_header_t); - if (is_own) { - header = (((tal_header_t *)p) - 1); - if (p) memcpy(ret, p, header->size); -#ifdef TAL_DEBUG - header->line_num = -header->line_num; -#endif - } else { - al->nb_allocs++; - } -#ifdef TAL_INFO - if (al->nb_peak < al->nb_allocs) - al->nb_peak = al->nb_allocs; - if (al->peak_p < al->p) - al->peak_p = al->p; - al->nb_total++; -#endif - return ret; - } else if (is_own) { - al->nb_allocs--; - ret = tal_realloc(*pal, 0, size); - header = (((tal_header_t *)p) - 1); - if (p) memcpy(ret, p, header->size); -#ifdef TAL_DEBUG - header->line_num = -header->line_num; -#endif - return ret; - } - if (al->next) { - al = al->next; - } else { - TinyAlloc *bottom = al, *next = al->top ? al->top : al; - - al = tal_new(pal, next->limit, next->size * 2); - al->next = next; - bottom->top = al; - } - goto tail_call; - } - if (is_own) { - al->nb_allocs--; - ret = tcc_malloc(size); - header = (((tal_header_t *)p) - 1); - if (p) memcpy(ret, p, header->size); -#ifdef TAL_DEBUG - header->line_num = -header->line_num; -#endif - } else if (al->next) { - al = al->next; - goto tail_call; - } else - ret = tcc_realloc(p, size); -#ifdef TAL_INFO - al->nb_missed++; -#endif - return ret; -} - -#endif /* USE_TAL */ - -/* ------------------------------------------------------------------------- */ -/* CString handling */ -static void cstr_realloc(CString *cstr, int new_size) -{ - int size; - - size = cstr->size_allocated; - if (size < 8) - size = 8; /* no need to allocate a too small first string */ - while (size < new_size) - size = size * 2; - cstr->data = tcc_realloc(cstr->data, size); - cstr->size_allocated = size; -} - -/* add a byte */ -ST_INLN void cstr_ccat(CString *cstr, int ch) -{ - int size; - size = cstr->size + 1; - if (size > cstr->size_allocated) - cstr_realloc(cstr, size); - ((unsigned char *)cstr->data)[size - 1] = ch; - cstr->size = size; -} - -ST_INLN char *unicode_to_utf8 (char *b, uint32_t Uc) -{ - if (Uc<0x80) *b++=Uc; - else if (Uc<0x800) *b++=192+Uc/64, *b++=128+Uc%64; - else if (Uc-0xd800u<0x800) goto error; - else if (Uc<0x10000) *b++=224+Uc/4096, *b++=128+Uc/64%64, *b++=128+Uc%64; - else if (Uc<0x110000) *b++=240+Uc/262144, *b++=128+Uc/4096%64, *b++=128+Uc/64%64, *b++=128+Uc%64; - else error: tcc_error("0x%x is not a valid universal character", Uc); - return b; -} - -/* add a unicode character expanded into utf8 */ -ST_INLN void cstr_u8cat(CString *cstr, int ch) -{ - char buf[4], *e; - e = unicode_to_utf8(buf, (uint32_t)ch); - cstr_cat(cstr, buf, e - buf); -} - -ST_FUNC void cstr_cat(CString *cstr, const char *str, int len) -{ - int size; - if (len <= 0) - len = strlen(str) + 1 + len; - size = cstr->size + len; - if (size > cstr->size_allocated) - cstr_realloc(cstr, size); - memmove(((unsigned char *)cstr->data) + cstr->size, str, len); - cstr->size = size; -} - -/* add a wide char */ -ST_FUNC void cstr_wccat(CString *cstr, int ch) -{ - int size; - size = cstr->size + sizeof(nwchar_t); - if (size > cstr->size_allocated) - cstr_realloc(cstr, size); - *(nwchar_t *)(((unsigned char *)cstr->data) + size - sizeof(nwchar_t)) = ch; - cstr->size = size; -} - -ST_FUNC void cstr_new(CString *cstr) -{ - memset(cstr, 0, sizeof(CString)); -} - -/* free string and reset it to NULL */ -ST_FUNC void cstr_free(CString *cstr) -{ - tcc_free(cstr->data); -} - -/* reset string to empty */ -ST_FUNC void cstr_reset(CString *cstr) -{ - cstr->size = 0; -} - -ST_FUNC int cstr_vprintf(CString *cstr, const char *fmt, va_list ap) -{ - va_list v; - int len, size = 80; - for (;;) { - size += cstr->size; - if (size > cstr->size_allocated) - cstr_realloc(cstr, size); - size = cstr->size_allocated - cstr->size; - va_copy(v, ap); - len = vsnprintf((char*)cstr->data + cstr->size, size, fmt, v); - va_end(v); - if (len >= 0 && len < size) - break; - size *= 2; - } - cstr->size += len; - return len; -} - -ST_FUNC int cstr_printf(CString *cstr, const char *fmt, ...) -{ - va_list ap; int len; - va_start(ap, fmt); - len = cstr_vprintf(cstr, fmt, ap); - va_end(ap); - return len; -} - -/* XXX: unicode ? */ -static void add_char(CString *cstr, int c) -{ - if (c == '\'' || c == '\"' || c == '\\') { - /* XXX: could be more precise if char or string */ - cstr_ccat(cstr, '\\'); - } - if (c >= 32 && c <= 126) { - cstr_ccat(cstr, c); - } else { - cstr_ccat(cstr, '\\'); - if (c == '\n') { - cstr_ccat(cstr, 'n'); - } else { - cstr_ccat(cstr, '0' + ((c >> 6) & 7)); - cstr_ccat(cstr, '0' + ((c >> 3) & 7)); - cstr_ccat(cstr, '0' + (c & 7)); - } - } -} - -/* ------------------------------------------------------------------------- */ -/* allocate a new token */ -static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len) -{ - TokenSym *ts, **ptable; - int i; - - if (tok_ident >= SYM_FIRST_ANOM) - tcc_error("memory full (symbols)"); - - /* expand token table if needed */ - i = tok_ident - TOK_IDENT; - if ((i % TOK_ALLOC_INCR) == 0) { - ptable = tcc_realloc(table_ident, (i + TOK_ALLOC_INCR) * sizeof(TokenSym *)); - table_ident = ptable; - } - - ts = tal_realloc(toksym_alloc, 0, sizeof(TokenSym) + len); - table_ident[i] = ts; - ts->tok = tok_ident++; - ts->sym_define = NULL; - ts->sym_label = NULL; - ts->sym_struct = NULL; - ts->sym_identifier = NULL; - ts->len = len; - ts->hash_next = NULL; - memcpy(ts->str, str, len); - ts->str[len] = '\0'; - *pts = ts; - return ts; -} - -#define TOK_HASH_INIT 1 -#define TOK_HASH_FUNC(h, c) ((h) + ((h) << 5) + ((h) >> 27) + (c)) - - -/* find a token and add it if not found */ -ST_FUNC TokenSym *tok_alloc(const char *str, int len) -{ - TokenSym *ts, **pts; - int i; - unsigned int h; - - h = TOK_HASH_INIT; - for(i=0;i<len;i++) - h = TOK_HASH_FUNC(h, ((unsigned char *)str)[i]); - h &= (TOK_HASH_SIZE - 1); - - pts = &hash_ident[h]; - for(;;) { - ts = *pts; - if (!ts) - break; - if (ts->len == len && !memcmp(ts->str, str, len)) - return ts; - pts = &(ts->hash_next); - } - return tok_alloc_new(pts, str, len); -} - -ST_FUNC int tok_alloc_const(const char *str) -{ - return tok_alloc(str, strlen(str))->tok; -} - - -/* XXX: buffer overflow */ -/* XXX: float tokens */ -ST_FUNC const char *get_tok_str(int v, CValue *cv) -{ - char *p; - int i, len; - - cstr_reset(&cstr_buf); - p = cstr_buf.data; - - switch(v) { - case TOK_CINT: - case TOK_CUINT: - case TOK_CLONG: - case TOK_CULONG: - case TOK_CLLONG: - case TOK_CULLONG: - /* XXX: not quite exact, but only useful for testing */ -#ifdef _WIN32 - sprintf(p, "%u", (unsigned)cv->i); -#else - sprintf(p, "%llu", (unsigned long long)cv->i); -#endif - break; - case TOK_LCHAR: - cstr_ccat(&cstr_buf, 'L'); - case TOK_CCHAR: - cstr_ccat(&cstr_buf, '\''); - add_char(&cstr_buf, cv->i); - cstr_ccat(&cstr_buf, '\''); - cstr_ccat(&cstr_buf, '\0'); - break; - case TOK_PPNUM: - case TOK_PPSTR: - return (char*)cv->str.data; - case TOK_LSTR: - cstr_ccat(&cstr_buf, 'L'); - case TOK_STR: - cstr_ccat(&cstr_buf, '\"'); - if (v == TOK_STR) { - len = cv->str.size - 1; - for(i=0;i<len;i++) - add_char(&cstr_buf, ((unsigned char *)cv->str.data)[i]); - } else { - len = (cv->str.size / sizeof(nwchar_t)) - 1; - for(i=0;i<len;i++) - add_char(&cstr_buf, ((nwchar_t *)cv->str.data)[i]); - } - cstr_ccat(&cstr_buf, '\"'); - cstr_ccat(&cstr_buf, '\0'); - break; - - case TOK_CFLOAT: - return strcpy(p, "<float>"); - case TOK_CDOUBLE: - return strcpy(p, "<double>"); - case TOK_CLDOUBLE: - return strcpy(p, "<long double>"); - case TOK_LINENUM: - return strcpy(p, "<linenumber"); - - /* above tokens have value, the ones below don't */ - case TOK_LT: - v = '<'; - goto addv; - case TOK_GT: - v = '>'; - goto addv; - case TOK_DOTS: - return strcpy(p, "..."); - case TOK_A_SHL: - return strcpy(p, "<<="); - case TOK_A_SAR: - return strcpy(p, ">>="); - case TOK_EOF: - return strcpy(p, "<eof>"); - case 0: /* anonymous nameless symbols */ - return strcpy(p, "<no name>"); - default: - if (v < TOK_IDENT) { - /* search in two bytes table */ - const unsigned char *q = tok_two_chars; - while (*q) { - if (q[2] == v) { - *p++ = q[0]; - *p++ = q[1]; - *p = '\0'; - return cstr_buf.data; - } - q += 3; - } - if (v >= 127 || (v < 32 && !is_space(v) && v != '\n')) { - sprintf(p, "<\\x%02x>", v); - break; - } - addv: - *p++ = v; - *p = '\0'; - } else if (v < tok_ident) { - return table_ident[v - TOK_IDENT]->str; - } else if (v >= SYM_FIRST_ANOM) { - /* special name for anonymous symbol */ - sprintf(p, "L.%u", v - SYM_FIRST_ANOM); - } else { - /* should never happen */ - return NULL; - } - break; - } - return cstr_buf.data; -} - -static inline int check_space(int t, int *spc) -{ - if (t < 256 && (isidnum_table[t - CH_EOF] & IS_SPC)) { - if (*spc) - return 1; - *spc = 1; - } else - *spc = 0; - return 0; -} - -/* return the current character, handling end of block if necessary - (but not stray) */ -static int handle_eob(void) -{ - BufferedFile *bf = file; - int len; - - /* only tries to read if really end of buffer */ - if (bf->buf_ptr >= bf->buf_end) { - if (bf->fd >= 0) { -#if defined(PARSE_DEBUG) - len = 1; -#else - len = IO_BUF_SIZE; -#endif - len = read(bf->fd, bf->buffer, len); - if (len < 0) - len = 0; - } else { - len = 0; - } - total_bytes += len; - bf->buf_ptr = bf->buffer; - bf->buf_end = bf->buffer + len; - *bf->buf_end = CH_EOB; - } - if (bf->buf_ptr < bf->buf_end) { - return bf->buf_ptr[0]; - } else { - bf->buf_ptr = bf->buf_end; - return CH_EOF; - } -} - -/* read next char from current input file and handle end of input buffer */ -static int next_c(void) -{ - int ch = *++file->buf_ptr; - /* end of buffer/file handling */ - if (ch == CH_EOB && file->buf_ptr >= file->buf_end) - ch = handle_eob(); - return ch; -} - -/* input with '\[\r]\n' handling. */ -static int handle_stray_noerror(int err) -{ - int ch; - while ((ch = next_c()) == '\\') { - ch = next_c(); - if (ch == '\n') { - newl: - file->line_num++; - } else { - if (ch == '\r') { - ch = next_c(); - if (ch == '\n') - goto newl; - *--file->buf_ptr = '\r'; - } - if (err) - tcc_error("stray '\\' in program"); - /* may take advantage of 'BufferedFile.unget[4}' */ - return *--file->buf_ptr = '\\'; - } - } - return ch; -} - -#define ninp() handle_stray_noerror(0) - -/* handle '\\' in strings, comments and skipped regions */ -static int handle_bs(uint8_t **p) -{ - int c; - file->buf_ptr = *p - 1; - c = ninp(); - *p = file->buf_ptr; - return c; -} - -/* skip the stray and handle the \\n case. Output an error if - incorrect char after the stray */ -static int handle_stray(uint8_t **p) -{ - int c; - file->buf_ptr = *p - 1; - c = handle_stray_noerror(!(parse_flags & PARSE_FLAG_ACCEPT_STRAYS)); - *p = file->buf_ptr; - return c; -} - -/* handle the complicated stray case */ -#define PEEKC(c, p)\ -{\ - c = *++p;\ - if (c == '\\')\ - c = handle_stray(&p); \ -} - -static int skip_spaces(void) -{ - int ch; - --file->buf_ptr; - do { - ch = ninp(); - } while (isidnum_table[ch - CH_EOF] & IS_SPC); - return ch; -} - -/* single line C++ comments */ -static uint8_t *parse_line_comment(uint8_t *p) -{ - int c; - for(;;) { - for (;;) { - c = *++p; - redo: - if (c == '\n' || c == '\\') - break; - c = *++p; - if (c == '\n' || c == '\\') - break; - } - if (c == '\n') - break; - c = handle_bs(&p); - if (c == CH_EOF) - break; - if (c != '\\') - goto redo; - } - return p; -} - -/* C comments */ -static uint8_t *parse_comment(uint8_t *p) -{ - int c; - for(;;) { - /* fast skip loop */ - for(;;) { - c = *++p; - redo: - if (c == '\n' || c == '*' || c == '\\') - break; - c = *++p; - if (c == '\n' || c == '*' || c == '\\') - break; - } - /* now we can handle all the cases */ - if (c == '\n') { - file->line_num++; - } else if (c == '*') { - do { - c = *++p; - } while (c == '*'); - if (c == '\\') - c = handle_bs(&p); - if (c == '/') - break; - goto check_eof; - } else { - c = handle_bs(&p); - check_eof: - if (c == CH_EOF) - tcc_error("unexpected end of file in comment"); - if (c != '\\') - goto redo; - } - } - return p + 1; -} - -/* parse a string without interpreting escapes */ -static uint8_t *parse_pp_string(uint8_t *p, int sep, CString *str) -{ - int c; - for(;;) { - c = *++p; - redo: - if (c == sep) { - break; - } else if (c == '\\') { - c = handle_bs(&p); - if (c == CH_EOF) { - unterminated_string: - /* XXX: indicate line number of start of string */ - tok_flags &= ~TOK_FLAG_BOL; - tcc_error("missing terminating %c character", sep); - } else if (c == '\\') { - if (str) - cstr_ccat(str, c); - c = *++p; - /* add char after '\\' unconditionally */ - if (c == '\\') { - c = handle_bs(&p); - if (c == CH_EOF) - goto unterminated_string; - } - goto add_char; - } else { - goto redo; - } - } else if (c == '\n') { - add_lf: - if (ACCEPT_LF_IN_STRINGS) { - file->line_num++; - goto add_char; - } else if (str) { /* not skipping */ - goto unterminated_string; - } else { - //tcc_warning("missing terminating %c character", sep); - return p; - } - } else if (c == '\r') { - c = *++p; - if (c == '\\') - c = handle_bs(&p); - if (c == '\n') - goto add_lf; - if (c == CH_EOF) - goto unterminated_string; - if (str) - cstr_ccat(str, '\r'); - goto redo; - } else { - add_char: - if (str) - cstr_ccat(str, c); - } - } - p++; - return p; -} - -/* skip block of text until #else, #elif or #endif. skip also pairs of - #if/#endif */ -static void preprocess_skip(void) -{ - int a, start_of_line, c, in_warn_or_error; - uint8_t *p; - - p = file->buf_ptr; - a = 0; -redo_start: - start_of_line = 1; - in_warn_or_error = 0; - for(;;) { - redo_no_start: - c = *p; - switch(c) { - case ' ': - case '\t': - case '\f': - case '\v': - case '\r': - p++; - goto redo_no_start; - case '\n': - file->line_num++; - p++; - goto redo_start; - case '\\': - c = handle_bs(&p); - if (c == CH_EOF) - expect("#endif"); - if (c == '\\') - ++p; - goto redo_no_start; - /* skip strings */ - case '\"': - case '\'': - if (in_warn_or_error) - goto _default; - tok_flags &= ~TOK_FLAG_BOL; - p = parse_pp_string(p, c, NULL); - break; - /* skip comments */ - case '/': - if (in_warn_or_error) - goto _default; - ++p; - c = handle_bs(&p); - if (c == '*') { - p = parse_comment(p); - } else if (c == '/') { - p = parse_line_comment(p); - } - break; - case '#': - p++; - if (start_of_line) { - file->buf_ptr = p; - next_nomacro(); - p = file->buf_ptr; - if (a == 0 && - (tok == TOK_ELSE || tok == TOK_ELIF || tok == TOK_ENDIF)) - goto the_end; - if (tok == TOK_IF || tok == TOK_IFDEF || tok == TOK_IFNDEF) - a++; - else if (tok == TOK_ENDIF) - a--; - else if( tok == TOK_ERROR || tok == TOK_WARNING) - in_warn_or_error = 1; - else if (tok == TOK_LINEFEED) - goto redo_start; - else if (parse_flags & PARSE_FLAG_ASM_FILE) - p = parse_line_comment(p - 1); - } -#if !defined(TCC_TARGET_ARM) - else if (parse_flags & PARSE_FLAG_ASM_FILE) - p = parse_line_comment(p - 1); -#else - /* ARM assembly uses '#' for constants */ -#endif - break; -_default: - default: - p++; - break; - } - start_of_line = 0; - } - the_end: ; - file->buf_ptr = p; -} - -#if 0 -/* return the number of additional 'ints' necessary to store the - token */ -static inline int tok_size(const int *p) -{ - switch(*p) { - /* 4 bytes */ - case TOK_CINT: - case TOK_CUINT: - case TOK_CCHAR: - case TOK_LCHAR: - case TOK_CFLOAT: - case TOK_LINENUM: - return 1 + 1; - case TOK_STR: - case TOK_LSTR: - case TOK_PPNUM: - case TOK_PPSTR: - return 1 + ((sizeof(CString) + ((CString *)(p+1))->size + 3) >> 2); - case TOK_CLONG: - case TOK_CULONG: - return 1 + LONG_SIZE / 4; - case TOK_CDOUBLE: - case TOK_CLLONG: - case TOK_CULLONG: - return 1 + 2; - case TOK_CLDOUBLE: -#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE - return 1 + 8 / 4; -#else - return 1 + LDOUBLE_SIZE / 4; -#endif - default: - return 1 + 0; - } -} -#endif - -/* token string handling */ -ST_INLN void tok_str_new(TokenString *s) -{ - s->str = NULL; - s->len = s->lastlen = 0; - s->allocated_len = 0; - s->last_line_num = -1; -} - -ST_FUNC TokenString *tok_str_alloc(void) -{ - TokenString *str = tal_realloc(tokstr_alloc, 0, sizeof *str); - tok_str_new(str); - return str; -} - -ST_FUNC int *tok_str_dup(TokenString *s) -{ - int *str; - - str = tal_realloc(tokstr_alloc, 0, s->len * sizeof(int)); - memcpy(str, s->str, s->len * sizeof(int)); - return str; -} - -ST_FUNC void tok_str_free_str(int *str) -{ - tal_free(tokstr_alloc, str); -} - -ST_FUNC void tok_str_free(TokenString *str) -{ - tok_str_free_str(str->str); - tal_free(tokstr_alloc, str); -} - -ST_FUNC int *tok_str_realloc(TokenString *s, int new_size) -{ - int *str, size; - - size = s->allocated_len; - if (size < 16) - size = 16; - while (size < new_size) - size = size * 2; - if (size > s->allocated_len) { - str = tal_realloc(tokstr_alloc, s->str, size * sizeof(int)); - s->allocated_len = size; - s->str = str; - } - return s->str; -} - -ST_FUNC void tok_str_add(TokenString *s, int t) -{ - int len, *str; - - len = s->len; - str = s->str; - if (len >= s->allocated_len) - str = tok_str_realloc(s, len + 1); - str[len++] = t; - s->len = len; -} - -ST_FUNC void begin_macro(TokenString *str, int alloc) -{ - str->alloc = alloc; - str->prev = macro_stack; - str->prev_ptr = macro_ptr; - str->save_line_num = file->line_num; - macro_ptr = str->str; - macro_stack = str; -} - -ST_FUNC void end_macro(void) -{ - TokenString *str = macro_stack; - macro_stack = str->prev; - macro_ptr = str->prev_ptr; - file->line_num = str->save_line_num; - str->len = 0; /* matters if str not alloced, may be tokstr_buf */ - if (str->alloc != 0) { - if (str->alloc == 2) - str->str = NULL; /* don't free */ - tok_str_free(str); - } -} - -static void tok_str_add2(TokenString *s, int t, CValue *cv) -{ - int len, *str; - - len = s->lastlen = s->len; - str = s->str; - - /* allocate space for worst case */ - if (len + TOK_MAX_SIZE >= s->allocated_len) - str = tok_str_realloc(s, len + TOK_MAX_SIZE + 1); - str[len++] = t; - switch(t) { - case TOK_CINT: - case TOK_CUINT: - case TOK_CCHAR: - case TOK_LCHAR: - case TOK_CFLOAT: - case TOK_LINENUM: -#if LONG_SIZE == 4 - case TOK_CLONG: - case TOK_CULONG: -#endif - str[len++] = cv->tab[0]; - break; - case TOK_PPNUM: - case TOK_PPSTR: - case TOK_STR: - case TOK_LSTR: - { - /* Insert the string into the int array. */ - size_t nb_words = - 1 + (cv->str.size + sizeof(int) - 1) / sizeof(int); - if (len + nb_words >= s->allocated_len) - str = tok_str_realloc(s, len + nb_words + 1); - str[len] = cv->str.size; - memcpy(&str[len + 1], cv->str.data, cv->str.size); - len += nb_words; - } - break; - case TOK_CDOUBLE: - case TOK_CLLONG: - case TOK_CULLONG: -#if LONG_SIZE == 8 - case TOK_CLONG: - case TOK_CULONG: -#endif - str[len++] = cv->tab[0]; - str[len++] = cv->tab[1]; - break; - case TOK_CLDOUBLE: -#if LDOUBLE_SIZE == 8 || defined TCC_USING_DOUBLE_FOR_LDOUBLE - str[len++] = cv->tab[0]; - str[len++] = cv->tab[1]; -#elif LDOUBLE_SIZE == 12 - str[len++] = cv->tab[0]; - str[len++] = cv->tab[1]; - str[len++] = cv->tab[2]; -#elif LDOUBLE_SIZE == 16 - str[len++] = cv->tab[0]; - str[len++] = cv->tab[1]; - str[len++] = cv->tab[2]; - str[len++] = cv->tab[3]; -#else -#error add long double size support -#endif - break; - default: - break; - } - s->len = len; -} - -/* add the current parse token in token string 's' */ -ST_FUNC void tok_str_add_tok(TokenString *s) -{ - CValue cval; - - /* save line number info */ - if (file->line_num != s->last_line_num) { - s->last_line_num = file->line_num; - cval.i = s->last_line_num; - tok_str_add2(s, TOK_LINENUM, &cval); - } - tok_str_add2(s, tok, &tokc); -} - -/* get a token from an integer array and increment pointer. */ -static inline void tok_get(int *t, const int **pp, CValue *cv) -{ - const int *p = *pp; - int n, *tab; - - tab = cv->tab; - switch(*t = *p++) { -#if LONG_SIZE == 4 - case TOK_CLONG: -#endif - case TOK_CINT: - case TOK_CCHAR: - case TOK_LCHAR: - case TOK_LINENUM: - cv->i = *p++; - break; -#if LONG_SIZE == 4 - case TOK_CULONG: -#endif - case TOK_CUINT: - cv->i = (unsigned)*p++; - break; - case TOK_CFLOAT: - tab[0] = *p++; - break; - case TOK_STR: - case TOK_LSTR: - case TOK_PPNUM: - case TOK_PPSTR: - cv->str.size = *p++; - cv->str.data = p; - p += (cv->str.size + sizeof(int) - 1) / sizeof(int); - break; - case TOK_CDOUBLE: - case TOK_CLLONG: - case TOK_CULLONG: -#if LONG_SIZE == 8 - case TOK_CLONG: - case TOK_CULONG: -#endif - n = 2; - goto copy; - case TOK_CLDOUBLE: -#if LDOUBLE_SIZE == 8 || defined TCC_USING_DOUBLE_FOR_LDOUBLE - n = 2; -#elif LDOUBLE_SIZE == 12 - n = 3; -#elif LDOUBLE_SIZE == 16 - n = 4; -#else -# error add long double size support -#endif - copy: - do - *tab++ = *p++; - while (--n); - break; - default: - break; - } - *pp = p; -} - -#if 0 -# define TOK_GET(t,p,c) tok_get(t,p,c) -#else -# define TOK_GET(t,p,c) do { \ - int _t = **(p); \ - if (TOK_HAS_VALUE(_t)) \ - tok_get(t, p, c); \ - else \ - *(t) = _t, ++*(p); \ - } while (0) -#endif - -static int macro_is_equal(const int *a, const int *b) -{ - CValue cv; - int t; - - if (!a || !b) - return 1; - - while (*a && *b) { - cstr_reset(&tokcstr); - TOK_GET(&t, &a, &cv); - cstr_cat(&tokcstr, get_tok_str(t, &cv), 0); - TOK_GET(&t, &b, &cv); - if (strcmp(tokcstr.data, get_tok_str(t, &cv))) - return 0; - } - return !(*a || *b); -} - -/* defines handling */ -ST_INLN void define_push(int v, int macro_type, int *str, Sym *first_arg) -{ - Sym *s, *o; - - o = define_find(v); - s = sym_push2(&define_stack, v, macro_type, 0); - s->d = str; - s->next = first_arg; - table_ident[v - TOK_IDENT]->sym_define = s; - - if (o && !macro_is_equal(o->d, s->d)) - tcc_warning("%s redefined", get_tok_str(v, NULL)); -} - -/* undefined a define symbol. Its name is just set to zero */ -ST_FUNC void define_undef(Sym *s) -{ - int v = s->v; - if (v >= TOK_IDENT && v < tok_ident) - table_ident[v - TOK_IDENT]->sym_define = NULL; -} - -ST_INLN Sym *define_find(int v) -{ - v -= TOK_IDENT; - if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) - return NULL; - return table_ident[v]->sym_define; -} - -/* free define stack until top reaches 'b' */ -ST_FUNC void free_defines(Sym *b) -{ - while (define_stack != b) { - Sym *top = define_stack; - define_stack = top->prev; - tok_str_free_str(top->d); - define_undef(top); - sym_free(top); - } -} - -/* fake the nth "#if defined test_..." for tcc -dt -run */ -static void maybe_run_test(TCCState *s) -{ - const char *p; - if (s->include_stack_ptr != s->include_stack) - return; - p = get_tok_str(tok, NULL); - if (0 != memcmp(p, "test_", 5)) - return; - if (0 != --s->run_test) - return; - fprintf(s->ppfp, &"\n[%s]\n"[!(s->dflag & 32)], p), fflush(s->ppfp); - define_push(tok, MACRO_OBJ, NULL, NULL); -} - -static CachedInclude * -search_cached_include(TCCState *s1, const char *filename, int add); - -static int parse_include(TCCState *s1, int do_next, int test) -{ - int c, i; - char name[1024], buf[1024], *p; - CachedInclude *e; - - c = skip_spaces(); - if (c == '<' || c == '\"') { - cstr_reset(&tokcstr); - file->buf_ptr = parse_pp_string(file->buf_ptr, c == '<' ? '>' : c, &tokcstr); - i = tokcstr.size; - pstrncpy(name, tokcstr.data, i >= sizeof name ? sizeof name - 1 : i); - next_nomacro(); - } else { - /* computed #include : concatenate tokens until result is one of - the two accepted forms. Don't convert pp-tokens to tokens here. */ - parse_flags = PARSE_FLAG_PREPROCESS - | PARSE_FLAG_LINEFEED - | (parse_flags & PARSE_FLAG_ASM_FILE); - name[0] = 0; - for (;;) { - next(); - p = name, i = strlen(p) - 1; - if (i > 0 - && ((p[0] == '"' && p[i] == '"') - || (p[0] == '<' && p[i] == '>'))) - break; - if (tok == TOK_LINEFEED) - tcc_error("'#include' expects \"FILENAME\" or <FILENAME>"); - pstrcat(name, sizeof name, get_tok_str(tok, &tokc)); - } - c = p[0]; - /* remove '<>|""' */ - memmove(p, p + 1, i - 1), p[i - 1] = 0; - } - - i = do_next ? file->include_next_index : -1; - for (;;) { - ++i; - if (i == 0) { - /* check absolute include path */ - if (!IS_ABSPATH(name)) - continue; - buf[0] = '\0'; - } else if (i == 1) { - /* search in file's dir if "header.h" */ - if (c != '\"') - continue; - p = file->true_filename; - pstrncpy(buf, p, tcc_basename(p) - p); - } else { - int j = i - 2, k = j - s1->nb_include_paths; - if (k < 0) - p = s1->include_paths[j]; - else if (k < s1->nb_sysinclude_paths) - p = s1->sysinclude_paths[k]; - else if (test) - return 0; - else - tcc_error("include file '%s' not found", name); - pstrcpy(buf, sizeof buf, p); - pstrcat(buf, sizeof buf, "/"); - } - pstrcat(buf, sizeof buf, name); - e = search_cached_include(s1, buf, 0); - if (e && (define_find(e->ifndef_macro) || e->once == pp_once)) { - /* no need to parse the include because the 'ifndef macro' - is defined (or had #pragma once) */ -#ifdef INC_DEBUG - printf("%s: skipping cached %s\n", file->filename, buf); -#endif - return 1; - } - if (tcc_open(s1, buf) >= 0) - break; - } - - if (test) { - tcc_close(); - } else { - if (s1->include_stack_ptr >= s1->include_stack + INCLUDE_STACK_SIZE) - tcc_error("#include recursion too deep"); - /* push previous file on stack */ - *s1->include_stack_ptr++ = file->prev; - file->include_next_index = i; -#ifdef INC_DEBUG - printf("%s: including %s\n", file->prev->filename, file->filename); -#endif - /* update target deps */ - if (s1->gen_deps) { - BufferedFile *bf = file; - while (i == 1 && (bf = bf->prev)) - i = bf->include_next_index; - /* skip system include files */ - if (s1->include_sys_deps || i - 2 < s1->nb_include_paths) - dynarray_add(&s1->target_deps, &s1->nb_target_deps, - tcc_strdup(buf)); - } - /* add include file debug info */ - tcc_debug_bincl(s1); - tok_flags |= TOK_FLAG_BOF | TOK_FLAG_BOL; - } - return 1; -} - -/* eval an expression for #if/#elif */ -static int expr_preprocess(TCCState *s1) -{ - int c, t; - TokenString *str; - - str = tok_str_alloc(); - pp_expr = 1; - while (tok != TOK_LINEFEED && tok != TOK_EOF) { - next(); /* do macro subst */ - redo: - if (tok == TOK_DEFINED) { - next_nomacro(); - t = tok; - if (t == '(') - next_nomacro(); - if (tok < TOK_IDENT) - expect("identifier"); - if (s1->run_test) - maybe_run_test(s1); - c = 0; - if (define_find(tok) - || tok == TOK___HAS_INCLUDE - || tok == TOK___HAS_INCLUDE_NEXT) - c = 1; - if (t == '(') { - next_nomacro(); - if (tok != ')') - expect("')'"); - } - tok = TOK_CINT; - tokc.i = c; - } else if (tok == TOK___HAS_INCLUDE || - tok == TOK___HAS_INCLUDE_NEXT) { - t = tok; - next_nomacro(); - if (tok != '(') - expect("("); - c = parse_include(s1, t - TOK___HAS_INCLUDE, 1); - if (tok != ')') - expect("')'"); - tok = TOK_CINT; - tokc.i = c; - } else if (tok >= TOK_IDENT) { - /* if undefined macro, replace with zero, check for func-like */ - t = tok; - tok = TOK_CINT; - tokc.i = 0; - tok_str_add_tok(str); - next(); - if (tok == '(') - tcc_error("function-like macro '%s' is not defined", - get_tok_str(t, NULL)); - goto redo; - } - tok_str_add_tok(str); - } - pp_expr = 0; - tok_str_add(str, -1); /* simulate end of file */ - tok_str_add(str, 0); - /* now evaluate C constant expression */ - begin_macro(str, 1); - next(); - c = expr_const(); - end_macro(); - return c != 0; -} - - -/* parse after #define */ -ST_FUNC void parse_define(void) -{ - Sym *s, *first, **ps; - int v, t, varg, is_vaargs, spc; - int saved_parse_flags = parse_flags; - - v = tok; - if (v < TOK_IDENT || v == TOK_DEFINED) - tcc_error("invalid macro name '%s'", get_tok_str(tok, &tokc)); - /* XXX: should check if same macro (ANSI) */ - first = NULL; - t = MACRO_OBJ; - /* We have to parse the whole define as if not in asm mode, in particular - no line comment with '#' must be ignored. Also for function - macros the argument list must be parsed without '.' being an ID - character. */ - parse_flags = ((parse_flags & ~PARSE_FLAG_ASM_FILE) | PARSE_FLAG_SPACES); - /* '(' must be just after macro definition for MACRO_FUNC */ - next_nomacro(); - parse_flags &= ~PARSE_FLAG_SPACES; - if (tok == '(') { - int dotid = set_idnum('.', 0); - next_nomacro(); - ps = &first; - if (tok != ')') for (;;) { - varg = tok; - next_nomacro(); - is_vaargs = 0; - if (varg == TOK_DOTS) { - varg = TOK___VA_ARGS__; - is_vaargs = 1; - } else if (tok == TOK_DOTS && gnu_ext) { - is_vaargs = 1; - next_nomacro(); - } - if (varg < TOK_IDENT) - bad_list: - tcc_error("bad macro parameter list"); - s = sym_push2(&define_stack, varg | SYM_FIELD, is_vaargs, 0); - *ps = s; - ps = &s->next; - if (tok == ')') - break; - if (tok != ',' || is_vaargs) - goto bad_list; - next_nomacro(); - } - parse_flags |= PARSE_FLAG_SPACES; - next_nomacro(); - t = MACRO_FUNC; - set_idnum('.', dotid); - } - - tokstr_buf.len = 0; - spc = 2; - parse_flags |= PARSE_FLAG_ACCEPT_STRAYS | PARSE_FLAG_SPACES | PARSE_FLAG_LINEFEED; - /* The body of a macro definition should be parsed such that identifiers - are parsed like the file mode determines (i.e. with '.' being an - ID character in asm mode). But '#' should be retained instead of - regarded as line comment leader, so still don't set ASM_FILE - in parse_flags. */ - while (tok != TOK_LINEFEED && tok != TOK_EOF) { - /* remove spaces around ## and after '#' */ - if (TOK_TWOSHARPS == tok) { - if (2 == spc) - goto bad_twosharp; - if (1 == spc) - --tokstr_buf.len; - spc = 3; - tok = TOK_PPJOIN; - } else if ('#' == tok) { - spc = 4; - } else if (check_space(tok, &spc)) { - goto skip; - } - tok_str_add2(&tokstr_buf, tok, &tokc); - skip: - next_nomacro(); - } - - parse_flags = saved_parse_flags; - if (spc == 1) - --tokstr_buf.len; /* remove trailing space */ - tok_str_add(&tokstr_buf, 0); - if (3 == spc) -bad_twosharp: - tcc_error("'##' cannot appear at either end of macro"); - define_push(v, t, tok_str_dup(&tokstr_buf), first); -} - -#ifdef _WIN32 -static unsigned long long calc_file_hash(const char *filename) -{ - unsigned long long hash = 14695981039346656037ull; // FNV_offset_basis; - int fd = open (filename, O_RDONLY | O_BINARY); - - if (fd < 0) - return 0; - for (;;) { - unsigned char temp[IO_BUF_SIZE]; - int i, n = read(fd, temp, sizeof(temp)); - - if (n <= 0) - break; - for (i = 0; i < n; i++) - hash = hash * 1099511628211ull ^ temp[i]; // FNV_prime - } - close(fd); - return hash ? hash : 1ull; -} -#endif - -static CachedInclude *search_cached_include(TCCState *s1, const char *filename, int add) -{ - unsigned int h = 0; - CachedInclude *e; - int i; - struct stat st; -#ifdef _WIN32 - unsigned long long hash = 0; -#endif - - /* This is needed for #pragmae once - * We cannot use stat on windows because st_ino is not set correctly - * so we calculate a hash of file contents. - * This also works for hard/soft links as in gcc/clang. - */ - memset (&st, 0, sizeof(st)); - if (stat (filename, &st)) - goto skip; - h = st.st_size & (CACHED_INCLUDES_HASH_SIZE - 1); -#ifdef _WIN32 - /* Only calculate file hash if file size same. */ - i = s1->cached_includes_hash[h]; - for(;;) { - if (i == 0) - break; - e = s1->cached_includes[i - 1]; - if (e->st.st_size == st.st_size) { - if (0 == PATHCMP(e->filename, filename)) { - hash = e->hash; - break; - } - if (e->hash == 0) - e->hash = calc_file_hash(e->filename); - if (hash == 0) - hash = calc_file_hash(filename); - } - i = e->hash_next; - } -#endif - - i = s1->cached_includes_hash[h]; - for(;;) { - if (i == 0) - break; - e = s1->cached_includes[i - 1]; -#ifdef _WIN32 - if (e->st.st_size == st.st_size && e->hash == hash) -#else - if (st.st_dev == e->st.st_dev && st.st_ino == e->st.st_ino) -#endif - return e; - i = e->hash_next; - } -skip: - if (!add) - return NULL; - - e = tcc_malloc(sizeof(CachedInclude) + strlen(filename)); - e->st = st; -#ifdef _WIN32 - e->hash = hash; -#endif - strcpy(e->filename, filename); - e->ifndef_macro = e->once = 0; - dynarray_add(&s1->cached_includes, &s1->nb_cached_includes, e); - /* add in hash table */ - e->hash_next = s1->cached_includes_hash[h]; - s1->cached_includes_hash[h] = s1->nb_cached_includes; -#ifdef INC_DEBUG - printf("adding cached '%s'\n", filename); -#endif - return e; -} - -static void pragma_parse(TCCState *s1) -{ - next_nomacro(); - if (tok == TOK_push_macro || tok == TOK_pop_macro) { - int t = tok, v; - Sym *s; - - if (next(), tok != '(') - goto pragma_err; - if (next(), tok != TOK_STR) - goto pragma_err; - v = tok_alloc(tokc.str.data, tokc.str.size - 1)->tok; - if (next(), tok != ')') - goto pragma_err; - if (t == TOK_push_macro) { - while (NULL == (s = define_find(v))) - define_push(v, 0, NULL, NULL); - s->type.ref = s; /* set push boundary */ - } else { - for (s = define_stack; s; s = s->prev) - if (s->v == v && s->type.ref == s) { - s->type.ref = NULL; - break; - } - } - if (s) - table_ident[v - TOK_IDENT]->sym_define = s->d ? s : NULL; - else - tcc_warning("unbalanced #pragma pop_macro"); - pp_debug_tok = t, pp_debug_symv = v; - - } else if (tok == TOK_once) { - search_cached_include(s1, file->filename, 1)->once = pp_once; - - } else if (s1->output_type == TCC_OUTPUT_PREPROCESS) { - /* tcc -E: keep pragmas below unchanged */ - unget_tok(' '); - unget_tok(TOK_PRAGMA); - unget_tok('#'); - unget_tok(TOK_LINEFEED); - - } else if (tok == TOK_pack) { - /* This may be: - #pragma pack(1) // set - #pragma pack() // reset to default - #pragma pack(push) // push current - #pragma pack(push,1) // push & set - #pragma pack(pop) // restore previous */ - next(); - skip('('); - if (tok == TOK_ASM_pop) { - next(); - if (s1->pack_stack_ptr <= s1->pack_stack) { - stk_error: - tcc_error("out of pack stack"); - } - s1->pack_stack_ptr--; - } else { - int val = 0; - if (tok != ')') { - if (tok == TOK_ASM_push) { - next(); - if (s1->pack_stack_ptr >= s1->pack_stack + PACK_STACK_SIZE - 1) - goto stk_error; - val = *s1->pack_stack_ptr++; - if (tok != ',') - goto pack_set; - next(); - } - if (tok != TOK_CINT) - goto pragma_err; - val = tokc.i; - if (val < 1 || val > 16 || (val & (val - 1)) != 0) - goto pragma_err; - next(); - } - pack_set: - *s1->pack_stack_ptr = val; - } - if (tok != ')') - goto pragma_err; - - } else if (tok == TOK_comment) { - char *p; int t; - next(); - skip('('); - t = tok; - next(); - skip(','); - if (tok != TOK_STR) - goto pragma_err; - p = tcc_strdup((char *)tokc.str.data); - next(); - if (tok != ')') - goto pragma_err; - if (t == TOK_lib) { - dynarray_add(&s1->pragma_libs, &s1->nb_pragma_libs, p); - } else { - if (t == TOK_option) - tcc_set_options(s1, p); - tcc_free(p); - } - - } else - tcc_warning_c(warn_unsupported)("#pragma %s ignored", get_tok_str(tok, &tokc)); - return; - -pragma_err: - tcc_error("malformed #pragma directive"); - return; -} - -/* is_bof is true if first non space token at beginning of file */ -ST_FUNC void preprocess(int is_bof) -{ - TCCState *s1 = tcc_state; - int c, n, saved_parse_flags; - char buf[1024], *q; - Sym *s; - - saved_parse_flags = parse_flags; - parse_flags = PARSE_FLAG_PREPROCESS - | PARSE_FLAG_TOK_NUM - | PARSE_FLAG_TOK_STR - | PARSE_FLAG_LINEFEED - | (parse_flags & PARSE_FLAG_ASM_FILE) - ; - - next_nomacro(); - redo: - switch(tok) { - case TOK_DEFINE: - pp_debug_tok = tok; - next_nomacro(); - pp_debug_symv = tok; - parse_define(); - break; - case TOK_UNDEF: - pp_debug_tok = tok; - next_nomacro(); - pp_debug_symv = tok; - s = define_find(tok); - /* undefine symbol by putting an invalid name */ - if (s) - define_undef(s); - break; - case TOK_INCLUDE: - case TOK_INCLUDE_NEXT: - parse_include(s1, tok - TOK_INCLUDE, 0); - break; - case TOK_IFNDEF: - c = 1; - goto do_ifdef; - case TOK_IF: - c = expr_preprocess(s1); - goto do_if; - case TOK_IFDEF: - c = 0; - do_ifdef: - next_nomacro(); - if (tok < TOK_IDENT) - tcc_error("invalid argument for '#if%sdef'", c ? "n" : ""); - if (is_bof) { - if (c) { -#ifdef INC_DEBUG - printf("#ifndef %s\n", get_tok_str(tok, NULL)); -#endif - file->ifndef_macro = tok; - } - } - if (define_find(tok) - || tok == TOK___HAS_INCLUDE - || tok == TOK___HAS_INCLUDE_NEXT) - c ^= 1; - do_if: - if (s1->ifdef_stack_ptr >= s1->ifdef_stack + IFDEF_STACK_SIZE) - tcc_error("memory full (ifdef)"); - *s1->ifdef_stack_ptr++ = c; - goto test_skip; - case TOK_ELSE: - if (s1->ifdef_stack_ptr == s1->ifdef_stack) - tcc_error("#else without matching #if"); - if (s1->ifdef_stack_ptr[-1] & 2) - tcc_error("#else after #else"); - c = (s1->ifdef_stack_ptr[-1] ^= 3); - goto test_else; - case TOK_ELIF: - if (s1->ifdef_stack_ptr == s1->ifdef_stack) - tcc_error("#elif without matching #if"); - c = s1->ifdef_stack_ptr[-1]; - if (c > 1) - tcc_error("#elif after #else"); - /* last #if/#elif expression was true: we skip */ - if (c == 1) { - c = 0; - } else { - c = expr_preprocess(s1); - s1->ifdef_stack_ptr[-1] = c; - } - test_else: - if (s1->ifdef_stack_ptr == file->ifdef_stack_ptr + 1) - file->ifndef_macro = 0; - test_skip: - if (!(c & 1)) { - preprocess_skip(); - is_bof = 0; - goto redo; - } - break; - case TOK_ENDIF: - if (s1->ifdef_stack_ptr <= file->ifdef_stack_ptr) - tcc_error("#endif without matching #if"); - s1->ifdef_stack_ptr--; - /* '#ifndef macro' was at the start of file. Now we check if - an '#endif' is exactly at the end of file */ - if (file->ifndef_macro && - s1->ifdef_stack_ptr == file->ifdef_stack_ptr) { - file->ifndef_macro_saved = file->ifndef_macro; - /* need to set to zero to avoid false matches if another - #ifndef at middle of file */ - file->ifndef_macro = 0; - while (tok != TOK_LINEFEED) - next_nomacro(); - tok_flags |= TOK_FLAG_ENDIF; - goto the_end; - } - break; - case TOK_PPNUM: - n = strtoul((char*)tokc.str.data, &q, 10); - goto _line_num; - case TOK_LINE: - next(); - if (tok != TOK_CINT) - _line_err: - tcc_error("wrong #line format"); - n = tokc.i; - _line_num: - next(); - if (tok != TOK_LINEFEED) { - if (tok == TOK_STR) { - if (file->true_filename == file->filename) - file->true_filename = tcc_strdup(file->filename); - q = (char *)tokc.str.data; - buf[0] = 0; - if (!IS_ABSPATH(q)) { - /* prepend directory from real file */ - pstrcpy(buf, sizeof buf, file->true_filename); - *tcc_basename(buf) = 0; - } - pstrcat(buf, sizeof buf, q); - tcc_debug_putfile(s1, buf); - } else if (parse_flags & PARSE_FLAG_ASM_FILE) - break; - else - goto _line_err; - --n; - } - if (file->fd > 0) - total_lines += file->line_num - n; - file->line_num = n; - break; - case TOK_ERROR: - case TOK_WARNING: - q = buf; - c = skip_spaces(); - while (c != '\n' && c != CH_EOF) { - if ((q - buf) < sizeof(buf) - 1) - *q++ = c; - c = ninp(); - } - *q = '\0'; - if (tok == TOK_ERROR) - tcc_error("#error %s", buf); - else - tcc_warning("#warning %s", buf); - break; - case TOK_PRAGMA: - pragma_parse(s1); - break; - case TOK_LINEFEED: - goto the_end; - default: - /* ignore gas line comment in an 'S' file. */ - if (saved_parse_flags & PARSE_FLAG_ASM_FILE) - goto ignore; - if (tok == '!' && is_bof) - /* '!' is ignored at beginning to allow C scripts. */ - goto ignore; - tcc_warning("Ignoring unknown preprocessing directive #%s", get_tok_str(tok, &tokc)); - ignore: - file->buf_ptr = parse_line_comment(file->buf_ptr - 1); - goto the_end; - } - /* ignore other preprocess commands or #! for C scripts */ - while (tok != TOK_LINEFEED) - next_nomacro(); - the_end: - parse_flags = saved_parse_flags; -} - -/* evaluate escape codes in a string. */ -static void parse_escape_string(CString *outstr, const uint8_t *buf, int is_long) -{ - int c, n, i; - const uint8_t *p; - - p = buf; - for(;;) { - c = *p; - if (c == '\0') - break; - if (c == '\\') { - p++; - /* escape */ - c = *p; - switch(c) { - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - /* at most three octal digits */ - n = c - '0'; - p++; - c = *p; - if (isoct(c)) { - n = n * 8 + c - '0'; - p++; - c = *p; - if (isoct(c)) { - n = n * 8 + c - '0'; - p++; - } - } - c = n; - goto add_char_nonext; - case 'x': i = 0; goto parse_hex_or_ucn; - case 'u': i = 4; goto parse_hex_or_ucn; - case 'U': i = 8; goto parse_hex_or_ucn; - parse_hex_or_ucn: - p++; - n = 0; - do { - c = *p; - if (c >= 'a' && c <= 'f') - c = c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - c = c - 'A' + 10; - else if (isnum(c)) - c = c - '0'; - else if (i > 0) - expect("more hex digits in universal-character-name"); - else - goto add_hex_or_ucn; - n = n * 16 + c; - p++; - } while (--i); - if (is_long) { - add_hex_or_ucn: - c = n; - goto add_char_nonext; - } - cstr_u8cat(outstr, n); - continue; - case 'a': - c = '\a'; - break; - case 'b': - c = '\b'; - break; - case 'f': - c = '\f'; - break; - case 'n': - c = '\n'; - break; - case 'r': - c = '\r'; - break; - case 't': - c = '\t'; - break; - case 'v': - c = '\v'; - break; - case 'e': - if (!gnu_ext) - goto invalid_escape; - c = 27; - break; - case '\'': - case '\"': - case '\\': - case '?': - break; - default: - invalid_escape: - if (c >= '!' && c <= '~') - tcc_warning("unknown escape sequence: \'\\%c\'", c); - else - tcc_warning("unknown escape sequence: \'\\x%x\'", c); - break; - } - } else if (is_long && c >= 0x80) { - /* assume we are processing UTF-8 sequence */ - /* reference: The Unicode Standard, Version 10.0, ch3.9 */ - - int cont; /* count of continuation bytes */ - int skip; /* how many bytes should skip when error occurred */ - int i; - - /* decode leading byte */ - if (c < 0xC2) { - skip = 1; goto invalid_utf8_sequence; - } else if (c <= 0xDF) { - cont = 1; n = c & 0x1f; - } else if (c <= 0xEF) { - cont = 2; n = c & 0xf; - } else if (c <= 0xF4) { - cont = 3; n = c & 0x7; - } else { - skip = 1; goto invalid_utf8_sequence; - } - - /* decode continuation bytes */ - for (i = 1; i <= cont; i++) { - int l = 0x80, h = 0xBF; - - /* adjust limit for second byte */ - if (i == 1) { - switch (c) { - case 0xE0: l = 0xA0; break; - case 0xED: h = 0x9F; break; - case 0xF0: l = 0x90; break; - case 0xF4: h = 0x8F; break; - } - } - - if (p[i] < l || p[i] > h) { - skip = i; goto invalid_utf8_sequence; - } - - n = (n << 6) | (p[i] & 0x3f); - } - - /* advance pointer */ - p += 1 + cont; - c = n; - goto add_char_nonext; - - /* error handling */ - invalid_utf8_sequence: - tcc_warning("ill-formed UTF-8 subsequence starting with: \'\\x%x\'", c); - c = 0xFFFD; - p += skip; - goto add_char_nonext; - - } - p++; - add_char_nonext: - if (!is_long) - cstr_ccat(outstr, c); - else { -#ifdef TCC_TARGET_PE - /* store as UTF-16 */ - if (c < 0x10000) { - cstr_wccat(outstr, c); - } else { - c -= 0x10000; - cstr_wccat(outstr, (c >> 10) + 0xD800); - cstr_wccat(outstr, (c & 0x3FF) + 0xDC00); - } -#else - cstr_wccat(outstr, c); -#endif - } - } - /* add a trailing '\0' */ - if (!is_long) - cstr_ccat(outstr, '\0'); - else - cstr_wccat(outstr, '\0'); -} - -static void parse_string(const char *s, int len) -{ - uint8_t buf[1000], *p = buf; - int is_long, sep; - - if ((is_long = *s == 'L')) - ++s, --len; - sep = *s++; - len -= 2; - if (len >= sizeof buf) - p = tcc_malloc(len + 1); - memcpy(p, s, len); - p[len] = 0; - - cstr_reset(&tokcstr); - parse_escape_string(&tokcstr, p, is_long); - if (p != buf) - tcc_free(p); - - if (sep == '\'') { - int char_size, i, n, c; - /* XXX: make it portable */ - if (!is_long) - tok = TOK_CCHAR, char_size = 1; - else - tok = TOK_LCHAR, char_size = sizeof(nwchar_t); - n = tokcstr.size / char_size - 1; - if (n < 1) - tcc_error("empty character constant"); - if (n > 1) - tcc_warning_c(warn_all)("multi-character character constant"); - for (c = i = 0; i < n; ++i) { - if (is_long) - c = ((nwchar_t *)tokcstr.data)[i]; - else - c = (c << 8) | ((char *)tokcstr.data)[i]; - } - tokc.i = c; - } else { - tokc.str.size = tokcstr.size; - tokc.str.data = tokcstr.data; - if (!is_long) - tok = TOK_STR; - else - tok = TOK_LSTR; - } -} - -/* we use 64 bit numbers */ -#define BN_SIZE 2 - -/* bn = (bn << shift) | or_val */ -static void bn_lshift(unsigned int *bn, int shift, int or_val) -{ - int i; - unsigned int v; - for(i=0;i<BN_SIZE;i++) { - v = bn[i]; - bn[i] = (v << shift) | or_val; - or_val = v >> (32 - shift); - } -} - -static void bn_zero(unsigned int *bn) -{ - int i; - for(i=0;i<BN_SIZE;i++) { - bn[i] = 0; - } -} - -/* parse number in null terminated string 'p' and return it in the - current token */ -static void parse_number(const char *p) -{ - int b, t, shift, frac_bits, s, exp_val, ch; - char *q; - unsigned int bn[BN_SIZE]; - double d; - - /* number */ - q = token_buf; - ch = *p++; - t = ch; - ch = *p++; - *q++ = t; - b = 10; - if (t == '.') { - goto float_frac_parse; - } else if (t == '0') { - if (ch == 'x' || ch == 'X') { - q--; - ch = *p++; - b = 16; - } else if (tcc_state->tcc_ext && (ch == 'b' || ch == 'B')) { - q--; - ch = *p++; - b = 2; - } - } - /* parse all digits. cannot check octal numbers at this stage - because of floating point constants */ - while (1) { - if (ch >= 'a' && ch <= 'f') - t = ch - 'a' + 10; - else if (ch >= 'A' && ch <= 'F') - t = ch - 'A' + 10; - else if (isnum(ch)) - t = ch - '0'; - else - break; - if (t >= b) - break; - if (q >= token_buf + STRING_MAX_SIZE) { - num_too_long: - tcc_error("number too long"); - } - *q++ = ch; - ch = *p++; - } - if (ch == '.' || - ((ch == 'e' || ch == 'E') && b == 10) || - ((ch == 'p' || ch == 'P') && (b == 16 || b == 2))) { - if (b != 10) { - /* NOTE: strtox should support that for hexa numbers, but - non ISOC99 libcs do not support it, so we prefer to do - it by hand */ - /* hexadecimal or binary floats */ - /* XXX: handle overflows */ - *q = '\0'; - if (b == 16) - shift = 4; - else - shift = 1; - bn_zero(bn); - q = token_buf; - while (1) { - t = *q++; - if (t == '\0') { - break; - } else if (t >= 'a') { - t = t - 'a' + 10; - } else if (t >= 'A') { - t = t - 'A' + 10; - } else { - t = t - '0'; - } - bn_lshift(bn, shift, t); - } - frac_bits = 0; - if (ch == '.') { - ch = *p++; - while (1) { - t = ch; - if (t >= 'a' && t <= 'f') { - t = t - 'a' + 10; - } else if (t >= 'A' && t <= 'F') { - t = t - 'A' + 10; - } else if (t >= '0' && t <= '9') { - t = t - '0'; - } else { - break; - } - if (t >= b) - tcc_error("invalid digit"); - bn_lshift(bn, shift, t); - frac_bits += shift; - ch = *p++; - } - } - if (ch != 'p' && ch != 'P') - expect("exponent"); - ch = *p++; - s = 1; - exp_val = 0; - if (ch == '+') { - ch = *p++; - } else if (ch == '-') { - s = -1; - ch = *p++; - } - if (ch < '0' || ch > '9') - expect("exponent digits"); - while (ch >= '0' && ch <= '9') { - exp_val = exp_val * 10 + ch - '0'; - ch = *p++; - } - exp_val = exp_val * s; - - /* now we can generate the number */ - /* XXX: should patch directly float number */ - d = (double)bn[1] * 4294967296.0 + (double)bn[0]; - d = ldexp(d, exp_val - frac_bits); - t = toup(ch); - if (t == 'F') { - ch = *p++; - tok = TOK_CFLOAT; - /* float : should handle overflow */ - tokc.f = (float)d; - } else if (t == 'L') { - ch = *p++; - tok = TOK_CLDOUBLE; -#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE - tokc.d = d; -#else - /* XXX: not large enough */ - tokc.ld = (long double)d; -#endif - } else { - tok = TOK_CDOUBLE; - tokc.d = d; - } - } else { - /* decimal floats */ - if (ch == '.') { - if (q >= token_buf + STRING_MAX_SIZE) - goto num_too_long; - *q++ = ch; - ch = *p++; - float_frac_parse: - while (ch >= '0' && ch <= '9') { - if (q >= token_buf + STRING_MAX_SIZE) - goto num_too_long; - *q++ = ch; - ch = *p++; - } - } - if (ch == 'e' || ch == 'E') { - if (q >= token_buf + STRING_MAX_SIZE) - goto num_too_long; - *q++ = ch; - ch = *p++; - if (ch == '-' || ch == '+') { - if (q >= token_buf + STRING_MAX_SIZE) - goto num_too_long; - *q++ = ch; - ch = *p++; - } - if (ch < '0' || ch > '9') - expect("exponent digits"); - while (ch >= '0' && ch <= '9') { - if (q >= token_buf + STRING_MAX_SIZE) - goto num_too_long; - *q++ = ch; - ch = *p++; - } - } - *q = '\0'; - t = toup(ch); - errno = 0; - if (t == 'F') { - ch = *p++; - tok = TOK_CFLOAT; - tokc.f = strtof(token_buf, NULL); - } else if (t == 'L') { - ch = *p++; - tok = TOK_CLDOUBLE; -#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE - tokc.d = strtod(token_buf, NULL); -#else - tokc.ld = strtold(token_buf, NULL); -#endif - } else { - tok = TOK_CDOUBLE; - tokc.d = strtod(token_buf, NULL); - } - } - } else { - unsigned long long n, n1; - int lcount, ucount, ov = 0; - const char *p1; - - /* integer number */ - *q = '\0'; - q = token_buf; - if (b == 10 && *q == '0') { - b = 8; - q++; - } - n = 0; - while(1) { - t = *q++; - /* no need for checks except for base 10 / 8 errors */ - if (t == '\0') - break; - else if (t >= 'a') - t = t - 'a' + 10; - else if (t >= 'A') - t = t - 'A' + 10; - else - t = t - '0'; - if (t >= b) - tcc_error("invalid digit"); - n1 = n; - n = n * b + t; - /* detect overflow */ - if (n1 >= 0x1000000000000000ULL && n / b != n1) - ov = 1; - } - - /* Determine the characteristics (unsigned and/or 64bit) the type of - the constant must have according to the constant suffix(es) */ - lcount = ucount = 0; - p1 = p; - for(;;) { - t = toup(ch); - if (t == 'L') { - if (lcount >= 2) - tcc_error("three 'l's in integer constant"); - if (lcount && *(p - 1) != ch) - tcc_error("incorrect integer suffix: %s", p1); - lcount++; - ch = *p++; - } else if (t == 'U') { - if (ucount >= 1) - tcc_error("two 'u's in integer constant"); - ucount++; - ch = *p++; - } else { - break; - } - } - - /* Determine if it needs 64 bits and/or unsigned in order to fit */ - if (ucount == 0 && b == 10) { - if (lcount <= (LONG_SIZE == 4)) { - if (n >= 0x80000000U) - lcount = (LONG_SIZE == 4) + 1; - } - if (n >= 0x8000000000000000ULL) - ov = 1, ucount = 1; - } else { - if (lcount <= (LONG_SIZE == 4)) { - if (n >= 0x100000000ULL) - lcount = (LONG_SIZE == 4) + 1; - else if (n >= 0x80000000U) - ucount = 1; - } - if (n >= 0x8000000000000000ULL) - ucount = 1; - } - - if (ov) - tcc_warning("integer constant overflow"); - - tok = TOK_CINT; - if (lcount) { - tok = TOK_CLONG; - if (lcount == 2) - tok = TOK_CLLONG; - } - if (ucount) - ++tok; /* TOK_CU... */ - tokc.i = n; - } - if (ch) - tcc_error("invalid number"); -} - - -#define PARSE2(c1, tok1, c2, tok2) \ - case c1: \ - PEEKC(c, p); \ - if (c == c2) { \ - p++; \ - tok = tok2; \ - } else { \ - tok = tok1; \ - } \ - break; - -/* return next token without macro substitution */ -static inline void next_nomacro1(void) -{ - int t, c, is_long, len; - TokenSym *ts; - uint8_t *p, *p1; - unsigned int h; - - p = file->buf_ptr; - redo_no_start: - c = *p; - switch(c) { - case ' ': - case '\t': - tok = c; - p++; - maybe_space: - if (parse_flags & PARSE_FLAG_SPACES) - goto keep_tok_flags; - while (isidnum_table[*p - CH_EOF] & IS_SPC) - ++p; - goto redo_no_start; - case '\f': - case '\v': - case '\r': - p++; - goto redo_no_start; - case '\\': - /* first look if it is in fact an end of buffer */ - c = handle_stray(&p); - if (c == '\\') - goto parse_simple; - if (c == CH_EOF) { - TCCState *s1 = tcc_state; - if ((parse_flags & PARSE_FLAG_LINEFEED) - && !(tok_flags & TOK_FLAG_EOF)) { - tok_flags |= TOK_FLAG_EOF; - tok = TOK_LINEFEED; - goto keep_tok_flags; - } else if (!(parse_flags & PARSE_FLAG_PREPROCESS)) { - tok = TOK_EOF; - } else if (s1->ifdef_stack_ptr != file->ifdef_stack_ptr) { - tcc_error("missing #endif"); - } else if (s1->include_stack_ptr == s1->include_stack) { - /* no include left : end of file. */ - tok = TOK_EOF; - } else { - tok_flags &= ~TOK_FLAG_EOF; - /* pop include file */ - - /* test if previous '#endif' was after a #ifdef at - start of file */ - if (tok_flags & TOK_FLAG_ENDIF) { -#ifdef INC_DEBUG - printf("#endif %s\n", get_tok_str(file->ifndef_macro_saved, NULL)); -#endif - search_cached_include(s1, file->filename, 1) - ->ifndef_macro = file->ifndef_macro_saved; - tok_flags &= ~TOK_FLAG_ENDIF; - } - - /* add end of include file debug info */ - tcc_debug_eincl(tcc_state); - /* pop include stack */ - tcc_close(); - s1->include_stack_ptr--; - p = file->buf_ptr; - if (p == file->buffer) - tok_flags = TOK_FLAG_BOF; - tok_flags |= TOK_FLAG_BOL; - goto redo_no_start; - } - } else { - goto redo_no_start; - } - break; - - case '\n': - file->line_num++; - tok_flags |= TOK_FLAG_BOL; - p++; -maybe_newline: - if (0 == (parse_flags & PARSE_FLAG_LINEFEED)) - goto redo_no_start; - tok = TOK_LINEFEED; - goto keep_tok_flags; - - case '#': - /* XXX: simplify */ - PEEKC(c, p); - if ((tok_flags & TOK_FLAG_BOL) && - (parse_flags & PARSE_FLAG_PREPROCESS)) { - file->buf_ptr = p; - preprocess(tok_flags & TOK_FLAG_BOF); - p = file->buf_ptr; - goto maybe_newline; - } else { - if (c == '#') { - p++; - tok = TOK_TWOSHARPS; - } else { -#if !defined(TCC_TARGET_ARM) - if (parse_flags & PARSE_FLAG_ASM_FILE) { - p = parse_line_comment(p - 1); - goto redo_no_start; - } else -#endif - { - tok = '#'; - } - } - } - break; - - /* dollar is allowed to start identifiers when not parsing asm */ - case '$': - if (!(isidnum_table[c - CH_EOF] & IS_ID) - || (parse_flags & PARSE_FLAG_ASM_FILE)) - goto parse_simple; - - case 'a': case 'b': case 'c': case 'd': - case 'e': case 'f': case 'g': case 'h': - case 'i': case 'j': case 'k': case 'l': - case 'm': case 'n': case 'o': case 'p': - case 'q': case 'r': case 's': case 't': - case 'u': case 'v': case 'w': case 'x': - case 'y': case 'z': - case 'A': case 'B': case 'C': case 'D': - case 'E': case 'F': case 'G': case 'H': - case 'I': case 'J': case 'K': - case 'M': case 'N': case 'O': case 'P': - case 'Q': case 'R': case 'S': case 'T': - case 'U': case 'V': case 'W': case 'X': - case 'Y': case 'Z': - case '_': - parse_ident_fast: - p1 = p; - h = TOK_HASH_INIT; - h = TOK_HASH_FUNC(h, c); - while (c = *++p, isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM)) - h = TOK_HASH_FUNC(h, c); - len = p - p1; - if (c != '\\') { - TokenSym **pts; - - /* fast case : no stray found, so we have the full token - and we have already hashed it */ - h &= (TOK_HASH_SIZE - 1); - pts = &hash_ident[h]; - for(;;) { - ts = *pts; - if (!ts) - break; - if (ts->len == len && !memcmp(ts->str, p1, len)) - goto token_found; - pts = &(ts->hash_next); - } - ts = tok_alloc_new(pts, (char *) p1, len); - token_found: ; - } else { - /* slower case */ - cstr_reset(&tokcstr); - cstr_cat(&tokcstr, (char *) p1, len); - p--; - PEEKC(c, p); - parse_ident_slow: - while (isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM)) - { - cstr_ccat(&tokcstr, c); - PEEKC(c, p); - } - ts = tok_alloc(tokcstr.data, tokcstr.size); - } - tok = ts->tok; - break; - case 'L': - t = p[1]; - if (t != '\\' && t != '\'' && t != '\"') { - /* fast case */ - goto parse_ident_fast; - } else { - PEEKC(c, p); - if (c == '\'' || c == '\"') { - is_long = 1; - goto str_const; - } else { - cstr_reset(&tokcstr); - cstr_ccat(&tokcstr, 'L'); - goto parse_ident_slow; - } - } - break; - - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - case '8': case '9': - t = c; - PEEKC(c, p); - /* after the first digit, accept digits, alpha, '.' or sign if - prefixed by 'eEpP' */ - parse_num: - cstr_reset(&tokcstr); - for(;;) { - cstr_ccat(&tokcstr, t); - if (!((isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM)) - || c == '.' - || ((c == '+' || c == '-') - && (((t == 'e' || t == 'E') - && !(parse_flags & PARSE_FLAG_ASM_FILE - /* 0xe+1 is 3 tokens in asm */ - && ((char*)tokcstr.data)[0] == '0' - && toup(((char*)tokcstr.data)[1]) == 'X')) - || t == 'p' || t == 'P')))) - break; - t = c; - PEEKC(c, p); - } - /* We add a trailing '\0' to ease parsing */ - cstr_ccat(&tokcstr, '\0'); - tokc.str.size = tokcstr.size; - tokc.str.data = tokcstr.data; - tok = TOK_PPNUM; - break; - - case '.': - /* special dot handling because it can also start a number */ - PEEKC(c, p); - if (isnum(c)) { - t = '.'; - goto parse_num; - } else if ((isidnum_table['.' - CH_EOF] & IS_ID) - && (isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM))) { - *--p = c = '.'; - goto parse_ident_fast; - } else if (c == '.') { - PEEKC(c, p); - if (c == '.') { - p++; - tok = TOK_DOTS; - } else { - *--p = '.'; /* may underflow into file->unget[] */ - tok = '.'; - } - } else { - tok = '.'; - } - break; - case '\'': - case '\"': - is_long = 0; - str_const: - cstr_reset(&tokcstr); - if (is_long) - cstr_ccat(&tokcstr, 'L'); - cstr_ccat(&tokcstr, c); - p = parse_pp_string(p, c, &tokcstr); - cstr_ccat(&tokcstr, c); - cstr_ccat(&tokcstr, '\0'); - tokc.str.size = tokcstr.size; - tokc.str.data = tokcstr.data; - tok = TOK_PPSTR; - break; - - case '<': - PEEKC(c, p); - if (c == '=') { - p++; - tok = TOK_LE; - } else if (c == '<') { - PEEKC(c, p); - if (c == '=') { - p++; - tok = TOK_A_SHL; - } else { - tok = TOK_SHL; - } - } else { - tok = TOK_LT; - } - break; - case '>': - PEEKC(c, p); - if (c == '=') { - p++; - tok = TOK_GE; - } else if (c == '>') { - PEEKC(c, p); - if (c == '=') { - p++; - tok = TOK_A_SAR; - } else { - tok = TOK_SAR; - } - } else { - tok = TOK_GT; - } - break; - - case '&': - PEEKC(c, p); - if (c == '&') { - p++; - tok = TOK_LAND; - } else if (c == '=') { - p++; - tok = TOK_A_AND; - } else { - tok = '&'; - } - break; - - case '|': - PEEKC(c, p); - if (c == '|') { - p++; - tok = TOK_LOR; - } else if (c == '=') { - p++; - tok = TOK_A_OR; - } else { - tok = '|'; - } - break; - - case '+': - PEEKC(c, p); - if (c == '+') { - p++; - tok = TOK_INC; - } else if (c == '=') { - p++; - tok = TOK_A_ADD; - } else { - tok = '+'; - } - break; - - case '-': - PEEKC(c, p); - if (c == '-') { - p++; - tok = TOK_DEC; - } else if (c == '=') { - p++; - tok = TOK_A_SUB; - } else if (c == '>') { - p++; - tok = TOK_ARROW; - } else { - tok = '-'; - } - break; - - PARSE2('!', '!', '=', TOK_NE) - PARSE2('=', '=', '=', TOK_EQ) - PARSE2('*', '*', '=', TOK_A_MUL) - PARSE2('%', '%', '=', TOK_A_MOD) - PARSE2('^', '^', '=', TOK_A_XOR) - - /* comments or operator */ - case '/': - PEEKC(c, p); - if (c == '*') { - p = parse_comment(p); - /* comments replaced by a blank */ - tok = ' '; - goto maybe_space; - } else if (c == '/') { - p = parse_line_comment(p); - tok = ' '; - goto maybe_space; - } else if (c == '=') { - p++; - tok = TOK_A_DIV; - } else { - tok = '/'; - } - break; - - /* simple tokens */ - case '(': - case ')': - case '[': - case ']': - case '{': - case '}': - case ',': - case ';': - case ':': - case '?': - case '~': - case '@': /* only used in assembler */ - parse_simple: - tok = c; - p++; - break; - default: - if (c >= 0x80 && c <= 0xFF) /* utf8 identifiers */ - goto parse_ident_fast; - if (parse_flags & PARSE_FLAG_ASM_FILE) - goto parse_simple; - tcc_error("unrecognized character \\x%02x", c); - break; - } - tok_flags = 0; -keep_tok_flags: - file->buf_ptr = p; -#if defined(PARSE_DEBUG) - printf("token = %d %s\n", tok, get_tok_str(tok, &tokc)); -#endif -} - -static void macro_subst( - TokenString *tok_str, - Sym **nested_list, - const int *macro_str - ); - -/* substitute arguments in replacement lists in macro_str by the values in - args (field d) and return allocated string */ -static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args) -{ - int t, t0, t1, spc; - const int *st; - Sym *s; - CValue cval; - TokenString str; - - tok_str_new(&str); - t0 = t1 = 0; - while(1) { - TOK_GET(&t, ¯o_str, &cval); - if (!t) - break; - if (t == '#') { - /* stringize */ - TOK_GET(&t, ¯o_str, &cval); - if (!t) - goto bad_stringy; - s = sym_find2(args, t); - if (s) { - cstr_reset(&tokcstr); - cstr_ccat(&tokcstr, '\"'); - st = s->d; - spc = 0; - while (*st >= 0) { - TOK_GET(&t, &st, &cval); - if (t != TOK_PLCHLDR - && t != TOK_NOSUBST - && 0 == check_space(t, &spc)) { - const char *s = get_tok_str(t, &cval); - while (*s) { - if (t == TOK_PPSTR && *s != '\'') - add_char(&tokcstr, *s); - else - cstr_ccat(&tokcstr, *s); - ++s; - } - } - } - tokcstr.size -= spc; - cstr_ccat(&tokcstr, '\"'); - cstr_ccat(&tokcstr, '\0'); -#ifdef PP_DEBUG - printf("\nstringize: <%s>\n", (char *)tokcstr.data); -#endif - /* add string */ - cval.str.size = tokcstr.size; - cval.str.data = tokcstr.data; - tok_str_add2(&str, TOK_PPSTR, &cval); - } else { - bad_stringy: - expect("macro parameter after '#'"); - } - } else if (t >= TOK_IDENT) { - s = sym_find2(args, t); - if (s) { - st = s->d; - /* if '##' is present before or after, no arg substitution */ - if (*macro_str == TOK_PPJOIN || t1 == TOK_PPJOIN) { - /* special case for var arg macros : ## eats the ',' - if empty VA_ARGS variable. */ - if (t1 == TOK_PPJOIN && t0 == ',' && gnu_ext && s->type.t) { - if (*st <= 0) { - /* suppress ',' '##' */ - str.len -= 2; - } else { - /* suppress '##' and add variable */ - str.len--; - goto add_var; - } - } - } else { - add_var: - if (!s->next) { - /* Expand arguments tokens and store them. In most - cases we could also re-expand each argument if - used multiple times, but not if the argument - contains the __COUNTER__ macro. */ - TokenString str2; - sym_push2(&s->next, s->v, s->type.t, 0); - tok_str_new(&str2); - macro_subst(&str2, nested_list, st); - tok_str_add(&str2, 0); - s->next->d = str2.str; - } - st = s->next->d; - } - if (*st <= 0) { - /* expanded to empty string */ - tok_str_add(&str, TOK_PLCHLDR); - } else for (;;) { - int t2; - TOK_GET(&t2, &st, &cval); - if (t2 <= 0) - break; - tok_str_add2(&str, t2, &cval); - } - } else { - tok_str_add(&str, t); - } - } else { - tok_str_add2(&str, t, &cval); - } - t0 = t1, t1 = t; - } - tok_str_add(&str, 0); - return str.str; -} - -static char const ab_month_name[12][4] = -{ - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" -}; - -static int paste_tokens(int t1, CValue *v1, int t2, CValue *v2) -{ - int n, ret = 1; - - cstr_reset(&tokcstr); - if (t1 != TOK_PLCHLDR) - cstr_cat(&tokcstr, get_tok_str(t1, v1), -1); - n = tokcstr.size; - if (t2 != TOK_PLCHLDR) - cstr_cat(&tokcstr, get_tok_str(t2, v2), -1); - cstr_ccat(&tokcstr, '\0'); - //printf("paste <%s>\n", (char*)tokcstr.data); - - tcc_open_bf(tcc_state, ":paste:", tokcstr.size); - memcpy(file->buffer, tokcstr.data, tokcstr.size); - tok_flags = 0; - for (;;) { - next_nomacro1(); - if (0 == *file->buf_ptr) - break; - if (is_space(tok)) - continue; - tcc_warning("pasting \"%.*s\" and \"%s\" does not give a valid" - " preprocessing token", n, file->buffer, file->buffer + n); - ret = 0; - break; - } - tcc_close(); - return ret; -} - -/* handle the '##' operator. Return NULL if no '##' seen. Otherwise - return the resulting string (which must be freed). */ -static inline int *macro_twosharps(const int *ptr0) -{ - int t; - CValue cval; - TokenString macro_str1; - int start_of_nosubsts = -1; - const int *ptr; - - /* we search the first '##' */ - for (ptr = ptr0;;) { - TOK_GET(&t, &ptr, &cval); - if (t == TOK_PPJOIN) - break; - if (t == 0) - return NULL; - } - - tok_str_new(¯o_str1); - - //tok_print(" $$$", ptr0); - for (ptr = ptr0;;) { - TOK_GET(&t, &ptr, &cval); - if (t == 0) - break; - if (t == TOK_PPJOIN) - continue; - while (*ptr == TOK_PPJOIN) { - int t1; CValue cv1; - /* given 'a##b', remove nosubsts preceding 'a' */ - if (start_of_nosubsts >= 0) - macro_str1.len = start_of_nosubsts; - /* given 'a##b', remove nosubsts preceding 'b' */ - while ((t1 = *++ptr) == TOK_NOSUBST) - ; - if (t1 && t1 != TOK_PPJOIN) { - TOK_GET(&t1, &ptr, &cv1); - if (t != TOK_PLCHLDR || t1 != TOK_PLCHLDR) { - if (paste_tokens(t, &cval, t1, &cv1)) { - t = tok, cval = tokc; - } else { - tok_str_add2(¯o_str1, t, &cval); - t = t1, cval = cv1; - } - } - } - } - if (t == TOK_NOSUBST) { - if (start_of_nosubsts < 0) - start_of_nosubsts = macro_str1.len; - } else { - start_of_nosubsts = -1; - } - tok_str_add2(¯o_str1, t, &cval); - } - tok_str_add(¯o_str1, 0); - //tok_print(" ###", macro_str1.str); - return macro_str1.str; -} - -/* peek or read [ws_str == NULL] next token from function macro call, - walking up macro levels up to the file if necessary */ -static int next_argstream(Sym **nested_list, TokenString *ws_str) -{ - int t; - const int *p; - Sym *sa; - - for (;;) { - if (macro_ptr) { - p = macro_ptr, t = *p; - if (ws_str) { - while (is_space(t) || TOK_LINEFEED == t || TOK_PLCHLDR == t) - tok_str_add(ws_str, t), t = *++p; - } - if (t == 0) { - end_macro(); - /* also, end of scope for nested defined symbol */ - sa = *nested_list; - while (sa && sa->v == 0) - sa = sa->prev; - if (sa) - sa->v = 0; - continue; - } - } else { - uint8_t *p = file->buf_ptr; - int ch = handle_bs(&p); - if (ws_str) { - while (is_space(ch) || ch == '\n' || ch == '/') { - if (ch == '/') { - int c; - PEEKC(c, p); - if (c == '*') { - p = parse_comment(p) - 1; - } else if (c == '/') { - p = parse_line_comment(p) - 1; - } else { - *--p = ch; - break; - } - ch = ' '; - } - if (ch == '\n') - file->line_num++; - if (!(ch == '\f' || ch == '\v' || ch == '\r')) - tok_str_add(ws_str, ch); - PEEKC(ch, p); - } - } - file->buf_ptr = p; - t = ch; - } - - if (ws_str) - return t; - next_nomacro(); - return tok; - } -} - -/* do macro substitution of current token with macro 's' and add - result to (tok_str,tok_len). 'nested_list' is the list of all - macros we got inside to avoid recursing. Return non zero if no - substitution needs to be done */ -static int macro_subst_tok( - TokenString *tok_str, - Sym **nested_list, - Sym *s) -{ - Sym *args, *sa, *sa1; - int parlevel, t, t1, spc; - TokenString str; - char *cstrval; - CValue cval; - char buf[32]; - - /* if symbol is a macro, prepare substitution */ - /* special macros */ - if (tok == TOK___LINE__ || tok == TOK___COUNTER__) { - t = tok == TOK___LINE__ ? file->line_num : pp_counter++; - snprintf(buf, sizeof(buf), "%d", t); - cstrval = buf; - t1 = TOK_PPNUM; - goto add_cstr1; - } else if (tok == TOK___FILE__) { - cstrval = file->filename; - goto add_cstr; - } else if (tok == TOK___DATE__ || tok == TOK___TIME__) { - time_t ti; - struct tm *tm; - - time(&ti); - tm = localtime(&ti); - if (tok == TOK___DATE__) { - snprintf(buf, sizeof(buf), "%s %2d %d", - ab_month_name[tm->tm_mon], tm->tm_mday, tm->tm_year + 1900); - } else { - snprintf(buf, sizeof(buf), "%02d:%02d:%02d", - tm->tm_hour, tm->tm_min, tm->tm_sec); - } - cstrval = buf; - add_cstr: - t1 = TOK_STR; - add_cstr1: - cstr_reset(&tokcstr); - cstr_cat(&tokcstr, cstrval, 0); - cval.str.size = tokcstr.size; - cval.str.data = tokcstr.data; - tok_str_add2(tok_str, t1, &cval); - } else if (s->d) { - int saved_parse_flags = parse_flags; - int *joined_str = NULL; - int *mstr = s->d; - - if (s->type.t == MACRO_FUNC) { - /* whitespace between macro name and argument list */ - TokenString ws_str; - tok_str_new(&ws_str); - - spc = 0; - parse_flags |= PARSE_FLAG_SPACES | PARSE_FLAG_LINEFEED - | PARSE_FLAG_ACCEPT_STRAYS; - - /* get next token from argument stream */ - t = next_argstream(nested_list, &ws_str); - if (t != '(') { - /* not a macro substitution after all, restore the - * macro token plus all whitespace we've read. - * whitespace is intentionally not merged to preserve - * newlines. */ - parse_flags = saved_parse_flags; - tok_str_add(tok_str, tok); - if (parse_flags & PARSE_FLAG_SPACES) { - int i; - for (i = 0; i < ws_str.len; i++) - tok_str_add(tok_str, ws_str.str[i]); - } - if (ws_str.len && ws_str.str[ws_str.len - 1] == '\n') - tok_flags |= TOK_FLAG_BOL; - tok_str_free_str(ws_str.str); - return 0; - } else { - tok_str_free_str(ws_str.str); - } - do { - next_nomacro(); /* eat '(' */ - } while (tok == TOK_PLCHLDR || is_space(tok)); - - /* argument macro */ - args = NULL; - sa = s->next; - /* NOTE: empty args are allowed, except if no args */ - for(;;) { - do { - next_argstream(nested_list, NULL); - } while (tok == TOK_PLCHLDR || is_space(tok) || - TOK_LINEFEED == tok); - empty_arg: - /* handle '()' case */ - if (!args && !sa && tok == ')') - break; - if (!sa) - tcc_error("macro '%s' used with too many args", - get_tok_str(s->v, 0)); - tok_str_new(&str); - parlevel = spc = 0; - /* NOTE: non zero sa->t indicates VA_ARGS */ - while ((parlevel > 0 || - (tok != ')' && - (tok != ',' || sa->type.t)))) { - if (tok == TOK_EOF || tok == 0) - break; - if (tok == '(') - parlevel++; - else if (tok == ')') - parlevel--; - if (tok == TOK_LINEFEED) - tok = ' '; - if (!check_space(tok, &spc)) - tok_str_add2(&str, tok, &tokc); - next_argstream(nested_list, NULL); - } - if (parlevel) - expect(")"); - str.len -= spc; - tok_str_add(&str, -1); - tok_str_add(&str, 0); - sa1 = sym_push2(&args, sa->v & ~SYM_FIELD, sa->type.t, 0); - sa1->d = str.str; - sa = sa->next; - if (tok == ')') { - /* special case for gcc var args: add an empty - var arg argument if it is omitted */ - if (sa && sa->type.t && gnu_ext) - goto empty_arg; - break; - } - if (tok != ',') - expect(","); - } - if (sa) { - tcc_error("macro '%s' used with too few args", - get_tok_str(s->v, 0)); - } - - /* now subst each arg */ - mstr = macro_arg_subst(nested_list, mstr, args); - /* free memory */ - sa = args; - while (sa) { - sa1 = sa->prev; - tok_str_free_str(sa->d); - if (sa->next) { - tok_str_free_str(sa->next->d); - sym_free(sa->next); - } - sym_free(sa); - sa = sa1; - } - parse_flags = saved_parse_flags; - } - - sym_push2(nested_list, s->v, 0, 0); - parse_flags = saved_parse_flags; - joined_str = macro_twosharps(mstr); - macro_subst(tok_str, nested_list, joined_str ? joined_str : mstr); - - /* pop nested defined symbol */ - sa1 = *nested_list; - *nested_list = sa1->prev; - sym_free(sa1); - if (joined_str) - tok_str_free_str(joined_str); - if (mstr != s->d) - tok_str_free_str(mstr); - } - return 0; -} - -/* do macro substitution of macro_str and add result to - (tok_str,tok_len). 'nested_list' is the list of all macros we got - inside to avoid recursing. */ -static void macro_subst( - TokenString *tok_str, - Sym **nested_list, - const int *macro_str - ) -{ - Sym *s; - int t, spc, nosubst; - CValue cval; - - spc = nosubst = 0; - - while (1) { - TOK_GET(&t, ¯o_str, &cval); - if (t <= 0) - break; - - if (t >= TOK_IDENT && 0 == nosubst) { - s = define_find(t); - if (s == NULL) - goto no_subst; - - /* if nested substitution, do nothing */ - if (sym_find2(*nested_list, t)) { - /* and mark it as TOK_NOSUBST, so it doesn't get subst'd again */ - tok_str_add2(tok_str, TOK_NOSUBST, NULL); - goto no_subst; - } - - { - TokenString *str = tok_str_alloc(); - str->str = (int*)macro_str; - begin_macro(str, 2); - - tok = t; - macro_subst_tok(tok_str, nested_list, s); - - if (macro_stack != str) { - /* already finished by reading function macro arguments */ - break; - } - - macro_str = macro_ptr; - end_macro (); - } - if (tok_str->len) - spc = is_space(t = tok_str->str[tok_str->lastlen]); - } else { -no_subst: - if (!check_space(t, &spc)) - tok_str_add2(tok_str, t, &cval); - - if (nosubst) { - if (nosubst > 1 && (spc || (++nosubst == 3 && t == '('))) - continue; - nosubst = 0; - } - if (t == TOK_NOSUBST) - nosubst = 1; - } - /* GCC supports 'defined' as result of a macro substitution */ - if (t == TOK_DEFINED && pp_expr) - nosubst = 2; - } -} - -/* return next token without macro substitution. Can read input from - macro_ptr buffer */ -static void next_nomacro(void) -{ - int t; - if (macro_ptr) { - redo: - t = *macro_ptr; - if (TOK_HAS_VALUE(t)) { - tok_get(&tok, ¯o_ptr, &tokc); - if (t == TOK_LINENUM) { - file->line_num = tokc.i; - goto redo; - } - } else { - macro_ptr++; - if (t < TOK_IDENT) { - if (!(parse_flags & PARSE_FLAG_SPACES) - && (isidnum_table[t - CH_EOF] & IS_SPC)) - goto redo; - } - tok = t; - } - } else { - next_nomacro1(); - } -} - -/* return next token with macro substitution */ -ST_FUNC void next(void) -{ - int t; - redo: - next_nomacro(); - t = tok; - if (macro_ptr) { - if (!TOK_HAS_VALUE(t)) { - if (t == TOK_NOSUBST || t == TOK_PLCHLDR) { - /* discard preprocessor markers */ - goto redo; - } else if (t == 0) { - /* end of macro or unget token string */ - end_macro(); - goto redo; - } else if (t == '\\') { - if (!(parse_flags & PARSE_FLAG_ACCEPT_STRAYS)) - tcc_error("stray '\\' in program"); - } - return; - } - } else if (t >= TOK_IDENT && (parse_flags & PARSE_FLAG_PREPROCESS)) { - /* if reading from file, try to substitute macros */ - Sym *s = define_find(t); - if (s) { - Sym *nested_list = NULL; - tokstr_buf.len = 0; - macro_subst_tok(&tokstr_buf, &nested_list, s); - tok_str_add(&tokstr_buf, 0); - begin_macro(&tokstr_buf, 0); - goto redo; - } - return; - } - /* convert preprocessor tokens into C tokens */ - if (t == TOK_PPNUM) { - if (parse_flags & PARSE_FLAG_TOK_NUM) - parse_number((char *)tokc.str.data); - } else if (t == TOK_PPSTR) { - if (parse_flags & PARSE_FLAG_TOK_STR) - parse_string((char *)tokc.str.data, tokc.str.size - 1); - } -} - -/* push back current token and set current token to 'last_tok'. Only - identifier case handled for labels. */ -ST_INLN void unget_tok(int last_tok) -{ - - TokenString *str = tok_str_alloc(); - tok_str_add2(str, tok, &tokc); - tok_str_add(str, 0); - begin_macro(str, 1); - tok = last_tok; -} - -/* ------------------------------------------------------------------------- */ -/* init preprocessor */ - -static const char * const target_os_defs = -#ifdef TCC_TARGET_PE - "_WIN32\0" -# if PTR_SIZE == 8 - "_WIN64\0" -# endif -#else -# if defined TCC_TARGET_MACHO - "__APPLE__\0" -# elif TARGETOS_FreeBSD - "__FreeBSD__ 12\0" -# elif TARGETOS_FreeBSD_kernel - "__FreeBSD_kernel__\0" -# elif TARGETOS_NetBSD - "__NetBSD__\0" -# elif TARGETOS_OpenBSD - "__OpenBSD__\0" -# else - "__linux__\0" - "__linux\0" -# if TARGETOS_ANDROID - "__ANDROID__\0" -# endif -# endif - "__unix__\0" - "__unix\0" -#endif - ; - -static void putdef(CString *cs, const char *p) -{ - cstr_printf(cs, "#define %s%s\n", p, &" 1"[!!strchr(p, ' ')*2]); -} - -static void putdefs(CString *cs, const char *p) -{ - while (*p) - putdef(cs, p), p = strchr(p, 0) + 1; -} - -static void tcc_predefs(TCCState *s1, CString *cs, int is_asm) -{ - int a, b, c; - - sscanf(TCC_VERSION, "%d.%d.%d", &a, &b, &c); - cstr_printf(cs, "#define __TINYC__ %d\n", a*10000 + b*100 + c); - - putdefs(cs, target_machine_defs); - putdefs(cs, target_os_defs); - -#ifdef TCC_TARGET_ARM - if (s1->float_abi == ARM_HARD_FLOAT) - putdef(cs, "__ARM_PCS_VFP"); -#endif - if (is_asm) - putdef(cs, "__ASSEMBLER__"); - if (s1->output_type == TCC_OUTPUT_PREPROCESS) - putdef(cs, "__TCC_PP__"); - if (s1->output_type == TCC_OUTPUT_MEMORY) - putdef(cs, "__TCC_RUN__"); -#ifdef CONFIG_TCC_BACKTRACE - if (s1->do_backtrace) - putdef(cs, "__TCC_BACKTRACE__"); -#endif -#ifdef CONFIG_TCC_BCHECK - if (s1->do_bounds_check) - putdef(cs, "__TCC_BCHECK__"); -#endif - if (s1->char_is_unsigned) - putdef(cs, "__CHAR_UNSIGNED__"); - if (s1->optimize > 0) - putdef(cs, "__OPTIMIZE__"); - if (s1->option_pthread) - putdef(cs, "_REENTRANT"); - if (s1->leading_underscore) - putdef(cs, "__leading_underscore"); - cstr_printf(cs, "#define __SIZEOF_POINTER__ %d\n", PTR_SIZE); - cstr_printf(cs, "#define __SIZEOF_LONG__ %d\n", LONG_SIZE); - if (!is_asm) { - putdef(cs, "__STDC__"); - cstr_printf(cs, "#define __STDC_VERSION__ %dL\n", s1->cversion); - } - cstr_printf(cs, "#define __BASE_FILE__ \"%s\"\n", file->filename); -} - -ST_FUNC void preprocess_start(TCCState *s1, int filetype) -{ - int is_asm = !!(filetype & (AFF_TYPE_ASM|AFF_TYPE_ASMPP)); - - tccpp_new(s1); - - s1->include_stack_ptr = s1->include_stack; - s1->ifdef_stack_ptr = s1->ifdef_stack; - file->ifdef_stack_ptr = s1->ifdef_stack_ptr; - pp_expr = 0; - pp_counter = 0; - pp_debug_tok = pp_debug_symv = 0; - pp_once++; - s1->pack_stack[0] = 0; - s1->pack_stack_ptr = s1->pack_stack; - - set_idnum('$', !is_asm && s1->dollars_in_identifiers ? IS_ID : 0); - set_idnum('.', is_asm ? IS_ID : 0); - - if (!(filetype & AFF_TYPE_ASM)) { - CString cstr; - cstr_new(&cstr); - tcc_predefs(s1, &cstr, is_asm); - if (s1->cmdline_defs.size) - cstr_cat(&cstr, s1->cmdline_defs.data, s1->cmdline_defs.size); - if (s1->cmdline_incl.size) - cstr_cat(&cstr, s1->cmdline_incl.data, s1->cmdline_incl.size); - //printf("%s\n", (char*)cstr.data); - *s1->include_stack_ptr++ = file; - tcc_open_bf(s1, "<command line>", cstr.size); - memcpy(file->buffer, cstr.data, cstr.size); - cstr_free(&cstr); - } - - parse_flags = is_asm ? PARSE_FLAG_ASM_FILE : 0; - tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; -} - -/* cleanup from error/setjmp */ -ST_FUNC void preprocess_end(TCCState *s1) -{ - while (macro_stack) - end_macro(); - macro_ptr = NULL; - while (file) - tcc_close(); - tccpp_delete(s1); -} - -ST_FUNC int set_idnum(int c, int val) -{ - int prev = isidnum_table[c - CH_EOF]; - isidnum_table[c - CH_EOF] = val; - return prev; -} - -ST_FUNC void tccpp_new(TCCState *s) -{ - int i, c; - const char *p, *r; - - /* init isid table */ - for(i = CH_EOF; i<128; i++) - set_idnum(i, - is_space(i) ? IS_SPC - : isid(i) ? IS_ID - : isnum(i) ? IS_NUM - : 0); - - for(i = 128; i<256; i++) - set_idnum(i, IS_ID); - - /* init allocators */ - tal_new(&toksym_alloc, TOKSYM_TAL_LIMIT, TOKSYM_TAL_SIZE); - tal_new(&tokstr_alloc, TOKSTR_TAL_LIMIT, TOKSTR_TAL_SIZE); - - memset(hash_ident, 0, TOK_HASH_SIZE * sizeof(TokenSym *)); - memset(s->cached_includes_hash, 0, sizeof s->cached_includes_hash); - - cstr_new(&tokcstr); - cstr_new(&cstr_buf); - cstr_realloc(&cstr_buf, STRING_MAX_SIZE); - tok_str_new(&tokstr_buf); - tok_str_realloc(&tokstr_buf, TOKSTR_MAX_SIZE); - - tok_ident = TOK_IDENT; - p = tcc_keywords; - while (*p) { - r = p; - for(;;) { - c = *r++; - if (c == '\0') - break; - } - tok_alloc(p, r - p - 1); - p = r; - } - - /* we add dummy defines for some special macros to speed up tests - and to have working defined() */ - define_push(TOK___LINE__, MACRO_OBJ, NULL, NULL); - define_push(TOK___FILE__, MACRO_OBJ, NULL, NULL); - define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL); - define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL); - define_push(TOK___COUNTER__, MACRO_OBJ, NULL, NULL); -} - -ST_FUNC void tccpp_delete(TCCState *s) -{ - int i, n; - - dynarray_reset(&s->cached_includes, &s->nb_cached_includes); - - /* free tokens */ - n = tok_ident - TOK_IDENT; - if (n > total_idents) - total_idents = n; - for(i = 0; i < n; i++) - tal_free(toksym_alloc, table_ident[i]); - tcc_free(table_ident); - table_ident = NULL; - - /* free static buffers */ - cstr_free(&tokcstr); - cstr_free(&cstr_buf); - tok_str_free_str(tokstr_buf.str); - - /* free allocators */ - tal_delete(toksym_alloc); - toksym_alloc = NULL; - tal_delete(tokstr_alloc); - tokstr_alloc = NULL; -} - -/* ------------------------------------------------------------------------- */ -/* tcc -E [-P[1]] [-dD} support */ - -static void tok_print(const char *msg, const int *str) -{ - FILE *fp; - int t, s = 0; - CValue cval; - - fp = tcc_state->ppfp; - fprintf(fp, "%s", msg); - while (str) { - TOK_GET(&t, &str, &cval); - if (!t) - break; - fprintf(fp, &" %s"[s], get_tok_str(t, &cval)), s = 1; - } - fprintf(fp, "\n"); -} - -static void pp_line(TCCState *s1, BufferedFile *f, int level) -{ - int d = f->line_num - f->line_ref; - - if (s1->dflag & 4) - return; - - if (s1->Pflag == LINE_MACRO_OUTPUT_FORMAT_NONE) { - ; - } else if (level == 0 && f->line_ref && d < 8) { - while (d > 0) - fputs("\n", s1->ppfp), --d; - } else if (s1->Pflag == LINE_MACRO_OUTPUT_FORMAT_STD) { - fprintf(s1->ppfp, "#line %d \"%s\"\n", f->line_num, f->filename); - } else { - fprintf(s1->ppfp, "# %d \"%s\"%s\n", f->line_num, f->filename, - level > 0 ? " 1" : level < 0 ? " 2" : ""); - } - f->line_ref = f->line_num; -} - -static void define_print(TCCState *s1, int v) -{ - FILE *fp; - Sym *s; - - s = define_find(v); - if (NULL == s || NULL == s->d) - return; - - fp = s1->ppfp; - fprintf(fp, "#define %s", get_tok_str(v, NULL)); - if (s->type.t == MACRO_FUNC) { - Sym *a = s->next; - fprintf(fp,"("); - if (a) - for (;;) { - fprintf(fp,"%s", get_tok_str(a->v & ~SYM_FIELD, NULL)); - if (!(a = a->next)) - break; - fprintf(fp,","); - } - fprintf(fp,")"); - } - tok_print("", s->d); -} - -static void pp_debug_defines(TCCState *s1) -{ - int v, t; - const char *vs; - FILE *fp; - - t = pp_debug_tok; - if (t == 0) - return; - - file->line_num--; - pp_line(s1, file, 0); - file->line_ref = ++file->line_num; - - fp = s1->ppfp; - v = pp_debug_symv; - vs = get_tok_str(v, NULL); - if (t == TOK_DEFINE) { - define_print(s1, v); - } else if (t == TOK_UNDEF) { - fprintf(fp, "#undef %s\n", vs); - } else if (t == TOK_push_macro) { - fprintf(fp, "#pragma push_macro(\"%s\")\n", vs); - } else if (t == TOK_pop_macro) { - fprintf(fp, "#pragma pop_macro(\"%s\")\n", vs); - } - pp_debug_tok = 0; -} - -static void pp_debug_builtins(TCCState *s1) -{ - int v; - for (v = TOK_IDENT; v < tok_ident; ++v) - define_print(s1, v); -} - -/* Add a space between tokens a and b to avoid unwanted textual pasting */ -static int pp_need_space(int a, int b) -{ - return 'E' == a ? '+' == b || '-' == b - : '+' == a ? TOK_INC == b || '+' == b - : '-' == a ? TOK_DEC == b || '-' == b - : a >= TOK_IDENT ? b >= TOK_IDENT - : a == TOK_PPNUM ? b >= TOK_IDENT - : 0; -} - -/* maybe hex like 0x1e */ -static int pp_check_he0xE(int t, const char *p) -{ - if (t == TOK_PPNUM && toup(strchr(p, 0)[-1]) == 'E') - return 'E'; - return t; -} - -/* Preprocess the current file */ -ST_FUNC int tcc_preprocess(TCCState *s1) -{ - BufferedFile **iptr; - int token_seen, spcs, level; - const char *p; - char white[400]; - - parse_flags = PARSE_FLAG_PREPROCESS - | (parse_flags & PARSE_FLAG_ASM_FILE) - | PARSE_FLAG_LINEFEED - | PARSE_FLAG_SPACES - | PARSE_FLAG_ACCEPT_STRAYS - ; - /* Credits to Fabrice Bellard's initial revision to demonstrate its - capability to compile and run itself, provided all numbers are - given as decimals. tcc -E -P10 will do. */ - if (s1->Pflag == LINE_MACRO_OUTPUT_FORMAT_P10) - parse_flags |= PARSE_FLAG_TOK_NUM, s1->Pflag = 1; - - if (s1->do_bench) { - /* for PP benchmarks */ - do next(); while (tok != TOK_EOF); - return 0; - } - - if (s1->dflag & 1) { - pp_debug_builtins(s1); - s1->dflag &= ~1; - } - - token_seen = TOK_LINEFEED, spcs = 0, level = 0; - if (file->prev) - pp_line(s1, file->prev, level++); - pp_line(s1, file, level); - for (;;) { - iptr = s1->include_stack_ptr; - next(); - if (tok == TOK_EOF) - break; - - level = s1->include_stack_ptr - iptr; - if (level) { - if (level > 0) - pp_line(s1, *iptr, 0); - pp_line(s1, file, level); - } - if (s1->dflag & 7) { - pp_debug_defines(s1); - if (s1->dflag & 4) - continue; - } - - if (is_space(tok)) { - if (spcs < sizeof white - 1) - white[spcs++] = tok; - continue; - } else if (tok == TOK_LINEFEED) { - spcs = 0; - if (token_seen == TOK_LINEFEED) - continue; - ++file->line_ref; - } else if (token_seen == TOK_LINEFEED) { - pp_line(s1, file, 0); - } else if (spcs == 0 && pp_need_space(token_seen, tok)) { - white[spcs++] = ' '; - } - - white[spcs] = 0, fputs(white, s1->ppfp), spcs = 0; - fputs(p = get_tok_str(tok, &tokc), s1->ppfp); - token_seen = pp_check_he0xE(tok, p); - } - return 0; -} - -/* ------------------------------------------------------------------------- */ diff --git a/tinycc/tccrun.c b/tinycc/tccrun.c deleted file mode 100644 index d373abc..0000000 --- a/tinycc/tccrun.c +++ /dev/null @@ -1,1461 +0,0 @@ -/* - * TCC - Tiny C Compiler - Support for -run switch - * - * 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 - */ - -#include "tcc.h" - -/* only native compiler supports -run */ -#ifdef TCC_IS_NATIVE - -#ifdef CONFIG_TCC_BACKTRACE -typedef struct rt_context -{ - /* --> tccelf.c:tcc_add_btstub wants those below in that order: */ - union { - struct { - Stab_Sym *stab_sym, *stab_sym_end; - char *stab_str; - }; - struct { - unsigned char *dwarf_line, *dwarf_line_end, *dwarf_line_str; - }; - }; - addr_t dwarf; - ElfW(Sym) *esym_start, *esym_end; - char *elf_str; - addr_t prog_base; - void *bounds_start; - struct rt_context *next; - /* <-- */ - int num_callers; - addr_t ip, fp, sp; - void *top_func; - jmp_buf jmp_buf; - char do_jmp; -} rt_context; - -static rt_context g_rtctxt; -static void set_exception_handler(void); -static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap); -static void rt_exit(int code); -#endif /* CONFIG_TCC_BACKTRACE */ - -/* defined when included from lib/bt-exe.c */ -#ifndef CONFIG_TCC_BACKTRACE_ONLY - -#ifndef _WIN32 -# include <sys/mman.h> -#endif - -static int set_pages_executable(TCCState *s1, int mode, void *ptr, unsigned long length); -static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff); - -#ifdef _WIN64 -static void *win64_add_function_table(TCCState *s1); -static void win64_del_function_table(void *); -#endif - -/* ------------------------------------------------------------- */ -/* Do all relocations (needed before using tcc_get_symbol()) - Returns -1 on error. */ - -LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr) -{ - int size; - addr_t ptr_diff = 0; - - if (TCC_RELOCATE_AUTO != ptr) - return tcc_relocate_ex(s1, ptr, 0); - - size = tcc_relocate_ex(s1, NULL, 0); - if (size < 0) - return -1; - -#ifdef HAVE_SELINUX -{ - /* Using mmap instead of malloc */ - void *prx; - char tmpfname[] = "/tmp/.tccrunXXXXXX"; - int fd = mkstemp(tmpfname); - unlink(tmpfname); - ftruncate(fd, size); - - size = (size + (PAGESIZE-1)) & ~(PAGESIZE-1); - ptr = mmap(NULL, size * 2, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); - /* mmap RX memory at a fixed distance */ - prx = mmap((char*)ptr + size, size, PROT_READ|PROT_EXEC, MAP_SHARED|MAP_FIXED, fd, 0); - close(fd); - if (ptr == MAP_FAILED || prx == MAP_FAILED) - return tcc_error_noabort("tccrun: could not map memory"); - ptr_diff = (char*)prx - (char*)ptr; - //printf("map %p %p %p\n", ptr, prx, (void*)ptr_diff); -} -#else - ptr = tcc_malloc(size); -#endif - if (tcc_relocate_ex(s1, ptr, ptr_diff)) - return -1; - dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, (void*)(addr_t)size); - 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 += 2) { - unsigned size = (unsigned)(addr_t)s1->runtime_mem[i]; - void *ptr = s1->runtime_mem[i+1]; -#ifdef HAVE_SELINUX - munmap(ptr, size * 2); -#else - /* unprotect memory to make it usable for malloc again */ - set_pages_executable(s1, 2, ptr, size); -#ifdef _WIN64 - win64_del_function_table(*(void**)ptr); -#endif - tcc_free(ptr); -#endif - } - tcc_free(s1->runtime_mem); -} - -static void run_cdtors(TCCState *s1, const char *start, const char *end, - int argc, char **argv, char **envp) -{ - void **a = (void **)get_sym_addr(s1, start, 0, 0); - void **b = (void **)get_sym_addr(s1, end, 0, 0); - while (a != b) - ((void(*)(int, char **, char **))*a++)(argc, argv, envp); -} - -#define NR_AT_EXIT 32 - -static struct exit_context { - int exit_called; - int nr_exit; - void (*exitfunc[NR_AT_EXIT])(int, void *); - void *exitarg[NR_AT_EXIT]; -#ifndef CONFIG_TCC_BACKTRACE - jmp_buf run_jmp_buf; -#endif -} g_exit_context; - -static void init_exit(void) -{ - struct exit_context *e = &g_exit_context; - - e->exit_called = 0; - e->nr_exit = 0; -} - -static void call_exit(int ret) -{ - struct exit_context *e = &g_exit_context; - - while (e->nr_exit) { - e->nr_exit--; - e->exitfunc[e->nr_exit](ret, e->exitarg[e->nr_exit]); - } -} - -static int rt_atexit(void (*function)(void)) -{ - struct exit_context *e = &g_exit_context; - - if (e->nr_exit < NR_AT_EXIT) { - e->exitfunc[e->nr_exit] = (void (*)(int, void *))function; - e->exitarg[e->nr_exit++] = NULL; - return 0; - } - return 1; -} - -static int rt_on_exit(void (*function)(int, void *), void *arg) -{ - struct exit_context *e = &g_exit_context; - - if (e->nr_exit < NR_AT_EXIT) { - e->exitfunc[e->nr_exit] = function; - e->exitarg[e->nr_exit++] = arg; - return 0; - } - return 1; -} - -static void run_exit(int code) -{ - struct exit_context *e = &g_exit_context; - - e->exit_called = 1; -#ifdef CONFIG_TCC_BACKTRACE - longjmp((&g_rtctxt)->jmp_buf, code ? code : 256); -#else - longjmp(e->run_jmp_buf, code ? code : 256); -#endif -} - -/* launch the compiled program with the given arguments */ -LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv) -{ - int (*prog_main)(int, char **, char **), ret; -#ifdef CONFIG_TCC_BACKTRACE - rt_context *rc = &g_rtctxt; -#endif - -#if defined(__APPLE__) || defined(__FreeBSD__) - char **envp = NULL; -#elif defined(__OpenBSD__) || defined(__NetBSD__) - extern char **environ; - char **envp = environ; -#else - char **envp = environ; -#endif - - s1->runtime_main = s1->nostdlib ? "_start" : "main"; - if ((s1->dflag & 16) && (addr_t)-1 == get_sym_addr(s1, s1->runtime_main, 0, 1)) - return 0; - tcc_add_symbol(s1, "exit", run_exit); - tcc_add_symbol(s1, "atexit", rt_atexit); - tcc_add_symbol(s1, "on_exit", rt_on_exit); - if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0) - return -1; - prog_main = (void*)get_sym_addr(s1, s1->runtime_main, 1, 1); - if ((addr_t)-1 == (addr_t)prog_main) - return -1; - -#ifdef CONFIG_TCC_BACKTRACE - memset(rc, 0, sizeof *rc); - if (s1->do_debug) { - void *p; - if (s1->dwarf) { - rc->dwarf_line = dwarf_line_section->data; - rc->dwarf_line_end = dwarf_line_section->data + dwarf_line_section->data_offset; - if (dwarf_line_str_section) - rc->dwarf_line_str = dwarf_line_str_section->data; - } - else - { - rc->stab_sym = (Stab_Sym *)stab_section->data; - rc->stab_sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset); - rc->stab_str = (char *)stab_section->link->data; - } - rc->dwarf = s1->dwarf; - rc->esym_start = (ElfW(Sym) *)(symtab_section->data); - rc->esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset); - rc->elf_str = (char *)symtab_section->link->data; -#if PTR_SIZE == 8 - rc->prog_base = text_section->sh_addr & 0xffffffff00000000ULL; -#if defined TCC_TARGET_MACHO - if (s1->dwarf) - rc->prog_base = (addr_t) -1; -#else -#endif -#endif - rc->top_func = tcc_get_symbol(s1, "main"); - rc->num_callers = s1->rt_num_callers; - rc->do_jmp = 1; - if ((p = tcc_get_symbol(s1, "__rt_error"))) - *(void**)p = _rt_error; -#ifdef CONFIG_TCC_BCHECK - if (s1->do_bounds_check) { - rc->bounds_start = (void*)bounds_section->sh_addr; - if ((p = tcc_get_symbol(s1, "__bound_init"))) - ((void(*)(void*,int))p)(rc->bounds_start, 1); - } -#endif - set_exception_handler(); - } -#endif - - errno = 0; /* clean errno value */ - fflush(stdout); - fflush(stderr); - init_exit(); - /* These aren't C symbols, so don't need leading underscore handling. */ - run_cdtors(s1, "__init_array_start", "__init_array_end", argc, argv, envp); -#ifdef CONFIG_TCC_BACKTRACE - if (!(ret = setjmp(rc->jmp_buf))) -#else - if (!(ret = setjmp((&g_exit_context)->run_jmp_buf))) -#endif - { - ret = prog_main(argc, argv, envp); - } - run_cdtors(s1, "__fini_array_start", "__fini_array_end", 0, NULL, NULL); - call_exit(ret); - if ((s1->dflag & 16) && ret) - fprintf(s1->ppfp, "[returns %d]\n", ret), fflush(s1->ppfp); - if ((s1->dflag & 16) == 0 && (&g_exit_context)->exit_called) - exit(ret); - return ret; -} - -#define DEBUG_RUNMEN 0 - -/* enable rx/ro/rw permissions */ -#define CONFIG_RUNMEM_RO 1 - -#if CONFIG_RUNMEM_RO -# define PAGE_ALIGN PAGESIZE -#elif defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 -/* 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 */ -# define PAGE_ALIGN 64 -#else -# define PAGE_ALIGN 1 -#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, addr_t ptr_diff) -{ - Section *s; - unsigned offset, length, align, max_align, i, k, f; - unsigned n, copy; - addr_t mem, addr; - - if (NULL == ptr) { - s1->nb_errors = 0; -#ifdef TCC_TARGET_PE - pe_output_file(s1, NULL); -#else - tcc_add_runtime(s1); - resolve_common_syms(s1); - build_got_entries(s1, 0); -#endif - if (s1->nb_errors) - return -1; - } - - offset = max_align = 0, mem = (addr_t)ptr; -#ifdef _WIN64 - offset += sizeof (void*); /* space for function_table pointer */ -#endif - copy = 0; -redo: - for (k = 0; k < 3; ++k) { /* 0:rx, 1:ro, 2:rw sections */ - n = 0; addr = 0; - for(i = 1; i < s1->nb_sections; i++) { - static const char shf[] = { - SHF_ALLOC|SHF_EXECINSTR, SHF_ALLOC, SHF_ALLOC|SHF_WRITE - }; - s = s1->sections[i]; - if (shf[k] != (s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR))) - continue; - length = s->data_offset; - if (copy) { - if (addr == 0) - addr = s->sh_addr; - n = (s->sh_addr - addr) + length; - ptr = (void*)s->sh_addr; - if (k == 0) - ptr = (void*)(s->sh_addr - ptr_diff); - if (NULL == s->data || s->sh_type == SHT_NOBITS) - memset(ptr, 0, length); - else - memcpy(ptr, s->data, length); -#ifdef _WIN64 - if (s == s1->uw_pdata) - *(void**)mem = win64_add_function_table(s1); -#endif - if (s->data) { - tcc_free(s->data); - s->data = NULL; - s->data_allocated = 0; - } - s->data_offset = 0; - continue; - } - align = s->sh_addralign - 1; - if (++n == 1 && align < (PAGE_ALIGN - 1)) - align = (PAGE_ALIGN - 1); - if (max_align < align) - max_align = align; - addr = k ? mem : mem + ptr_diff; - offset += -(addr + offset) & align; - s->sh_addr = mem ? addr + offset : 0; - offset += length; -#if DEBUG_RUNMEN - if (mem) - printf("%d: %-16s %p len %04x align %04x\n", - k, s->name, (void*)s->sh_addr, length, align + 1); -#endif - } - if (copy) { /* set permissions */ - if (k == 0 && ptr_diff) - continue; /* not with HAVE_SELINUX */ - f = k; -#if !CONFIG_RUNMEM_RO - if (f != 0) - continue; - f = 3; /* change only SHF_EXECINSTR to rwx */ -#endif -#if DEBUG_RUNMEN - printf("protect %d %p %04x\n", f, (void*)addr, n); -#endif - if (n) { - if (set_pages_executable(s1, f, (void*)addr, n)) - return -1; - } - } - } - - if (copy) - return 0; - - /* relocate symbols */ - relocate_syms(s1, s1->symtab, !(s1->nostdlib)); - if (s1->nb_errors) - return -1; - if (0 == mem) - return offset + max_align; - -#ifdef TCC_TARGET_PE - s1->pe_imagebase = mem; -#endif - - /* relocate sections */ -#ifndef TCC_TARGET_PE - relocate_plt(s1); -#endif - relocate_sections(s1); - copy = 1; - goto redo; -} - -/* ------------------------------------------------------------- */ -/* allow to run code in memory */ - -static int set_pages_executable(TCCState *s1, int mode, void *ptr, unsigned long length) -{ -#ifdef _WIN32 - static const unsigned char protect[] = { - PAGE_EXECUTE_READ, - PAGE_READONLY, - PAGE_READWRITE, - PAGE_EXECUTE_READWRITE - }; - DWORD old; - if (!VirtualProtect(ptr, length, protect[mode], &old)) - return -1; - return 0; -#else - static const unsigned char protect[] = { - PROT_READ | PROT_EXEC, - PROT_READ, - PROT_READ | PROT_WRITE, - PROT_READ | PROT_WRITE | PROT_EXEC - }; - addr_t start, end; - start = (addr_t)ptr & ~(PAGESIZE - 1); - end = (addr_t)ptr + length; - end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1); - if (mprotect((void *)start, end - start, protect[mode])) - return tcc_error_noabort("mprotect failed: did you mean to configure --with-selinux?"); -/* XXX: BSD sometimes dump core with bad system call */ -# if (defined TCC_TARGET_ARM && !TARGETOS_BSD) || defined TCC_TARGET_ARM64 - if (mode == 0 || mode == 3) { - void __clear_cache(void *beginning, void *end); - __clear_cache(ptr, (char *)ptr + length); - } -# endif - return 0; -#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), - s1->pe_imagebase - ); - s1->uw_pdata = NULL; - } - return p; -} - -static void win64_del_function_table(void *p) -{ - if (p) { - RtlDeleteFunctionTable((RUNTIME_FUNCTION*)p); - } -} -#endif -#endif //ndef CONFIG_TCC_BACKTRACE_ONLY -/* ------------------------------------------------------------- */ -#ifdef CONFIG_TCC_BACKTRACE - -static int rt_vprintf(const char *fmt, va_list ap) -{ - int ret = vfprintf(stderr, fmt, ap); - fflush(stderr); - return ret; -} - -static int rt_printf(const char *fmt, ...) -{ - va_list ap; - int r; - va_start(ap, fmt); - r = rt_vprintf(fmt, ap); - va_end(ap); - return r; -} - -static char *rt_elfsym(rt_context *rc, addr_t wanted_pc, addr_t *func_addr) -{ - ElfW(Sym) *esym; - for (esym = rc->esym_start + 1; esym < rc->esym_end; ++esym) { - int type = ELFW(ST_TYPE)(esym->st_info); - if ((type == STT_FUNC || type == STT_GNU_IFUNC) - && wanted_pc >= esym->st_value - && wanted_pc < esym->st_value + esym->st_size) { - *func_addr = esym->st_value; - return rc->elf_str + esym->st_name; - } - } - return NULL; -} - - -/* print the position in the source file of PC value 'pc' by reading - the stabs debug information */ -static addr_t rt_printline (rt_context *rc, addr_t wanted_pc, - const char *msg, const char *skip) -{ - char func_name[128]; - addr_t func_addr, last_pc, pc; - const char *incl_files[INCLUDE_STACK_SIZE]; - int incl_index, last_incl_index, len, last_line_num, i; - const char *str, *p; - Stab_Sym *sym; - -next: - func_name[0] = '\0'; - func_addr = 0; - incl_index = 0; - last_pc = (addr_t)-1; - last_line_num = 1; - last_incl_index = 0; - - for (sym = rc->stab_sym + 1; sym < rc->stab_sym_end; ++sym) { - str = rc->stab_str + sym->n_strx; - pc = sym->n_value; - - switch(sym->n_type) { - case N_SLINE: - if (func_addr) - goto rel_pc; - case N_SO: - case N_SOL: - goto abs_pc; - case N_FUN: - if (sym->n_strx == 0) /* end of function */ - goto rel_pc; - abs_pc: -#if PTR_SIZE == 8 - /* Stab_Sym.n_value is only 32bits */ - pc += rc->prog_base; -#endif - goto check_pc; - rel_pc: - pc += func_addr; - check_pc: - if (pc >= wanted_pc && wanted_pc >= last_pc) - goto found; - break; - } - - switch(sym->n_type) { - /* function start or end */ - case N_FUN: - if (sym->n_strx == 0) - goto reset_func; - p = strchr(str, ':'); - if (0 == p || (len = p - str + 1, len > sizeof func_name)) - len = sizeof func_name; - pstrcpy(func_name, len, str); - func_addr = pc; - break; - /* line number info */ - case N_SLINE: - last_pc = pc; - last_line_num = sym->n_desc; - last_incl_index = incl_index; - break; - /* include files */ - case N_BINCL: - if (incl_index < INCLUDE_STACK_SIZE) - incl_files[incl_index++] = str; - break; - case N_EINCL: - if (incl_index > 1) - incl_index--; - break; - /* start/end of translation unit */ - case N_SO: - incl_index = 0; - if (sym->n_strx) { - /* do not add path */ - len = strlen(str); - if (len > 0 && str[len - 1] != '/') - incl_files[incl_index++] = str; - } - reset_func: - func_name[0] = '\0'; - func_addr = 0; - last_pc = (addr_t)-1; - break; - /* alternative file name (from #line or #include directives) */ - case N_SOL: - if (incl_index) - incl_files[incl_index-1] = str; - break; - } - } - - func_name[0] = '\0'; - func_addr = 0; - last_incl_index = 0; - /* we try symtab symbols (no line number info) */ - p = rt_elfsym(rc, wanted_pc, &func_addr); - if (p) { - pstrcpy(func_name, sizeof func_name, p); - goto found; - } - if ((rc = rc->next)) - goto next; -found: - i = last_incl_index; - if (i > 0) { - str = incl_files[--i]; - if (skip[0] && strstr(str, skip)) - return (addr_t)-1; - rt_printf("%s:%d: ", str, last_line_num); - } else - rt_printf("%08llx : ", (long long)wanted_pc); - rt_printf("%s %s", msg, func_name[0] ? func_name : "???"); -#if 0 - if (--i >= 0) { - rt_printf(" (included from "); - for (;;) { - rt_printf("%s", incl_files[i]); - if (--i < 0) - break; - rt_printf(", "); - } - rt_printf(")"); - } -#endif - return func_addr; -} - -/* ------------------------------------------------------------- */ -/* rt_printline - dwarf version */ - -#define MAX_128 ((8 * sizeof (long long) + 6) / 7) - -#define DIR_TABLE_SIZE (64) -#define FILE_TABLE_SIZE (512) - -#define dwarf_read_1(ln,end) \ - ((ln) < (end) ? *(ln)++ : 0) -#define dwarf_read_2(ln,end) \ - ((ln) + 2 < (end) ? (ln) += 2, read16le((ln) - 2) : 0) -#define dwarf_read_4(ln,end) \ - ((ln) + 4 < (end) ? (ln) += 4, read32le((ln) - 4) : 0) -#define dwarf_read_8(ln,end) \ - ((ln) + 8 < (end) ? (ln) += 8, read64le((ln) - 8) : 0) -#define dwarf_ignore_type(ln, end) /* timestamp/size/md5/... */ \ - switch (entry_format[j].form) { \ - case DW_FORM_data1: (ln) += 1; break; \ - case DW_FORM_data2: (ln) += 2; break; \ - case DW_FORM_data4: (ln) += 3; break; \ - case DW_FORM_data8: (ln) += 8; break; \ - case DW_FORM_data16: (ln) += 16; break; \ - case DW_FORM_udata: dwarf_read_uleb128(&(ln), (end)); break; \ - default: goto next_line; \ - } - -static unsigned long long -dwarf_read_uleb128(unsigned char **ln, unsigned char *end) -{ - unsigned char *cp = *ln; - unsigned long long retval = 0; - int i; - - for (i = 0; i < MAX_128; i++) { - unsigned long long byte = dwarf_read_1(cp, end); - - retval |= (byte & 0x7f) << (i * 7); - if ((byte & 0x80) == 0) - break; - } - *ln = cp; - return retval; -} - -static long long -dwarf_read_sleb128(unsigned char **ln, unsigned char *end) -{ - unsigned char *cp = *ln; - long long retval = 0; - int i; - - for (i = 0; i < MAX_128; i++) { - unsigned long long byte = dwarf_read_1(cp, end); - - retval |= (byte & 0x7f) << (i * 7); - if ((byte & 0x80) == 0) { - if ((byte & 0x40) && (i + 1) * 7 < 64) - retval |= -1LL << ((i + 1) * 7); - break; - } - } - *ln = cp; - return retval; -} - -static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc, - const char *msg, const char *skip) -{ - unsigned char *ln; - unsigned char *cp; - unsigned char *end; - unsigned char *opcode_length; - unsigned long long size; - unsigned int length; - unsigned char version; - unsigned int min_insn_length; - unsigned int max_ops_per_insn; - int line_base; - unsigned int line_range; - unsigned int opcode_base; - unsigned int opindex; - unsigned int col; - unsigned int i; - unsigned int j; - unsigned int len; - unsigned long long value; - struct { - unsigned int type; - unsigned int form; - } entry_format[256]; - unsigned int dir_size; -#if 0 - char *dirs[DIR_TABLE_SIZE]; -#endif - unsigned int filename_size; - struct dwarf_filename_struct { - unsigned int dir_entry; - char *name; - } filename_table[FILE_TABLE_SIZE]; - addr_t last_pc; - addr_t pc; - addr_t func_addr; - int line; - char *filename; - char *function; - -next: - ln = rc->dwarf_line; - while (ln < rc->dwarf_line_end) { - dir_size = 0; - filename_size = 0; - last_pc = 0; - pc = 0; - func_addr = 0; - line = 1; - filename = NULL; - function = NULL; - length = 4; - size = dwarf_read_4(ln, rc->dwarf_line_end); - if (size == 0xffffffffu) // dwarf 64 - length = 8, size = dwarf_read_8(ln, rc->dwarf_line_end); - end = ln + size; - if (end < ln || end > rc->dwarf_line_end) - break; - version = dwarf_read_2(ln, end); - if (version >= 5) - ln += length + 2; // address size, segment selector, prologue Length - else - ln += length; // prologue Length - min_insn_length = dwarf_read_1(ln, end); - if (version >= 4) - max_ops_per_insn = dwarf_read_1(ln, end); - else - max_ops_per_insn = 1; - ln++; // Initial value of 'is_stmt' - line_base = dwarf_read_1(ln, end); - line_base |= line_base >= 0x80 ? ~0xff : 0; - line_range = dwarf_read_1(ln, end); - opcode_base = dwarf_read_1(ln, end); - opcode_length = ln; - ln += opcode_base - 1; - opindex = 0; - if (version >= 5) { - col = dwarf_read_1(ln, end); - for (i = 0; i < col; i++) { - entry_format[i].type = dwarf_read_uleb128(&ln, end); - entry_format[i].form = dwarf_read_uleb128(&ln, end); - } - dir_size = dwarf_read_uleb128(&ln, end); - for (i = 0; i < dir_size; i++) { - for (j = 0; j < col; j++) { - if (entry_format[j].type == DW_LNCT_path) { - if (entry_format[j].form != DW_FORM_line_strp) - goto next_line; -#if 0 - value = length == 4 ? dwarf_read_4(ln, end) - : dwarf_read_8(ln, end); - if (i < DIR_TABLE_SIZE) - dirs[i] = (char *)rc->dwarf_line_str + value; -#else - length == 4 ? dwarf_read_4(ln, end) - : dwarf_read_8(ln, end); -#endif - } - else - dwarf_ignore_type(ln, end); - } - } - col = dwarf_read_1(ln, end); - for (i = 0; i < col; i++) { - entry_format[i].type = dwarf_read_uleb128(&ln, end); - entry_format[i].form = dwarf_read_uleb128(&ln, end); - } - filename_size = dwarf_read_uleb128(&ln, end); - for (i = 0; i < filename_size; i++) - for (j = 0; j < col; j++) { - if (entry_format[j].type == DW_LNCT_path) { - if (entry_format[j].form != DW_FORM_line_strp) - goto next_line; - value = length == 4 ? dwarf_read_4(ln, end) - : dwarf_read_8(ln, end); - if (i < FILE_TABLE_SIZE) - filename_table[i].name = - (char *)rc->dwarf_line_str + value; - } - else if (entry_format[j].type == DW_LNCT_directory_index) { - switch (entry_format[j].form) { - case DW_FORM_data1: value = dwarf_read_1(ln, end); break; - case DW_FORM_data2: value = dwarf_read_2(ln, end); break; - case DW_FORM_data4: value = dwarf_read_4(ln, end); break; - case DW_FORM_udata: value = dwarf_read_uleb128(&ln, end); break; - default: goto next_line; - } - if (i < FILE_TABLE_SIZE) - filename_table[i].dir_entry = value; - } - else - dwarf_ignore_type(ln, end); - } - } - else { - while ((dwarf_read_1(ln, end))) { -#if 0 - if (++dir_size < DIR_TABLE_SIZE) - dirs[dir_size - 1] = (char *)ln - 1; -#endif - while (dwarf_read_1(ln, end)) {} - } - while ((dwarf_read_1(ln, end))) { - if (++filename_size < FILE_TABLE_SIZE) { - filename_table[filename_size - 1].name = (char *)ln - 1; - while (dwarf_read_1(ln, end)) {} - filename_table[filename_size - 1].dir_entry = - dwarf_read_uleb128(&ln, end); - } - else { - while (dwarf_read_1(ln, end)) {} - dwarf_read_uleb128(&ln, end); - } - dwarf_read_uleb128(&ln, end); // time - dwarf_read_uleb128(&ln, end); // size - } - } - if (filename_size >= 1) - filename = filename_table[0].name; - while (ln < end) { - last_pc = pc; - i = dwarf_read_1(ln, end); - if (i >= opcode_base) { - if (max_ops_per_insn == 1) - pc += ((i - opcode_base) / line_range) * min_insn_length; - else { - pc += (opindex + (i - opcode_base) / line_range) / - max_ops_per_insn * min_insn_length; - opindex = (opindex + (i - opcode_base) / line_range) % - max_ops_per_insn; - } - i = (int)((i - opcode_base) % line_range) + line_base; -check_pc: - if (pc >= wanted_pc && wanted_pc >= last_pc) - goto found; - line += i; - } - else { - switch (i) { - case 0: - len = dwarf_read_uleb128(&ln, end); - cp = ln; - ln += len; - if (len == 0) - goto next_line; - switch (dwarf_read_1(cp, end)) { - case DW_LNE_end_sequence: - break; - case DW_LNE_set_address: -#if PTR_SIZE == 4 - pc = dwarf_read_4(cp, end); -#else - pc = dwarf_read_8(cp, end); -#endif -#if defined TCC_TARGET_MACHO - if (rc->prog_base != (addr_t) -1) - pc += rc->prog_base; -#endif - opindex = 0; - break; - case DW_LNE_define_file: /* deprecated */ - if (++filename_size < FILE_TABLE_SIZE) { - filename_table[filename_size - 1].name = (char *)ln - 1; - while (dwarf_read_1(ln, end)) {} - filename_table[filename_size - 1].dir_entry = - dwarf_read_uleb128(&ln, end); - } - else { - while (dwarf_read_1(ln, end)) {} - dwarf_read_uleb128(&ln, end); - } - dwarf_read_uleb128(&ln, end); // time - dwarf_read_uleb128(&ln, end); // size - break; - case DW_LNE_hi_user - 1: - function = (char *)cp; - func_addr = pc; - break; - default: - break; - } - break; - case DW_LNS_advance_pc: - if (max_ops_per_insn == 1) - pc += dwarf_read_uleb128(&ln, end) * min_insn_length; - else { - unsigned long long off = dwarf_read_uleb128(&ln, end); - - pc += (opindex + off) / max_ops_per_insn * - min_insn_length; - opindex = (opindex + off) % max_ops_per_insn; - } - i = 0; - goto check_pc; - case DW_LNS_advance_line: - line += dwarf_read_sleb128(&ln, end); - break; - case DW_LNS_set_file: - i = dwarf_read_uleb128(&ln, end); - i -= i > 0 && version < 5; - if (i < FILE_TABLE_SIZE && i < filename_size) - filename = filename_table[i].name; - break; - case DW_LNS_const_add_pc: - if (max_ops_per_insn == 1) - pc += ((255 - opcode_base) / line_range) * min_insn_length; - else { - unsigned int off = (255 - opcode_base) / line_range; - - pc += ((opindex + off) / max_ops_per_insn) * - min_insn_length; - opindex = (opindex + off) % max_ops_per_insn; - } - i = 0; - goto check_pc; - case DW_LNS_fixed_advance_pc: - i = dwarf_read_2(ln, end); - pc += i; - opindex = 0; - i = 0; - goto check_pc; - default: - for (j = 0; j < opcode_length[i - 1]; j++) - dwarf_read_uleb128 (&ln, end); - break; - } - } - } -next_line: - ln = end; - } - - filename = NULL; - func_addr = 0; - /* we try symtab symbols (no line number info) */ - function = rt_elfsym(rc, wanted_pc, &func_addr); - if (function) - goto found; - if ((rc = rc->next)) - goto next; -found: - if (filename) { - if (skip[0] && strstr(filename, skip)) - return (addr_t)-1; - rt_printf("%s:%d: ", filename, line); - } - else - rt_printf("0x%08llx : ", (long long)wanted_pc); - rt_printf("%s %s", msg, function ? function : "???"); - return (addr_t)func_addr; -} -/* ------------------------------------------------------------- */ - -static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level); - -static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap) -{ - rt_context *rc = &g_rtctxt; - addr_t pc = 0; - char skip[100]; - int i, level, ret, n; - const char *a, *b, *msg; - - if (fp) { - /* we're called from tcc_backtrace. */ - rc->fp = (addr_t)fp; - rc->ip = (addr_t)ip; - msg = ""; - } else { - /* we're called from signal/exception handler */ - msg = "RUNTIME ERROR: "; - } - - skip[0] = 0; - /* If fmt is like "^file.c^..." then skip calls from 'file.c' */ - if (fmt[0] == '^' && (b = strchr(a = fmt + 1, fmt[0]))) { - memcpy(skip, a, b - a), skip[b - a] = 0; - fmt = b + 1; - } - - n = rc->num_callers ? rc->num_callers : 6; - for (i = level = 0; level < n; i++) { - ret = rt_get_caller_pc(&pc, rc, i); - a = "%s"; - if (ret != -1) { - if (rc->dwarf) - pc = rt_printline_dwarf(rc, pc, level ? "by" : "at", skip); - else - pc = rt_printline(rc, pc, level ? "by" : "at", skip); - if (pc == (addr_t)-1) - continue; - a = ": %s"; - } - if (level == 0) { - rt_printf(a, msg); - rt_vprintf(fmt, ap); - } else if (ret == -1) - break; - rt_printf("\n"); - if (ret == -1 || (pc == (addr_t)rc->top_func && pc)) - break; - ++level; - } - - rc->ip = rc->fp = 0; - return 0; -} - -/* emit a run time error at position 'pc' */ -static int rt_error(const char *fmt, ...) -{ - va_list ap; - int ret; - va_start(ap, fmt); - ret = _rt_error(0, 0, fmt, ap); - va_end(ap); - return ret; -} - -static void rt_exit(int code) -{ - rt_context *rc = &g_rtctxt; - if (rc->do_jmp) - longjmp(rc->jmp_buf, code ? code : 256); - exit(code); -} - -/* ------------------------------------------------------------- */ - -#ifndef _WIN32 -# include <signal.h> -# ifndef __OpenBSD__ -# include <sys/ucontext.h> -# endif -#else -# define ucontext_t CONTEXT -#endif - -/* translate from ucontext_t* to internal rt_context * */ -static void rt_getcontext(ucontext_t *uc, rt_context *rc) -{ -#if defined _WIN64 - rc->ip = uc->Rip; - rc->fp = uc->Rbp; - rc->sp = uc->Rsp; -#elif defined _WIN32 - rc->ip = uc->Eip; - rc->fp = uc->Ebp; - rc->sp = uc->Esp; -#elif defined __i386__ -# if defined(__APPLE__) - rc->ip = uc->uc_mcontext->__ss.__eip; - rc->fp = uc->uc_mcontext->__ss.__ebp; -# elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) - rc->ip = uc->uc_mcontext.mc_eip; - rc->fp = uc->uc_mcontext.mc_ebp; -# elif defined(__dietlibc__) - rc->ip = uc->uc_mcontext.eip; - rc->fp = uc->uc_mcontext.ebp; -# elif defined(__NetBSD__) - rc->ip = uc->uc_mcontext.__gregs[_REG_EIP]; - rc->fp = uc->uc_mcontext.__gregs[_REG_EBP]; -# elif defined(__OpenBSD__) - rc->ip = uc->sc_eip; - rc->fp = uc->sc_ebp; -# elif !defined REG_EIP && defined EIP /* fix for glibc 2.1 */ - rc->ip = uc->uc_mcontext.gregs[EIP]; - rc->fp = uc->uc_mcontext.gregs[EBP]; -# else - rc->ip = uc->uc_mcontext.gregs[REG_EIP]; - rc->fp = uc->uc_mcontext.gregs[REG_EBP]; -# endif -#elif defined(__x86_64__) -# if defined(__APPLE__) - rc->ip = uc->uc_mcontext->__ss.__rip; - rc->fp = uc->uc_mcontext->__ss.__rbp; -# elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) - rc->ip = uc->uc_mcontext.mc_rip; - rc->fp = uc->uc_mcontext.mc_rbp; -# elif defined(__NetBSD__) - rc->ip = uc->uc_mcontext.__gregs[_REG_RIP]; - rc->fp = uc->uc_mcontext.__gregs[_REG_RBP]; -# elif defined(__OpenBSD__) - rc->ip = uc->sc_rip; - rc->fp = uc->sc_rbp; -# else - rc->ip = uc->uc_mcontext.gregs[REG_RIP]; - rc->fp = uc->uc_mcontext.gregs[REG_RBP]; -# endif -#elif defined(__arm__) && defined(__NetBSD__) - rc->ip = uc->uc_mcontext.__gregs[_REG_PC]; - rc->fp = uc->uc_mcontext.__gregs[_REG_FP]; -#elif defined(__arm__) && defined(__OpenBSD__) - rc->ip = uc->sc_pc; - rc->fp = uc->sc_r11; -#elif defined(__arm__) && defined(__FreeBSD__) - rc->ip = uc->uc_mcontext.__gregs[_REG_PC]; - rc->fp = uc->uc_mcontext.__gregs[_REG_FP]; -#elif defined(__arm__) - rc->ip = uc->uc_mcontext.arm_pc; - rc->fp = uc->uc_mcontext.arm_fp; -#elif defined(__aarch64__) && defined(__APPLE__) - // see: - // /Library/Developer/CommandLineTools/SDKs/MacOSX11.1.sdk/usr/include/mach/arm/_structs.h - rc->ip = uc->uc_mcontext->__ss.__pc; - rc->fp = uc->uc_mcontext->__ss.__fp; -#elif defined(__aarch64__) && defined(__FreeBSD__) - rc->ip = uc->uc_mcontext.mc_gpregs.gp_elr; /* aka REG_PC */ - rc->fp = uc->uc_mcontext.mc_gpregs.gp_x[29]; -#elif defined(__aarch64__) && defined(__NetBSD__) - rc->ip = uc->uc_mcontext.__gregs[_REG_PC]; - rc->fp = uc->uc_mcontext.__gregs[_REG_FP]; -#elif defined(__aarch64__) && defined(__OpenBSD__) - rc->ip = uc->sc_elr; - rc->fp = uc->sc_x[29]; -#elif defined(__aarch64__) - rc->ip = uc->uc_mcontext.pc; - rc->fp = uc->uc_mcontext.regs[29]; -#elif defined(__riscv) && defined(__OpenBSD__) - rc->ip = uc->sc_sepc; - rc->fp = uc->sc_s[0]; -#elif defined(__riscv) - rc->ip = uc->uc_mcontext.__gregs[REG_PC]; - rc->fp = uc->uc_mcontext.__gregs[REG_S0]; -#endif -} - -/* ------------------------------------------------------------- */ -#ifndef _WIN32 -/* signal handler for fatal errors */ -static void sig_error(int signum, siginfo_t *siginf, void *puc) -{ - rt_context *rc = &g_rtctxt; - rt_getcontext(puc, rc); - - switch(signum) { - case SIGFPE: - switch(siginf->si_code) { - case FPE_INTDIV: - case FPE_FLTDIV: - rt_error("division by zero"); - break; - default: - rt_error("floating point exception"); - break; - } - break; - case SIGBUS: - case SIGSEGV: - rt_error("invalid memory access"); - break; - case SIGILL: - rt_error("illegal instruction"); - break; - case SIGABRT: - rt_error("abort() called"); - break; - default: - rt_error("caught signal %d", signum); - break; - } - rt_exit(255); -} - -#ifndef SA_SIGINFO -# define SA_SIGINFO 0x00000004u -#endif - -/* Generate a stack backtrace when a CPU exception occurs. */ -static void set_exception_handler(void) -{ - struct sigaction sigact; - /* install TCC signal handlers to print debug info on fatal - runtime errors */ - sigemptyset (&sigact.sa_mask); - sigact.sa_flags = SA_SIGINFO | SA_RESETHAND; -#if 0//def SIGSTKSZ // this causes signals not to work at all on some (older) linuxes - sigact.sa_flags |= SA_ONSTACK; -#endif - sigact.sa_sigaction = sig_error; - sigemptyset(&sigact.sa_mask); - sigaction(SIGFPE, &sigact, NULL); - sigaction(SIGILL, &sigact, NULL); - sigaction(SIGSEGV, &sigact, NULL); - sigaction(SIGBUS, &sigact, NULL); - sigaction(SIGABRT, &sigact, NULL); -#if 0//def SIGSTKSZ - /* This allows stack overflow to be reported instead of a SEGV */ - { - stack_t ss; - static unsigned char stack[SIGSTKSZ] __attribute__((aligned(16))); - - ss.ss_sp = stack; - ss.ss_size = SIGSTKSZ; - ss.ss_flags = 0; - sigaltstack(&ss, NULL); - } -#endif -} - -#else /* WIN32 */ - -/* signal handler for fatal errors */ -static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info) -{ - rt_context *rc = &g_rtctxt; - unsigned code; - rt_getcontext(ex_info->ContextRecord, rc); - - switch (code = ex_info->ExceptionRecord->ExceptionCode) { - case EXCEPTION_ACCESS_VIOLATION: - rt_error("invalid memory access"); - break; - case EXCEPTION_STACK_OVERFLOW: - rt_error("stack overflow"); - break; - case EXCEPTION_INT_DIVIDE_BY_ZERO: - rt_error("division by zero"); - break; - case EXCEPTION_BREAKPOINT: - case EXCEPTION_SINGLE_STEP: - rc->ip = *(addr_t*)rc->sp; - rt_error("breakpoint/single-step exception:"); - return EXCEPTION_CONTINUE_SEARCH; - default: - rt_error("caught exception %08x", code); - break; - } - if (rc->do_jmp) - rt_exit(255); - return EXCEPTION_EXECUTE_HANDLER; -} - -/* Generate a stack backtrace when a CPU exception occurs. */ -static void set_exception_handler(void) -{ - SetUnhandledExceptionFilter(cpu_exception_handler); -} - -#endif - -/* ------------------------------------------------------------- */ -/* return the PC at frame level 'level'. Return negative if not found */ -#if defined(__i386__) || defined(__x86_64__) -static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level) -{ - addr_t ip, fp; - if (level == 0) { - ip = rc->ip; - } else { - ip = 0; - fp = rc->fp; - while (--level) { - /* XXX: check address validity with program info */ - if (fp <= 0x1000) - break; - fp = ((addr_t *)fp)[0]; - } - if (fp > 0x1000) - ip = ((addr_t *)fp)[1]; - } - if (ip <= 0x1000) - return -1; - *paddr = ip; - return 0; -} - -#elif defined(__arm__) -static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level) -{ - /* XXX: only supports linux/bsd */ -#if !defined(__linux__) && \ - !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) - return -1; -#else - if (level == 0) { - *paddr = rc->ip; - } else { - addr_t fp = rc->fp; - while (--level) - fp = ((addr_t *)fp)[0]; - *paddr = ((addr_t *)fp)[2]; - } - return 0; -#endif -} - -#elif defined(__aarch64__) -static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level) -{ - if (level == 0) { - *paddr = rc->ip; - } else { - addr_t *fp = (addr_t*)rc->fp; - while (--level) - fp = (addr_t *)fp[0]; - *paddr = fp[1]; - } - return 0; -} - -#elif defined(__riscv) -static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level) -{ - if (level == 0) { - *paddr = rc->ip; - } else { - addr_t *fp = (addr_t*)rc->fp; - while (--level && fp >= (addr_t*)0x1000) - fp = (addr_t *)fp[-2]; - if (fp < (addr_t*)0x1000) - return -1; - *paddr = fp[-1]; - } - return 0; -} - -#else -#warning add arch specific rt_get_caller_pc() -static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level) -{ - return -1; -} - -#endif -#endif /* CONFIG_TCC_BACKTRACE */ -/* ------------------------------------------------------------- */ -#ifdef CONFIG_TCC_STATIC - -/* dummy function for profiling */ -ST_FUNC void *dlopen(const char *filename, int flag) -{ - return NULL; -} - -ST_FUNC void dlclose(void *p) -{ -} - -ST_FUNC const char *dlerror(void) -{ - return "error"; -} - -typedef struct TCCSyms { - char *str; - void *ptr; -} TCCSyms; - - -/* add the symbol you want here if no dynamic linking is done */ -static TCCSyms tcc_syms[] = { -#if !defined(CONFIG_TCCBOOT) -#define TCCSYM(a) { #a, &a, }, - TCCSYM(printf) - TCCSYM(fprintf) - TCCSYM(fopen) - TCCSYM(fclose) -#undef TCCSYM -#endif - { NULL, NULL }, -}; - -ST_FUNC void *dlsym(void *handle, const char *symbol) -{ - TCCSyms *p; - p = tcc_syms; - while (p->str != NULL) { - if (!strcmp(p->str, symbol)) - return p->ptr; - p++; - } - return NULL; -} - -#endif /* CONFIG_TCC_STATIC */ -#endif /* TCC_IS_NATIVE */ -/* ------------------------------------------------------------- */ diff --git a/tinycc/tcctok.h b/tinycc/tcctok.h deleted file mode 100644 index cfdc60d..0000000 --- a/tinycc/tcctok.h +++ /dev/null @@ -1,420 +0,0 @@ -/*********************************************************************/ -/* keywords */ - DEF(TOK_INT, "int") - DEF(TOK_VOID, "void") - DEF(TOK_CHAR, "char") - DEF(TOK_IF, "if") - DEF(TOK_ELSE, "else") - DEF(TOK_WHILE, "while") - DEF(TOK_BREAK, "break") - DEF(TOK_RETURN, "return") - DEF(TOK_FOR, "for") - DEF(TOK_EXTERN, "extern") - DEF(TOK_STATIC, "static") - DEF(TOK_UNSIGNED, "unsigned") - DEF(TOK_GOTO, "goto") - DEF(TOK_DO, "do") - DEF(TOK_CONTINUE, "continue") - DEF(TOK_SWITCH, "switch") - DEF(TOK_CASE, "case") - - DEF(TOK__Atomic, "_Atomic") - DEF(TOK_CONST1, "const") - DEF(TOK_CONST2, "__const") /* gcc keyword */ - DEF(TOK_CONST3, "__const__") /* gcc keyword */ - DEF(TOK_VOLATILE1, "volatile") - DEF(TOK_VOLATILE2, "__volatile") /* gcc keyword */ - DEF(TOK_VOLATILE3, "__volatile__") /* gcc keyword */ - DEF(TOK_LONG, "long") - DEF(TOK_REGISTER, "register") - DEF(TOK_SIGNED1, "signed") - DEF(TOK_SIGNED2, "__signed") /* gcc keyword */ - DEF(TOK_SIGNED3, "__signed__") /* gcc keyword */ - DEF(TOK_AUTO, "auto") - DEF(TOK_INLINE1, "inline") - DEF(TOK_INLINE2, "__inline") /* gcc keyword */ - DEF(TOK_INLINE3, "__inline__") /* gcc keyword */ - DEF(TOK_RESTRICT1, "restrict") - DEF(TOK_RESTRICT2, "__restrict") - DEF(TOK_RESTRICT3, "__restrict__") - DEF(TOK_EXTENSION, "__extension__") /* gcc keyword */ - DEF(TOK_THREAD_LOCAL, "_Thread_local") /* C11 thread-local storage */ - - DEF(TOK_GENERIC, "_Generic") - DEF(TOK_STATIC_ASSERT, "_Static_assert") - - DEF(TOK_FLOAT, "float") - DEF(TOK_DOUBLE, "double") - DEF(TOK_BOOL, "_Bool") - DEF(TOK_COMPLEX, "_Complex") - DEF(TOK_SHORT, "short") - DEF(TOK_STRUCT, "struct") - DEF(TOK_UNION, "union") - DEF(TOK_TYPEDEF, "typedef") - DEF(TOK_DEFAULT, "default") - DEF(TOK_ENUM, "enum") - DEF(TOK_SIZEOF, "sizeof") - DEF(TOK_ATTRIBUTE1, "__attribute") - DEF(TOK_ATTRIBUTE2, "__attribute__") - DEF(TOK_ALIGNOF1, "__alignof") - DEF(TOK_ALIGNOF2, "__alignof__") - DEF(TOK_ALIGNOF3, "_Alignof") - DEF(TOK_ALIGNAS, "_Alignas") - DEF(TOK_TYPEOF1, "typeof") - DEF(TOK_TYPEOF2, "__typeof") - DEF(TOK_TYPEOF3, "__typeof__") - DEF(TOK_LABEL, "__label__") - DEF(TOK_ASM1, "asm") - 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 */ - DEF(TOK_DEFINE, "define") - DEF(TOK_INCLUDE, "include") - DEF(TOK_INCLUDE_NEXT, "include_next") - DEF(TOK_IFDEF, "ifdef") - DEF(TOK_IFNDEF, "ifndef") - DEF(TOK_ELIF, "elif") - DEF(TOK_ENDIF, "endif") - DEF(TOK_DEFINED, "defined") - DEF(TOK_UNDEF, "undef") - DEF(TOK_ERROR, "error") - DEF(TOK_WARNING, "warning") - DEF(TOK_LINE, "line") - DEF(TOK_PRAGMA, "pragma") - DEF(TOK___LINE__, "__LINE__") - DEF(TOK___FILE__, "__FILE__") - DEF(TOK___DATE__, "__DATE__") - DEF(TOK___TIME__, "__TIME__") - DEF(TOK___FUNCTION__, "__FUNCTION__") - DEF(TOK___VA_ARGS__, "__VA_ARGS__") - DEF(TOK___COUNTER__, "__COUNTER__") - DEF(TOK___HAS_INCLUDE, "__has_include") - DEF(TOK___HAS_INCLUDE_NEXT, "__has_include_next") - -/* special identifiers */ - DEF(TOK___FUNC__, "__func__") - -/* special floating point values */ - DEF(TOK___NAN__, "__nan__") - DEF(TOK___SNAN__, "__snan__") - DEF(TOK___INF__, "__inf__") -#if defined TCC_TARGET_X86_64 - DEF(TOK___mzerosf, "__mzerosf") /* -0.0 */ - DEF(TOK___mzerodf, "__mzerodf") /* -0.0 */ -#endif - -/* attribute identifiers */ -/* XXX: handle all tokens generically since speed is not critical */ - DEF(TOK_SECTION1, "section") - DEF(TOK_SECTION2, "__section__") - DEF(TOK_ALIGNED1, "aligned") - DEF(TOK_ALIGNED2, "__aligned__") - DEF(TOK_PACKED1, "packed") - DEF(TOK_PACKED2, "__packed__") - DEF(TOK_WEAK1, "weak") - DEF(TOK_WEAK2, "__weak__") - DEF(TOK_ALIAS1, "alias") - DEF(TOK_ALIAS2, "__alias__") - DEF(TOK_UNUSED1, "unused") - DEF(TOK_UNUSED2, "__unused__") - DEF(TOK_NODEBUG1, "nodebug") - DEF(TOK_NODEBUG2, "__nodebug__") - DEF(TOK_CDECL1, "cdecl") - DEF(TOK_CDECL2, "__cdecl") - DEF(TOK_CDECL3, "__cdecl__") - DEF(TOK_STDCALL1, "stdcall") - DEF(TOK_STDCALL2, "__stdcall") - DEF(TOK_STDCALL3, "__stdcall__") - DEF(TOK_FASTCALL1, "fastcall") - DEF(TOK_FASTCALL2, "__fastcall") - DEF(TOK_FASTCALL3, "__fastcall__") - DEF(TOK_REGPARM1, "regparm") - DEF(TOK_REGPARM2, "__regparm__") - DEF(TOK_CLEANUP1, "cleanup") - DEF(TOK_CLEANUP2, "__cleanup__") - DEF(TOK_CONSTRUCTOR1, "constructor") - DEF(TOK_CONSTRUCTOR2, "__constructor__") - DEF(TOK_DESTRUCTOR1, "destructor") - DEF(TOK_DESTRUCTOR2, "__destructor__") - DEF(TOK_ALWAYS_INLINE1, "always_inline") - DEF(TOK_ALWAYS_INLINE2, "__always_inline__") - - 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_NODECORATE, "nodecorate") - DEF(TOK_NORETURN1, "noreturn") - DEF(TOK_NORETURN2, "__noreturn__") - DEF(TOK_NORETURN3, "_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") - /*DEF(TOK_builtin_va_list, "__builtin_va_list")*/ -#if defined TCC_TARGET_PE && defined TCC_TARGET_X86_64 - DEF(TOK_builtin_va_start, "__builtin_va_start") -#elif defined TCC_TARGET_X86_64 - DEF(TOK_builtin_va_arg_types, "__builtin_va_arg_types") -#elif defined TCC_TARGET_ARM64 - DEF(TOK_builtin_va_start, "__builtin_va_start") - DEF(TOK_builtin_va_arg, "__builtin_va_arg") -#elif defined TCC_TARGET_RISCV64 - DEF(TOK_builtin_va_start, "__builtin_va_start") -#endif - -/* atomic operations */ -#define DEF_ATOMIC(ID) DEF(TOK_##__##ID, "__"#ID) - DEF_ATOMIC(atomic_store) - DEF_ATOMIC(atomic_load) - DEF_ATOMIC(atomic_exchange) - DEF_ATOMIC(atomic_compare_exchange) - DEF_ATOMIC(atomic_fetch_add) - DEF_ATOMIC(atomic_fetch_sub) - DEF_ATOMIC(atomic_fetch_or) - DEF_ATOMIC(atomic_fetch_xor) - DEF_ATOMIC(atomic_fetch_and) - DEF_ATOMIC(atomic_fetch_nand) - DEF_ATOMIC(atomic_add_fetch) - DEF_ATOMIC(atomic_sub_fetch) - DEF_ATOMIC(atomic_or_fetch) - DEF_ATOMIC(atomic_xor_fetch) - DEF_ATOMIC(atomic_and_fetch) - DEF_ATOMIC(atomic_nand_fetch) - -/* pragma */ - DEF(TOK_pack, "pack") -#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_X86_64) && \ - !defined(TCC_TARGET_ARM) && !defined(TCC_TARGET_ARM64) - /* already defined for assembler */ - 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") - DEF(TOK_option, "option") - -/* builtin functions or variables */ -#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 - DEF(TOK_memcpy, "__aeabi_memcpy") - DEF(TOK_memmove, "__aeabi_memmove") - DEF(TOK_memmove4, "__aeabi_memmove4") - DEF(TOK_memmove8, "__aeabi_memmove8") - 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") - DEF(TOK___udivsi3, "__aeabi_uidiv") - DEF(TOK___floatdisf, "__aeabi_l2f") - DEF(TOK___floatdidf, "__aeabi_l2d") - DEF(TOK___fixsfdi, "__aeabi_f2lz") - DEF(TOK___fixdfdi, "__aeabi_d2lz") - DEF(TOK___ashrdi3, "__aeabi_lasr") - DEF(TOK___lshrdi3, "__aeabi_llsr") - DEF(TOK___ashldi3, "__aeabi_llsl") - DEF(TOK___floatundisf, "__aeabi_ul2f") - DEF(TOK___floatundidf, "__aeabi_ul2d") - DEF(TOK___fixunssfdi, "__aeabi_f2ulz") - DEF(TOK___fixunsdfdi, "__aeabi_d2ulz") -# 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 - -#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 - -#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 -#if defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64 - 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 - DEF(TOK___bound_ptr_add, "__bound_ptr_add") - DEF(TOK___bound_ptr_indir1, "__bound_ptr_indir1") - DEF(TOK___bound_ptr_indir2, "__bound_ptr_indir2") - DEF(TOK___bound_ptr_indir4, "__bound_ptr_indir4") - 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") - DEF(TOK___bound_setjmp, "__bound_setjmp") - DEF(TOK___bound_longjmp, "__bound_longjmp") - DEF(TOK___bound_new_region, "__bound_new_region") -# ifdef TCC_TARGET_PE -# ifdef TCC_TARGET_X86_64 - DEF(TOK___bound_alloca_nr, "__bound_alloca_nr") -# endif -# else - DEF(TOK_sigsetjmp, "sigsetjmp") - DEF(TOK___sigsetjmp, "__sigsetjmp") - DEF(TOK_siglongjmp, "siglongjmp") -# endif - DEF(TOK_setjmp, "setjmp") - DEF(TOK__setjmp, "_setjmp") - DEF(TOK_longjmp, "longjmp") -#endif - - -/*********************************************************************/ -/* Tiny Assembler */ -#define DEF_ASM(x) DEF(TOK_ASM_ ## x, #x) -#define DEF_ASMDIR(x) DEF(TOK_ASMDIR_ ## x, "." #x) -#define TOK_ASM_int TOK_INT - -#define TOK_ASMDIR_FIRST TOK_ASMDIR_byte -#define TOK_ASMDIR_LAST TOK_ASMDIR_section - - 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_ASMDIR(code16) - DEF_ASMDIR(code32) -#elif defined(TCC_TARGET_X86_64) - 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" -#endif - -#if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64 -#include "arm-tok.h" -#endif - -#if defined TCC_TARGET_RISCV64 -#include "riscv64-tok.h" -#endif diff --git a/tinycc/tcctools.c b/tinycc/tcctools.c deleted file mode 100644 index bef21ef..0000000 --- a/tinycc/tcctools.c +++ /dev/null @@ -1,631 +0,0 @@ -/* -------------------------------------------------------------- */ -/* - * 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 [crstvx] lib [files]\n"); - fprintf(stderr, "create library ([abdiopN] not supported).\n"); - return ret; -} - -ST_FUNC int tcc_tool_ar(TCCState *s1, int argc, char **argv) -{ - static const ArHdr arhdr_init = { - "/ ", - "0 ", - "0 ", - "0 ", - "0 ", - "0 ", - ARFMAG - }; - - ArHdr arhdr = arhdr_init; - ArHdr arhdro = arhdr_init; - - 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; - const char *ops_conflict = "habdiopN"; // unsupported but destructive if ignored. - int extract = 0; - int table = 0; - 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, "x")) - extract = 1; - if (strstr(a, "t")) - table = 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_lib) // i_obj implies also i_lib. - ret = 1; - i_obj = i_obj ? i_obj : argc; // An empty archive will be generated if no input file is given - - if (ret == 1) - return ar_usage(ret); - - if (extract || table) { - if ((fh = fopen(argv[i_lib], "rb")) == NULL) - { - fprintf(stderr, "tcc: ar: can't open file %s\n", argv[i_lib]); - goto finish; - } - fread(stmp, 1, 8, fh); - if (memcmp(stmp,ARMAG,8)) - { -no_ar: - fprintf(stderr, "tcc: ar: not an ar archive %s\n", argv[i_lib]); - goto finish; - } - while (fread(&arhdr, 1, sizeof(arhdr), fh) == sizeof(arhdr)) { - char *p, *e; - - if (memcmp(arhdr.ar_fmag, ARFMAG, 2)) - goto no_ar; - p = arhdr.ar_name; - for (e = p + sizeof arhdr.ar_name; e > p && e[-1] == ' ';) - e--; - *e = '\0'; - arhdr.ar_size[sizeof arhdr.ar_size-1] = 0; - fsize = atoi(arhdr.ar_size); - buf = tcc_malloc(fsize + 1); - fread(buf, fsize, 1, fh); - if (strcmp(arhdr.ar_name,"/") && strcmp(arhdr.ar_name,"/SYM64/")) { - if (e > p && e[-1] == '/') - e[-1] = '\0'; - /* tv not implemented */ - if (table || verbose) - printf("%s%s\n", extract ? "x - " : "", arhdr.ar_name); - if (extract) { - if ((fo = fopen(arhdr.ar_name, "wb")) == NULL) - { - fprintf(stderr, "tcc: ar: can't create file %s\n", - arhdr.ar_name); - tcc_free(buf); - goto finish; - } - fwrite(buf, fsize, 1, fo); - fclose(fo); - /* ignore date/uid/gid/mode */ - } - } - tcc_free(buf); - } - ret = 0; -finish: - if (fh) - fclose(fh); - return ret; - } - - if ((fh = fopen(argv[i_lib], "wb")) == NULL) - { - fprintf(stderr, "tcc: ar: can't create 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, "100644", 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 - || sym->st_info == 0x20 - || sym->st_info == 0x21 - || sym->st_info == 0x22 - )) { - //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(ARMAG, 8, 1, fh); - // create an empty archive - if (!funccnt) { - ret = 0; - goto the_end; - } - sprintf(stmp, "%-10d", (int)(strpos + (funccnt+1) * sizeof(int)) + fpos); - 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[260]; - char outfile[260]; - - const char *file; - char *p, *q; - FILE *fp, *op; - -#ifdef _WIN32 - char path[260]; -#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 == -1 ? "can't find file" : - ret == 1 ? "can't read symbols" : - ret == 0 ? "no symbols found in" : - "unknown file type", file); - ret = 1; - goto the_end; - } - - if (v) - printf("-> %s\n", file); - - op = fopen(outfile, "wb"); - 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: - 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 int tcc_tool_cross(TCCState *s1, char **argv, int option) -{ - tcc_error_noabort("-m%d not implemented.", option); - return 1; -} - -#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 int tcc_tool_cross(TCCState *s1, 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_noabort("could not run '%s'", program); - return 1; -} - -#endif /* TCC_TARGET_I386 && TCC_TARGET_X86_64 */ -/* -------------------------------------------------------------- */ -/* enable commandline wildcard expansion (tcc -o x.exe *.c) */ - -#ifdef _WIN32 -const int _CRT_glob = 1; -#ifndef _CRT_glob -const int _dowildcard = 1; -#endif -#endif - -/* -------------------------------------------------------------- */ -/* generate xxx.d file */ - -static char *escape_target_dep(const char *s) { - char *res = tcc_malloc(strlen(s) * 2 + 1); - int j; - for (j = 0; *s; s++, j++) { - if (is_space(*s)) { - res[j++] = '\\'; - } - res[j] = *s; - } - res[j] = '\0'; - return res; -} - -ST_FUNC int gen_makedeps(TCCState *s1, const char *target, const char *filename) -{ - FILE *depout; - char buf[1024], *escaped_target; - int i, k; - - 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(!strcmp(filename, "-")) - depout = fdopen(1, "w"); - else - /* XXX return err codes instead of error() ? */ - depout = fopen(filename, "w"); - if (!depout) - return tcc_error_noabort("could not open '%s'", filename); - if (s1->verbose) - printf("<- %s\n", filename); - - fprintf(depout, "%s:", target); - for (i = 0; i<s1->nb_target_deps; ++i) { - for (k = 0; k < i; ++k) - if (0 == strcmp(s1->target_deps[i], s1->target_deps[k])) - goto next; - escaped_target = escape_target_dep(s1->target_deps[i]); - fprintf(depout, " \\\n %s", escaped_target); - tcc_free(escaped_target); - next:; - } - fprintf(depout, "\n"); - fclose(depout); - return 0; -} - -/* -------------------------------------------------------------- */ diff --git a/tinycc/texi2pod.pl b/tinycc/texi2pod.pl deleted file mode 100644 index d86e176..0000000 --- a/tinycc/texi2pod.pl +++ /dev/null @@ -1,427 +0,0 @@ -#! /usr/bin/perl -w - -# Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. - -# This file is part of GNU CC. - -# GNU CC 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, or (at your option) -# any later version. - -# GNU CC 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 GNU CC; see the file COPYING. If not, write to -# the Free Software Foundation, 59 Temple Place - Suite 330, -# Boston MA 02111-1307, USA. - -# This does trivial (and I mean _trivial_) conversion of Texinfo -# markup to Perl POD format. It's intended to be used to extract -# something suitable for a manpage from a Texinfo document. - -$output = 0; -$skipping = 0; -%sects = (); -$section = ""; -@icstack = (); -@endwstack = (); -@skstack = (); -@instack = (); -$shift = ""; -%defs = (); -$fnno = 1; -$inf = ""; -$ibase = ""; - -while ($_ = shift) { - if (/^-D(.*)$/) { - if ($1 ne "") { - $flag = $1; - } else { - $flag = shift; - } - $value = ""; - ($flag, $value) = ($flag =~ /^([^=]+)(?:=(.+))?/); - die "no flag specified for -D\n" - unless $flag ne ""; - die "flags may only contain letters, digits, hyphens, dashes and underscores\n" - unless $flag =~ /^[a-zA-Z0-9_-]+$/; - $defs{$flag} = $value; - } elsif (/^-/) { - usage(); - } else { - $in = $_, next unless defined $in; - $out = $_, next unless defined $out; - usage(); - } -} - -if (defined $in) { - $inf = gensym(); - open($inf, "<$in") or die "opening \"$in\": $!\n"; - $ibase = $1 if $in =~ m|^(.+)/[^/]+$|; -} else { - $inf = \*STDIN; -} - -if (defined $out) { - open(STDOUT, ">$out") or die "opening \"$out\": $!\n"; -} - -while(defined $inf) { -while(<$inf>) { - # Certain commands are discarded without further processing. - /^\@(?: - [a-z]+index # @*index: useful only in complete manual - |need # @need: useful only in printed manual - |(?:end\s+)?group # @group .. @end group: ditto - |page # @page: ditto - |node # @node: useful only in .info file - |(?:end\s+)?ifnottex # @ifnottex .. @end ifnottex: use contents - )\b/x and next; - - chomp; - - # Look for filename and title markers. - /^\@setfilename\s+([^.]+)/ and $fn = $1, next; - /^\@settitle\s+([^.]+)/ and $tl = postprocess($1), next; - - # Identify a man title but keep only the one we are interested in. - /^\@c\s+man\s+title\s+([A-Za-z0-9-]+)\s+(.+)/ and do { - if (exists $defs{$1}) { - $fn = $1; - $tl = postprocess($2); - } - next; - }; - - # Look for blocks surrounded by @c man begin SECTION ... @c man end. - # This really oughta be @ifman ... @end ifman and the like, but such - # would require rev'ing all other Texinfo translators. - /^\@c\s+man\s+begin\s+([A-Z]+)\s+([A-Za-z0-9-]+)/ and do { - $output = 1 if exists $defs{$2}; - $sect = $1; - next; - }; - /^\@c\s+man\s+begin\s+([A-Z]+)/ and $sect = $1, $output = 1, next; - /^\@c\s+man\s+end/ and do { - $sects{$sect} = "" unless exists $sects{$sect}; - $sects{$sect} .= postprocess($section); - $section = ""; - $output = 0; - next; - }; - - # handle variables - /^\@set\s+([a-zA-Z0-9_-]+)\s*(.*)$/ and do { - $defs{$1} = $2; - next; - }; - /^\@clear\s+([a-zA-Z0-9_-]+)/ and do { - delete $defs{$1}; - next; - }; - - next unless $output; - - # Discard comments. (Can't do it above, because then we'd never see - # @c man lines.) - /^\@c\b/ and next; - - # End-block handler goes up here because it needs to operate even - # if we are skipping. - /^\@end\s+([a-z]+)/ and do { - # Ignore @end foo, where foo is not an operation which may - # cause us to skip, if we are presently skipping. - my $ended = $1; - next if $skipping && $ended !~ /^(?:ifset|ifclear|ignore|menu|iftex)$/; - - die "\@end $ended without \@$ended at line $.\n" unless defined $endw; - die "\@$endw ended by \@end $ended at line $.\n" unless $ended eq $endw; - - $endw = pop @endwstack; - - if ($ended =~ /^(?:ifset|ifclear|ignore|menu|iftex)$/) { - $skipping = pop @skstack; - next; - } elsif ($ended =~ /^(?:example|smallexample|display)$/) { - $shift = ""; - $_ = ""; # need a paragraph break - } elsif ($ended =~ /^(?:itemize|enumerate|[fv]?table)$/) { - $_ = "\n=back\n"; - $ic = pop @icstack; - } else { - die "unknown command \@end $ended at line $.\n"; - } - }; - - # We must handle commands which can cause skipping even while we - # are skipping, otherwise we will not process nested conditionals - # correctly. - /^\@ifset\s+([a-zA-Z0-9_-]+)/ and do { - push @endwstack, $endw; - push @skstack, $skipping; - $endw = "ifset"; - $skipping = 1 unless exists $defs{$1}; - next; - }; - - /^\@ifclear\s+([a-zA-Z0-9_-]+)/ and do { - push @endwstack, $endw; - push @skstack, $skipping; - $endw = "ifclear"; - $skipping = 1 if exists $defs{$1}; - next; - }; - - /^\@(ignore|menu|iftex)\b/ and do { - push @endwstack, $endw; - push @skstack, $skipping; - $endw = $1; - $skipping = 1; - next; - }; - - next if $skipping; - - # Character entities. First the ones that can be replaced by raw text - # or discarded outright: - s/\@copyright\{\}/(c)/g; - s/\@dots\{\}/.../g; - s/\@enddots\{\}/..../g; - s/\@([.!? ])/$1/g; - s/\@[:-]//g; - s/\@bullet(?:\{\})?/*/g; - s/\@TeX\{\}/TeX/g; - s/\@pounds\{\}/\#/g; - s/\@minus(?:\{\})?/-/g; - s/\\,/,/g; - - # Now the ones that have to be replaced by special escapes - # (which will be turned back into text by unmunge()) - s/&/&/g; - s/\@\{/{/g; - s/\@\}/}/g; - s/\@\@/&at;/g; - - # Inside a verbatim block, handle @var specially. - if ($shift ne "") { - s/\@var\{([^\}]*)\}/<$1>/g; - } - - # POD doesn't interpret E<> inside a verbatim block. - if ($shift eq "") { - s/</</g; - s/>/>/g; - } else { - s/</</g; - s/>/>/g; - } - - # Single line command handlers. - - /^\@include\s+(.+)$/ and do { - push @instack, $inf; - $inf = gensym(); - - # Try cwd and $ibase. - open($inf, "<" . $1) - or open($inf, "<" . $ibase . "/" . $1) - or die "cannot open $1 or $ibase/$1: $!\n"; - next; - }; - - /^\@(?:section|unnumbered|unnumberedsec|center)\s+(.+)$/ - and $_ = "\n=head2 $1\n"; - /^\@subsection\s+(.+)$/ - and $_ = "\n=head3 $1\n"; - - # Block command handlers: - /^\@itemize\s+(\@[a-z]+|\*|-)/ and do { - push @endwstack, $endw; - push @icstack, $ic; - $ic = $1; - $_ = "\n=over 4\n"; - $endw = "itemize"; - }; - - /^\@enumerate(?:\s+([a-zA-Z0-9]+))?/ and do { - push @endwstack, $endw; - push @icstack, $ic; - if (defined $1) { - $ic = $1 . "."; - } else { - $ic = "1."; - } - $_ = "\n=over 4\n"; - $endw = "enumerate"; - }; - - /^\@([fv]?table)\s+(\@[a-z]+)/ and do { - push @endwstack, $endw; - push @icstack, $ic; - $endw = $1; - $ic = $2; - $ic =~ s/\@(?:samp|strong|key|gcctabopt|option|env)/B/; - $ic =~ s/\@(?:code|kbd)/C/; - $ic =~ s/\@(?:dfn|var|emph|cite|i)/I/; - $ic =~ s/\@(?:file)/F/; - $_ = "\n=over 4\n"; - }; - - /^\@((?:small)?example|display)/ and do { - push @endwstack, $endw; - $endw = $1; - $shift = "\t"; - $_ = ""; # need a paragraph break - }; - - /^\@itemx?\s*(.+)?$/ and do { - if (defined $1) { - # Entity escapes prevent munging by the <> processing below. - $_ = "\n=item $ic\<$1\>\n"; - } else { - $_ = "\n=item $ic\n"; - $ic =~ y/A-Ya-y/B-Zb-z/; - $ic =~ s/(\d+)/$1 + 1/eg; - } - }; - - $section .= $shift.$_."\n"; -} -# End of current file. -close($inf); -$inf = pop @instack; -} - -die "No filename or title\n" unless defined $fn && defined $tl; - -$sects{NAME} = "$fn \- $tl\n"; -$sects{FOOTNOTES} .= "=back\n" if exists $sects{FOOTNOTES}; - -for $sect (qw(NAME SYNOPSIS DESCRIPTION OPTIONS ENVIRONMENT FILES - BUGS NOTES FOOTNOTES SEEALSO AUTHOR COPYRIGHT)) { - if(exists $sects{$sect}) { - $head = $sect; - $head =~ s/SEEALSO/SEE ALSO/; - print "=head1 $head\n\n"; - print scalar unmunge ($sects{$sect}); - print "\n"; - } -} - -sub usage -{ - die "usage: $0 [-D toggle...] [infile [outfile]]\n"; -} - -sub postprocess -{ - local $_ = $_[0]; - - # @value{foo} is replaced by whatever 'foo' is defined as. - while (m/(\@value\{([a-zA-Z0-9_-]+)\})/g) { - if (! exists $defs{$2}) { - print STDERR "Option $2 not defined\n"; - s/\Q$1\E//; - } else { - $value = $defs{$2}; - s/\Q$1\E/$value/; - } - } - - # Formatting commands. - # Temporary escape for @r. - s/\@r\{([^\}]*)\}/R<$1>/g; - s/\@(?:dfn|var|emph|cite|i)\{([^\}]*)\}/I<$1>/g; - s/\@(?:code|kbd)\{([^\}]*)\}/C<$1>/g; - s/\@(?:gccoptlist|samp|strong|key|option|env|command|b)\{([^\}]*)\}/B<$1>/g; - s/\@sc\{([^\}]*)\}/\U$1/g; - s/\@file\{([^\}]*)\}/F<$1>/g; - s/\@w\{([^\}]*)\}/S<$1>/g; - s/\@(?:dmn|math)\{([^\}]*)\}/$1/g; - - # Cross references are thrown away, as are @noindent and @refill. - # (@noindent is impossible in .pod, and @refill is unnecessary.) - # @* is also impossible in .pod; we discard it and any newline that - # follows it. Similarly, our macro @gol must be discarded. - - s/\(?\@xref\{(?:[^\}]*)\}(?:[^.<]|(?:<[^<>]*>))*\.\)?//g; - s/\s+\(\@pxref\{(?:[^\}]*)\}\)//g; - s/;\s+\@pxref\{(?:[^\}]*)\}//g; - s/\@noindent\s*//g; - s/\@refill//g; - s/\@gol//g; - s/\@\*\s*\n?//g; - - # @uref can take one, two, or three arguments, with different - # semantics each time. @url and @email are just like @uref with - # one argument, for our purposes. - s/\@(?:uref|url|email)\{([^\},]*)\}/<B<$1>>/g; - s/\@uref\{([^\},]*),([^\},]*)\}/$2 (C<$1>)/g; - s/\@uref\{([^\},]*),([^\},]*),([^\},]*)\}/$3/g; - - # Turn B<blah I<blah> blah> into B<blah> I<blah> B<blah> to - # match Texinfo semantics of @emph inside @samp. Also handle @r - # inside bold. - s/</</g; - s/>/>/g; - 1 while s/B<((?:[^<>]|I<[^<>]*>)*)R<([^>]*)>/B<$1>${2}B</g; - 1 while (s/B<([^<>]*)I<([^>]+)>/B<$1>I<$2>B</g); - 1 while (s/I<([^<>]*)B<([^>]+)>/I<$1>B<$2>I</g); - s/[BI]<>//g; - s/([BI])<(\s+)([^>]+)>/$2$1<$3>/g; - s/([BI])<([^>]+?)(\s+)>/$1<$2>$3/g; - - # Extract footnotes. This has to be done after all other - # processing because otherwise the regexp will choke on formatting - # inside @footnote. - while (/\@footnote/g) { - s/\@footnote\{([^\}]+)\}/[$fnno]/; - add_footnote($1, $fnno); - $fnno++; - } - - return $_; -} - -sub unmunge -{ - # Replace escaped symbols with their equivalents. - local $_ = $_[0]; - - s/</E<lt>/g; - s/>/E<gt>/g; - s/{/\{/g; - s/}/\}/g; - s/&at;/\@/g; - s/&/&/g; - return $_; -} - -sub add_footnote -{ - unless (exists $sects{FOOTNOTES}) { - $sects{FOOTNOTES} = "\n=over 4\n\n"; - } - - $sects{FOOTNOTES} .= "=item $fnno.\n\n"; $fnno++; - $sects{FOOTNOTES} .= $_[0]; - $sects{FOOTNOTES} .= "\n\n"; -} - -# stolen from Symbol.pm -{ - my $genseq = 0; - sub gensym - { - my $name = "GEN" . $genseq++; - my $ref = \*{$name}; - delete $::{$name}; - return $ref; - } -} diff --git a/tinycc/x86_64-asm.h b/tinycc/x86_64-asm.h deleted file mode 100644 index 339e1df..0000000 --- a/tinycc/x86_64-asm.h +++ /dev/null @@ -1,544 +0,0 @@ - DEF_ASM_OP0(clc, 0xf8) /* must be first OP0 */ - DEF_ASM_OP0(cld, 0xfc) - DEF_ASM_OP0(cli, 0xfa) - DEF_ASM_OP0(clts, 0x0f06) - DEF_ASM_OP0(cmc, 0xf5) - DEF_ASM_OP0(lahf, 0x9f) - DEF_ASM_OP0(sahf, 0x9e) - DEF_ASM_OP0(pushfq, 0x9c) - DEF_ASM_OP0(popfq, 0x9d) - DEF_ASM_OP0(pushf, 0x9c) - DEF_ASM_OP0(popf, 0x9d) - DEF_ASM_OP0(stc, 0xf9) - DEF_ASM_OP0(std, 0xfd) - DEF_ASM_OP0(sti, 0xfb) - DEF_ASM_OP0(aaa, 0x37) - DEF_ASM_OP0(aas, 0x3f) - DEF_ASM_OP0(daa, 0x27) - DEF_ASM_OP0(das, 0x2f) - DEF_ASM_OP0(aad, 0xd50a) - DEF_ASM_OP0(aam, 0xd40a) - DEF_ASM_OP0(cbw, 0x6698) - DEF_ASM_OP0(cwd, 0x6699) - DEF_ASM_OP0(cwde, 0x98) - DEF_ASM_OP0(cdq, 0x99) - DEF_ASM_OP0(cbtw, 0x6698) - DEF_ASM_OP0(cwtl, 0x98) - DEF_ASM_OP0(cwtd, 0x6699) - DEF_ASM_OP0(cltd, 0x99) - DEF_ASM_OP0(cqto, 0x4899) - DEF_ASM_OP0(int3, 0xcc) - DEF_ASM_OP0(into, 0xce) - DEF_ASM_OP0(iret, 0xcf) - DEF_ASM_OP0(iretw, 0x66cf) - DEF_ASM_OP0(iretl, 0xcf) - DEF_ASM_OP0(iretq, 0x48cf) - DEF_ASM_OP0(rsm, 0x0faa) - DEF_ASM_OP0(hlt, 0xf4) - DEF_ASM_OP0(wait, 0x9b) - DEF_ASM_OP0(nop, 0x90) - DEF_ASM_OP0(pause, 0xf390) - DEF_ASM_OP0(xlat, 0xd7) - - DEF_ASM_OP0L(vmcall, 0xc1, 0, OPC_0F01) - DEF_ASM_OP0L(vmlaunch, 0xc2, 0, OPC_0F01) - DEF_ASM_OP0L(vmresume, 0xc3, 0, OPC_0F01) - DEF_ASM_OP0L(vmxoff, 0xc4, 0, OPC_0F01) - - /* strings */ -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_BWLX)) -ALT(DEF_ASM_OP0L(slodb, 0xac, 0, OPC_BWLX)) - -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_BWLX)) -ALT(DEF_ASM_OP0L(sscab, 0xae, 0, OPC_BWLX)) - -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_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_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_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_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_WLX, OPT_REGW, OPT_REGW | OPT_EA)) -ALT(DEF_ASM_OP2(btcw, 0x0fba, 7, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA)) - -ALT(DEF_ASM_OP2(popcntw, 0xf30fb8, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW)) - -ALT(DEF_ASM_OP2(tzcntw, 0xf30fbc, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW)) -ALT(DEF_ASM_OP2(lzcntw, 0xf30fbd, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW)) - - /* prefixes */ - DEF_ASM_OP0(lock, 0xf0) - DEF_ASM_OP0(rep, 0xf3) - DEF_ASM_OP0(repe, 0xf3) - DEF_ASM_OP0(repz, 0xf3) - DEF_ASM_OP0(repne, 0xf2) - DEF_ASM_OP0(repnz, 0xf2) - - DEF_ASM_OP0(invd, 0x0f08) - DEF_ASM_OP0(wbinvd, 0x0f09) - DEF_ASM_OP0(cpuid, 0x0fa2) - DEF_ASM_OP0(wrmsr, 0x0f30) - DEF_ASM_OP0(rdtsc, 0x0f31) - DEF_ASM_OP0(rdmsr, 0x0f32) - DEF_ASM_OP0(rdpmc, 0x0f33) - - DEF_ASM_OP0(syscall, 0x0f05) - DEF_ASM_OP0(sysret, 0x0f07) - DEF_ASM_OP0L(sysretq, 0x480f07, 0, 0) - DEF_ASM_OP0(ud2, 0x0f0b) - - /* NOTE: we took the same order as gas opcode definition order */ -/* Right now we can't express the fact that 0xa1/0xa3 can't use $eax and a - 32 bit moffset as operands. -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)) -/* The moves are special: the 0xb8 form supports IM64 (the only insn that - does) with REG64. It doesn't support IM32 with REG64, it would use - the full movabs form (64bit immediate). For IM32->REG64 we prefer - the 0xc7 opcode. So disallow all 64bit forms and code the rest by hand. */ -ALT(DEF_ASM_OP2(movb, 0xb0, 0, OPC_REG | OPC_BWLX, OPT_IM, OPT_REG)) -ALT(DEF_ASM_OP2(mov, 0xb8, 0, OPC_REG, OPT_IM64, OPT_REG64)) -ALT(DEF_ASM_OP2(movq, 0xb8, 0, OPC_REG, OPT_IM64, OPT_REG64)) -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_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_WLX, OPT_CR, OPT_REG64)) -ALT(DEF_ASM_OP2(movw, 0x0f21, 0, OPC_MODRM | OPC_WLX, OPT_DB, OPT_REG64)) -ALT(DEF_ASM_OP2(movw, 0x0f22, 0, OPC_MODRM | OPC_WLX, OPT_REG64, OPT_CR)) -ALT(DEF_ASM_OP2(movw, 0x0f23, 0, OPC_MODRM | OPC_WLX, OPT_REG64, OPT_DB)) - -ALT(DEF_ASM_OP2(movsbw, 0x660fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REG16)) -ALT(DEF_ASM_OP2(movsbl, 0x0fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REG32)) -ALT(DEF_ASM_OP2(movsbq, 0x0fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REGW)) -ALT(DEF_ASM_OP2(movswl, 0x0fbf, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32)) -ALT(DEF_ASM_OP2(movswq, 0x0fbf, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG)) -ALT(DEF_ASM_OP2(movslq, 0x63, 0, OPC_MODRM, OPT_REG32 | OPT_EA, OPT_REG)) -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_OP2(movzwq, 0x0fb7, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG)) - -ALT(DEF_ASM_OP1(pushq, 0x6a, 0, 0, OPT_IM8S)) -ALT(DEF_ASM_OP1(push, 0x6a, 0, 0, OPT_IM8S)) -ALT(DEF_ASM_OP1(pushw, 0x666a, 0, 0, OPT_IM8S)) -ALT(DEF_ASM_OP1(pushw, 0x50, 0, OPC_REG | OPC_WLX, OPT_REG64)) -ALT(DEF_ASM_OP1(pushw, 0x50, 0, OPC_REG | OPC_WLX, OPT_REG16)) -ALT(DEF_ASM_OP1(pushw, 0xff, 6, OPC_MODRM | OPC_WLX, OPT_REG64 | OPT_EA)) -ALT(DEF_ASM_OP1(pushw, 0x6668, 0, 0, OPT_IM16)) -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_WLX, OPT_REG64)) -ALT(DEF_ASM_OP1(popw, 0x58, 0, OPC_REG | OPC_WLX, OPT_REG16)) -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_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)) -ALT(DEF_ASM_OP2(inb, 0xec, 0, OPC_BWL, OPT_DX, OPT_EAX)) -ALT(DEF_ASM_OP1(inb, 0xec, 0, OPC_BWL, OPT_DX)) - -ALT(DEF_ASM_OP2(outb, 0xe6, 0, OPC_BWL, OPT_EAX, OPT_IM8)) -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_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)) -ALT(DEF_ASM_OP2(lss, 0x0fb2, 0, OPC_MODRM, OPT_EA, OPT_REG32)) -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_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_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(incb, 0xfe, 0, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) -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_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_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_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_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_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_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, 0, OPT_DISP)) -ALT(DEF_ASM_OP1(jmp, 0xff, 4, OPC_MODRM, OPT_INDIR)) -ALT(DEF_ASM_OP1(jmp, 0xeb, 0, 0, OPT_DISP8)) - -ALT(DEF_ASM_OP1(lcall, 0xff, 3, OPC_MODRM, OPT_EA)) -ALT(DEF_ASM_OP1(ljmp, 0xff, 5, OPC_MODRM, OPT_EA)) - DEF_ASM_OP1(ljmpw, 0x66ff, 5, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(ljmpl, 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) - DEF_ASM_OP0(retq, 0xc3) -ALT(DEF_ASM_OP1(retq, 0xc2, 0, 0, OPT_IM16)) -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_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, 0x67e3, 0, 0, OPT_DISP8) - - /* float */ - /* specific fcomp handling */ -ALT(DEF_ASM_OP0L(fcomp, 0xd8d9, 0, 0)) - -ALT(DEF_ASM_OP1(fadd, 0xd8c0, 0, OPC_FARITH | OPC_REG, OPT_ST)) -ALT(DEF_ASM_OP2(fadd, 0xd8c0, 0, OPC_FARITH | OPC_REG, OPT_ST, OPT_ST0)) -ALT(DEF_ASM_OP2(fadd, 0xdcc0, 0, OPC_FARITH | OPC_REG, OPT_ST0, OPT_ST)) -ALT(DEF_ASM_OP2(fmul, 0xdcc8, 0, OPC_FARITH | OPC_REG, OPT_ST0, OPT_ST)) -ALT(DEF_ASM_OP0L(fadd, 0xdec1, 0, OPC_FARITH)) -ALT(DEF_ASM_OP1(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST)) -ALT(DEF_ASM_OP2(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST, OPT_ST0)) -ALT(DEF_ASM_OP2(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST0, OPT_ST)) -ALT(DEF_ASM_OP0L(faddp, 0xdec1, 0, OPC_FARITH)) -ALT(DEF_ASM_OP1(fadds, 0xd8, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) -ALT(DEF_ASM_OP1(fiaddl, 0xda, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) -ALT(DEF_ASM_OP1(faddl, 0xdc, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) -ALT(DEF_ASM_OP1(fiadds, 0xde, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) - - DEF_ASM_OP0(fucompp, 0xdae9) - DEF_ASM_OP0(ftst, 0xd9e4) - DEF_ASM_OP0(fxam, 0xd9e5) - DEF_ASM_OP0(fld1, 0xd9e8) - DEF_ASM_OP0(fldl2t, 0xd9e9) - DEF_ASM_OP0(fldl2e, 0xd9ea) - DEF_ASM_OP0(fldpi, 0xd9eb) - DEF_ASM_OP0(fldlg2, 0xd9ec) - DEF_ASM_OP0(fldln2, 0xd9ed) - DEF_ASM_OP0(fldz, 0xd9ee) - - DEF_ASM_OP0(f2xm1, 0xd9f0) - DEF_ASM_OP0(fyl2x, 0xd9f1) - DEF_ASM_OP0(fptan, 0xd9f2) - DEF_ASM_OP0(fpatan, 0xd9f3) - DEF_ASM_OP0(fxtract, 0xd9f4) - DEF_ASM_OP0(fprem1, 0xd9f5) - DEF_ASM_OP0(fdecstp, 0xd9f6) - DEF_ASM_OP0(fincstp, 0xd9f7) - DEF_ASM_OP0(fprem, 0xd9f8) - DEF_ASM_OP0(fyl2xp1, 0xd9f9) - DEF_ASM_OP0(fsqrt, 0xd9fa) - DEF_ASM_OP0(fsincos, 0xd9fb) - DEF_ASM_OP0(frndint, 0xd9fc) - DEF_ASM_OP0(fscale, 0xd9fd) - DEF_ASM_OP0(fsin, 0xd9fe) - DEF_ASM_OP0(fcos, 0xd9ff) - DEF_ASM_OP0(fchs, 0xd9e0) - DEF_ASM_OP0(fabs, 0xd9e1) - DEF_ASM_OP0(fninit, 0xdbe3) - DEF_ASM_OP0(fnclex, 0xdbe2) - DEF_ASM_OP0(fnop, 0xd9d0) - DEF_ASM_OP0(fwait, 0x9b) - - /* fp load */ - DEF_ASM_OP1(fld, 0xd9c0, 0, OPC_REG, OPT_ST) - DEF_ASM_OP1(fldl, 0xd9c0, 0, OPC_REG, OPT_ST) - DEF_ASM_OP1(flds, 0xd9, 0, OPC_MODRM, OPT_EA) -ALT(DEF_ASM_OP1(fldl, 0xdd, 0, OPC_MODRM, OPT_EA)) - DEF_ASM_OP1(fildl, 0xdb, 0, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fildq, 0xdf, 5, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fildll, 0xdf, 5, OPC_MODRM,OPT_EA) - DEF_ASM_OP1(fldt, 0xdb, 5, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fbld, 0xdf, 4, OPC_MODRM, OPT_EA) - - /* fp store */ - DEF_ASM_OP1(fst, 0xddd0, 0, OPC_REG, OPT_ST) - DEF_ASM_OP1(fstl, 0xddd0, 0, OPC_REG, OPT_ST) - DEF_ASM_OP1(fsts, 0xd9, 2, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fstps, 0xd9, 3, OPC_MODRM, OPT_EA) -ALT(DEF_ASM_OP1(fstl, 0xdd, 2, OPC_MODRM, OPT_EA)) - DEF_ASM_OP1(fstpl, 0xdd, 3, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fist, 0xdf, 2, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fistp, 0xdf, 3, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fistl, 0xdb, 2, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fistpl, 0xdb, 3, OPC_MODRM, OPT_EA) - - DEF_ASM_OP1(fstp, 0xddd8, 0, OPC_REG, OPT_ST) - DEF_ASM_OP1(fistpq, 0xdf, 7, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fistpll, 0xdf, 7, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fstpt, 0xdb, 7, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fbstp, 0xdf, 6, OPC_MODRM, OPT_EA) - - /* exchange */ - DEF_ASM_OP0(fxch, 0xd9c9) -ALT(DEF_ASM_OP1(fxch, 0xd9c8, 0, OPC_REG, OPT_ST)) - - /* misc FPU */ - DEF_ASM_OP1(fucom, 0xdde0, 0, OPC_REG, OPT_ST ) - DEF_ASM_OP1(fucomp, 0xdde8, 0, OPC_REG, OPT_ST ) - - DEF_ASM_OP0L(finit, 0xdbe3, 0, OPC_FWAIT) - DEF_ASM_OP1(fldcw, 0xd9, 5, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(fnstcw, 0xd9, 7, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(fstcw, 0xd9, 7, OPC_MODRM | OPC_FWAIT, OPT_EA ) - DEF_ASM_OP0(fnstsw, 0xdfe0) -ALT(DEF_ASM_OP1(fnstsw, 0xdfe0, 0, 0, OPT_EAX )) -ALT(DEF_ASM_OP1(fnstsw, 0xdd, 7, OPC_MODRM, OPT_EA )) - DEF_ASM_OP1(fstsw, 0xdfe0, 0, OPC_FWAIT, OPT_EAX ) -ALT(DEF_ASM_OP0L(fstsw, 0xdfe0, 0, OPC_FWAIT)) -ALT(DEF_ASM_OP1(fstsw, 0xdd, 7, OPC_MODRM | OPC_FWAIT, OPT_EA )) - DEF_ASM_OP0L(fclex, 0xdbe2, 0, OPC_FWAIT) - DEF_ASM_OP1(fnstenv, 0xd9, 6, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(fstenv, 0xd9, 6, OPC_MODRM | OPC_FWAIT, OPT_EA ) - DEF_ASM_OP1(fldenv, 0xd9, 4, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(fnsave, 0xdd, 6, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(fsave, 0xdd, 6, OPC_MODRM | OPC_FWAIT, OPT_EA ) - DEF_ASM_OP1(frstor, 0xdd, 4, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(ffree, 0xddc0, 4, OPC_REG, OPT_ST ) - DEF_ASM_OP1(ffreep, 0xdfc0, 4, OPC_REG, OPT_ST ) - DEF_ASM_OP1(fxsave, 0x0fae, 0, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(fxrstor, 0x0fae, 1, OPC_MODRM, OPT_EA ) - /* The *q forms of fxrstor/fxsave use a REX prefix. - If the operand would use extended registers we would have to modify - it instead of generating a second one. Currently that's no - problem with TCC, we don't use extended registers. */ - DEF_ASM_OP1(fxsaveq, 0x0fae, 0, OPC_MODRM | OPC_48, OPT_EA ) - DEF_ASM_OP1(fxrstorq, 0x0fae, 1, OPC_MODRM | OPC_48, OPT_EA ) - - /* segments */ - DEF_ASM_OP2(arpl, 0x63, 0, OPC_MODRM, OPT_REG16, OPT_REG16 | OPT_EA) -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(lgdtq, 0x0f01, 2, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(lidt, 0x0f01, 3, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(lidtq, 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_WLX, OPT_EA | OPT_REG, OPT_REG)) - DEF_ASM_OP1(ltr, 0x0f00, 3, OPC_MODRM, OPT_EA | OPT_REG16) - DEF_ASM_OP1(sgdt, 0x0f01, 0, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(sgdtq, 0x0f01, 0, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(sidt, 0x0f01, 1, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(sidtq, 0x0f01, 1, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(sldt, 0x0f00, 0, OPC_MODRM, OPT_REG | OPT_EA) - DEF_ASM_OP1(smsw, 0x0f01, 4, OPC_MODRM, OPT_REG | OPT_EA) - DEF_ASM_OP1(str, 0x0f00, 1, OPC_MODRM, OPT_REG32 | OPT_EA) -ALT(DEF_ASM_OP1(str, 0x660f00, 1, OPC_MODRM, OPT_REG16)) -ALT(DEF_ASM_OP1(str, 0x0f00, 1, OPC_MODRM | OPC_48, OPT_REG64)) - DEF_ASM_OP1(verr, 0x0f00, 4, OPC_MODRM, OPT_REG | OPT_EA) - DEF_ASM_OP1(verw, 0x0f00, 5, OPC_MODRM, OPT_REG | OPT_EA) - DEF_ASM_OP0L(swapgs, 0x0f01, 7, OPC_MODRM) - - /* 486 */ - /* bswap can't be applied to 16bit regs */ - DEF_ASM_OP1(bswap, 0x0fc8, 0, OPC_REG, OPT_REG32 ) - DEF_ASM_OP1(bswapl, 0x0fc8, 0, OPC_REG, OPT_REG32 ) - DEF_ASM_OP1(bswapq, 0x0fc8, 0, OPC_REG | OPC_48, OPT_REG64 ) - -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 ) - - /* pentium */ - DEF_ASM_OP1(cmpxchg8b, 0x0fc7, 1, OPC_MODRM, OPT_EA ) - - /* AMD 64 */ - DEF_ASM_OP1(cmpxchg16b, 0x0fc7, 1, OPC_MODRM | OPC_48, OPT_EA ) - - /* pentium pro */ -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 ) - DEF_ASM_OP2(fcmovu, 0xdad8, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcmovnb, 0xdbc0, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcmovne, 0xdbc8, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcmovnbe, 0xdbd0, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcmovnu, 0xdbd8, 0, OPC_REG, OPT_ST, OPT_ST0 ) - - DEF_ASM_OP2(fucomi, 0xdbe8, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcomi, 0xdbf0, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fucomip, 0xdfe8, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcomip, 0xdff0, 0, OPC_REG, OPT_ST, OPT_ST0 ) - - /* mmx */ - DEF_ASM_OP0(emms, 0x0f77) /* must be last OP0 */ - DEF_ASM_OP2(movd, 0x0f6e, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_MMXSSE ) - /* movd shouldn't accept REG64, but AMD64 spec uses it for 32 and 64 bit - moves, so let's be compatible. */ -ALT(DEF_ASM_OP2(movd, 0x0f6e, 0, OPC_MODRM, OPT_EA | OPT_REG64, OPT_MMXSSE )) -ALT(DEF_ASM_OP2(movq, 0x0f6e, 0, OPC_MODRM | OPC_48, OPT_REG64, OPT_MMXSSE )) -ALT(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(movd, 0x0f7e, 0, OPC_MODRM, OPT_MMXSSE, OPT_EA | OPT_REG64 )) -ALT(DEF_ASM_OP2(movq, 0x0f7f, 0, OPC_MODRM, OPT_MMX, OPT_EA | 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 )) -ALT(DEF_ASM_OP2(movq, 0x0f7e, 0, OPC_MODRM, OPT_MMXSSE, OPT_EA | OPT_REG64 )) - - 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_OP1(ldmxcsr, 0x0fae, 2, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(stmxcsr, 0x0fae, 3, OPC_MODRM, OPT_EA) - 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 ) - - /* movnti should only accept REG32 and REG64, we accept more */ - DEF_ASM_OP2(movnti, 0x0fc3, 0, OPC_MODRM, OPT_REG, OPT_EA) - DEF_ASM_OP2(movntil, 0x0fc3, 0, OPC_MODRM, OPT_REG32, OPT_EA) - DEF_ASM_OP2(movntiq, 0x0fc3, 0, OPC_MODRM | OPC_48, OPT_REG64, OPT_EA) - DEF_ASM_OP1(prefetchnta, 0x0f18, 0, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(prefetcht0, 0x0f18, 1, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(prefetcht1, 0x0f18, 2, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(prefetcht2, 0x0f18, 3, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(prefetchw, 0x0f0d, 1, OPC_MODRM, OPT_EA) - DEF_ASM_OP0L(lfence, 0x0fae, 5, OPC_MODRM) - DEF_ASM_OP0L(mfence, 0x0fae, 6, OPC_MODRM) - DEF_ASM_OP0L(sfence, 0x0fae, 7, OPC_MODRM) - DEF_ASM_OP1(clflush, 0x0fae, 7, OPC_MODRM, OPT_EA) -#undef ALT -#undef DEF_ASM_OP0 -#undef DEF_ASM_OP0L -#undef DEF_ASM_OP1 -#undef DEF_ASM_OP2 -#undef DEF_ASM_OP3 diff --git a/tinycc/x86_64-gen.c b/tinycc/x86_64-gen.c deleted file mode 100644 index 0fe9cee..0000000 --- a/tinycc/x86_64-gen.c +++ /dev/null @@ -1,2328 +0,0 @@ -/* - * x86-64 code generator for TCC - * - * Copyright (c) 2008 Shinichiro Hamaji - * - * Based on i386-gen.c by 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 - */ - -#ifdef TARGET_DEFS_ONLY - -/* number of available registers */ -#define NB_REGS 25 -#define NB_ASM_REGS 16 -#define CONFIG_TCC_ASM - -/* a register can belong to several classes. The classes must be - sorted from more general to more precise (see gv2() code which does - assumptions on it). */ -#define RC_INT 0x0001 /* generic integer register */ -#define RC_FLOAT 0x0002 /* generic float register */ -#define RC_RAX 0x0004 -#define RC_RCX 0x0008 -#define RC_RDX 0x0010 -#define RC_RSI 0x0020 -#define RC_RDI 0x0040 -#define RC_ST0 0x0080 /* only for long double */ -#define RC_R8 0x0100 -#define RC_R9 0x0200 -#define RC_R10 0x0400 -#define RC_R11 0x0800 -#define RC_XMM0 0x1000 -#define RC_XMM1 0x2000 -#define RC_XMM2 0x4000 -#define RC_XMM3 0x8000 -#define RC_XMM4 0x10000 -#define RC_XMM5 0x20000 -#define RC_XMM6 0x40000 -#define RC_XMM7 0x80000 -#define RC_IRET RC_RAX /* function return: integer register */ -#define RC_IRE2 RC_RDX /* function return: second integer register */ -#define RC_FRET RC_XMM0 /* function return: float register */ -#define RC_FRE2 RC_XMM1 /* function return: second float register */ - -/* pretty names for the registers */ -enum { - TREG_RAX = 0, - TREG_RCX = 1, - TREG_RDX = 2, - TREG_RSP = 4, - TREG_RSI = 6, - TREG_RDI = 7, - - TREG_R8 = 8, - TREG_R9 = 9, - TREG_R10 = 10, - TREG_R11 = 11, - - TREG_XMM0 = 16, - TREG_XMM1 = 17, - TREG_XMM2 = 18, - TREG_XMM3 = 19, - TREG_XMM4 = 20, - TREG_XMM5 = 21, - TREG_XMM6 = 22, - TREG_XMM7 = 23, - - TREG_ST0 = 24, - - TREG_MEM = 0x20 -}; - -#define REX_BASE(reg) (((reg) >> 3) & 1) -#define REG_VALUE(reg) ((reg) & 7) - -/* return registers for function */ -#define REG_IRET TREG_RAX /* single word int return register */ -#define REG_IRE2 TREG_RDX /* second word return register (for long long) */ -#define REG_FRET TREG_XMM0 /* float return register */ -#define REG_FRE2 TREG_XMM1 /* second float return register */ - -/* defined if function parameters must be evaluated in reverse order */ -#define INVERT_FUNC_PARAMS - -/* pointer size, in bytes */ -#define PTR_SIZE 8 - -/* long double size and alignment, in bytes */ -#define LDOUBLE_SIZE 16 -#define LDOUBLE_ALIGN 16 -/* maximum alignment (for aligned attribute support) */ -#define MAX_ALIGN 16 - -/* define if return values need to be extended explicitely - at caller side (for interfacing with non-TCC compilers) */ -#define PROMOTE_RET - -#define TCC_TARGET_NATIVE_STRUCT_COPY -ST_FUNC void gen_struct_copy(int size); - -/******************************************************/ -#else /* ! TARGET_DEFS_ONLY */ -/******************************************************/ -#define USING_GLOBALS -#include "tcc.h" -#include <assert.h> - -ST_DATA const char * const target_machine_defs = - "__x86_64__\0" - "__amd64__\0" - ; - -ST_DATA const int reg_classes[NB_REGS] = { - /* eax */ RC_INT | RC_RAX, - /* ecx */ RC_INT | RC_RCX, - /* edx */ RC_INT | RC_RDX, - 0, - 0, - 0, - RC_RSI, - RC_RDI, - RC_R8, - RC_R9, - RC_R10, - RC_R11, - 0, - 0, - 0, - 0, - /* xmm0 */ RC_FLOAT | RC_XMM0, - /* xmm1 */ RC_FLOAT | RC_XMM1, - /* xmm2 */ RC_FLOAT | RC_XMM2, - /* xmm3 */ RC_FLOAT | RC_XMM3, - /* xmm4 */ RC_FLOAT | RC_XMM4, - /* xmm5 */ RC_FLOAT | RC_XMM5, - /* xmm6 an xmm7 are included so gv() can be used on them, - but they are not tagged with RC_FLOAT because they are - callee saved on Windows */ - RC_XMM6, - RC_XMM7, - /* st0 */ RC_ST0 -}; - -static unsigned long func_sub_sp_offset; -static int func_ret_sub; - -#if defined(CONFIG_TCC_BCHECK) -static addr_t func_bound_offset; -static unsigned long func_bound_ind; -ST_DATA int func_bound_add_epilog; -#endif - -#ifdef TCC_TARGET_PE -static int func_scratch, func_alloca; -#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); - cur_text_section->data[ind] = c; - ind = ind1; -} - -ST_FUNC void o(unsigned int c) -{ - while (c) { - g(c); - c = c >> 8; - } -} - -ST_FUNC void gen_le16(int v) -{ - g(v); - g(v >> 8); -} - -ST_FUNC void gen_le32(int c) -{ - g(c); - g(c >> 8); - g(c >> 16); - g(c >> 24); -} - -ST_FUNC void gen_le64(int64_t c) -{ - g(c); - g(c >> 8); - g(c >> 16); - g(c >> 24); - g(c >> 32); - g(c >> 40); - g(c >> 48); - g(c >> 56); -} - -static void orex(int ll, int r, int r2, int b) -{ - if ((r & VT_VALMASK) >= VT_CONST) - r = 0; - if ((r2 & VT_VALMASK) >= VT_CONST) - r2 = 0; - if (ll || REX_BASE(r) || REX_BASE(r2)) - o(0x40 | REX_BASE(r) | (REX_BASE(r2) << 2) | (ll << 3)); - o(b); -} - -/* output a symbol and patch all calls to it */ -ST_FUNC void gsym_addr(int t, int a) -{ - while (t) { - unsigned char *ptr = cur_text_section->data + t; - uint32_t n = read32le(ptr); /* next value */ - write32le(ptr, a < 0 ? -a : a - t - 4); - t = n; - } -} - -static int is64_type(int t) -{ - return ((t & VT_BTYPE) == VT_PTR || - (t & VT_BTYPE) == VT_FUNC || - (t & VT_BTYPE) == VT_LLONG); -} - -/* instruction + 4 bytes data. Return the address of the data */ -static int oad(int c, int s) -{ - int t; - if (nocode_wanted) - return s; - o(c); - t = ind; - gen_le32(s); - return t; -} - -/* generate jmp to a label */ -#define gjmp2(instr,lbl) oad(instr,lbl) - -ST_FUNC void gen_addr32(int r, Sym *sym, int c) -{ - if (r & VT_SYM) - greloca(cur_text_section, sym, ind, R_X86_64_32S, c), c=0; - gen_le32(c); -} - -/* output constant with relocation if 'r & VT_SYM' is true */ -ST_FUNC void gen_addr64(int r, Sym *sym, int64_t c) -{ - if (r & VT_SYM) - greloca(cur_text_section, sym, ind, R_X86_64_64, c), c=0; - gen_le64(c); -} - -/* output constant with relocation if 'r & VT_SYM' is true */ -ST_FUNC void gen_addrpc32(int r, Sym *sym, int c) -{ - if (r & VT_SYM) - greloca(cur_text_section, sym, ind, R_X86_64_PC32, c-4), c=4; - gen_le32(c-4); -} - -/* output got address with relocation */ -static void gen_gotpcrel(int r, Sym *sym, int c) -{ -#ifdef TCC_TARGET_PE - tcc_error("internal error: no GOT on PE: %s %x %x | %02x %02x %02x\n", - get_tok_str(sym->v, NULL), c, r, - cur_text_section->data[ind-3], - cur_text_section->data[ind-2], - cur_text_section->data[ind-1] - ); -#endif - greloca(cur_text_section, sym, ind, R_X86_64_GOTPCREL, -4); - gen_le32(0); - if (c) { - /* we use add c, %xxx for displacement */ - orex(1, r, 0, 0x81); - o(0xc0 + REG_VALUE(r)); - gen_le32(c); - } -} - -static void gen_modrm_impl(int op_reg, int r, Sym *sym, int c, int is_got) -{ - op_reg = REG_VALUE(op_reg) << 3; - if ((r & VT_VALMASK) == VT_CONST) { - /* constant memory reference */ - if (!(r & VT_SYM)) { - /* Absolute memory reference */ - o(0x04 | op_reg); /* [sib] | destreg */ - oad(0x25, c); /* disp32 */ - } else { - o(0x05 | op_reg); /* (%rip)+disp32 | destreg */ - if (is_got) { - gen_gotpcrel(r, sym, c); - } else { - gen_addrpc32(r, sym, c); - } - } - } else if ((r & VT_VALMASK) == VT_LOCAL) { - /* currently, we use only ebp as base */ - if (c == (char)c) { - /* short reference */ - o(0x45 | op_reg); - g(c); - } else { - oad(0x85 | op_reg, c); - } - } else if ((r & VT_VALMASK) >= TREG_MEM) { - if (c) { - g(0x80 | op_reg | REG_VALUE(r)); - gen_le32(c); - } else { - g(0x00 | op_reg | REG_VALUE(r)); - } - } else { - g(0x00 | op_reg | REG_VALUE(r)); - } -} - -/* generate a modrm reference. 'op_reg' contains the additional 3 - opcode bits */ -static void gen_modrm(int op_reg, int r, Sym *sym, int c) -{ - gen_modrm_impl(op_reg, r, sym, c, 0); -} - -/* generate a modrm reference. 'op_reg' contains the additional 3 - opcode bits */ -static void gen_modrm64(int opcode, int op_reg, int r, Sym *sym, int c) -{ - int is_got; - is_got = (op_reg & TREG_MEM) && !(sym->type.t & VT_STATIC); - orex(1, r, op_reg, opcode); - gen_modrm_impl(op_reg, r, sym, c, is_got); -} - - -/* load 'r' from value 'sv' */ -void load(int r, SValue *sv) -{ - int v, t, ft, fc, fr; - SValue v1; - -#ifdef TCC_TARGET_PE - SValue v2; - sv = pe_getimport(sv, &v2); -#endif - - fr = sv->r; - ft = sv->type.t & ~VT_DEFSIGN; - fc = sv->c.i; - if (fc != sv->c.i && (fr & VT_SYM)) - tcc_error("64 bit addend in load"); - - ft &= ~(VT_VOLATILE | VT_CONSTANT); - -#ifndef TCC_TARGET_PE - /* we use indirect access via got */ - if ((fr & VT_VALMASK) == VT_CONST && (fr & VT_SYM) && - (fr & VT_LVAL) && !(sv->sym->type.t & VT_STATIC)) { - /* use the result register as a temporal register */ - int tr = r | TREG_MEM; - if (is_float(ft)) { - /* we cannot use float registers as a temporal register */ - tr = get_reg(RC_INT) | TREG_MEM; - } - gen_modrm64(0x8b, tr, fr, sv->sym, 0); - - /* load from the temporal register */ - fr = tr | VT_LVAL; - } -#endif - - v = fr & VT_VALMASK; - if (fr & VT_LVAL) { - int b, ll; - if (v == VT_LLOCAL) { - v1.type.t = VT_PTR; - v1.r = VT_LOCAL | VT_LVAL; - v1.c.i = fc; - fr = r; - if (!(reg_classes[fr] & (RC_INT|RC_R11))) - fr = get_reg(RC_INT); - load(fr, &v1); - } - if (fc != sv->c.i) { - /* If the addends doesn't fit into a 32bit signed - we must use a 64bit move. We've checked above - that this doesn't have a sym associated. */ - v1.type.t = VT_LLONG; - v1.r = VT_CONST; - v1.c.i = sv->c.i; - fr = r; - if (!(reg_classes[fr] & (RC_INT|RC_R11))) - fr = get_reg(RC_INT); - load(fr, &v1); - fc = 0; - } - ll = 0; - /* Like GCC we can load from small enough properly sized - structs and unions as well. - XXX maybe move to generic operand handling, but should - occur only with asm, so tccasm.c might also be a better place */ - if ((ft & VT_BTYPE) == VT_STRUCT) { - int align; - switch (type_size(&sv->type, &align)) { - case 1: ft = VT_BYTE; break; - case 2: ft = VT_SHORT; break; - case 4: ft = VT_INT; break; - case 8: ft = VT_LLONG; break; - default: - tcc_error("invalid aggregate type for register load"); - break; - } - } - if ((ft & VT_BTYPE) == VT_FLOAT) { - b = 0x6e0f66; - r = REG_VALUE(r); /* movd */ - } else if ((ft & VT_BTYPE) == VT_DOUBLE) { - b = 0x7e0ff3; /* movq */ - r = REG_VALUE(r); - } else if ((ft & VT_BTYPE) == VT_LDOUBLE) { - b = 0xdb, r = 5; /* fldt */ - } else if ((ft & VT_TYPE) == VT_BYTE || (ft & VT_TYPE) == VT_BOOL) { - b = 0xbe0f; /* movsbl */ - } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) { - b = 0xb60f; /* movzbl */ - } else if ((ft & VT_TYPE) == VT_SHORT) { - b = 0xbf0f; /* movswl */ - } else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) { - b = 0xb70f; /* movzwl */ - } else if ((ft & VT_TYPE) == (VT_VOID)) { - /* Can happen with zero size structs */ - return; - } else { - assert(((ft & VT_BTYPE) == VT_INT) - || ((ft & VT_BTYPE) == VT_LLONG) - || ((ft & VT_BTYPE) == VT_PTR) - || ((ft & VT_BTYPE) == VT_FUNC) - ); - ll = is64_type(ft); - b = 0x8b; - } - if (ll) { - gen_modrm64(b, r, fr, sv->sym, fc); - } else { - orex(ll, fr, r, b); - gen_modrm(r, fr, sv->sym, fc); - } - } else { - if (v == VT_CONST) { - if (fr & VT_SYM) { -#ifdef TCC_TARGET_PE - orex(1,0,r,0x8d); - o(0x05 + REG_VALUE(r) * 8); /* lea xx(%rip), r */ - gen_addrpc32(fr, sv->sym, fc); -#else - if (sv->sym->type.t & VT_STATIC) { - orex(1,0,r,0x8d); - o(0x05 + REG_VALUE(r) * 8); /* lea xx(%rip), r */ - gen_addrpc32(fr, sv->sym, fc); - } else { - orex(1,0,r,0x8b); - o(0x05 + REG_VALUE(r) * 8); /* mov xx(%rip), r */ - gen_gotpcrel(r, sv->sym, fc); - } -#endif - } else if (is64_type(ft)) { - orex(1,r,0, 0xb8 + REG_VALUE(r)); /* mov $xx, r */ - gen_le64(sv->c.i); - } else { - orex(0,r,0, 0xb8 + REG_VALUE(r)); /* mov $xx, r */ - gen_le32(fc); - } - } else if (v == VT_LOCAL) { - orex(1,0,r,0x8d); /* lea xxx(%ebp), r */ - gen_modrm(r, VT_LOCAL, sv->sym, fc); - } else if (v == VT_CMP) { - if (fc & 0x100) - { - v = vtop->cmp_r; - fc &= ~0x100; - /* This was a float compare. If the parity bit is - set the result was unordered, meaning false for everything - except TOK_NE, and true for TOK_NE. */ - orex(0, r, 0, 0xb0 + REG_VALUE(r)); /* mov $0/1,%al */ - g(v ^ fc ^ (v == TOK_NE)); - o(0x037a + (REX_BASE(r) << 8)); - } - orex(0,r,0, 0x0f); /* setxx %br */ - o(fc); - o(0xc0 + REG_VALUE(r)); - orex(0,r,0, 0x0f); - o(0xc0b6 + REG_VALUE(r) * 0x900); /* movzbl %al, %eax */ - } else if (v == VT_JMP || v == VT_JMPI) { - t = v & 1; - orex(0,r,0,0); - oad(0xb8 + REG_VALUE(r), t); /* mov $1, r */ - o(0x05eb + (REX_BASE(r) << 8)); /* jmp after */ - gsym(fc); - orex(0,r,0,0); - oad(0xb8 + REG_VALUE(r), t ^ 1); /* mov $0, r */ - } else if (v != r) { - if ((r >= TREG_XMM0) && (r <= TREG_XMM7)) { - if (v == TREG_ST0) { - /* gen_cvt_ftof(VT_DOUBLE); */ - o(0xf0245cdd); /* fstpl -0x10(%rsp) */ - /* movsd -0x10(%rsp),%xmmN */ - o(0x100ff2); - o(0x44 + REG_VALUE(r)*8); /* %xmmN */ - o(0xf024); - } else { - assert((v >= TREG_XMM0) && (v <= TREG_XMM7)); - if ((ft & VT_BTYPE) == VT_FLOAT) { - o(0x100ff3); - } else { - assert((ft & VT_BTYPE) == VT_DOUBLE); - o(0x100ff2); - } - o(0xc0 + REG_VALUE(v) + REG_VALUE(r)*8); - } - } else if (r == TREG_ST0) { - assert((v >= TREG_XMM0) && (v <= TREG_XMM7)); - /* gen_cvt_ftof(VT_LDOUBLE); */ - /* movsd %xmmN,-0x10(%rsp) */ - o(0x110ff2); - o(0x44 + REG_VALUE(r)*8); /* %xmmN */ - o(0xf024); - o(0xf02444dd); /* fldl -0x10(%rsp) */ - } else { - orex(is64_type(ft), r, v, 0x89); - o(0xc0 + REG_VALUE(r) + REG_VALUE(v) * 8); /* mov v, r */ - } - } - } -} - -/* store register 'r' in lvalue 'v' */ -void store(int r, SValue *v) -{ - int fr, bt, ft, fc; - int op64 = 0; - /* store the REX prefix in this variable when PIC is enabled */ - int pic = 0; - -#ifdef TCC_TARGET_PE - SValue v2; - v = pe_getimport(v, &v2); -#endif - - fr = v->r & VT_VALMASK; - ft = v->type.t; - fc = v->c.i; - if (fc != v->c.i && (fr & VT_SYM)) - tcc_error("64 bit addend in store"); - ft &= ~(VT_VOLATILE | VT_CONSTANT); - bt = ft & VT_BTYPE; - -#ifndef TCC_TARGET_PE - /* we need to access the variable via got */ - if (fr == VT_CONST - && (v->r & VT_SYM) - && !(v->sym->type.t & VT_STATIC)) { - /* mov xx(%rip), %r11 */ - o(0x1d8b4c); - gen_gotpcrel(TREG_R11, v->sym, v->c.i); - pic = is64_type(bt) ? 0x49 : 0x41; - } -#endif - - /* XXX: incorrect if float reg to reg */ - if (bt == VT_FLOAT) { - o(0x66); - o(pic); - o(0x7e0f); /* movd */ - r = REG_VALUE(r); - } else if (bt == VT_DOUBLE) { - o(0x66); - o(pic); - o(0xd60f); /* movq */ - r = REG_VALUE(r); - } else if (bt == VT_LDOUBLE) { - o(0xc0d9); /* fld %st(0) */ - o(pic); - o(0xdb); /* fstpt */ - r = 7; - } else { - if (bt == VT_SHORT) - o(0x66); - o(pic); - if (bt == VT_BYTE || bt == VT_BOOL) - orex(0, 0, r, 0x88); - else if (is64_type(bt)) - op64 = 0x89; - else - orex(0, 0, r, 0x89); - } - if (pic) { - /* xxx r, (%r11) where xxx is mov, movq, fld, or etc */ - if (op64) - o(op64); - o(3 + (r << 3)); - } else if (op64) { - if (fr == VT_CONST || fr == VT_LOCAL || (v->r & VT_LVAL)) { - gen_modrm64(op64, r, v->r, v->sym, fc); - } else if (fr != r) { - orex(1, fr, r, op64); - o(0xc0 + fr + r * 8); /* mov r, fr */ - } - } else { - if (fr == VT_CONST || fr == VT_LOCAL || (v->r & VT_LVAL)) { - gen_modrm(r, v->r, v->sym, fc); - } else if (fr != r) { - o(0xc0 + fr + r * 8); /* mov r, fr */ - } - } -} - -/* '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 && - ((vtop->r & VT_SYM) && (vtop->c.i-4) == (int)(vtop->c.i-4))) { - /* constant symbolic case -> simple relocation */ -#ifdef TCC_TARGET_PE - greloca(cur_text_section, vtop->sym, ind + 1, R_X86_64_PC32, (int)(vtop->c.i-4)); -#else - greloca(cur_text_section, vtop->sym, ind + 1, R_X86_64_PLT32, (int)(vtop->c.i-4)); -#endif - oad(0xe8 + is_jmp, 0); /* call/jmp im */ - } else { - /* otherwise, indirect call */ - r = TREG_R11; - load(r, vtop); - o(0x41); /* REX */ - o(0xff); /* call/jmp *r */ - o(0xd0 + REG_VALUE(r) + (is_jmp << 4)); - } -} - -#if defined(CONFIG_TCC_BCHECK) - -static void gen_bounds_call(int v) -{ - Sym *sym = external_helper_sym(v); - oad(0xe8, 0); -#ifdef TCC_TARGET_PE - greloca(cur_text_section, sym, ind-4, R_X86_64_PC32, -4); -#else - greloca(cur_text_section, sym, ind-4, R_X86_64_PLT32, -4); -#endif -} - -#ifdef TCC_TARGET_PE -# define TREG_FASTCALL_1 TREG_RCX -#else -# define TREG_FASTCALL_1 TREG_RDI -#endif - -static void gen_bounds_prolog(void) -{ - /* leave some room for bound checking code */ - func_bound_offset = lbounds_section->data_offset; - func_bound_ind = ind; - func_bound_add_epilog = 0; - o(0x0d8d48 + ((TREG_FASTCALL_1 == TREG_RDI) * 0x300000)); /*lbound section pointer */ - gen_le32 (0); - oad(0xb8, 0); /* call to function */ -} - -static void gen_bounds_epilog(void) -{ - addr_t saved_ind; - addr_t *bounds_ptr; - Sym *sym_data; - int offset_modified = func_bound_offset != lbounds_section->data_offset; - - if (!offset_modified && !func_bound_add_epilog) - return; - - /* add end of table info */ - bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t)); - *bounds_ptr = 0; - - sym_data = get_sym_ref(&char_pointer_type, lbounds_section, - func_bound_offset, PTR_SIZE); - - /* generate bound local allocation */ - if (offset_modified) { - saved_ind = ind; - ind = func_bound_ind; - greloca(cur_text_section, sym_data, ind + 3, R_X86_64_PC32, -4); - ind = ind + 7; - gen_bounds_call(TOK___bound_local_new); - ind = saved_ind; - } - - /* generate bound check local freeing */ - o(0x5250); /* save returned value, if any */ - o(0x20ec8348); /* sub $32,%rsp */ - o(0x290f); /* movaps %xmm0,0x10(%rsp) */ - o(0x102444); - o(0x240c290f); /* movaps %xmm1,(%rsp) */ - greloca(cur_text_section, sym_data, ind + 3, R_X86_64_PC32, -4); - o(0x0d8d48 + ((TREG_FASTCALL_1 == TREG_RDI) * 0x300000)); /* lea xxx(%rip), %rcx/rdi */ - gen_le32 (0); - gen_bounds_call(TOK___bound_local_delete); - o(0x280f); /* movaps 0x10(%rsp),%xmm0 */ - o(0x102444); - o(0x240c280f); /* movaps (%rsp),%xmm1 */ - o(0x20c48348); /* add $32,%rsp */ - o(0x585a); /* restore returned value, if any */ -} -#endif - -#ifdef TCC_TARGET_PE - -#define REGN 4 -static const uint8_t arg_regs[REGN] = { - TREG_RCX, TREG_RDX, TREG_R8, TREG_R9 -}; - -/* Prepare arguments in R10 and R11 rather than RCX and RDX - because gv() will not ever use these */ -static int arg_prepare_reg(int idx) { - if (idx == 0 || idx == 1) - /* idx=0: r10, idx=1: r11 */ - return idx + 10; - else - return idx >= 0 && idx < REGN ? arg_regs[idx] : 0; -} - -/* 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. */ - -static void gen_offs_sp(int b, int r, int d) -{ - orex(1,0,r & 0x100 ? 0 : r, b); - if (d == (char)d) { - o(0x2444 | (REG_VALUE(r) << 3)); - g(d); - } else { - o(0x2484 | (REG_VALUE(r) << 3)); - gen_le32(d); - } -} - -static int using_regs(int size) -{ - return !(size > 8 || (size & (size - 1))); -} - -/* 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) -{ - int size, align; - *ret_align = 1; // Never have to re-align return values for x86-64 - *regsize = 8; - size = type_size(vt, &align); - if (!using_regs(size)) - 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; -} - -static int is_sse_float(int t) { - int bt; - bt = t & VT_BTYPE; - return bt == VT_DOUBLE || bt == VT_FLOAT; -} - -static int gfunc_arg_size(CType *type) { - int align; - if (type->t & (VT_ARRAY|VT_BITFIELD)) - return 8; - return type_size(type, &align); -} - -void gfunc_call(int nb_args) -{ - int size, r, args_size, i, d, bt, struct_size; - int arg; - -#ifdef CONFIG_TCC_BCHECK - if (tcc_state->do_bounds_check) - gbound_args(nb_args); -#endif - - args_size = (nb_args < REGN ? REGN : nb_args) * PTR_SIZE; - arg = nb_args; - - /* for struct arguments, we need to call memcpy and the function - call breaks register passing arguments we are preparing. - So, we process arguments which will be passed by stack first. */ - struct_size = args_size; - for(i = 0; i < nb_args; i++) { - SValue *sv; - - --arg; - sv = &vtop[-i]; - bt = (sv->type.t & VT_BTYPE); - size = gfunc_arg_size(&sv->type); - - if (using_regs(size)) - continue; /* arguments smaller than 8 bytes passed in registers or on stack */ - - if (bt == VT_STRUCT) { - /* align to stack align size */ - size = (size + 15) & ~15; - /* generate structure store */ - r = get_reg(RC_INT); - gen_offs_sp(0x8d, r, struct_size); - struct_size += size; - - /* generate memcpy call */ - vset(&sv->type, r | VT_LVAL, 0); - vpushv(sv); - vstore(); - --vtop; - } else if (bt == VT_LDOUBLE) { - gv(RC_ST0); - gen_offs_sp(0xdb, 0x107, struct_size); - struct_size += 16; - } - } - - if (func_scratch < struct_size) - func_scratch = struct_size; - - arg = nb_args; - struct_size = args_size; - - for(i = 0; i < nb_args; i++) { - --arg; - bt = (vtop->type.t & VT_BTYPE); - - size = gfunc_arg_size(&vtop->type); - if (!using_regs(size)) { - /* align to stack align size */ - size = (size + 15) & ~15; - if (arg >= REGN) { - d = get_reg(RC_INT); - gen_offs_sp(0x8d, d, struct_size); - gen_offs_sp(0x89, d, arg*8); - } else { - d = arg_prepare_reg(arg); - gen_offs_sp(0x8d, d, struct_size); - } - struct_size += size; - } else { - if (is_sse_float(vtop->type.t)) { - if (tcc_state->nosse) - tcc_error("SSE disabled"); - if (arg >= REGN) { - gv(RC_XMM0); - /* movq %xmm0, j*8(%rsp) */ - gen_offs_sp(0xd60f66, 0x100, arg*8); - } else { - /* Load directly to xmmN register */ - gv(RC_XMM0 << arg); - d = arg_prepare_reg(arg); - /* mov %xmmN, %rxx */ - o(0x66); - orex(1,d,0, 0x7e0f); - o(0xc0 + arg*8 + REG_VALUE(d)); - } - } else { - if (bt == VT_STRUCT) { - vtop->type.ref = NULL; - vtop->type.t = size > 4 ? VT_LLONG : size > 2 ? VT_INT - : size > 1 ? VT_SHORT : VT_BYTE; - } - - r = gv(RC_INT); - if (arg >= REGN) { - gen_offs_sp(0x89, r, arg*8); - } else { - d = arg_prepare_reg(arg); - orex(1,d,r,0x89); /* mov */ - o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d)); - } - } - } - vtop--; - } - save_regs(0); - /* Copy R10 and R11 into RCX and RDX, respectively */ - if (nb_args > 0) { - o(0xd1894c); /* mov %r10, %rcx */ - if (nb_args > 1) { - o(0xda894c); /* mov %r11, %rdx */ - } - } - - gcall_or_jmp(0); - - if ((vtop->r & VT_SYM) && vtop->sym->v == TOK_alloca) { - /* need to add the "func_scratch" area after alloca */ - o(0x48); func_alloca = oad(0x05, func_alloca); /* add $NN, %rax */ -#ifdef CONFIG_TCC_BCHECK - if (tcc_state->do_bounds_check) - gen_bounds_call(TOK___bound_alloca_nr); /* new region */ -#endif - } - vtop--; -} - - -#define FUNC_PROLOG_SIZE 11 - -/* generate function prolog of type 't' */ -void gfunc_prolog(Sym *func_sym) -{ - CType *func_type = &func_sym->type; - int addr, reg_param_index, bt, size; - Sym *sym; - CType *type; - - func_ret_sub = 0; - func_scratch = 32; - func_alloca = 0; - loc = 0; - - addr = PTR_SIZE * 2; - ind += FUNC_PROLOG_SIZE; - func_sub_sp_offset = ind; - reg_param_index = 0; - - sym = func_type->ref; - - /* if the function returns a structure, then add an - implicit pointer parameter */ - size = gfunc_arg_size(&func_vt); - if (!using_regs(size)) { - gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); - func_vc = addr; - reg_param_index++; - addr += 8; - } - - /* define parameters */ - while ((sym = sym->next) != NULL) { - type = &sym->type; - bt = type->t & VT_BTYPE; - size = gfunc_arg_size(type); - if (!using_regs(size)) { - if (reg_param_index < REGN) { - gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); - } - sym_push(sym->v & ~SYM_FIELD, type, - VT_LLOCAL | VT_LVAL, addr); - } else { - if (reg_param_index < REGN) { - /* save arguments passed by register */ - if ((bt == VT_FLOAT) || (bt == VT_DOUBLE)) { - if (tcc_state->nosse) - tcc_error("SSE disabled"); - o(0xd60f66); /* movq */ - gen_modrm(reg_param_index, VT_LOCAL, NULL, addr); - } else { - gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); - } - } - sym_push(sym->v & ~SYM_FIELD, type, - VT_LOCAL | VT_LVAL, addr); - } - addr += 8; - reg_param_index++; - } - - while (reg_param_index < REGN) { - if (func_var) { - gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); - addr += 8; - } - reg_param_index++; - } -#ifdef CONFIG_TCC_BCHECK - if (tcc_state->do_bounds_check) - gen_bounds_prolog(); -#endif -} - -/* generate function epilog */ -void gfunc_epilog(void) -{ - int v, saved_ind; - - /* align local size to word & save local variables */ - func_scratch = (func_scratch + 15) & -16; - loc = (loc & -16) - func_scratch; - -#ifdef CONFIG_TCC_BCHECK - if (tcc_state->do_bounds_check) - gen_bounds_epilog(); -#endif - - o(0xc9); /* leave */ - if (func_ret_sub == 0) { - o(0xc3); /* ret */ - } else { - o(0xc2); /* ret n */ - g(func_ret_sub); - g(func_ret_sub >> 8); - } - - saved_ind = ind; - ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; - v = -loc; - - if (v >= 4096) { - Sym *sym = external_helper_sym(TOK___chkstk); - oad(0xb8, v); /* mov stacksize, %eax */ - oad(0xe8, 0); /* call __chkstk, (does the stackframe too) */ - greloca(cur_text_section, sym, ind-4, R_X86_64_PC32, -4); - o(0x90); /* fill for FUNC_PROLOG_SIZE = 11 bytes */ - } else { - o(0xe5894855); /* push %rbp, mov %rsp, %rbp */ - o(0xec8148); /* sub rsp, stacksize */ - gen_le32(v); - } - - /* add the "func_scratch" area after each alloca seen */ - gsym_addr(func_alloca, -func_scratch); - - cur_text_section->data_offset = saved_ind; - pe_add_unwind_data(ind, saved_ind, v); - ind = cur_text_section->data_offset; -} - -#else - -static void gadd_sp(int val) -{ - if (val == (char)val) { - o(0xc48348); - g(val); - } else { - oad(0xc48148, val); /* add $xxx, %rsp */ - } -} - -typedef enum X86_64_Mode { - x86_64_mode_none, - x86_64_mode_memory, - x86_64_mode_integer, - x86_64_mode_sse, - x86_64_mode_x87 -} X86_64_Mode; - -static X86_64_Mode classify_x86_64_merge(X86_64_Mode a, X86_64_Mode b) -{ - if (a == b) - return a; - else if (a == x86_64_mode_none) - return b; - else if (b == x86_64_mode_none) - return a; - else if ((a == x86_64_mode_memory) || (b == x86_64_mode_memory)) - return x86_64_mode_memory; - else if ((a == x86_64_mode_integer) || (b == x86_64_mode_integer)) - return x86_64_mode_integer; - else if ((a == x86_64_mode_x87) || (b == x86_64_mode_x87)) - return x86_64_mode_memory; - else - return x86_64_mode_sse; -} - -static X86_64_Mode classify_x86_64_inner(CType *ty) -{ - X86_64_Mode mode; - Sym *f; - - switch (ty->t & VT_BTYPE) { - case VT_VOID: return x86_64_mode_none; - - case VT_INT: - case VT_BYTE: - case VT_SHORT: - case VT_LLONG: - case VT_BOOL: - case VT_PTR: - case VT_FUNC: - return x86_64_mode_integer; - - case VT_FLOAT: - case VT_DOUBLE: return x86_64_mode_sse; - - case VT_LDOUBLE: return x86_64_mode_x87; - - case VT_STRUCT: - f = ty->ref; - - mode = x86_64_mode_none; - for (f = f->next; f; f = f->next) - mode = classify_x86_64_merge(mode, classify_x86_64_inner(&f->type)); - - return mode; - } - assert(0); - return 0; -} - -static X86_64_Mode classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *palign, int *reg_count) -{ - X86_64_Mode mode; - int size, align, ret_t = 0; - - if (ty->t & (VT_BITFIELD|VT_ARRAY)) { - *psize = 8; - *palign = 8; - *reg_count = 1; - ret_t = ty->t; - mode = x86_64_mode_integer; - } else { - size = type_size(ty, &align); - *psize = (size + 7) & ~7; - *palign = (align + 7) & ~7; - *reg_count = 0; /* avoid compiler warning */ - - if (size > 16) { - mode = x86_64_mode_memory; - } else { - mode = classify_x86_64_inner(ty); - switch (mode) { - case x86_64_mode_integer: - if (size > 8) { - *reg_count = 2; - ret_t = VT_QLONG; - } else { - *reg_count = 1; - if (size > 4) - ret_t = VT_LLONG; - else if (size > 2) - ret_t = VT_INT; - else if (size > 1) - ret_t = VT_SHORT; - else - ret_t = VT_BYTE; - if ((ty->t & VT_BTYPE) == VT_STRUCT || (ty->t & VT_UNSIGNED)) - ret_t |= VT_UNSIGNED; - } - break; - - case x86_64_mode_x87: - *reg_count = 1; - ret_t = VT_LDOUBLE; - break; - - case x86_64_mode_sse: - if (size > 8) { - *reg_count = 2; - ret_t = VT_QFLOAT; - } else { - *reg_count = 1; - ret_t = (size > 4) ? VT_DOUBLE : VT_FLOAT; - } - break; - default: break; /* nothing to be done for x86_64_mode_memory and x86_64_mode_none*/ - } - } - } - - if (ret) { - ret->ref = NULL; - ret->t = ret_t; - } - - return mode; -} - -ST_FUNC int classify_x86_64_va_arg(CType *ty) -{ - /* This definition must be synced with stdarg.h */ - enum __va_arg_type { - __va_gen_reg, __va_float_reg, __va_stack - }; - int size, align, reg_count; - X86_64_Mode mode = classify_x86_64_arg(ty, NULL, &size, &align, ®_count); - switch (mode) { - default: return __va_stack; - case x86_64_mode_integer: return __va_gen_reg; - case x86_64_mode_sse: return __va_float_reg; - } -} - -/* 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) -{ - int size, align, reg_count; - *ret_align = 1; // Never have to re-align return values for x86-64 - *regsize = 8; - return (classify_x86_64_arg(vt, ret, &size, &align, ®_count) != x86_64_mode_memory); -} - -#define REGN 6 -static const uint8_t arg_regs[REGN] = { - TREG_RDI, TREG_RSI, TREG_RDX, TREG_RCX, TREG_R8, TREG_R9 -}; - -static int arg_prepare_reg(int idx) { - if (idx == 2 || idx == 3) - /* idx=2: r10, idx=3: r11 */ - return idx + 8; - else - return idx >= 0 && idx < REGN ? arg_regs[idx] : 0; -} - -/* 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. */ -void gfunc_call(int nb_args) -{ - X86_64_Mode mode; - CType type; - int size, align, r, args_size, stack_adjust, i, reg_count, k; - int nb_reg_args = 0; - int nb_sse_args = 0; - int sse_reg, gen_reg; - char *onstack = tcc_malloc((nb_args + 1) * sizeof (char)); - -#ifdef CONFIG_TCC_BCHECK - if (tcc_state->do_bounds_check) - gbound_args(nb_args); -#endif - - /* calculate the number of integer/float register arguments, remember - arguments to be passed via stack (in onstack[]), and also remember - if we have to align the stack pointer to 16 (onstack[i] == 2). Needs - to be done in a left-to-right pass over arguments. */ - stack_adjust = 0; - for(i = nb_args - 1; i >= 0; i--) { - mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count); - if (size == 0) continue; - if (mode == x86_64_mode_sse && nb_sse_args + reg_count <= 8) { - nb_sse_args += reg_count; - onstack[i] = 0; - } else if (mode == x86_64_mode_integer && nb_reg_args + reg_count <= REGN) { - nb_reg_args += reg_count; - onstack[i] = 0; - } else if (mode == x86_64_mode_none) { - onstack[i] = 0; - } else { - if (align == 16 && (stack_adjust &= 15)) { - onstack[i] = 2; - stack_adjust = 0; - } else - onstack[i] = 1; - stack_adjust += size; - } - } - - if (nb_sse_args && tcc_state->nosse) - tcc_error("SSE disabled but floating point arguments passed"); - - /* fetch cpu flag before generating any code */ - if ((vtop->r & VT_VALMASK) == VT_CMP) - gv(RC_INT); - - /* for struct arguments, we need to call memcpy and the function - call breaks register passing arguments we are preparing. - So, we process arguments which will be passed by stack first. */ - gen_reg = nb_reg_args; - sse_reg = nb_sse_args; - args_size = 0; - stack_adjust &= 15; - for (i = k = 0; i < nb_args;) { - mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count); - if (size) { - if (!onstack[i + k]) { - ++i; - continue; - } - /* Possibly adjust stack to align SSE boundary. We're processing - args from right to left while allocating happens left to right - (stack grows down), so the adjustment needs to happen _after_ - an argument that requires it. */ - if (stack_adjust) { - o(0x50); /* push %rax; aka sub $8,%rsp */ - args_size += 8; - stack_adjust = 0; - } - if (onstack[i + k] == 2) - stack_adjust = 1; - } - - vrotb(i+1); - - switch (vtop->type.t & VT_BTYPE) { - case VT_STRUCT: - /* allocate the necessary size on stack */ - o(0x48); - oad(0xec81, size); /* sub $xxx, %rsp */ - /* generate structure store */ - r = get_reg(RC_INT); - orex(1, r, 0, 0x89); /* mov %rsp, r */ - o(0xe0 + REG_VALUE(r)); - vset(&vtop->type, r | VT_LVAL, 0); - vswap(); - /* keep stack aligned for (__bound_)memmove call */ - o(0x10ec8348); /* sub $16,%rsp */ - o(0xf0e48348); /* and $-16,%rsp */ - orex(0,r,0,0x50 + REG_VALUE(r)); /* push r (last %rsp) */ - o(0x08ec8348); /* sub $8,%rsp */ - vstore(); - o(0x08c48348); /* add $8,%rsp */ - o(0x5c); /* pop %rsp */ - break; - - case VT_LDOUBLE: - gv(RC_ST0); - oad(0xec8148, size); /* sub $xxx, %rsp */ - o(0x7cdb); /* fstpt 0(%rsp) */ - g(0x24); - g(0x00); - break; - - case VT_FLOAT: - case VT_DOUBLE: - assert(mode == x86_64_mode_sse); - r = gv(RC_FLOAT); - o(0x50); /* push $rax */ - /* movq %xmmN, (%rsp) */ - o(0xd60f66); - o(0x04 + REG_VALUE(r)*8); - o(0x24); - break; - - default: - assert(mode == x86_64_mode_integer); - /* simple type */ - /* XXX: implicit cast ? */ - r = gv(RC_INT); - orex(0,r,0,0x50 + REG_VALUE(r)); /* push r */ - break; - } - args_size += size; - - vpop(); - --nb_args; - k++; - } - - tcc_free(onstack); - - /* XXX This should be superfluous. */ - save_regs(0); /* save used temporary registers */ - - /* then, we prepare register passing arguments. - Note that we cannot set RDX and RCX in this loop because gv() - may break these temporary registers. Let's use R10 and R11 - instead of them */ - assert(gen_reg <= REGN); - assert(sse_reg <= 8); - for(i = 0; i < nb_args; i++) { - mode = classify_x86_64_arg(&vtop->type, &type, &size, &align, ®_count); - if (size == 0) continue; - /* Alter stack entry type so that gv() knows how to treat it */ - vtop->type = type; - if (mode == x86_64_mode_sse) { - if (reg_count == 2) { - sse_reg -= 2; - gv(RC_FRET); /* Use pair load into xmm0 & xmm1 */ - if (sse_reg) { /* avoid redundant movaps %xmm0, %xmm0 */ - /* movaps %xmm1, %xmmN */ - o(0x280f); - o(0xc1 + ((sse_reg+1) << 3)); - /* movaps %xmm0, %xmmN */ - o(0x280f); - o(0xc0 + (sse_reg << 3)); - } - } else { - assert(reg_count == 1); - --sse_reg; - /* Load directly to register */ - gv(RC_XMM0 << sse_reg); - } - } else if (mode == x86_64_mode_integer) { - /* simple type */ - /* XXX: implicit cast ? */ - int d; - gen_reg -= reg_count; - r = gv(RC_INT); - d = arg_prepare_reg(gen_reg); - orex(1,d,r,0x89); /* mov */ - o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d)); - if (reg_count == 2) { - d = arg_prepare_reg(gen_reg+1); - orex(1,d,vtop->r2,0x89); /* mov */ - o(0xc0 + REG_VALUE(vtop->r2) * 8 + REG_VALUE(d)); - } - } - vtop--; - } - assert(gen_reg == 0); - assert(sse_reg == 0); - - /* We shouldn't have many operands on the stack anymore, but the - call address itself is still there, and it might be in %eax - (or edx/ecx) currently, which the below writes would clobber. - So evict all remaining operands here. */ - save_regs(0); - - /* Copy R10 and R11 into RDX and RCX, respectively */ - if (nb_reg_args > 2) { - o(0xd2894c); /* mov %r10, %rdx */ - if (nb_reg_args > 3) { - o(0xd9894c); /* mov %r11, %rcx */ - } - } - - if (vtop->type.ref->f.func_type != FUNC_NEW) /* implies FUNC_OLD or FUNC_ELLIPSIS */ - oad(0xb8, nb_sse_args < 8 ? nb_sse_args : 8); /* mov nb_sse_args, %eax */ - gcall_or_jmp(0); - if (args_size) - gadd_sp(args_size); - vtop--; -} - -#define FUNC_PROLOG_SIZE 11 - -static void push_arg_reg(int i) { - loc -= 8; - gen_modrm64(0x89, arg_regs[i], VT_LOCAL, NULL, loc); -} - -/* generate function prolog of type 't' */ -void gfunc_prolog(Sym *func_sym) -{ - CType *func_type = &func_sym->type; - X86_64_Mode mode, ret_mode; - int i, addr, align, size, reg_count; - int param_addr = 0, reg_param_index, sse_param_index; - Sym *sym; - CType *type; - - sym = func_type->ref; - addr = PTR_SIZE * 2; - loc = 0; - ind += FUNC_PROLOG_SIZE; - func_sub_sp_offset = ind; - func_ret_sub = 0; - ret_mode = classify_x86_64_arg(&func_vt, NULL, &size, &align, ®_count); - - if (func_var) { - int seen_reg_num, seen_sse_num, seen_stack_size; - seen_reg_num = ret_mode == x86_64_mode_memory; - seen_sse_num = 0; - /* frame pointer and return address */ - seen_stack_size = PTR_SIZE * 2; - /* count the number of seen parameters */ - sym = func_type->ref; - while ((sym = sym->next) != NULL) { - type = &sym->type; - mode = classify_x86_64_arg(type, NULL, &size, &align, ®_count); - switch (mode) { - default: - stack_arg: - seen_stack_size = ((seen_stack_size + align - 1) & -align) + size; - break; - - case x86_64_mode_integer: - if (seen_reg_num + reg_count > REGN) - goto stack_arg; - seen_reg_num += reg_count; - break; - - case x86_64_mode_sse: - if (seen_sse_num + reg_count > 8) - goto stack_arg; - seen_sse_num += reg_count; - break; - } - } - - loc -= 24; - /* movl $0x????????, -0x18(%rbp) */ - o(0xe845c7); - gen_le32(seen_reg_num * 8); - /* movl $0x????????, -0x14(%rbp) */ - o(0xec45c7); - gen_le32(seen_sse_num * 16 + 48); - /* leaq $0x????????, %r11 */ - o(0x9d8d4c); - gen_le32(seen_stack_size); - /* movq %r11, -0x10(%rbp) */ - o(0xf05d894c); - /* leaq $-192(%rbp), %r11 */ - o(0x9d8d4c); - gen_le32(-176 - 24); - /* movq %r11, -0x8(%rbp) */ - o(0xf85d894c); - - /* save all register passing arguments */ - for (i = 0; i < 8; i++) { - loc -= 16; - if (!tcc_state->nosse) { - o(0xd60f66); /* movq */ - gen_modrm(7 - i, VT_LOCAL, NULL, loc); - } - /* movq $0, loc+8(%rbp) */ - o(0x85c748); - gen_le32(loc + 8); - gen_le32(0); - } - for (i = 0; i < REGN; i++) { - push_arg_reg(REGN-1-i); - } - } - - sym = func_type->ref; - reg_param_index = 0; - sse_param_index = 0; - - /* if the function returns a structure, then add an - implicit pointer parameter */ - if (ret_mode == x86_64_mode_memory) { - push_arg_reg(reg_param_index); - func_vc = loc; - reg_param_index++; - } - /* define parameters */ - while ((sym = sym->next) != NULL) { - type = &sym->type; - mode = classify_x86_64_arg(type, NULL, &size, &align, ®_count); - switch (mode) { - case x86_64_mode_sse: - if (tcc_state->nosse) - tcc_error("SSE disabled but floating point arguments used"); - if (sse_param_index + reg_count <= 8) { - /* save arguments passed by register */ - loc -= reg_count * 8; - param_addr = loc; - for (i = 0; i < reg_count; ++i) { - o(0xd60f66); /* movq */ - gen_modrm(sse_param_index, VT_LOCAL, NULL, param_addr + i*8); - ++sse_param_index; - } - } else { - addr = (addr + align - 1) & -align; - param_addr = addr; - addr += size; - } - break; - - case x86_64_mode_memory: - case x86_64_mode_x87: - addr = (addr + align - 1) & -align; - param_addr = addr; - addr += size; - break; - - case x86_64_mode_integer: { - if (reg_param_index + reg_count <= REGN) { - /* save arguments passed by register */ - loc -= reg_count * 8; - param_addr = loc; - for (i = 0; i < reg_count; ++i) { - gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, param_addr + i*8); - ++reg_param_index; - } - } else { - addr = (addr + align - 1) & -align; - param_addr = addr; - addr += size; - } - break; - } - default: break; /* nothing to be done for x86_64_mode_none */ - } - sym_push(sym->v & ~SYM_FIELD, type, - VT_LOCAL | VT_LVAL, param_addr); - } - -#ifdef CONFIG_TCC_BCHECK - if (tcc_state->do_bounds_check) - gen_bounds_prolog(); -#endif -} - -/* generate function epilog */ -void gfunc_epilog(void) -{ - int v, saved_ind; - -#ifdef CONFIG_TCC_BCHECK - if (tcc_state->do_bounds_check) - gen_bounds_epilog(); -#endif - o(0xc9); /* leave */ - if (func_ret_sub == 0) { - o(0xc3); /* ret */ - } else { - o(0xc2); /* ret n */ - g(func_ret_sub); - g(func_ret_sub >> 8); - } - /* align local size to word & save local variables */ - v = (-loc + 15) & -16; - saved_ind = ind; - ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; - o(0xe5894855); /* push %rbp, mov %rsp, %rbp */ - o(0xec8148); /* sub rsp, stacksize */ - gen_le32(v); - ind = saved_ind; -} - -#endif /* not PE */ - -ST_FUNC void gen_fill_nops(int bytes) -{ - while (bytes--) - g(0x90); -} - -/* generate a jump to a label */ -int gjmp(int t) -{ - return gjmp2(0xe9, t); -} - -/* generate a jump to a fixed address */ -void gjmp_addr(int a) -{ - int r; - r = a - ind - 2; - if (r == (char)r) { - g(0xeb); - g(r); - } else { - oad(0xe9, a - ind - 5); - } -} - -ST_FUNC int gjmp_append(int n, int t) -{ - void *p; - /* insert vtop->c jump list in t */ - if (n) { - uint32_t n1 = n, n2; - while ((n2 = read32le(p = cur_text_section->data + n1))) - n1 = n2; - write32le(p, t); - t = n; - } - return t; -} - -ST_FUNC int gjmp_cond(int op, int t) -{ - if (op & 0x100) - { - /* This was a float compare. If the parity flag is set - the result was unordered. For anything except != this - means false and we don't jump (anding both conditions). - For != this means true (oring both). - Take care about inverting the test. We need to jump - to our target if the result was unordered and test wasn't NE, - otherwise if unordered we don't want to jump. */ - int v = vtop->cmp_r; - op &= ~0x100; - if (op ^ v ^ (v != TOK_NE)) - o(0x067a); /* jp +6 */ - else - { - g(0x0f); - t = gjmp2(0x8a, t); /* jp t */ - } - } - g(0x0f); - t = gjmp2(op - 16, t); - return t; -} - -/* generate an integer binary operation */ -void gen_opi(int op) -{ - int r, fr, opc, c; - int ll, uu, cc; - - ll = is64_type(vtop[-1].type.t); - uu = (vtop[-1].type.t & VT_UNSIGNED) != 0; - cc = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; - - switch(op) { - case '+': - case TOK_ADDC1: /* add with carry generation */ - opc = 0; - gen_op8: - if (cc && (!ll || (int)vtop->c.i == vtop->c.i)) { - /* constant case */ - vswap(); - r = gv(RC_INT); - vswap(); - c = vtop->c.i; - if (c == (char)c) { - /* XXX: generate inc and dec for smaller code ? */ - orex(ll, r, 0, 0x83); - o(0xc0 | (opc << 3) | REG_VALUE(r)); - g(c); - } else { - orex(ll, r, 0, 0x81); - oad(0xc0 | (opc << 3) | REG_VALUE(r), c); - } - } else { - gv2(RC_INT, RC_INT); - r = vtop[-1].r; - fr = vtop[0].r; - orex(ll, r, fr, (opc << 3) | 0x01); - o(0xc0 + REG_VALUE(r) + REG_VALUE(fr) * 8); - } - vtop--; - if (op >= TOK_ULT && op <= TOK_GT) - vset_VT_CMP(op); - break; - case '-': - case TOK_SUBC1: /* sub with carry generation */ - opc = 5; - goto gen_op8; - case TOK_ADDC2: /* add with carry use */ - opc = 2; - goto gen_op8; - case TOK_SUBC2: /* sub with carry use */ - opc = 3; - goto gen_op8; - case '&': - opc = 4; - goto gen_op8; - case '^': - opc = 6; - goto gen_op8; - case '|': - opc = 1; - goto gen_op8; - case '*': - gv2(RC_INT, RC_INT); - r = vtop[-1].r; - fr = vtop[0].r; - orex(ll, fr, r, 0xaf0f); /* imul fr, r */ - o(0xc0 + REG_VALUE(fr) + REG_VALUE(r) * 8); - vtop--; - break; - case TOK_SHL: - opc = 4; - goto gen_shift; - case TOK_SHR: - opc = 5; - goto gen_shift; - case TOK_SAR: - opc = 7; - gen_shift: - opc = 0xc0 | (opc << 3); - if (cc) { - /* constant case */ - vswap(); - r = gv(RC_INT); - vswap(); - orex(ll, r, 0, 0xc1); /* shl/shr/sar $xxx, r */ - o(opc | REG_VALUE(r)); - g(vtop->c.i & (ll ? 63 : 31)); - } else { - /* we generate the shift in ecx */ - gv2(RC_INT, RC_RCX); - r = vtop[-1].r; - orex(ll, r, 0, 0xd3); /* shl/shr/sar %cl, r */ - o(opc | REG_VALUE(r)); - } - vtop--; - break; - case TOK_UDIV: - case TOK_UMOD: - uu = 1; - goto divmod; - case '/': - case '%': - case TOK_PDIV: - uu = 0; - divmod: - /* first operand must be in eax */ - /* XXX: need better constraint for second operand */ - gv2(RC_RAX, RC_RCX); - r = vtop[-1].r; - fr = vtop[0].r; - vtop--; - save_reg(TREG_RDX); - orex(ll, 0, 0, uu ? 0xd231 : 0x99); /* xor %edx,%edx : cqto */ - orex(ll, fr, 0, 0xf7); /* div fr, %eax */ - o((uu ? 0xf0 : 0xf8) + REG_VALUE(fr)); - if (op == '%' || op == TOK_UMOD) - r = TREG_RDX; - else - r = TREG_RAX; - vtop->r = r; - break; - default: - opc = 7; - goto gen_op8; - } -} - -void gen_opl(int op) -{ - gen_opi(op); -} - -void vpush_const(int t, int v) -{ - CType ctype = { t | VT_CONSTANT, 0 }; - vpushsym(&ctype, external_global_sym(v, &ctype)); - vtop->r |= VT_LVAL; -} - -/* generate a floating point operation 'v = t1 op t2' instruction. The - two operands are guaranteed to have the same floating point type */ -/* XXX: need to use ST1 too */ -void gen_opf(int op) -{ - int a, ft, fc, swapped, r; - int bt = vtop->type.t & VT_BTYPE; - int float_type = bt == VT_LDOUBLE ? RC_ST0 : RC_FLOAT; - - if (op == TOK_NEG) { /* unary minus */ - gv(float_type); - if (float_type == RC_ST0) { - o(0xe0d9); /* fchs */ - } else { - /* -0.0, in libtcc1.c */ - vpush_const(bt, bt == VT_FLOAT ? TOK___mzerosf : TOK___mzerodf); - gv(RC_FLOAT); - if (bt == VT_DOUBLE) - o(0x66); - /* xorp[sd] %xmm1, %xmm0 */ - o(0xc0570f | (REG_VALUE(vtop[0].r) + REG_VALUE(vtop[-1].r)*8) << 16); - vtop--; - } - return; - } - - /* convert constants to memory references */ - if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { - vswap(); - gv(float_type); - vswap(); - } - if ((vtop[0].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) - gv(float_type); - - /* must put at least one value in the floating point register */ - if ((vtop[-1].r & VT_LVAL) && - (vtop[0].r & VT_LVAL)) { - vswap(); - gv(float_type); - vswap(); - } - swapped = 0; - /* swap the stack if needed so that t1 is the register and t2 is - the memory reference */ - if (vtop[-1].r & VT_LVAL) { - vswap(); - swapped = 1; - } - if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { - if (op >= TOK_ULT && op <= TOK_GT) { - /* load on stack second operand */ - load(TREG_ST0, vtop); - save_reg(TREG_RAX); /* eax is used by FP comparison code */ - if (op == TOK_GE || op == TOK_GT) - swapped = !swapped; - else if (op == TOK_EQ || op == TOK_NE) - swapped = 0; - if (swapped) - o(0xc9d9); /* fxch %st(1) */ - 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 */ - o(0x40fC80); /* cmp $0x40, %ah */ - } else if (op == TOK_NE) { - o(0x45e480); /* and $0x45, %ah */ - o(0x40f480); /* xor $0x40, %ah */ - op = TOK_NE; - } else if (op == TOK_GE || op == TOK_LE) { - o(0x05c4f6); /* test $0x05, %ah */ - op = TOK_EQ; - } else { - o(0x45c4f6); /* test $0x45, %ah */ - op = TOK_EQ; - } - vtop--; - vset_VT_CMP(op); - } else { - /* no memory reference possible for long double operations */ - load(TREG_ST0, vtop); - swapped = !swapped; - - switch(op) { - default: - case '+': - a = 0; - break; - case '-': - a = 4; - if (swapped) - a++; - break; - case '*': - a = 1; - break; - case '/': - a = 6; - if (swapped) - a++; - break; - } - ft = vtop->type.t; - fc = vtop->c.i; - o(0xde); /* fxxxp %st, %st(1) */ - o(0xc1 + (a << 3)); - vtop--; - } - } else { - if (op >= TOK_ULT && op <= TOK_GT) { - /* if saved lvalue, then we must reload it */ - r = vtop->r; - fc = vtop->c.i; - if ((r & VT_VALMASK) == VT_LLOCAL) { - SValue v1; - r = get_reg(RC_INT); - v1.type.t = VT_PTR; - v1.r = VT_LOCAL | VT_LVAL; - v1.c.i = fc; - load(r, &v1); - fc = 0; - vtop->r = r = r | VT_LVAL; - } - - if (op == TOK_EQ || op == TOK_NE) { - swapped = 0; - } else { - if (op == TOK_LE || op == TOK_LT) - swapped = !swapped; - if (op == TOK_LE || op == TOK_GE) { - op = 0x93; /* setae */ - } else { - op = 0x97; /* seta */ - } - } - - if (swapped) { - gv(RC_FLOAT); - vswap(); - } - assert(!(vtop[-1].r & VT_LVAL)); - - if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) - o(0x66); - if (op == TOK_EQ || op == TOK_NE) - o(0x2e0f); /* ucomisd */ - else - o(0x2f0f); /* comisd */ - - if (vtop->r & VT_LVAL) { - gen_modrm(vtop[-1].r, r, vtop->sym, fc); - } else { - o(0xc0 + REG_VALUE(vtop[0].r) + REG_VALUE(vtop[-1].r)*8); - } - - vtop--; - vset_VT_CMP(op | 0x100); - vtop->cmp_r = op; - } else { - assert((vtop->type.t & VT_BTYPE) != VT_LDOUBLE); - switch(op) { - default: - case '+': - a = 0; - break; - case '-': - a = 4; - break; - case '*': - a = 1; - break; - case '/': - a = 6; - break; - } - ft = vtop->type.t; - fc = vtop->c.i; - assert((ft & VT_BTYPE) != VT_LDOUBLE); - - r = vtop->r; - /* if saved lvalue, then we must reload it */ - if ((vtop->r & VT_VALMASK) == VT_LLOCAL) { - SValue v1; - r = get_reg(RC_INT); - v1.type.t = VT_PTR; - v1.r = VT_LOCAL | VT_LVAL; - v1.c.i = fc; - load(r, &v1); - fc = 0; - vtop->r = r = r | VT_LVAL; - } - - assert(!(vtop[-1].r & VT_LVAL)); - if (swapped) { - assert(vtop->r & VT_LVAL); - gv(RC_FLOAT); - vswap(); - } - - if ((ft & VT_BTYPE) == VT_DOUBLE) { - o(0xf2); - } else { - o(0xf3); - } - o(0x0f); - o(0x58 + a); - - if (vtop->r & VT_LVAL) { - gen_modrm(vtop[-1].r, r, vtop->sym, fc); - } else { - o(0xc0 + REG_VALUE(vtop[0].r) + REG_VALUE(vtop[-1].r)*8); - } - - vtop--; - } - } -} - -/* convert integers to fp 't' type. Must handle 'int', 'unsigned int' - and 'long long' cases. */ -void gen_cvt_itof(int t) -{ - if ((t & VT_BTYPE) == VT_LDOUBLE) { - save_reg(TREG_ST0); - gv(RC_INT); - if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { - /* signed long long to float/double/long double (unsigned case - is handled generically) */ - o(0x50 + (vtop->r & VT_VALMASK)); /* push r */ - o(0x242cdf); /* fildll (%rsp) */ - o(0x08c48348); /* add $8, %rsp */ - } else if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == - (VT_INT | VT_UNSIGNED)) { - /* unsigned int to float/double/long double */ - o(0x6a); /* push $0 */ - g(0x00); - o(0x50 + (vtop->r & VT_VALMASK)); /* push r */ - o(0x242cdf); /* fildll (%rsp) */ - o(0x10c48348); /* add $16, %rsp */ - } else { - /* int to float/double/long double */ - o(0x50 + (vtop->r & VT_VALMASK)); /* push r */ - o(0x2404db); /* fildl (%rsp) */ - o(0x08c48348); /* add $8, %rsp */ - } - vtop->r = TREG_ST0; - } else { - int r = get_reg(RC_FLOAT); - gv(RC_INT); - o(0xf2 + ((t & VT_BTYPE) == VT_FLOAT?1:0)); - if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == - (VT_INT | VT_UNSIGNED) || - (vtop->type.t & VT_BTYPE) == VT_LLONG) { - o(0x48); /* REX */ - } - o(0x2a0f); - o(0xc0 + (vtop->r & VT_VALMASK) + REG_VALUE(r)*8); /* cvtsi2sd */ - vtop->r = r; - } -} - -/* convert from one floating point type to another */ -void gen_cvt_ftof(int t) -{ - int ft, bt, tbt; - - ft = vtop->type.t; - bt = ft & VT_BTYPE; - tbt = t & VT_BTYPE; - - if (bt == VT_FLOAT) { - gv(RC_FLOAT); - if (tbt == VT_DOUBLE) { - o(0x140f); /* unpcklps */ - o(0xc0 + REG_VALUE(vtop->r)*9); - o(0x5a0f); /* cvtps2pd */ - o(0xc0 + REG_VALUE(vtop->r)*9); - } else if (tbt == VT_LDOUBLE) { - save_reg(RC_ST0); - /* movss %xmm0,-0x10(%rsp) */ - o(0x110ff3); - o(0x44 + REG_VALUE(vtop->r)*8); - o(0xf024); - o(0xf02444d9); /* flds -0x10(%rsp) */ - vtop->r = TREG_ST0; - } - } else if (bt == VT_DOUBLE) { - gv(RC_FLOAT); - if (tbt == VT_FLOAT) { - o(0x140f66); /* unpcklpd */ - o(0xc0 + REG_VALUE(vtop->r)*9); - o(0x5a0f66); /* cvtpd2ps */ - o(0xc0 + REG_VALUE(vtop->r)*9); - } else if (tbt == VT_LDOUBLE) { - save_reg(RC_ST0); - /* movsd %xmm0,-0x10(%rsp) */ - o(0x110ff2); - o(0x44 + REG_VALUE(vtop->r)*8); - o(0xf024); - o(0xf02444dd); /* fldl -0x10(%rsp) */ - vtop->r = TREG_ST0; - } - } else { - int r; - gv(RC_ST0); - r = get_reg(RC_FLOAT); - if (tbt == VT_DOUBLE) { - o(0xf0245cdd); /* fstpl -0x10(%rsp) */ - /* movsd -0x10(%rsp),%xmm0 */ - o(0x100ff2); - o(0x44 + REG_VALUE(r)*8); - o(0xf024); - vtop->r = r; - } else if (tbt == VT_FLOAT) { - o(0xf0245cd9); /* fstps -0x10(%rsp) */ - /* movss -0x10(%rsp),%xmm0 */ - o(0x100ff3); - o(0x44 + REG_VALUE(r)*8); - o(0xf024); - vtop->r = r; - } - } -} - -/* convert fp to int 't' type */ -void gen_cvt_ftoi(int t) -{ - int ft, bt, size, r; - ft = vtop->type.t; - bt = ft & VT_BTYPE; - if (bt == VT_LDOUBLE) { - gen_cvt_ftof(VT_DOUBLE); - bt = VT_DOUBLE; - } - - gv(RC_FLOAT); - if (t != VT_INT) - size = 8; - else - size = 4; - - r = get_reg(RC_INT); - if (bt == VT_FLOAT) { - o(0xf3); - } else if (bt == VT_DOUBLE) { - o(0xf2); - } else { - assert(0); - } - orex(size == 8, r, 0, 0x2c0f); /* cvttss2si or cvttsd2si */ - o(0xc0 + REG_VALUE(vtop->r) + REG_VALUE(r)*8); - vtop->r = r; -} - -// Generate sign extension from 32 to 64 bits: -ST_FUNC void gen_cvt_sxtw(void) -{ - int r = gv(RC_INT); - /* x86_64 specific: movslq */ - o(0x6348); - o(0xc0 + (REG_VALUE(r) << 3) + REG_VALUE(r)); -} - -/* char/short to int conversion */ -ST_FUNC void gen_cvt_csti(int t) -{ - int r, sz, xl, ll; - r = gv(RC_INT); - sz = !(t & VT_UNSIGNED); - xl = (t & VT_BTYPE) == VT_SHORT; - ll = (vtop->type.t & VT_BTYPE) == VT_LLONG; - orex(ll, r, 0, 0xc0b60f /* mov[sz] %a[xl], %eax */ - | (sz << 3 | xl) << 8 - | (REG_VALUE(r) << 3 | REG_VALUE(r)) << 16 - ); -} - -/* increment tcov counter */ -ST_FUNC void gen_increment_tcov (SValue *sv) -{ - o(0x058348); /* addq $1, xxx(%rip) */ - greloca(cur_text_section, sv->sym, ind, R_X86_64_PC32, -5); - gen_le32(0); - o(1); -} - -/* computed goto support */ -ST_FUNC void ggoto(void) -{ - gcall_or_jmp(1); - vtop--; -} - -/* Save the stack pointer onto the stack and return the location of its address */ -ST_FUNC void gen_vla_sp_save(int addr) { - /* mov %rsp,addr(%rbp)*/ - gen_modrm64(0x89, TREG_RSP, VT_LOCAL, NULL, addr); -} - -/* Restore the SP from a location on the stack */ -ST_FUNC void gen_vla_sp_restore(int addr) { - gen_modrm64(0x8b, TREG_RSP, VT_LOCAL, NULL, addr); -} - -#ifdef TCC_TARGET_PE -/* Save result of gen_vla_alloc onto the stack */ -ST_FUNC void gen_vla_result(int addr) { - /* mov %rax,addr(%rbp)*/ - gen_modrm64(0x89, TREG_RAX, VT_LOCAL, NULL, addr); -} -#endif - -/* Subtract from the stack pointer, and push the resulting value onto the stack */ -ST_FUNC void gen_vla_alloc(CType *type, int align) { - int use_call = 0; - -#if defined(CONFIG_TCC_BCHECK) - use_call = tcc_state->do_bounds_check; -#endif -#ifdef TCC_TARGET_PE /* alloca does more than just adjust %rsp on Windows */ - use_call = 1; -#endif - if (use_call) - { - vpush_helper_func(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(0x2b48); - o(0xe0 | REG_VALUE(r)); - /* We align to 16 bytes rather than align */ - /* and ~15, %rsp */ - o(0xf0e48348); - vpop(); - } -} - -/* - * Assmuing the top part of the stack looks like below, - * src dest src - */ -ST_FUNC void gen_struct_copy(int size) -{ - int n = size / PTR_SIZE; -#ifdef TCC_TARGET_PE - o(0x5756); /* push rsi, rdi */ -#endif - gv2(RC_RDI, RC_RSI); - if (n <= 4) { - while (n) - o(0xa548), --n; - } else { - vpushi(n); - gv(RC_RCX); - o(0xa548f3); - vpop(); - } - if (size & 0x04) - o(0xa5); - if (size & 0x02) - o(0xa566); - if (size & 0x01) - o(0xa4); -#ifdef TCC_TARGET_PE - o(0x5e5f); /* pop rdi, rsi */ -#endif - vpop(); - vpop(); -} - -/* end of x86-64 code generator */ -/*************************************************************/ -#endif /* ! TARGET_DEFS_ONLY */ -/******************************************************/ diff --git a/tinycc/x86_64-link.c b/tinycc/x86_64-link.c deleted file mode 100644 index 1b6aa09..0000000 --- a/tinycc/x86_64-link.c +++ /dev/null @@ -1,403 +0,0 @@ -#ifdef TARGET_DEFS_ONLY - -#define EM_TCC_TARGET EM_X86_64 - -/* relocation type for 32 bit data relocation */ -#define R_DATA_32 R_X86_64_32S -#define R_DATA_PTR R_X86_64_64 -#define R_JMP_SLOT R_X86_64_JUMP_SLOT -#define R_GLOB_DAT R_X86_64_GLOB_DAT -#define R_COPY R_X86_64_COPY -#define R_RELATIVE R_X86_64_RELATIVE - -#define R_NUM R_X86_64_NUM - -#define ELF_START_ADDR 0x400000 -#define ELF_PAGE_SIZE 0x200000 - -#define PCRELATIVE_DLLPLT 1 -#define RELOCATE_DLLPLT 1 - -#else /* !TARGET_DEFS_ONLY */ - -#include "tcc.h" - -#ifdef NEED_RELOC_TYPE -/* 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_X86_64_32: - case R_X86_64_32S: - case R_X86_64_64: - case R_X86_64_GOTPC32: - case R_X86_64_GOTPC64: - case R_X86_64_GOTPCREL: - case R_X86_64_GOTPCRELX: - case R_X86_64_REX_GOTPCRELX: - case R_X86_64_GOTTPOFF: - case R_X86_64_GOT32: - case R_X86_64_GOT64: - case R_X86_64_GLOB_DAT: - case R_X86_64_COPY: - case R_X86_64_RELATIVE: - case R_X86_64_GOTOFF64: - case R_X86_64_TLSGD: - case R_X86_64_TLSLD: - case R_X86_64_DTPOFF32: - case R_X86_64_TPOFF32: - case R_X86_64_DTPOFF64: - case R_X86_64_TPOFF64: - return 0; - - case R_X86_64_PC32: - case R_X86_64_PC64: - case R_X86_64_PLT32: - case R_X86_64_PLTOFF64: - case R_X86_64_JUMP_SLOT: - return 1; - } - return -1; -} - -/* Returns an enumerator to describe whether 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_X86_64_GLOB_DAT: - case R_X86_64_JUMP_SLOT: - case R_X86_64_COPY: - case R_X86_64_RELATIVE: - return NO_GOTPLT_ENTRY; - - /* The following relocs wouldn't normally need GOT or PLT - slots, but we need them for simplicity in the link - editor part. See our caller for comments. */ - case R_X86_64_32: - case R_X86_64_32S: - case R_X86_64_64: - case R_X86_64_PC32: - case R_X86_64_PC64: - return AUTO_GOTPLT_ENTRY; - - case R_X86_64_GOTTPOFF: - return BUILD_GOT_ONLY; - - case R_X86_64_GOT32: - case R_X86_64_GOT64: - case R_X86_64_GOTPC32: - case R_X86_64_GOTPC64: - case R_X86_64_GOTOFF64: - case R_X86_64_GOTPCREL: - case R_X86_64_GOTPCRELX: - case R_X86_64_TLSGD: - case R_X86_64_TLSLD: - case R_X86_64_DTPOFF32: - case R_X86_64_TPOFF32: - case R_X86_64_DTPOFF64: - case R_X86_64_TPOFF64: - case R_X86_64_REX_GOTPCRELX: - case R_X86_64_PLT32: - case R_X86_64_PLTOFF64: - return ALWAYS_GOTPLT_ENTRY; - } - - return -1; -} - -#ifdef NEED_BUILD_GOT -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; - - modrm = 0x25; - - /* empty PLT: create PLT0 entry that pushes the library identifier - (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->plt->reloc ? s1->plt->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 */ - /* On x86-64, the relocation is referred to by _index_ */ - write32le(p + 7, relofs / sizeof (ElfW_Rel) - 1); - 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) { - int x = s1->got->sh_addr - s1->plt->sh_addr - 6; - add32le(p + 2, x); - add32le(p + 8, x - 6); - p += 16; - while (p < p_end) { - add32le(p + 2, x + (s1->plt->data - p)); - p += 16; - } - } - - if (s1->plt->reloc) { - ElfW_Rel *rel; - int x = s1->plt->sh_addr + 16 + 6; - p = s1->got->data; - for_each_elem(s1->plt->reloc, 0, rel, ElfW_Rel) { - write64le(p + rel->r_offset, x); - x += 16; - } - } -} -#endif -#endif - -void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned 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_X86_64_64: - if (s1->output_type & TCC_OUTPUT_DYN) { - esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index; - qrel->r_offset = rel->r_offset; - if (esym_index) { - qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_64); - qrel->r_addend = rel->r_addend; - qrel++; - break; - } else { - qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE); - qrel->r_addend = read64le(ptr) + val; - qrel++; - } - } - add64le(ptr, val); - break; - case R_X86_64_32: - case R_X86_64_32S: - if (s1->output_type & TCC_OUTPUT_DYN) { - /* XXX: this logic may depend on TCC's codegen - now TCC uses R_X86_64_32 even for a 64bit pointer */ - qrel->r_offset = rel->r_offset; - qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE); - /* Use sign extension! */ - qrel->r_addend = (int)read32le(ptr) + val; - qrel++; - } - add32le(ptr, val); - break; - - case R_X86_64_PC32: - if (s1->output_type == TCC_OUTPUT_DLL) { - /* DLL relocation */ - esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index; - if (esym_index) { - qrel->r_offset = rel->r_offset; - qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_PC32); - /* Use sign extension! */ - qrel->r_addend = (int)read32le(ptr) + rel->r_addend; - qrel++; - break; - } - } - goto plt32pc32; - - case R_X86_64_PLT32: - /* fallthrough: val already holds the PLT slot address */ - - plt32pc32: - { - long long diff; - diff = (long long)val - addr; - if (diff < -2147483648LL || diff > 2147483647LL) { -#ifdef TCC_TARGET_PE - /* ignore overflow with undefined weak symbols */ - if (((ElfW(Sym)*)symtab_section->data)[sym_index].st_shndx != SHN_UNDEF) -#endif - tcc_error_noabort("internal error: relocation failed"); - } - add32le(ptr, diff); - } - break; - - case R_X86_64_COPY: - break; - - case R_X86_64_PLTOFF64: - add64le(ptr, val - s1->got->sh_addr + rel->r_addend); - break; - - case R_X86_64_PC64: - if (s1->output_type == TCC_OUTPUT_DLL) { - /* DLL relocation */ - esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index; - if (esym_index) { - qrel->r_offset = rel->r_offset; - qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_PC64); - qrel->r_addend = read64le(ptr) + rel->r_addend; - qrel++; - break; - } - } - add64le(ptr, val - addr); - break; - - case R_X86_64_GLOB_DAT: - case R_X86_64_JUMP_SLOT: - /* They don't need addend */ - write64le(ptr, val - rel->r_addend); - break; - case R_X86_64_GOTPCREL: - case R_X86_64_GOTPCRELX: - case R_X86_64_REX_GOTPCRELX: - add32le(ptr, s1->got->sh_addr - addr + - get_sym_attr(s1, sym_index, 0)->got_offset - 4); - break; - case R_X86_64_GOTPC32: - add32le(ptr, s1->got->sh_addr - addr + rel->r_addend); - break; - case R_X86_64_GOTPC64: - add64le(ptr, s1->got->sh_addr - addr + rel->r_addend); - break; - case R_X86_64_GOTTPOFF: - add32le(ptr, val - s1->got->sh_addr); - break; - case R_X86_64_GOT32: - /* we load the got offset */ - add32le(ptr, get_sym_attr(s1, sym_index, 0)->got_offset); - break; - case R_X86_64_GOT64: - /* we load the got offset */ - add64le(ptr, get_sym_attr(s1, sym_index, 0)->got_offset); - break; - case R_X86_64_GOTOFF64: - add64le(ptr, val - s1->got->sh_addr); - break; - case R_X86_64_TLSGD: - { - static const unsigned char expect[] = { - /* .byte 0x66; lea 0(%rip),%rdi */ - 0x66, 0x48, 0x8d, 0x3d, 0x00, 0x00, 0x00, 0x00, - /* .word 0x6666; rex64; call __tls_get_addr@PLT */ - 0x66, 0x66, 0x48, 0xe8, 0x00, 0x00, 0x00, 0x00 }; - static const unsigned char replace[] = { - /* mov %fs:0,%rax */ - 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, - /* lea -4(%rax),%rax */ - 0x48, 0x8d, 0x80, 0x00, 0x00, 0x00, 0x00 }; - - if (memcmp (ptr-4, expect, sizeof(expect)) == 0) { - ElfW(Sym) *sym; - Section *sec; - int32_t x; - - memcpy(ptr-4, replace, sizeof(replace)); - rel[1].r_info = ELFW(R_INFO)(0, R_X86_64_NONE); - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - sec = s1->sections[sym->st_shndx]; - x = sym->st_value - sec->sh_addr - sec->data_offset; - add32le(ptr + 8, x); - } - else - tcc_error_noabort("unexpected R_X86_64_TLSGD pattern"); - } - break; - case R_X86_64_TLSLD: - { - static const unsigned char expect[] = { - /* lea 0(%rip),%rdi */ - 0x48, 0x8d, 0x3d, 0x00, 0x00, 0x00, 0x00, - /* call __tls_get_addr@PLT */ - 0xe8, 0x00, 0x00, 0x00, 0x00 }; - static const unsigned char replace[] = { - /* data16 data16 data16 mov %fs:0,%rax */ - 0x66, 0x66, 0x66, 0x64, 0x48, 0x8b, 0x04, 0x25, - 0x00, 0x00, 0x00, 0x00 }; - - if (memcmp (ptr-3, expect, sizeof(expect)) == 0) { - memcpy(ptr-3, replace, sizeof(replace)); - rel[1].r_info = ELFW(R_INFO)(0, R_X86_64_NONE); - } - else - tcc_error_noabort("unexpected R_X86_64_TLSLD pattern"); - } - break; - case R_X86_64_DTPOFF32: - case R_X86_64_TPOFF32: - { - ElfW(Sym) *sym; - Section *sec; - int32_t x; - - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - sec = s1->sections[sym->st_shndx]; - x = val - sec->sh_addr - sec->data_offset; - add32le(ptr, x); - } - break; - case R_X86_64_DTPOFF64: - case R_X86_64_TPOFF64: - { - ElfW(Sym) *sym; - Section *sec; - int32_t x; - - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - sec = s1->sections[sym->st_shndx]; - x = val - sec->sh_addr - sec->data_offset; - add64le(ptr, x); - } - break; - case R_X86_64_NONE: - break; - case R_X86_64_RELATIVE: -#ifdef TCC_TARGET_PE - add32le(ptr, val - s1->pe_imagebase); -#endif - /* do nothing */ - break; - default: - fprintf(stderr,"FIXME: handle reloc type %d at %x [%p] to %x\n", - type, (unsigned)addr, ptr, (unsigned)val); - break; - } -} - -#endif /* !TARGET_DEFS_ONLY */ |
