mirror of
https://github.com/mirror/tinycc.git
synced 2026-08-28 11:53:52 +08:00
Compare commits
92 Commits
release_0_
...
release_0_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b8d7f44b4 | ||
|
|
27feb1adac | ||
|
|
1c1919072b | ||
|
|
be5e9cb962 | ||
|
|
48c85f1b15 | ||
|
|
398e22c541 | ||
|
|
6bbfb8f610 | ||
|
|
1d0e5e8b01 | ||
|
|
1e1d3ff687 | ||
|
|
736b565766 | ||
|
|
c2ec76a41f | ||
|
|
6b52984ce4 | ||
|
|
c9c05ca5f0 | ||
|
|
32ba2eadf6 | ||
|
|
3e74b91de6 | ||
|
|
e657dfb491 | ||
|
|
2a6c104722 | ||
|
|
38e8a23025 | ||
|
|
bb07bf31aa | ||
|
|
eb79471184 | ||
|
|
59c3563827 | ||
|
|
45466d2df6 | ||
|
|
807321efba | ||
|
|
ff3a5daf25 | ||
|
|
0bd402d2eb | ||
|
|
9668499b9f | ||
|
|
72a88fbab0 | ||
|
|
4d9f6d2bcf | ||
|
|
d65463809c | ||
|
|
62f99adb71 | ||
|
|
aa7ef7919e | ||
|
|
13affef3f1 | ||
|
|
c50af8399d | ||
|
|
ec7d36326d | ||
|
|
bf45336afb | ||
|
|
6e5b1cc43a | ||
|
|
3bd3c71fd1 | ||
|
|
79c72b2419 | ||
|
|
df36de6507 | ||
|
|
c52df4de38 | ||
|
|
8da6027e73 | ||
|
|
c1265d1616 | ||
|
|
22d8df96c6 | ||
|
|
8da2d689df | ||
|
|
fe203057c2 | ||
|
|
114883e078 | ||
|
|
7a5123a770 | ||
|
|
4df5bd2eb0 | ||
|
|
44cea6aee9 | ||
|
|
77a19bf50e | ||
|
|
b7f12dfbdf | ||
|
|
9890ea1233 | ||
|
|
feed3262c9 | ||
|
|
bef8703f77 | ||
|
|
46169b92d9 | ||
|
|
d369a77647 | ||
|
|
c5ce5eaeda | ||
|
|
9c1106d854 | ||
|
|
f8d0241764 | ||
|
|
c5959b77b4 | ||
|
|
7b940fcb1b | ||
|
|
21d2d99bdc | ||
|
|
277e01cd64 | ||
|
|
9d95be78c8 | ||
|
|
370f5e571c | ||
|
|
d0476a0e2e | ||
|
|
4e6edcdcdd | ||
|
|
98713a6be3 | ||
|
|
fe3b68b087 | ||
|
|
770ef5ed1f | ||
|
|
7b05ed6b81 | ||
|
|
8f5e44a439 | ||
|
|
813acdc691 | ||
|
|
638e666c42 | ||
|
|
e58bda52cd | ||
|
|
f0d5a74bcd | ||
|
|
6cdf6f88d7 | ||
|
|
5908725ad5 | ||
|
|
edbfa7715f | ||
|
|
c4e6b2e9be | ||
|
|
71f119fe25 | ||
|
|
68c800981e | ||
|
|
a901c5f204 | ||
|
|
2b64f2f570 | ||
|
|
7828683e60 | ||
|
|
60efcfe27c | ||
|
|
356fa0c3bb | ||
|
|
9791bfaf48 | ||
|
|
0eef235475 | ||
|
|
410fc57ba0 | ||
|
|
066d5e7a84 | ||
|
|
214ccccea7 |
24
.cvsignore
24
.cvsignore
@@ -1,40 +1,26 @@
|
||||
tcc_g
|
||||
tcc
|
||||
tc.c.1
|
||||
t.c
|
||||
tc2.c
|
||||
p3.s
|
||||
ex3
|
||||
ex1.c
|
||||
ex2.c
|
||||
otcc1.c
|
||||
doc
|
||||
tc3s.c
|
||||
p3.c
|
||||
tc1.c
|
||||
error.c
|
||||
p1.s
|
||||
t.s
|
||||
userlist.txt
|
||||
tcc1.c
|
||||
i386-gen1.c
|
||||
ex4.c
|
||||
test.out2
|
||||
test.out3
|
||||
web.sh
|
||||
ex3.c
|
||||
memdebug.c
|
||||
bench
|
||||
ex5.c
|
||||
tcc-newparse.c
|
||||
COPYING
|
||||
p1.c
|
||||
Makefile.uClibc
|
||||
boundtest
|
||||
p4.c
|
||||
p5.c
|
||||
prog.ref
|
||||
contacts.txt
|
||||
test.ref
|
||||
a.c
|
||||
p3
|
||||
@@ -51,11 +37,15 @@ linux.tcc
|
||||
wintest.c
|
||||
ldtest
|
||||
libtcc_test
|
||||
p2.il
|
||||
short.prof
|
||||
tccp.c
|
||||
instr.S
|
||||
p.c
|
||||
p2.c
|
||||
tcctest[1234]
|
||||
test[1234].out
|
||||
.gdb_history
|
||||
tcc.1
|
||||
tcc.pod
|
||||
config.h
|
||||
config.mak
|
||||
config.texi
|
||||
gcctestsuite.sh
|
||||
|
||||
504
COPYING
Normal file
504
COPYING
Normal file
@@ -0,0 +1,504 @@
|
||||
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!
|
||||
|
||||
|
||||
56
Changelog
56
Changelog
@@ -1,3 +1,59 @@
|
||||
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)
|
||||
|
||||
85
Makefile
85
Makefile
@@ -4,7 +4,10 @@
|
||||
include config.mak
|
||||
|
||||
CFLAGS=-O2 -g -Wall
|
||||
ifndef CONFIG_WIN32
|
||||
LIBS=-ldl
|
||||
BCHECK_O=bcheck.o
|
||||
endif
|
||||
CFLAGS_P=$(CFLAGS) -pg -static -DCONFIG_TCC_STATIC
|
||||
LIBS_P=
|
||||
|
||||
@@ -12,16 +15,18 @@ CFLAGS+=-mpreferred-stack-boundary=2
|
||||
ifeq ($(GCC_MAJOR),2)
|
||||
CFLAGS+=-m386 -malign-functions=0
|
||||
else
|
||||
CFLAGS+=-march=i386 -falign-functions=0
|
||||
CFLAGS+=-march=i386 -falign-functions=0 -fno-strict-aliasing
|
||||
endif
|
||||
|
||||
DISAS=objdump -d
|
||||
INSTALL=install
|
||||
|
||||
PROGS=tcc$(EXESUF) c67-tcc$(EXESUF) arm-tcc$(EXESUF)
|
||||
# run local version of tcc with local libraries and includes
|
||||
TCC=./tcc -B. -I.
|
||||
|
||||
all: tcc libtcc1.o bcheck.o tcc-doc.html libtcc.a libtcc_test
|
||||
all: $(PROGS) \
|
||||
libtcc1$(LIBSUF) $(BCHECK_O) tcc-doc.html tcc.1 libtcc$(LIBSUF) \
|
||||
libtcc_test$(EXESUF)
|
||||
|
||||
Makefile: config.mak
|
||||
|
||||
@@ -108,63 +113,73 @@ ex3: ex3.c
|
||||
|
||||
# Native Tiny C Compiler
|
||||
|
||||
tcc_g: tcc.c i386-gen.c tccelf.c tccasm.c i386-asm.c tcctok.h libtcc.h i386-asm.h Makefile
|
||||
tcc_g$(EXESUF): tcc.c i386-gen.c tccelf.c tccasm.c i386-asm.c tcctok.h libtcc.h i386-asm.h Makefile
|
||||
$(CC) $(CFLAGS) -o $@ $< $(LIBS)
|
||||
|
||||
tcc: tcc_g Makefile
|
||||
strip -s -R .comment -R .note -o $@ $<
|
||||
tcc$(EXESUF): tcc_g$(EXESUF) Makefile
|
||||
$(STRIP) -o $@ $<
|
||||
|
||||
c67-tcc$(EXESUF): tcc.c c67-gen.c tccelf.c tccasm.c tcctok.h libtcc.h tcccoff.c Makefile
|
||||
$(CC) $(CFLAGS) -DTCC_TARGET_C67 -o $@ $< $(LIBS)
|
||||
|
||||
arm-tcc$(EXESUF): tcc.c arm-gen.c tccelf.c tccasm.c tcctok.h libtcc.h Makefile
|
||||
$(CC) $(CFLAGS) -DTCC_TARGET_ARM -o $@ $< $(LIBS)
|
||||
|
||||
# TinyCC runtime libraries
|
||||
libtcc1.o: libtcc1.c
|
||||
$(CC) -O2 -Wall -c -o $@ $<
|
||||
|
||||
libtcc1$(LIBSUF): libtcc1.o
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
bcheck.o: bcheck.c
|
||||
$(CC) -O2 -Wall -c -o $@ $<
|
||||
|
||||
install: tcc_install libinstall
|
||||
|
||||
tcc_install: tcc libtcc1.o bcheck.o
|
||||
$(INSTALL) -m755 tcc $(bindir)
|
||||
$(INSTALL) tcc.1 $(mandir)/man1
|
||||
mkdir -p $(libdir)/tcc
|
||||
mkdir -p $(libdir)/tcc/include
|
||||
$(INSTALL) -m644 libtcc1.o bcheck.o $(libdir)/tcc
|
||||
tcc_install: $(PROGS) tcc.1 libtcc1$(LIBSUF) $(BCHECK_O) tcc-doc.html tcc.1
|
||||
mkdir -p "$(bindir)"
|
||||
$(INSTALL) -s -m755 $(PROGS) "$(bindir)"
|
||||
ifndef CONFIG_WIN32
|
||||
mkdir -p "$(mandir)/man1"
|
||||
$(INSTALL) tcc.1 "$(mandir)/man1"
|
||||
endif
|
||||
mkdir -p "$(libdir)/tcc"
|
||||
mkdir -p "$(libdir)/tcc/include"
|
||||
$(INSTALL) -m644 libtcc1$(LIBSUF) $(BCHECK_O) "$(libdir)/tcc"
|
||||
$(INSTALL) -m644 stdarg.h stddef.h stdbool.h float.h varargs.h \
|
||||
tcclib.h $(libdir)/tcc/include
|
||||
tcclib.h "$(libdir)/tcc/include"
|
||||
mkdir -p "$(docdir)"
|
||||
$(INSTALL) -m644 tcc-doc.html "$(docdir)"
|
||||
|
||||
clean:
|
||||
rm -f *~ *.o tcc tcc1 tcct tcc_g tcctest.ref *.bin *.i ex2 \
|
||||
core gmon.out test.out test.ref a.out tcc_p \
|
||||
*.exe tcc-doc.html libtcc.a libtcc_test \
|
||||
tcctest[1234] test[1234].out
|
||||
*.exe tcc-doc.html tcc.pod tcc.1 libtcc$(LIBSUF) libtcc_test \
|
||||
tcctest[1234] test[1234].out c67-tcc arm-tcc
|
||||
|
||||
distclean: clean
|
||||
rm -f config.h config.mak config.texi
|
||||
|
||||
# win32 TCC
|
||||
tcc_g.exe: tcc.c i386-gen.c bcheck.c Makefile
|
||||
i386-mingw32msvc-gcc $(CFLAGS) -DCONFIG_TCC_STATIC -o $@ $<
|
||||
|
||||
tcc.exe: tcc_g.exe
|
||||
i386-mingw32msvc-strip -o $@ $<
|
||||
|
||||
# profiling version
|
||||
tcc_p: tcc.c Makefile
|
||||
$(CC) $(CFLAGS_P) -o $@ $< $(LIBS_P)
|
||||
|
||||
# libtcc generation and example
|
||||
libinstall: libtcc.a
|
||||
$(INSTALL) -m644 libtcc.a $(libdir)
|
||||
$(INSTALL) -m644 libtcc.h $(includedir)
|
||||
libinstall: libtcc$(LIBSUF)
|
||||
mkdir -p "$(libdir)"
|
||||
$(INSTALL) -m644 libtcc$(LIBSUF) "$(libdir)"
|
||||
mkdir -p "$(includedir)"
|
||||
$(INSTALL) -m644 libtcc.h "$(includedir)"
|
||||
|
||||
libtcc.o: tcc.c i386-gen.c bcheck.c Makefile
|
||||
libtcc.o: tcc.c i386-gen.c Makefile
|
||||
$(CC) $(CFLAGS) -DLIBTCC -c -o $@ $<
|
||||
|
||||
libtcc.a: libtcc.o
|
||||
libtcc$(LIBSUF): libtcc.o
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
libtcc_test: libtcc_test.c libtcc.a
|
||||
$(CC) $(CFLAGS) -I. -o $@ $< -L. -ltcc -ldl
|
||||
libtcc_test$(EXESUF): libtcc_test.c libtcc$(LIBSUF)
|
||||
$(CC) $(CFLAGS) -o $@ $< libtcc$(LIBSUF) $(LIBS)
|
||||
|
||||
libtest: libtcc_test
|
||||
./libtcc_test
|
||||
@@ -201,21 +216,27 @@ cache: tcc_g
|
||||
cachegrind ./tcc_g -o /tmp/linpack -lm bench/linpack.c
|
||||
vg_annotate tcc.c > /tmp/linpack.cache.log
|
||||
|
||||
# documentation
|
||||
# documentation and man page
|
||||
tcc-doc.html: tcc-doc.texi
|
||||
texi2html -monolithic -number $<
|
||||
|
||||
tcc.1: tcc-doc.texi
|
||||
./texi2pod.pl $< tcc.pod
|
||||
pod2man --section=1 --center=" " --release=" " tcc.pod > $@
|
||||
|
||||
FILES= Makefile Makefile.uClibc configure VERSION \
|
||||
README TODO COPYING \
|
||||
Changelog tcc-doc.texi tcc-doc.html \
|
||||
tcc.1 \
|
||||
tcc.c i386-gen.c tccelf.c tcctok.h tccasm.c i386-asm.c i386-asm.h\
|
||||
tcc.c tccelf.c tcctok.h tccasm.c i386-asm.c i386-asm.h \
|
||||
tcccoff.c coff.h \
|
||||
i386-gen.c c67-gen.c arm-gen.c \
|
||||
bcheck.c libtcc1.c \
|
||||
elf.h stab.h stab.def \
|
||||
stddef.h stdarg.h stdbool.h float.h varargs.h \
|
||||
tcclib.h libtcc.h libtcc_test.c \
|
||||
ex1.c ex2.c ex3.c ex4.c ex5.c \
|
||||
tcctest.c boundtest.c gcctestsuite.sh
|
||||
tcctest.c boundtest.c gcctestsuite.sh texi2pod.pl
|
||||
|
||||
FILE=tcc-$(VERSION)
|
||||
|
||||
|
||||
9
README
9
README
@@ -50,7 +50,7 @@ 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' on the first
|
||||
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
|
||||
@@ -84,10 +84,7 @@ Please read tcc-doc.html to have all the features of TCC.
|
||||
License:
|
||||
-------
|
||||
|
||||
TCC is distributed under the GNU General Public License (see COPYING
|
||||
file).
|
||||
|
||||
License may be changed to LGPL or X11 style, so I would prefer that
|
||||
you indicate in submitted patches that you accept such a change.
|
||||
TCC is distributed under the GNU Lesser General Public License (see
|
||||
COPYING file).
|
||||
|
||||
Fabrice Bellard.
|
||||
|
||||
31
TODO
31
TODO
@@ -1,38 +1,45 @@
|
||||
TODO list:
|
||||
|
||||
- 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
|
||||
- constructors
|
||||
- cast bug (Peter Wang)
|
||||
- define incomplete type if defined several times (Peter Wang).
|
||||
- long long constant evaluation
|
||||
- configure --cc=tcc (still one bug in libtcc1.c)
|
||||
- disable-asm and disable-bcheck options
|
||||
- test binutils/gcc compile
|
||||
- add alloca(), __builtin_expect()
|
||||
- gcc '-E' option.
|
||||
- optimize VT_LOCAL + const
|
||||
- tci patch + argument.
|
||||
- '-b' bug.
|
||||
- atexit (Nigel Horne)
|
||||
- see -lxxx bug (Michael Charity).
|
||||
- handle inline functions as macros.
|
||||
- see transparent union pb in /urs/include/sys/socket.h
|
||||
- precise behaviour of typeof with arrays ? (__put_user macro)
|
||||
- #include_next support for /usr/include/limits ?
|
||||
but should suffice for most cases)
|
||||
- handle '? x, y : z' in reversed function arguments or unsized
|
||||
variable initialization (',' is considered incorrectly as separator
|
||||
in preparser) : change func argument code generator ?
|
||||
- handle '? x, y : z' in unsized variable initialization (',' is
|
||||
considered incorrectly as separator in preparser)
|
||||
- function pointers/lvalues in ? : (linux kernel net/core/dev.c)
|
||||
- transform functions to function pointers in function parameters (net/ipv4/ip_output.c)
|
||||
- fix function pointer type display
|
||||
- fix bound exit on RedHat 7.3
|
||||
- fix static link on RedHat 7.3
|
||||
- check lcc test suite -> fix bitfield binary operations
|
||||
- check section alignment in C
|
||||
- fix invalid cast in comparison 'if (v == (int8_t)v)'
|
||||
- packed attribute
|
||||
- look at patches from Scott Lafferty
|
||||
- look at bugs from Jason Petrasko.
|
||||
- support link once trick (gcc 3.2 / glibc compilation issue)
|
||||
- finish varargs.h support (gcc 3.2 testsuite issue)
|
||||
- add alloca()
|
||||
- fix static functions declared inside block
|
||||
- C99: add variable size arrays (gcc 3.2 testsuite issue)
|
||||
- C99: add complex types (gcc 3.2 testsuite issue)
|
||||
- postfix compound literals (see 20010124-1.c)
|
||||
- fix multiple unions init
|
||||
- test includes in libtcc_test.
|
||||
- look at GCC 3.2 compatibility problems.
|
||||
- add option for auto run
|
||||
- setjmp is not supported properly in bound checking.
|
||||
- better local variables handling (needed for other targets)
|
||||
- fix bound check code with '&' on local variables (currently done
|
||||
|
||||
17
asmtest.S
17
asmtest.S
@@ -12,6 +12,7 @@
|
||||
.align 16, 0x90
|
||||
.skip 3
|
||||
.skip 15, 0x90
|
||||
.string "hello\0world"
|
||||
|
||||
/* some label tests */
|
||||
|
||||
@@ -42,6 +43,8 @@ movl $2, 0x100(%ebx,%edx,2)
|
||||
movl %eax, 0x100(%ebx,%edx,2)
|
||||
movl 0x100(%ebx,%edx,2), %edx
|
||||
movw %ax, 0x100(%ebx,%edx,2)
|
||||
|
||||
mov %eax, 0x12(,%edx,2)
|
||||
|
||||
mov %cr3, %edx
|
||||
mov %ecx, %cr3
|
||||
@@ -519,6 +522,8 @@ int $0x10
|
||||
bts %edx, 0x1000
|
||||
btsl $2, 0x1000
|
||||
|
||||
|
||||
|
||||
boundl %edx, 0x10000
|
||||
boundw %bx, 0x1000
|
||||
|
||||
@@ -539,3 +544,15 @@ int $0x10
|
||||
|
||||
verr 0x1000
|
||||
verw 0x1000
|
||||
|
||||
push %ds
|
||||
pushw %ds
|
||||
pushl %ds
|
||||
pop %ds
|
||||
popw %ds
|
||||
popl %ds
|
||||
fxsave 1(%ebx)
|
||||
fxrstor 1(%ecx)
|
||||
pushl $1
|
||||
pushw $1
|
||||
push $1
|
||||
|
||||
26
bcheck.c
26
bcheck.c
@@ -36,7 +36,7 @@
|
||||
|
||||
#define HAVE_MEMALIGN
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#if defined(__FreeBSD__) || defined(__dietlibc__)
|
||||
#warning Bound checking not fully supported on FreeBSD
|
||||
#undef CONFIG_TCC_MALLOC_HOOKS
|
||||
#undef HAVE_MEMALIGN
|
||||
@@ -74,19 +74,7 @@ void __bound_init(void);
|
||||
void __bound_new_region(void *p, unsigned long size);
|
||||
int __bound_delete_region(void *p);
|
||||
|
||||
/* currently, tcc cannot compile that because we use unsupported GNU C
|
||||
extensions */
|
||||
#if !defined(__TINYC__)
|
||||
void *__bound_ptr_add(void *p, int offset) __attribute__((regparm(2)));
|
||||
void *__bound_ptr_indir1(void *p, int offset) __attribute__((regparm(2)));
|
||||
void *__bound_ptr_indir2(void *p, int offset) __attribute__((regparm(2)));
|
||||
void *__bound_ptr_indir4(void *p, int offset) __attribute__((regparm(2)));
|
||||
void *__bound_ptr_indir8(void *p, int offset) __attribute__((regparm(2)));
|
||||
void *__bound_ptr_indir12(void *p, int offset) __attribute__((regparm(2)));
|
||||
void *__bound_ptr_indir16(void *p, int offset) __attribute__((regparm(2)));
|
||||
void __bound_local_new(void *p) __attribute__((regparm(1)));
|
||||
void __bound_local_delete(void *p) __attribute__((regparm(1)));
|
||||
#endif
|
||||
#define FASTCALL __attribute__((regparm(3)))
|
||||
|
||||
void *__bound_malloc(size_t size, const void *caller);
|
||||
void *__bound_memalign(size_t size, size_t align, const void *caller);
|
||||
@@ -168,7 +156,7 @@ static void bound_alloc_error(void)
|
||||
|
||||
/* return '(p + offset)' for pointer arithmetic (a pointer can reach
|
||||
the end of a region in this case */
|
||||
void *__bound_ptr_add(void *p, int offset)
|
||||
void * FASTCALL __bound_ptr_add(void *p, int offset)
|
||||
{
|
||||
unsigned long addr = (unsigned long)p;
|
||||
BoundEntry *e;
|
||||
@@ -194,7 +182,7 @@ void *__bound_ptr_add(void *p, int 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, int offset) \
|
||||
void * FASTCALL __bound_ptr_indir ## dsize (void *p, int offset) \
|
||||
{ \
|
||||
unsigned long addr = (unsigned long)p; \
|
||||
BoundEntry *e; \
|
||||
@@ -227,7 +215,7 @@ void *__bound_ptr_indir ## dsize (void *p, int offset) \
|
||||
#endif
|
||||
|
||||
/* called when entering a function to add all the local regions */
|
||||
void __bound_local_new(void *p1)
|
||||
void FASTCALL __bound_local_new(void *p1)
|
||||
{
|
||||
unsigned long addr, size, fp, *p = p1;
|
||||
GET_CALLER_FP(fp);
|
||||
@@ -243,7 +231,7 @@ void __bound_local_new(void *p1)
|
||||
}
|
||||
|
||||
/* called when leaving a function to delete all the local regions */
|
||||
void __bound_local_delete(void *p1)
|
||||
void FASTCALL __bound_local_delete(void *p1)
|
||||
{
|
||||
unsigned long addr, fp, *p = p1;
|
||||
GET_CALLER_FP(fp);
|
||||
@@ -782,7 +770,7 @@ void *__bound_calloc(size_t nmemb, size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
size = size * nmemb;
|
||||
ptr = __bound_malloc(size);
|
||||
ptr = __bound_malloc(size, NULL);
|
||||
if (!ptr)
|
||||
return NULL;
|
||||
memset(ptr, 0, size);
|
||||
|
||||
446
coff.h
Normal file
446
coff.h
Normal file
@@ -0,0 +1,446 @@
|
||||
/**************************************************************************/
|
||||
/* 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 nunbers 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"
|
||||
59
configure
vendored
59
configure
vendored
@@ -18,7 +18,7 @@ TMPS="${TMPDIR1}/tcc-conf-${RANDOM}-$$-${RANDOM}.S"
|
||||
TMPH="${TMPDIR1}/tcc-conf-${RANDOM}-$$-${RANDOM}.h"
|
||||
|
||||
# default parameters
|
||||
prefix="/usr/local"
|
||||
prefix=""
|
||||
execprefix=""
|
||||
bindir=""
|
||||
libdir=""
|
||||
@@ -56,10 +56,16 @@ case "$cpu" in
|
||||
esac
|
||||
gprof="no"
|
||||
bigendian="no"
|
||||
mingw32="no"
|
||||
LIBSUF=".a"
|
||||
EXESUF=""
|
||||
|
||||
# OS specific
|
||||
targetos=`uname -s`
|
||||
case $targetos in
|
||||
MINGW32*)
|
||||
mingw32="yes"
|
||||
;;
|
||||
*) ;;
|
||||
esac
|
||||
|
||||
@@ -106,6 +112,8 @@ for opt do
|
||||
;;
|
||||
--enable-gprof) gprof="yes"
|
||||
;;
|
||||
--enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -118,6 +126,11 @@ cc="${cross_prefix}${cc}"
|
||||
ar="${cross_prefix}${ar}"
|
||||
strip="${cross_prefix}${strip}"
|
||||
|
||||
if test "$mingw32" = "yes" ; then
|
||||
LIBSUF=".lib"
|
||||
EXESUF=".exe"
|
||||
fi
|
||||
|
||||
if test -z "$cross_prefix" ; then
|
||||
|
||||
# ---
|
||||
@@ -188,26 +201,43 @@ echo ""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test x"$execprefix" = x""; then
|
||||
execprefix="${prefix}"
|
||||
fi
|
||||
if test x"$bindir" = x""; then
|
||||
bindir="${execprefix}/bin"
|
||||
fi
|
||||
if test "$mingw32" = "yes" ; then
|
||||
if test -z "$prefix" ; then
|
||||
prefix="/c/Program Files/tcc"
|
||||
fi
|
||||
execprefix="$prefix"
|
||||
bindir="$prefix"
|
||||
docdir="$prefix/doc"
|
||||
else
|
||||
if test -z "$prefix" ; then
|
||||
prefix="/usr/local"
|
||||
fi
|
||||
if test x"$execprefix" = x""; then
|
||||
execprefix="${prefix}"
|
||||
fi
|
||||
if test x"$bindir" = x""; then
|
||||
bindir="${execprefix}/bin"
|
||||
fi
|
||||
if test x"$docdir" = x""; then
|
||||
docdir="$prefix/share/doc/tcc"
|
||||
fi
|
||||
fi # mingw32
|
||||
|
||||
if test x"$libdir" = x""; then
|
||||
libdir="${execprefix}/lib"
|
||||
fi
|
||||
if test x"$includedir" = x""; then
|
||||
includedir="${prefix}/include"
|
||||
fi
|
||||
if test x"$mandir" = x""; then
|
||||
mandir="${prefix}/man"
|
||||
fi
|
||||
if test x"$includedir" = x""; then
|
||||
includedir="${prefix}/include"
|
||||
fi
|
||||
|
||||
echo "Binary directory $bindir"
|
||||
echo "Library directory $libdir"
|
||||
echo "Include directory $includedir"
|
||||
echo "Manual directory $mandir"
|
||||
echo "Manual directory $mandir"
|
||||
echo "Doc directory $docdir"
|
||||
echo "Source path $source_path"
|
||||
echo "C compiler $cc"
|
||||
echo "make $make"
|
||||
@@ -225,6 +255,7 @@ echo "bindir=$bindir" >> config.mak
|
||||
echo "libdir=$libdir" >> config.mak
|
||||
echo "includedir=$includedir" >> config.mak
|
||||
echo "mandir=$mandir" >> config.mak
|
||||
echo "docdir=$docdir" >> config.mak
|
||||
echo "#define CONFIG_TCC_LIBDIR \"$libdir\"" >> $TMPH
|
||||
echo "MAKE=$make" >> config.mak
|
||||
echo "CC=$cc" >> config.mak
|
||||
@@ -235,6 +266,8 @@ echo "AR=$ar" >> config.mak
|
||||
echo "STRIP=$strip -s -R .comment -R .note" >> config.mak
|
||||
echo "CFLAGS=$CFLAGS" >> config.mak
|
||||
echo "LDFLAGS=$LDFLAGS" >> config.mak
|
||||
echo "LIBSUF=$LIBSUF" >> config.mak
|
||||
echo "EXESUF=$EXESUF" >> config.mak
|
||||
if test "$cpu" = "x86" ; then
|
||||
echo "ARCH=i386" >> config.mak
|
||||
echo "#define HOST_I386 1" >> $TMPH
|
||||
@@ -257,6 +290,10 @@ else
|
||||
echo "Unsupported CPU"
|
||||
exit 1
|
||||
fi
|
||||
if test "$mingw32" = "yes" ; then
|
||||
echo "CONFIG_WIN32=yes" >> config.mak
|
||||
echo "#define CONFIG_WIN32 1" >> $TMPH
|
||||
fi
|
||||
if test "$bigendian" = "yes" ; then
|
||||
echo "WORDS_BIGENDIAN=yes" >> config.mak
|
||||
echo "#define WORDS_BIGENDIAN 1" >> $TMPH
|
||||
|
||||
18
elf.h
18
elf.h
@@ -217,6 +217,7 @@ typedef struct
|
||||
chances of collision with official or non-GNU unofficial values. */
|
||||
|
||||
#define EM_ALPHA 0x9026
|
||||
#define EM_C60 0x9c60
|
||||
|
||||
/* Legal values for e_version (version). */
|
||||
|
||||
@@ -1592,4 +1593,21 @@ typedef Elf32_Addr Elf32_Conflict;
|
||||
/* 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_C60HI16 0x55 // high 16 bit MVKH embedded
|
||||
#define R_C60LO16 0x54 // low 16 bit MVKL embedded
|
||||
|
||||
#endif /* elf.h */
|
||||
|
||||
8
ex1.c
Executable file
8
ex1.c
Executable file
@@ -0,0 +1,8 @@
|
||||
#! /usr/local/bin/tcc -run
|
||||
#include <tcclib.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("Hello World\n");
|
||||
return 0;
|
||||
}
|
||||
97
ex2.c
Normal file
97
ex2.c
Normal file
@@ -0,0 +1,97 @@
|
||||
#include "tcclib.h"
|
||||
|
||||
#define N 20
|
||||
|
||||
int nb_num;
|
||||
int tab[N];
|
||||
int stack_ptr;
|
||||
int stack_op[N];
|
||||
int stack_res[60];
|
||||
int result;
|
||||
|
||||
int find(int n, int i1, int a, int b, int op)
|
||||
{
|
||||
int i, j;
|
||||
int c;
|
||||
|
||||
if (stack_ptr >= 0) {
|
||||
stack_res[3*stack_ptr] = a;
|
||||
stack_op[stack_ptr] = op;
|
||||
stack_res[3*stack_ptr+1] = b;
|
||||
stack_res[3*stack_ptr+2] = n;
|
||||
if (n == result)
|
||||
return 1;
|
||||
tab[i1] = n;
|
||||
}
|
||||
|
||||
for(i=0;i<nb_num;i++) {
|
||||
for(j=i+1;j<nb_num;j++) {
|
||||
a = tab[i];
|
||||
b = tab[j];
|
||||
if (a != 0 && b != 0) {
|
||||
|
||||
tab[j] = 0;
|
||||
stack_ptr++;
|
||||
|
||||
if (find(a + b, i, a, b, '+'))
|
||||
return 1;
|
||||
if (find(a - b, i, a, b, '-'))
|
||||
return 1;
|
||||
if (find(b - a, i, b, a, '-'))
|
||||
return 1;
|
||||
if (find(a * b, i, a, b, '*'))
|
||||
return 1;
|
||||
if (b != 0) {
|
||||
c = a / b;
|
||||
if (find(c, i, a, b, '/'))
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (a != 0) {
|
||||
c = b / a;
|
||||
if (find(c, i, b, a, '/'))
|
||||
return 1;
|
||||
}
|
||||
|
||||
stack_ptr--;
|
||||
tab[i] = a;
|
||||
tab[j] = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, res, p;
|
||||
|
||||
if (argc < 3) {
|
||||
printf("usage: %s: result numbers...\n"
|
||||
"Try to find result from numbers with the 4 basic operations.\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
p = 1;
|
||||
result = atoi(argv[p]);
|
||||
printf("result=%d\n", result);
|
||||
nb_num = 0;
|
||||
for(i=p+1;i<argc;i++) {
|
||||
tab[nb_num++] = atoi(argv[i]);
|
||||
}
|
||||
|
||||
stack_ptr = -1;
|
||||
res = find(0, 0, 0, 0, ' ');
|
||||
if (res) {
|
||||
for(i=0;i<=stack_ptr;i++) {
|
||||
printf("%d %c %d = %d\n",
|
||||
stack_res[3*i], stack_op[i],
|
||||
stack_res[3*i+1], stack_res[3*i+2]);
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
printf("Impossible\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
23
ex3.c
Normal file
23
ex3.c
Normal file
@@ -0,0 +1,23 @@
|
||||
#include <tcclib.h>
|
||||
|
||||
int fib(n)
|
||||
{
|
||||
if (n <= 2)
|
||||
return 1;
|
||||
else
|
||||
return fib(n-1) + fib(n-2);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int n;
|
||||
if (argc < 2) {
|
||||
printf("usage: fib n\n"
|
||||
"Compute nth Fibonacci number\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
n = atoi(argv[1]);
|
||||
printf("fib(%d) = %d\n", n, fib(n, 2));
|
||||
return 0;
|
||||
}
|
||||
25
ex4.c
Executable file
25
ex4.c
Executable file
@@ -0,0 +1,25 @@
|
||||
#!./tcc -run -L/usr/X11R6/lib -lX11
|
||||
#include <stdlib.h>
|
||||
/* Yes, TCC can use X11 too ! */
|
||||
#include <stdio.h>
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
Display *display;
|
||||
Screen *screen;
|
||||
|
||||
display = XOpenDisplay("");
|
||||
if (!display) {
|
||||
fprintf(stderr, "Could not open X11 display\n");
|
||||
exit(1);
|
||||
}
|
||||
printf("X11 display opened.\n");
|
||||
screen = XScreenOfDisplay(display, 0);
|
||||
printf("width = %d\nheight = %d\ndepth = %d\n",
|
||||
screen->width,
|
||||
screen->height,
|
||||
screen->root_depth);
|
||||
XCloseDisplay(display);
|
||||
return 0;
|
||||
}
|
||||
8
ex5.c
Normal file
8
ex5.c
Normal file
@@ -0,0 +1,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("Hello World\n");
|
||||
return 0;
|
||||
}
|
||||
33
gcctestsuite.sh
Executable file
33
gcctestsuite.sh
Executable file
@@ -0,0 +1,33 @@
|
||||
#!/bin/sh
|
||||
|
||||
TESTSUITE_PATH=$HOME/gcc/gcc-3.2/gcc/testsuite/gcc.c-torture
|
||||
TCC="./tcc -B. -I. -DNO_TRAMPOLINES"
|
||||
rm -f tcc.sum tcc.log
|
||||
nb_failed="0"
|
||||
|
||||
for src in $TESTSUITE_PATH/compile/*.c ; do
|
||||
echo $TCC -o /tmp/test.o -c $src
|
||||
$TCC -o /tmp/test.o -c $src >> tcc.log 2>&1
|
||||
if [ "$?" == "0" ] ; then
|
||||
result="PASS"
|
||||
else
|
||||
result="FAIL"
|
||||
nb_failed=$[ $nb_failed + 1 ]
|
||||
fi
|
||||
echo "$result: $src" >> tcc.sum
|
||||
done
|
||||
|
||||
for src in $TESTSUITE_PATH/execute/*.c ; do
|
||||
echo $TCC $src
|
||||
$TCC $src >> tcc.log 2>&1
|
||||
if [ "$?" == "0" ] ; then
|
||||
result="PASS"
|
||||
else
|
||||
result="FAIL"
|
||||
nb_failed=$[ $nb_failed + 1 ]
|
||||
fi
|
||||
echo "$result: $src" >> tcc.sum
|
||||
done
|
||||
|
||||
echo "$nb_failed test(s) failed." >> tcc.sum
|
||||
echo "$nb_failed test(s) failed."
|
||||
273
i386-asm.c
273
i386-asm.c
@@ -3,19 +3,19 @@
|
||||
*
|
||||
* Copyright (c) 2001, 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 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 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.
|
||||
* 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 General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* 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 MAX_OPERANDS 3
|
||||
@@ -364,7 +364,7 @@ static void gen_le16(int v)
|
||||
/* generate the modrm operand */
|
||||
static inline void asm_modrm(int reg, Operand *op)
|
||||
{
|
||||
int mod, reg1, reg2;
|
||||
int mod, reg1, reg2, sib_reg1;
|
||||
|
||||
if (op->type & (OP_REG | OP_MMX | OP_SSE)) {
|
||||
g(0xc0 + (reg << 3) + op->reg);
|
||||
@@ -373,8 +373,12 @@ static inline void asm_modrm(int reg, Operand *op)
|
||||
g(0x05 + (reg << 3));
|
||||
gen_expr32(&op->e);
|
||||
} else {
|
||||
sib_reg1 = op->reg;
|
||||
/* fist compute displacement encoding */
|
||||
if (op->e.v == 0 && !op->e.sym && op->reg != 5) {
|
||||
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;
|
||||
@@ -391,13 +395,13 @@ static inline void asm_modrm(int reg, Operand *op)
|
||||
reg2 = op->reg2;
|
||||
if (reg2 == -1)
|
||||
reg2 = 4; /* indicate no index */
|
||||
g((op->shift << 6) + (reg2 << 3) + op->reg);
|
||||
g((op->shift << 6) + (reg2 << 3) + sib_reg1);
|
||||
}
|
||||
|
||||
/* add offset */
|
||||
if (mod == 0x40) {
|
||||
g(op->e.v);
|
||||
} else if (mod == 0x80) {
|
||||
} else if (mod == 0x80 || op->reg == -1) {
|
||||
gen_expr32(&op->e);
|
||||
}
|
||||
}
|
||||
@@ -517,7 +521,11 @@ static void asm_opcode(TCCState *s1, int opcode)
|
||||
s = reg_to_size[ops[i].type & OP_REG];
|
||||
}
|
||||
if (s == 3) {
|
||||
error("cannot infer opcode suffix");
|
||||
if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) &&
|
||||
(ops[0].type & (OP_SEG | OP_IM8S | OP_IM32)))
|
||||
s = 2;
|
||||
else
|
||||
error("cannot infer opcode suffix");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -745,50 +753,63 @@ static inline int constraint_priority(const char *str)
|
||||
return priority;
|
||||
}
|
||||
|
||||
static void asm_compute_constraints(uint8_t *regs_allocated,
|
||||
ASMOperand *operands,
|
||||
int nb_operands1, int nb_outputs,
|
||||
int is_output,
|
||||
uint8_t *input_regs_allocated)
|
||||
static const char *skip_constraint_modifiers(const char *p)
|
||||
{
|
||||
while (*p == '=' || *p == '&' || *p == '+' || *p == '%')
|
||||
p++;
|
||||
return p;
|
||||
}
|
||||
|
||||
#define REG_OUT_MASK 0x01
|
||||
#define REG_IN_MASK 0x02
|
||||
|
||||
#define is_reg_allocated(reg) (regs_allocated[reg] & reg_mask)
|
||||
|
||||
static 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, base, nb_operands;
|
||||
int i, j, k, p1, p2, tmp, reg, c, reg_mask;
|
||||
const char *str;
|
||||
uint8_t regs_allocated[NB_ASM_REGS];
|
||||
|
||||
if (is_output) {
|
||||
base = 0;
|
||||
nb_operands = nb_outputs;
|
||||
} else {
|
||||
base = nb_outputs;
|
||||
nb_operands = nb_operands1 - nb_outputs;
|
||||
/* 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++) {
|
||||
j = base + i;
|
||||
op = &operands[j];
|
||||
op = &operands[i];
|
||||
str = op->constraint;
|
||||
op->ref_index = -1;
|
||||
op->reg = -1;
|
||||
if (!is_output && (isnum(*str) || *str == '[')) {
|
||||
str = skip_constraint_modifiers(str);
|
||||
if (isnum(*str) || *str == '[') {
|
||||
/* this is a reference to another constraint */
|
||||
k = find_constraint(operands, nb_operands1, str, NULL);
|
||||
if ((unsigned)k >= j)
|
||||
k = find_constraint(operands, nb_operands, str, NULL);
|
||||
if ((unsigned)k >= i || i < nb_outputs)
|
||||
error("invalid reference in constraint %d ('%s')",
|
||||
j, str);
|
||||
i, str);
|
||||
op->ref_index = k;
|
||||
str = operands[k].constraint;
|
||||
if (operands[k].input_index >= 0)
|
||||
error("cannot reference twice the same operand");
|
||||
operands[k].input_index = i;
|
||||
op->priority = 5;
|
||||
} else {
|
||||
op->priority = constraint_priority(str);
|
||||
}
|
||||
while (*str == '=' || *str == '&' || *str == '+')
|
||||
str++;
|
||||
op->priority = constraint_priority(str);
|
||||
}
|
||||
|
||||
/* sort operands according to their priority */
|
||||
for(i=0;i<nb_operands;i++)
|
||||
sorted_op[i] = base + 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;
|
||||
@@ -801,33 +822,55 @@ static void asm_compute_constraints(uint8_t *regs_allocated,
|
||||
}
|
||||
}
|
||||
|
||||
memset(regs_allocated, 0, NB_ASM_REGS);
|
||||
regs_allocated[4] = 1; /* esp cannot be used */
|
||||
regs_allocated[5] = 1; /* ebp cannot be used yet */
|
||||
|
||||
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;
|
||||
|
||||
if (op->ref_index >= 0) {
|
||||
str = operands[op->ref_index].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;
|
||||
}
|
||||
|
||||
while (*str == '=' || *str == '&' || *str == '+')
|
||||
str++;
|
||||
try_next:
|
||||
c = *str++;
|
||||
switch(c) {
|
||||
case '=':
|
||||
goto try_next;
|
||||
case '+':
|
||||
op->is_rw = 1;
|
||||
/* FALL THRU */
|
||||
case '&':
|
||||
if (j >= nb_outputs)
|
||||
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 (regs_allocated[TREG_EAX] || regs_allocated[TREG_EDX])
|
||||
if (is_reg_allocated(TREG_EAX) ||
|
||||
is_reg_allocated(TREG_EDX))
|
||||
goto try_next;
|
||||
op->is_llong = 1;
|
||||
op->reg = TREG_EAX;
|
||||
regs_allocated[TREG_EAX] = 1;
|
||||
regs_allocated[TREG_EDX] = 1;
|
||||
regs_allocated[TREG_EAX] |= reg_mask;
|
||||
regs_allocated[TREG_EDX] |= reg_mask;
|
||||
break;
|
||||
case 'a':
|
||||
reg = TREG_EAX;
|
||||
@@ -847,20 +890,20 @@ static void asm_compute_constraints(uint8_t *regs_allocated,
|
||||
case 'D':
|
||||
reg = 7;
|
||||
alloc_reg:
|
||||
if (regs_allocated[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 (!regs_allocated[reg])
|
||||
if (!is_reg_allocated(reg))
|
||||
goto reg_found;
|
||||
}
|
||||
goto try_next;
|
||||
case 'r':
|
||||
/* any general register */
|
||||
for(reg = 0; reg < 8; reg++) {
|
||||
if (!regs_allocated[reg])
|
||||
if (!is_reg_allocated(reg))
|
||||
goto reg_found;
|
||||
}
|
||||
goto try_next;
|
||||
@@ -868,7 +911,7 @@ static void asm_compute_constraints(uint8_t *regs_allocated,
|
||||
/* now we can reload in the register */
|
||||
op->is_llong = 0;
|
||||
op->reg = reg;
|
||||
regs_allocated[reg] = 1;
|
||||
regs_allocated[reg] |= reg_mask;
|
||||
break;
|
||||
case 'i':
|
||||
if (!((op->vt->r & (VT_VALMASK | VT_LVAL)) == VT_CONST))
|
||||
@@ -882,25 +925,27 @@ static void asm_compute_constraints(uint8_t *regs_allocated,
|
||||
break;
|
||||
case 'm':
|
||||
case 'g':
|
||||
/* nothing special to do because the operand is
|
||||
already in memory */
|
||||
/* 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 (is_output) {
|
||||
/* 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 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 (!input_regs_allocated[reg])
|
||||
if (!(regs_allocated[reg] & REG_IN_MASK))
|
||||
goto reg_found1;
|
||||
}
|
||||
goto try_next;
|
||||
reg_found1:
|
||||
/* now we can reload in the register */
|
||||
input_regs_allocated[reg] = 1;
|
||||
regs_allocated[reg] |= REG_IN_MASK;
|
||||
op->reg = reg;
|
||||
op->is_memory = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -909,14 +954,34 @@ static void asm_compute_constraints(uint8_t *regs_allocated,
|
||||
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;
|
||||
}
|
||||
error("could not find free output register for reloading");
|
||||
reg_found2:
|
||||
*pout_reg = reg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* print sorted constraints */
|
||||
#ifdef ASM_DEBUG
|
||||
if (is_output)
|
||||
printf("outputs=\n");
|
||||
else
|
||||
printf("inputs=\n");
|
||||
for(i=0;i<nb_operands;i++) {
|
||||
j = sorted_op[i];
|
||||
op = &operands[j];
|
||||
@@ -927,6 +992,8 @@ static void asm_compute_constraints(uint8_t *regs_allocated,
|
||||
op->vt->r,
|
||||
op->reg);
|
||||
}
|
||||
if (*pout_reg >= 0)
|
||||
printf("out_reg=%d\n", *pout_reg);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1013,7 +1080,8 @@ static void subst_asm_operand(CString *add_str,
|
||||
/* generate prolog and epilog code for asm statment */
|
||||
static void asm_gen_code(ASMOperand *operands, int nb_operands,
|
||||
int nb_outputs, int is_output,
|
||||
uint8_t *clobber_regs)
|
||||
uint8_t *clobber_regs,
|
||||
int out_reg)
|
||||
{
|
||||
uint8_t regs_allocated[NB_ASM_REGS];
|
||||
ASMOperand *op;
|
||||
@@ -1036,39 +1104,52 @@ static void asm_gen_code(ASMOperand *operands, int nb_operands,
|
||||
}
|
||||
|
||||
/* generate load code */
|
||||
for(i = nb_outputs ; i < nb_operands; i++) {
|
||||
for(i = 0; i < nb_operands; i++) {
|
||||
op = &operands[i];
|
||||
if (op->reg >= 0) {
|
||||
load(op->reg, op->vt);
|
||||
if (op->is_llong) {
|
||||
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.c.ul += 4;
|
||||
load(TREG_EDX, &sv);
|
||||
sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL;
|
||||
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.ul += 4;
|
||||
load(TREG_EDX, &sv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* generate load code for output memory references */
|
||||
for(i = 0 ; i < nb_outputs; i++) {
|
||||
op = &operands[i];
|
||||
if (op->reg >= 0 && ((op->vt->r & VT_VALMASK) == VT_LLOCAL)) {
|
||||
SValue sv;
|
||||
sv = *op->vt;
|
||||
sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL;
|
||||
load(op->reg, &sv);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* generate save code */
|
||||
for(i = 0 ; i < nb_outputs; i++) {
|
||||
op = &operands[i];
|
||||
if (op->reg >= 0 && ((op->vt->r & VT_VALMASK) != VT_LLOCAL)) {
|
||||
store(op->reg, op->vt);
|
||||
if (op->is_llong) {
|
||||
SValue sv;
|
||||
sv = *op->vt;
|
||||
sv.c.ul += 4;
|
||||
store(TREG_EDX, &sv);
|
||||
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;
|
||||
load(out_reg, &sv);
|
||||
|
||||
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.ul += 4;
|
||||
store(TREG_EDX, &sv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
10
i386-asm.h
10
i386-asm.h
@@ -120,13 +120,13 @@ ALT(DEF_ASM_OP2(movzwl, 0x0fb7, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32))
|
||||
|
||||
ALT(DEF_ASM_OP1(pushw, 0x50, 0, OPC_REG | OPC_WL, OPT_REGW))
|
||||
ALT(DEF_ASM_OP1(pushw, 0xff, 6, OPC_MODRM | OPC_WL, OPT_REGW | OPT_EA))
|
||||
ALT(DEF_ASM_OP1(push, 0x6a, 0, 0, OPT_IM8S))
|
||||
ALT(DEF_ASM_OP1(push, 0x68, 0, 0, OPT_IM32))
|
||||
ALT(DEF_ASM_OP1(push, 0x06, 0, 0, OPT_SEG))
|
||||
ALT(DEF_ASM_OP1(pushw, 0x6a, 0, OPC_WL, OPT_IM8S))
|
||||
ALT(DEF_ASM_OP1(pushw, 0x68, 0, OPC_WL, OPT_IM32))
|
||||
ALT(DEF_ASM_OP1(pushw, 0x06, 0, OPC_WL, OPT_SEG))
|
||||
|
||||
ALT(DEF_ASM_OP1(popw, 0x58, 0, OPC_REG | OPC_WL, OPT_REGW))
|
||||
ALT(DEF_ASM_OP1(popw, 0x8f, 0, OPC_MODRM | OPC_WL, OPT_REGW | OPT_EA))
|
||||
ALT(DEF_ASM_OP1(pop, 0x07, 0, 0, OPT_SEG))
|
||||
ALT(DEF_ASM_OP1(popw, 0x07, 0, OPC_WL, OPT_SEG))
|
||||
|
||||
ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WL, OPT_REG, OPT_EAX))
|
||||
ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WL, OPT_EAX, OPT_REG))
|
||||
@@ -330,6 +330,8 @@ ALT(DEF_ASM_OP1(fstsw, 0xdd, 7, 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)
|
||||
|
||||
218
i386-gen.c
218
i386-gen.c
@@ -1,21 +1,21 @@
|
||||
/*
|
||||
* X86 code generator for TCC
|
||||
*
|
||||
* Copyright (c) 2001, 2002 Fabrice Bellard
|
||||
* Copyright (c) 2001-2004 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 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 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.
|
||||
* 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 General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* number of available registers */
|
||||
@@ -70,14 +70,18 @@ int reg_classes[NB_REGS] = {
|
||||
/* maximum alignment (for aligned attribute support) */
|
||||
#define MAX_ALIGN 8
|
||||
|
||||
/* relocation type for 32 bit data relocation */
|
||||
#define R_DATA_32 R_386_32
|
||||
/******************************************************/
|
||||
/* ELF defines */
|
||||
|
||||
/* function call context */
|
||||
typedef struct GFuncContext {
|
||||
int args_size;
|
||||
int func_call; /* func call type (FUNC_STDCALL or FUNC_CDECL) */
|
||||
} GFuncContext;
|
||||
#define EM_TCC_TARGET EM_386
|
||||
|
||||
/* relocation type for 32 bit data relocation */
|
||||
#define R_DATA_32 R_386_32
|
||||
#define R_JMP_SLOT R_386_JMP_SLOT
|
||||
#define R_COPY R_386_COPY
|
||||
|
||||
#define ELF_START_ADDR 0x08048000
|
||||
#define ELF_PAGE_SIZE 0x1000
|
||||
|
||||
/******************************************************/
|
||||
|
||||
@@ -96,11 +100,11 @@ void g(int c)
|
||||
ind = ind1;
|
||||
}
|
||||
|
||||
void o(int c)
|
||||
void o(unsigned int c)
|
||||
{
|
||||
while (c) {
|
||||
g(c);
|
||||
c = c / 256;
|
||||
c = c >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,65 +286,6 @@ void store(int r, SValue *v)
|
||||
}
|
||||
}
|
||||
|
||||
/* start function call and return function call context */
|
||||
void gfunc_start(GFuncContext *c, int func_call)
|
||||
{
|
||||
c->args_size = 0;
|
||||
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)
|
||||
{
|
||||
int size, align, r;
|
||||
|
||||
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 */
|
||||
oad(0xec81, size); /* sub $xxx, %esp */
|
||||
/* generate structure store */
|
||||
r = get_reg(RC_INT);
|
||||
o(0x89); /* mov %esp, r */
|
||||
o(0xe0 + r);
|
||||
vset(&vtop->type, r | VT_LVAL, 0);
|
||||
vswap();
|
||||
vstore();
|
||||
c->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);
|
||||
c->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 */
|
||||
c->args_size += size;
|
||||
}
|
||||
vtop--;
|
||||
}
|
||||
|
||||
static void gadd_sp(int val)
|
||||
{
|
||||
if (val == (char)val) {
|
||||
@@ -375,38 +320,118 @@ static void gcall_or_jmp(int is_jmp)
|
||||
}
|
||||
}
|
||||
|
||||
/* generate function call with address in (vtop->t, vtop->c) and free function
|
||||
context. Stack entry is popped */
|
||||
void gfunc_call(GFuncContext *c)
|
||||
static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
|
||||
|
||||
/* 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)
|
||||
{
|
||||
int size, align, r, args_size, i, func_call;
|
||||
Sym *func_sym;
|
||||
|
||||
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 */
|
||||
oad(0xec81, size); /* sub $xxx, %esp */
|
||||
/* generate structure store */
|
||||
r = get_reg(RC_INT);
|
||||
o(0x89); /* mov %esp, r */
|
||||
o(0xe0 + 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->r;
|
||||
/* fast call case */
|
||||
if (func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) {
|
||||
int fastcall_nb_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[i]); /* pop r */
|
||||
/* XXX: incorrect for struct/floats */
|
||||
args_size -= 4;
|
||||
}
|
||||
}
|
||||
gcall_or_jmp(0);
|
||||
if (c->args_size && c->func_call == FUNC_CDECL)
|
||||
gadd_sp(c->args_size);
|
||||
if (args_size && func_sym->r != FUNC_STDCALL)
|
||||
gadd_sp(args_size);
|
||||
vtop--;
|
||||
}
|
||||
|
||||
/* generate function prolog of type 't' */
|
||||
void gfunc_prolog(CType *func_type)
|
||||
{
|
||||
int addr, align, size, func_call;
|
||||
int addr, align, size, func_call, fastcall_nb_regs;
|
||||
int param_index, param_addr;
|
||||
Sym *sym;
|
||||
CType *type;
|
||||
|
||||
sym = func_type->ref;
|
||||
func_call = sym->r;
|
||||
addr = 8;
|
||||
loc = 0;
|
||||
if (func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) {
|
||||
fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1;
|
||||
} else {
|
||||
fastcall_nb_regs = 0;
|
||||
}
|
||||
param_index = 0;
|
||||
|
||||
o(0xe58955); /* push %ebp, mov %esp, %ebp */
|
||||
func_sub_sp_offset = oad(0xec81, 0); /* sub $xxx, %esp */
|
||||
|
||||
/* if the function returns a structure, then add an
|
||||
implicit pointer parameter */
|
||||
func_vt = sym->type;
|
||||
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
|
||||
/* XXX: fastcall case ? */
|
||||
func_vc = addr;
|
||||
addr += 4;
|
||||
param_index++;
|
||||
}
|
||||
/* define parameters */
|
||||
while ((sym = sym->next) != NULL) {
|
||||
type = &sym->type;
|
||||
sym_push(sym->v & ~SYM_FIELD, type,
|
||||
VT_LOCAL | VT_LVAL, addr);
|
||||
size = type_size(type, &align);
|
||||
size = (size + 3) & ~3;
|
||||
#ifdef FUNC_STRUCT_PARAM_AS_PTR
|
||||
@@ -415,14 +440,25 @@ void gfunc_prolog(CType *func_type)
|
||||
size = 4;
|
||||
}
|
||||
#endif
|
||||
addr += size;
|
||||
if (param_index < fastcall_nb_regs) {
|
||||
/* save FASTCALL register */
|
||||
loc -= 4;
|
||||
o(0x89); /* movl */
|
||||
gen_modrm(fastcall_regs[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 ? */
|
||||
if (func_call == FUNC_STDCALL)
|
||||
func_ret_sub = addr - 8;
|
||||
o(0xe58955); /* push %ebp, mov %esp, %ebp */
|
||||
func_sub_sp_offset = oad(0xec81, 0); /* sub $xxx, %esp */
|
||||
|
||||
/* leave some room for bound checking code */
|
||||
if (do_bounds_check) {
|
||||
oad(0xb8, 0); /* lbound section pointer */
|
||||
|
||||
19
libtcc.h
19
libtcc.h
@@ -1,6 +1,10 @@
|
||||
#ifndef LIBTCC_H
|
||||
#define LIBTCC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct TCCState;
|
||||
|
||||
typedef struct TCCState TCCState;
|
||||
@@ -18,6 +22,9 @@ void tcc_enable_debug(TCCState *s);
|
||||
void tcc_set_error_func(TCCState *s, void *error_opaque,
|
||||
void (*error_func)(void *opaque, const char *msg));
|
||||
|
||||
/* set/reset a warning */
|
||||
int tcc_set_warning(TCCState *s, const char *warning_name, int value);
|
||||
|
||||
/*****************************/
|
||||
/* preprocessor */
|
||||
|
||||
@@ -55,6 +62,10 @@ int tcc_compile_string(TCCState *s, const char *buf);
|
||||
#define TCC_OUTPUT_OBJ 3 /* object file */
|
||||
int tcc_set_output_type(TCCState *s, int output_type);
|
||||
|
||||
#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 */
|
||||
|
||||
/* equivalent to -Lpath option */
|
||||
int tcc_add_library_path(TCCState *s, const char *pathname);
|
||||
|
||||
@@ -76,7 +87,11 @@ int tcc_run(TCCState *s, int argc, char **argv);
|
||||
non zero if link error. */
|
||||
int tcc_relocate(TCCState *s);
|
||||
|
||||
/* return symbol value or error */
|
||||
void *tcc_get_symbol(TCCState *s, const char *name);
|
||||
/* return symbol value. return 0 if OK, -1 if symbol not found */
|
||||
int tcc_get_symbol(TCCState *s, unsigned long *pval, const char *name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
39
libtcc1.c
39
libtcc1.c
@@ -421,19 +421,58 @@ unsigned long long __umoddi3(unsigned long long u, unsigned long long v)
|
||||
/* XXX: fix tcc's code generator to do this instead */
|
||||
long long __sardi3(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 __shrdi3(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 __shldi3(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) | (u.s.low >> (32 - b));
|
||||
u.s.low = (unsigned)u.s.low << b;
|
||||
}
|
||||
return u.ll;
|
||||
#else
|
||||
return a << b;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__i386__)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <libtcc.h>
|
||||
#include "libtcc.h"
|
||||
|
||||
/* this function is called by the generated code */
|
||||
int add(int a, int b)
|
||||
@@ -35,7 +35,8 @@ int main(int argc, char **argv)
|
||||
{
|
||||
TCCState *s;
|
||||
int (*func)(int);
|
||||
|
||||
unsigned long val;
|
||||
|
||||
s = tcc_new();
|
||||
if (!s) {
|
||||
fprintf(stderr, "Could not create tcc state\n");
|
||||
@@ -54,8 +55,9 @@ int main(int argc, char **argv)
|
||||
|
||||
tcc_relocate(s);
|
||||
|
||||
func = tcc_get_symbol(s, "foo");
|
||||
|
||||
tcc_get_symbol(s, &val, "foo");
|
||||
func = (void *)val;
|
||||
|
||||
func(32);
|
||||
|
||||
tcc_delete(s);
|
||||
|
||||
2
stddef.h
2
stddef.h
@@ -10,7 +10,7 @@ typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
||||
/* need to do that because of glibc 2.1 bug (should have a way to test
|
||||
presence of 'long long' without __GNUC__, or TCC should define
|
||||
__GNUC__ ? */
|
||||
#ifndef __int8_t_defined
|
||||
#if !defined(__int8_t_defined) && !defined(__dietlibc__)
|
||||
#define __int8_t_defined
|
||||
typedef char int8_t;
|
||||
typedef short int int16_t;
|
||||
|
||||
162
tcc-doc.texi
162
tcc-doc.texi
@@ -58,6 +58,11 @@ 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. 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}.
|
||||
|
||||
@node Invoke
|
||||
@chapter Command line invocation
|
||||
|
||||
@@ -66,12 +71,13 @@ generation (@pxref{Libtcc}).
|
||||
@section Quick start
|
||||
|
||||
@example
|
||||
usage: tcc [-v] [-c] [-o outfile] [-Bdir] [-bench] [-Idir] [-Dsym[=val]] [-Usym]
|
||||
[-g] [-b] [-bt N] [-Ldir] [-llib] [-shared] [-static]
|
||||
[infile1 infile2...] [-run infile args...]
|
||||
@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.
|
||||
@@ -120,7 +126,7 @@ 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
|
||||
#!/usr/local/bin/tcc -run
|
||||
#include <stdio.h>
|
||||
|
||||
int main()
|
||||
@@ -129,11 +135,13 @@ int main()
|
||||
return 0;
|
||||
@}
|
||||
@end example
|
||||
@c man end
|
||||
|
||||
@section Option summary
|
||||
|
||||
General Options:
|
||||
|
||||
@c man begin OPTIONS
|
||||
@table @option
|
||||
@item -v
|
||||
Display current TCC version.
|
||||
@@ -151,8 +159,28 @@ Set the path where the tcc internal libraries can be found (default is
|
||||
@item -bench
|
||||
Output compilation statistics.
|
||||
|
||||
@item -run
|
||||
Run compiled source.
|
||||
@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:
|
||||
|
||||
@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
|
||||
#include <stdlib.h>
|
||||
int main(int argc, char **argv)
|
||||
@{
|
||||
...
|
||||
@}
|
||||
@end example
|
||||
|
||||
@end table
|
||||
|
||||
Preprocessor options:
|
||||
@@ -176,6 +204,54 @@ also be defined: @option{-DF(a)=a+1}
|
||||
Undefine preprocessor symbol @samp{sym}.
|
||||
@end table
|
||||
|
||||
Compilation flags:
|
||||
|
||||
Note: each of the following warning 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.
|
||||
|
||||
@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 warnings are issued.
|
||||
|
||||
@item -Wall
|
||||
Activate all warnings, except @option{-Werror}, @option{-Wunusupported} and
|
||||
@option{-Wwrite-strings}.
|
||||
|
||||
@end table
|
||||
|
||||
Linker options:
|
||||
|
||||
@table @option
|
||||
@@ -196,10 +272,28 @@ must also be given).
|
||||
Generate a statically linked executable (default is a shared linked
|
||||
executable) (@option{-o} option must also be given).
|
||||
|
||||
@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 (@option{-o} option must
|
||||
also be given).
|
||||
|
||||
@item -Wl,-Ttext,address
|
||||
Set the start of the .text section to @var{address}.
|
||||
|
||||
@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
|
||||
|
||||
@end table
|
||||
|
||||
Debugger options:
|
||||
@@ -222,8 +316,24 @@ Display N callers in stack traces. This is useful with @option{-g} or
|
||||
|
||||
@end table
|
||||
|
||||
Note: GCC options @option{-Ox}, @option{-Wx}, @option{-fx} and @option{-mx} are
|
||||
Note: GCC options @option{-Ox}, @option{-fx} and @option{-mx} are
|
||||
ignored.
|
||||
@c man end
|
||||
|
||||
@ignore
|
||||
|
||||
@setfilename tcc
|
||||
@settitle Tiny C Compiler
|
||||
|
||||
@c man begin SEEALSO
|
||||
gcc(1)
|
||||
@c man end
|
||||
|
||||
@c man begin AUTHOR
|
||||
Fabrice Bellard
|
||||
@c man end
|
||||
|
||||
@end ignore
|
||||
|
||||
@chapter C language support
|
||||
|
||||
@@ -413,6 +523,9 @@ 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.
|
||||
|
||||
@end itemize
|
||||
|
||||
@section TinyCC extensions
|
||||
@@ -510,6 +623,13 @@ They can be defined several times in the same source. Use 'b'
|
||||
@cindex .short
|
||||
@cindex .int
|
||||
@cindex .long
|
||||
@cindex .string
|
||||
@cindex .globl
|
||||
@cindex .global
|
||||
@cindex .section
|
||||
@cindex .text
|
||||
@cindex .data
|
||||
@cindex .bss
|
||||
|
||||
All directives are preceeded by a '.'. The following directives are
|
||||
supported:
|
||||
@@ -523,6 +643,19 @@ supported:
|
||||
@item .short value1[,value2...]
|
||||
@item .int value1[,value2...]
|
||||
@item .long value1[,value2...]
|
||||
@item .string string
|
||||
@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
|
||||
@@ -545,13 +678,13 @@ 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 librairy
|
||||
position independent code (PIC). It means that the dynamic library
|
||||
code generated by TCC cannot be factorized among processes yet.
|
||||
|
||||
TCC linker cannot currently eliminate unused object code. But TCC
|
||||
will soon integrate a novel feature not found in GNU tools: unused code
|
||||
will be eliminated at the function or variable level, provided you only
|
||||
use TCC to compile your files.
|
||||
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
|
||||
|
||||
@@ -563,12 +696,15 @@ libraries (.so).
|
||||
@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.
|
||||
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
|
||||
|
||||
136
tcc.1
136
tcc.1
@@ -1,136 +0,0 @@
|
||||
.TH TCC 1 "2002 Feb 6" TCC
|
||||
.SH NAME
|
||||
tcc \- tiny C compiler - the smallest ANSI C compiler
|
||||
.SH SYNOPSIS
|
||||
.B tcc
|
||||
[-\fBI\fP\fIdir\fP]
|
||||
[-\fBD\fP\fImacro\fP[=\fIdefn\fP]]
|
||||
[-\fBU\fP\fIsym\fP]
|
||||
[-\fBl\fP\fIlib\fP]
|
||||
[-\fBg\fP]
|
||||
[-\fBb\fP]
|
||||
[-\fBi\fP\fI<file>\fP]
|
||||
<file>
|
||||
[infile_args...]
|
||||
.SH DESCRIPTION
|
||||
|
||||
\fItcc\fP (tiny C compiler) is small, fast, unlimited, and safe. You
|
||||
can compile and execute C code everywhere (e.g., on rescue disks). It
|
||||
generates optimized x86 code, and can compile, assemble, and link
|
||||
several times faster than 'gcc -O0'. Any C dynamic library can be
|
||||
used directly. It includes an optional memory and bounds checker, and
|
||||
bounds-checked code can be mixed freely with standard code. C script
|
||||
is also supported--just add '#!/usr/bin/tcc' at the first line of your
|
||||
C source, and execute it directly from the command line.
|
||||
|
||||
.TP
|
||||
.BI "\-I" "dir"
|
||||
Append directory \c
|
||||
.I dir\c
|
||||
\& to the list of directories searched for include files.
|
||||
.TP
|
||||
.BI \-D macro
|
||||
Define macro \c
|
||||
.I macro\c
|
||||
\& with the string `\|\c
|
||||
.B 1\c
|
||||
\&\|' as its definition.
|
||||
.TP
|
||||
.BI \-D macro = defn
|
||||
Define macro \c
|
||||
.I macro\c
|
||||
\& as \c
|
||||
.I defn\c
|
||||
\&. All instances of `\|\c
|
||||
.B \-D\c
|
||||
\&\|' on
|
||||
the command line are processed before any `\|\c
|
||||
.B \-U\c
|
||||
\&\|' options.
|
||||
.TP
|
||||
.BI \-U macro
|
||||
Undefine macro \c
|
||||
.I macro\c
|
||||
\&. `\|\c
|
||||
.B \-U\c
|
||||
\&\|' options are evaluated after all `\|\c
|
||||
.B \-D\c
|
||||
\&\|' options, but before any `\|\c
|
||||
.B \-include\c
|
||||
\&\|' and `\|\c
|
||||
.B \-imacros\c
|
||||
\&\|' options.
|
||||
.TP
|
||||
.BI \-l library
|
||||
Use the library named \c
|
||||
.I library\c
|
||||
\& when linking.
|
||||
|
||||
|
||||
.TP
|
||||
\fB\-l\fRlib
|
||||
link with dynamic library 'lib'
|
||||
.TP
|
||||
\fB\-g\f
|
||||
generate runtime debug info
|
||||
.TP
|
||||
\fB\-b\f
|
||||
compile with built-in memory and bounds checker (implies -g)
|
||||
.TP
|
||||
\fB\-i\fR <file>
|
||||
compile <file>
|
||||
.SH SEE ALSO
|
||||
\fIgcc\fP(1)
|
||||
.SH PROBLEMS AND BUGS
|
||||
We haven't found any bugs yet. Perhaps there are bugs but it's
|
||||
unlikely.
|
||||
|
||||
If you have problems with `tcc' or think you've found a
|
||||
bug, please report it to the developers; we cannot promise to do
|
||||
anything but we might well want to fix it.
|
||||
|
||||
Before reporting a bug, make sure you've actually found a real bug.
|
||||
Carefully reread the documentation and see if it really says you can
|
||||
do what you're trying to do. If it's not clear whether you should be
|
||||
able to do something or not, report that too; it's a bug in the
|
||||
documentation!
|
||||
|
||||
Before reporting a bug or trying to fix it yourself, try to isolate it
|
||||
to the smallest possible conditions that reproduces the problem. Then
|
||||
send us the description and the exact results `tcc' gave
|
||||
you. Also say what you expected to occur; this will help us decide
|
||||
whether the problem was really in the documentation.
|
||||
|
||||
Once you've got a precise problem, please send electronic mail to:
|
||||
|
||||
Fabrice Bellard <fabrice.bellard@free.fr>
|
||||
|
||||
Please include the version number of `tcc' you are using.
|
||||
Be sure also to include the type of machine and operating system you
|
||||
are using.
|
||||
.SH COPYRIGHT
|
||||
\fItcc\fP is Copyright \(co 2001, 2002 by Fabrice Bellard
|
||||
.PP
|
||||
Permission is granted to make and distribute verbatim copies of
|
||||
this manual page provided the copyright notice and this permission
|
||||
notice are preserved on all copies.
|
||||
.ig
|
||||
Permission is granted to process this file through troff and print the
|
||||
results, provided the printed document carries copying permission
|
||||
notice identical to this one except for the removal of this paragraph
|
||||
(this paragraph not being relevant to the printed manual page).
|
||||
..
|
||||
.PP
|
||||
Permission is granted to copy and distribute modified versions of this
|
||||
manual page under the conditions for verbatim copying, provided that
|
||||
the entire resulting derived work is distributed under the terms of a
|
||||
permission notice identical to this one.
|
||||
.PP
|
||||
Permission is granted to copy and distribute translations of this
|
||||
manual page into another language, under the above conditions for
|
||||
modified versions, except that this permission notice may be stated in
|
||||
a translation approved by the Foundation.
|
||||
.SH AUTHORS
|
||||
This program was written by Fabrice Bellard <fabrice.bellard@free.fr>.
|
||||
It may be freely distributed under the terms of the GNU General Public
|
||||
License. There is ABSOLUTELY NO WARRANTY for this program.
|
||||
368
tccasm.c
368
tccasm.c
@@ -1,21 +1,21 @@
|
||||
/*
|
||||
* GAS like assembler for TCC
|
||||
*
|
||||
* Copyright (c) 2001, 2002 Fabrice Bellard
|
||||
* Copyright (c) 2001-2004 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 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 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.
|
||||
* 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 General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* 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
|
||||
*/
|
||||
|
||||
static int asm_get_local_label_name(TCCState *s1, unsigned int n)
|
||||
@@ -28,6 +28,8 @@ static int asm_get_local_label_name(TCCState *s1, unsigned int n)
|
||||
return ts->tok;
|
||||
}
|
||||
|
||||
static void asm_expr(TCCState *s1, ExprValue *pe);
|
||||
|
||||
/* We do not use the C expression parser to handle symbols. Maybe the
|
||||
C expression parser could be tweaked to do so. */
|
||||
|
||||
@@ -40,7 +42,7 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
|
||||
switch(tok) {
|
||||
case TOK_PPNUM:
|
||||
p = tokc.cstr->data;
|
||||
n = strtol(p, (char **)&p, 0);
|
||||
n = strtoul(p, (char **)&p, 0);
|
||||
if (*p == 'b' || *p == 'f') {
|
||||
/* backward or forward label */
|
||||
label = asm_get_local_label_name(s1, n);
|
||||
@@ -85,6 +87,17 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
|
||||
else
|
||||
pe->v = ~pe->v;
|
||||
break;
|
||||
case TOK_CCHAR:
|
||||
case TOK_LCHAR:
|
||||
pe->v = tokc.i;
|
||||
pe->sym = NULL;
|
||||
next();
|
||||
break;
|
||||
case '(':
|
||||
next();
|
||||
asm_expr(s1, pe);
|
||||
skip(')');
|
||||
break;
|
||||
default:
|
||||
if (tok >= TOK_IDENT) {
|
||||
/* label case : if the label was not found, add one */
|
||||
@@ -94,8 +107,14 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
|
||||
/* NOTE: by default, the symbol is global */
|
||||
sym->type.t = VT_VOID;
|
||||
}
|
||||
pe->v = 0;
|
||||
pe->sym = sym;
|
||||
if (sym->r == SHN_ABS) {
|
||||
/* if absolute symbol, no need to put a symbol value */
|
||||
pe->v = (long)sym->next;
|
||||
pe->sym = NULL;
|
||||
} else {
|
||||
pe->v = 0;
|
||||
pe->sym = sym;
|
||||
}
|
||||
next();
|
||||
} else {
|
||||
error("bad expression syntax [%s]", get_tok_str(tok, &tokc));
|
||||
@@ -235,7 +254,8 @@ static int asm_int_expr(TCCState *s1)
|
||||
|
||||
/* NOTE: the same name space as C labels is used to avoid using too
|
||||
much memory when storing labels in TokenStrings */
|
||||
static void asm_new_label(TCCState *s1, int label, int is_local)
|
||||
static void asm_new_label1(TCCState *s1, int label, int is_local,
|
||||
int sh_num, int value)
|
||||
{
|
||||
Sym *sym;
|
||||
|
||||
@@ -256,26 +276,51 @@ static void asm_new_label(TCCState *s1, int label, int is_local)
|
||||
sym = label_push(&s1->asm_labels, label, 0);
|
||||
sym->type.t = VT_STATIC | VT_VOID;
|
||||
}
|
||||
sym->r = cur_text_section->sh_num;
|
||||
sym->next = (void *)ind;
|
||||
sym->r = sh_num;
|
||||
sym->next = (void *)value;
|
||||
}
|
||||
|
||||
static void asm_new_label(TCCState *s1, int label, int is_local)
|
||||
{
|
||||
asm_new_label1(s1, label, is_local, cur_text_section->sh_num, ind);
|
||||
}
|
||||
|
||||
static void asm_free_labels(TCCState *st)
|
||||
{
|
||||
Sym *s, *s1;
|
||||
Section *sec;
|
||||
|
||||
for(s = st->asm_labels; s != NULL; s = s1) {
|
||||
s1 = s->prev;
|
||||
/* define symbol value in object file */
|
||||
if (s->r) {
|
||||
put_extern_sym(s, st->sections[s->r], (long)s->next, 0);
|
||||
if (s->r == SHN_ABS)
|
||||
sec = SECTION_ABS;
|
||||
else
|
||||
sec = st->sections[s->r];
|
||||
put_extern_sym(s, sec, (long)s->next, 0);
|
||||
}
|
||||
/* remove label */
|
||||
table_ident[s->v - TOK_IDENT]->sym_label = NULL;
|
||||
tcc_free(s);
|
||||
sym_free(s);
|
||||
}
|
||||
st->asm_labels = NULL;
|
||||
}
|
||||
|
||||
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 asm_parse_directive(TCCState *s1)
|
||||
{
|
||||
int n, offset, v, size, tok1;
|
||||
@@ -297,6 +342,9 @@ static void asm_parse_directive(TCCState *s1)
|
||||
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 {
|
||||
size = n;
|
||||
}
|
||||
@@ -305,6 +353,7 @@ static void asm_parse_directive(TCCState *s1)
|
||||
next();
|
||||
v = asm_int_expr(s1);
|
||||
}
|
||||
zero_pad:
|
||||
if (sec->sh_type != SHT_NOBITS) {
|
||||
sec->data_offset = ind;
|
||||
ptr = section_ptr_add(sec, size);
|
||||
@@ -312,6 +361,33 @@ static void asm_parse_directive(TCCState *s1)
|
||||
}
|
||||
ind += size;
|
||||
break;
|
||||
case TOK_ASM_quad:
|
||||
next();
|
||||
for(;;) {
|
||||
uint64_t vl;
|
||||
const char *p;
|
||||
|
||||
p = tokc.cstr->data;
|
||||
if (tok != TOK_PPNUM) {
|
||||
error_constant:
|
||||
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;
|
||||
case TOK_ASM_byte:
|
||||
size = 1;
|
||||
goto asm_data;
|
||||
@@ -346,8 +422,157 @@ static void asm_parse_directive(TCCState *s1)
|
||||
next();
|
||||
}
|
||||
break;
|
||||
case TOK_ASM_fill:
|
||||
{
|
||||
int repeat, size, val, i, j;
|
||||
uint8_t repeat_buf[8];
|
||||
next();
|
||||
repeat = asm_int_expr(s1);
|
||||
if (repeat < 0) {
|
||||
error("repeat < 0; .fill ignored");
|
||||
break;
|
||||
}
|
||||
size = 1;
|
||||
val = 0;
|
||||
if (tok == ',') {
|
||||
next();
|
||||
size = asm_int_expr(s1);
|
||||
if (size < 0) {
|
||||
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_ASM_org:
|
||||
{
|
||||
unsigned long n;
|
||||
next();
|
||||
/* XXX: handle section symbols too */
|
||||
n = asm_int_expr(s1);
|
||||
if (n < ind)
|
||||
error("attempt to .org backwards");
|
||||
v = 0;
|
||||
size = n - ind;
|
||||
goto zero_pad;
|
||||
}
|
||||
break;
|
||||
case TOK_ASM_globl:
|
||||
case TOK_ASM_global:
|
||||
{
|
||||
Sym *sym;
|
||||
|
||||
next();
|
||||
sym = label_find(tok);
|
||||
if (!sym) {
|
||||
sym = label_push(&s1->asm_labels, tok, 0);
|
||||
sym->type.t = VT_VOID;
|
||||
}
|
||||
sym->type.t &= ~VT_STATIC;
|
||||
next();
|
||||
}
|
||||
break;
|
||||
case TOK_ASM_string:
|
||||
case TOK_ASM_ascii:
|
||||
case TOK_ASM_asciz:
|
||||
{
|
||||
const uint8_t *p;
|
||||
int i, size, t;
|
||||
|
||||
t = tok;
|
||||
next();
|
||||
for(;;) {
|
||||
if (tok != TOK_STR)
|
||||
expect("string constant");
|
||||
p = tokc.cstr->data;
|
||||
size = tokc.cstr->size;
|
||||
if (t == TOK_ASM_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_ASM_text:
|
||||
case TOK_ASM_data:
|
||||
case TOK_ASM_bss:
|
||||
{
|
||||
char sname[64];
|
||||
tok1 = tok;
|
||||
n = 0;
|
||||
next();
|
||||
if (tok != ';' && tok != TOK_LINEFEED) {
|
||||
n = asm_int_expr(s1);
|
||||
next();
|
||||
}
|
||||
sprintf(sname, (n?".%s%d":".%s"), get_tok_str(tok1, NULL), n);
|
||||
use_section(s1, sname);
|
||||
}
|
||||
break;
|
||||
case TOK_SECTION1:
|
||||
{
|
||||
char sname[256];
|
||||
|
||||
/* XXX: support more options */
|
||||
next();
|
||||
sname[0] = '\0';
|
||||
while (tok != ';' && tok != TOK_LINEFEED && tok != ',') {
|
||||
if (tok == TOK_STR)
|
||||
pstrcat(sname, sizeof(sname), tokc.cstr->data);
|
||||
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();
|
||||
}
|
||||
last_text_section = cur_text_section;
|
||||
use_section(s1, sname);
|
||||
}
|
||||
break;
|
||||
case TOK_ASM_previous:
|
||||
{
|
||||
Section *sec;
|
||||
next();
|
||||
if (!last_text_section)
|
||||
error("no previous section referenced");
|
||||
sec = cur_text_section;
|
||||
use_section1(s1, last_text_section);
|
||||
last_text_section = sec;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error("unknown assembler directive .%s", get_tok_str(tok, NULL));
|
||||
error("unknown assembler directive '.%s'", get_tok_str(tok, NULL));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -394,7 +619,7 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
|
||||
|
||||
ch = file->buf_ptr[0];
|
||||
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
|
||||
parse_flags = 0;
|
||||
parse_flags = PARSE_FLAG_ASM_COMMENTS;
|
||||
if (do_preprocess)
|
||||
parse_flags |= PARSE_FLAG_PREPROCESS;
|
||||
next();
|
||||
@@ -413,7 +638,7 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
|
||||
const char *p;
|
||||
int n;
|
||||
p = tokc.cstr->data;
|
||||
n = strtol(p, (char **)&p, 10);
|
||||
n = strtoul(p, (char **)&p, 10);
|
||||
if (*p != '\0')
|
||||
expect("':'");
|
||||
/* new local label */
|
||||
@@ -430,6 +655,12 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
|
||||
asm_new_label(s1, opcode, 0);
|
||||
next();
|
||||
goto redo;
|
||||
} else if (tok == '=') {
|
||||
int n;
|
||||
next();
|
||||
n = asm_int_expr(s1);
|
||||
asm_new_label1(s1, opcode, 0, SHN_ABS, n);
|
||||
goto redo;
|
||||
} else {
|
||||
asm_opcode(s1, opcode);
|
||||
}
|
||||
@@ -450,6 +681,7 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
|
||||
/* Assemble the current file */
|
||||
static int tcc_assemble(TCCState *s1, int do_preprocess)
|
||||
{
|
||||
Sym *define_start;
|
||||
int ret;
|
||||
|
||||
preprocess_init(s1);
|
||||
@@ -458,9 +690,14 @@ static int tcc_assemble(TCCState *s1, int do_preprocess)
|
||||
cur_text_section = text_section;
|
||||
ind = cur_text_section->data_offset;
|
||||
|
||||
define_start = define_stack;
|
||||
|
||||
ret = tcc_assemble_internal(s1, do_preprocess);
|
||||
|
||||
cur_text_section->data_offset = ind;
|
||||
|
||||
free_defines(define_start);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -614,12 +851,14 @@ static void parse_asm_operands(ASMOperand *operands, int *nb_operands_ptr,
|
||||
if (is_output) {
|
||||
test_lvalue();
|
||||
} else {
|
||||
/* we want to avoid LLOCAL case. note that it may come
|
||||
from register storage, so we need to convert (reg)
|
||||
/* 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)) {
|
||||
(vtop->r & VT_VALMASK) < VT_CONST) &&
|
||||
!strchr(op->constraint, 'm')) {
|
||||
gv(RC_INT);
|
||||
}
|
||||
}
|
||||
@@ -635,14 +874,27 @@ static void parse_asm_operands(ASMOperand *operands, int *nb_operands_ptr,
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_asm_str(CString *astr)
|
||||
{
|
||||
skip('(');
|
||||
/* read the string */
|
||||
if (tok != TOK_STR)
|
||||
expect("string constant");
|
||||
cstr_new(astr);
|
||||
while (tok == TOK_STR) {
|
||||
/* XXX: add \0 handling too ? */
|
||||
cstr_cat(astr, tokc.cstr->data);
|
||||
next();
|
||||
}
|
||||
cstr_ccat(astr, '\0');
|
||||
}
|
||||
|
||||
/* parse the GCC asm() instruction */
|
||||
static void asm_instr(void)
|
||||
{
|
||||
CString astr, astr1;
|
||||
ASMOperand operands[MAX_ASM_OPERANDS];
|
||||
int nb_inputs, nb_outputs, nb_operands, i;
|
||||
uint8_t input_regs_allocated[NB_ASM_REGS];
|
||||
uint8_t output_regs_allocated[NB_ASM_REGS];
|
||||
int nb_inputs, nb_outputs, nb_operands, i, must_subst, out_reg;
|
||||
uint8_t clobber_regs[NB_ASM_REGS];
|
||||
|
||||
next();
|
||||
@@ -651,22 +903,14 @@ static void asm_instr(void)
|
||||
if (tok == TOK_VOLATILE1 || tok == TOK_VOLATILE2 || tok == TOK_VOLATILE3) {
|
||||
next();
|
||||
}
|
||||
skip('(');
|
||||
/* read the string */
|
||||
if (tok != TOK_STR)
|
||||
expect("string constant");
|
||||
cstr_new(&astr);
|
||||
while (tok == TOK_STR) {
|
||||
/* XXX: add \0 handling too ? */
|
||||
cstr_cat(&astr, tokc.cstr->data);
|
||||
next();
|
||||
}
|
||||
cstr_ccat(&astr, '\0');
|
||||
parse_asm_str(&astr);
|
||||
nb_operands = 0;
|
||||
nb_outputs = 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;
|
||||
@@ -703,19 +947,15 @@ static void asm_instr(void)
|
||||
save_regs(0);
|
||||
|
||||
/* compute constraints */
|
||||
asm_compute_constraints(input_regs_allocated,
|
||||
operands, nb_operands, nb_outputs, 0,
|
||||
NULL);
|
||||
asm_compute_constraints(output_regs_allocated,
|
||||
operands, nb_operands, nb_outputs, 1,
|
||||
input_regs_allocated);
|
||||
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 (nb_operands > 0) {
|
||||
if (must_subst) {
|
||||
subst_asm_operands(operands, nb_operands, nb_outputs, &astr1, &astr);
|
||||
cstr_free(&astr);
|
||||
} else {
|
||||
@@ -726,7 +966,8 @@ static void asm_instr(void)
|
||||
#endif
|
||||
|
||||
/* generate loads */
|
||||
asm_gen_code(operands, nb_operands, nb_outputs, 0, clobber_regs);
|
||||
asm_gen_code(operands, nb_operands, nb_outputs, 0,
|
||||
clobber_regs, out_reg);
|
||||
|
||||
/* assemble the string with tcc internal assembler */
|
||||
tcc_assemble_inline(tcc_state, astr1.data, astr1.size - 1);
|
||||
@@ -735,7 +976,8 @@ static void asm_instr(void)
|
||||
next();
|
||||
|
||||
/* store the output values if needed */
|
||||
asm_gen_code(operands, nb_operands, nb_outputs, 1, clobber_regs);
|
||||
asm_gen_code(operands, nb_operands, nb_outputs, 1,
|
||||
clobber_regs, out_reg);
|
||||
|
||||
/* free everything */
|
||||
for(i=0;i<nb_operands;i++) {
|
||||
@@ -747,3 +989,31 @@ static void asm_instr(void)
|
||||
cstr_free(&astr1);
|
||||
}
|
||||
|
||||
static void asm_global_instr(void)
|
||||
{
|
||||
CString astr;
|
||||
|
||||
next();
|
||||
parse_asm_str(&astr);
|
||||
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);
|
||||
|
||||
cur_text_section->data_offset = ind;
|
||||
|
||||
/* restore the current C token */
|
||||
next();
|
||||
|
||||
cstr_free(&astr);
|
||||
}
|
||||
|
||||
967
tcccoff.c
Normal file
967
tcccoff.c
Normal file
@@ -0,0 +1,967 @@
|
||||
/*
|
||||
* 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 "coff.h"
|
||||
|
||||
#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];
|
||||
|
||||
BOOL OutputTheSection(Section * sect);
|
||||
short int GetCoffFlags(const char *s);
|
||||
void SortSymbolTable(void);
|
||||
Section *FindSection(TCCState * s1, const char *sname);
|
||||
|
||||
int C67_main_entry_point;
|
||||
|
||||
int FindCoffSymbolIndex(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;
|
||||
|
||||
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;
|
||||
|
||||
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("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 (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 (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 (do_debug)
|
||||
SortSymbolTable();
|
||||
|
||||
// write line no data
|
||||
|
||||
for (i = 1; i < s1->nb_sections; i++) {
|
||||
coff_sec = §ion_header[i];
|
||||
tcc_sect = s1->sections[i];
|
||||
|
||||
if (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(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 (do_debug) {
|
||||
int k;
|
||||
struct syment csym;
|
||||
AUXFUNC auxfunc;
|
||||
AUXBF auxbf;
|
||||
AUXEF auxef;
|
||||
int i;
|
||||
Elf32_Sym *p;
|
||||
char *name;
|
||||
char _name[MAX_FUNCS];
|
||||
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++) {
|
||||
|
||||
/* don't add underscores for Code Composer Version 2.xx */
|
||||
|
||||
#define ADD_UNDERSCORE 0
|
||||
|
||||
name = (char *) symtab_section->link->data + p->st_name;
|
||||
|
||||
#if ADD_UNDERSCORE
|
||||
_name[0] = '_';
|
||||
strcpy(_name + 1, name);
|
||||
#else
|
||||
strcpy(_name, name);
|
||||
#endif
|
||||
|
||||
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)
|
||||
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) {
|
||||
char s[256];
|
||||
|
||||
sprintf(s, "debug info can't find function: %s", name);
|
||||
|
||||
error(s);
|
||||
}
|
||||
// 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 (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(void)
|
||||
{
|
||||
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) {
|
||||
char s[256];
|
||||
|
||||
sprintf(s,
|
||||
"debug (sort) info can't find function: %s",
|
||||
name2);
|
||||
|
||||
error(s);
|
||||
}
|
||||
|
||||
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)
|
||||
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(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
|
||||
}
|
||||
|
||||
BOOL OutputTheSection(Section * sect)
|
||||
{
|
||||
const char *s = sect->name;
|
||||
|
||||
if (!strcmp(s, ".text"))
|
||||
return true;
|
||||
else if (!strcmp(s, ".data"))
|
||||
return true;
|
||||
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;
|
||||
}
|
||||
|
||||
error("could not find section %s", sname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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) {
|
||||
error("Unable to open .out file for input");
|
||||
}
|
||||
|
||||
if (fread(&file_hdr, FILHSZ, 1, f) != 1)
|
||||
error("error reading .out file for input");
|
||||
|
||||
if (fread(&o_filehdr, sizeof(o_filehdr), 1, f) != 1)
|
||||
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))
|
||||
error("error reading .out file for input");
|
||||
|
||||
if (fread(&str_size, sizeof(int), 1, f) != 1)
|
||||
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)
|
||||
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))
|
||||
error("error reading .out file for input");
|
||||
|
||||
for (i = 0; i < file_hdr.f_nsyms; i++) {
|
||||
if (fread(&csym, SYMESZ, 1, f) != 1)
|
||||
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, csym.n_value);
|
||||
}
|
||||
// skip any aux records
|
||||
|
||||
if (csym.n_numaux == 1) {
|
||||
if (fread(&csym, SYMESZ, 1, f) != 1)
|
||||
error("error reading .out file for input");
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
655
tccelf.c
655
tccelf.c
@@ -1,21 +1,21 @@
|
||||
/*
|
||||
* ELF file handling for TCC
|
||||
*
|
||||
* Copyright (c) 2001, 2002 Fabrice Bellard
|
||||
* Copyright (c) 2001-2004 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 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 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.
|
||||
* 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 General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* 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
|
||||
*/
|
||||
|
||||
static int put_elf_str(Section *s, const char *sym)
|
||||
@@ -154,16 +154,25 @@ static int find_elf_sym(Section *s, const char *name)
|
||||
}
|
||||
|
||||
/* return elf symbol value or error */
|
||||
void *tcc_get_symbol(TCCState *s, const char *name)
|
||||
int tcc_get_symbol(TCCState *s, unsigned long *pval, const char *name)
|
||||
{
|
||||
int sym_index;
|
||||
Elf32_Sym *sym;
|
||||
|
||||
sym_index = find_elf_sym(symtab_section, name);
|
||||
if (!sym_index)
|
||||
error("%s not defined", name);
|
||||
return -1;
|
||||
sym = &((Elf32_Sym *)symtab_section->data)[sym_index];
|
||||
return (void *)sym->st_value;
|
||||
*pval = sym->st_value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *tcc_get_symbol_err(TCCState *s, const char *name)
|
||||
{
|
||||
unsigned long val;
|
||||
if (tcc_get_symbol(s, &val, name) < 0)
|
||||
error("%s not defined", name);
|
||||
return (void *)val;
|
||||
}
|
||||
|
||||
/* add an elf symbol : check if it is already defined and patch
|
||||
@@ -439,9 +448,12 @@ static void relocate_section(TCCState *s1, Section *s)
|
||||
Section *sr;
|
||||
Elf32_Rel *rel, *rel_end, *qrel;
|
||||
Elf32_Sym *sym;
|
||||
int type, sym_index, esym_index;
|
||||
int type, sym_index;
|
||||
unsigned char *ptr;
|
||||
unsigned long val, addr;
|
||||
#if defined(TCC_TARGET_I386)
|
||||
int esym_index;
|
||||
#endif
|
||||
|
||||
sr = s->reloc;
|
||||
rel_end = (Elf32_Rel *)(sr->data + sr->data_offset);
|
||||
@@ -459,6 +471,7 @@ static void relocate_section(TCCState *s1, Section *s)
|
||||
|
||||
/* CPU specific */
|
||||
switch(type) {
|
||||
#if defined(TCC_TARGET_I386)
|
||||
case R_386_32:
|
||||
if (s1->output_type == TCC_OUTPUT_DLL) {
|
||||
esym_index = s1->symtab_to_dynsym[sym_index];
|
||||
@@ -504,6 +517,69 @@ static void relocate_section(TCCState *s1, Section *s)
|
||||
/* we load the got offset */
|
||||
*(int *)ptr += s1->got_offsets[sym_index];
|
||||
break;
|
||||
#elif defined(TCC_TARGET_ARM)
|
||||
case R_ARM_PC24:
|
||||
case R_ARM_PLT32:
|
||||
{
|
||||
int x;
|
||||
x = (*(int *)ptr)&0xffffff;
|
||||
(*(int *)ptr) &= 0xff000000;
|
||||
if (x & 0x800000)
|
||||
x -= 0x1000000;
|
||||
x *= 4;
|
||||
x += val - addr;
|
||||
if((x & 3) != 0 || x >= 0x4000000 || x < -0x4000000)
|
||||
error("can't relocate value at %x",addr);
|
||||
x >>= 2;
|
||||
x &= 0xffffff;
|
||||
(*(int *)ptr) |= x;
|
||||
}
|
||||
break;
|
||||
case R_ARM_ABS32:
|
||||
*(int *)ptr += val;
|
||||
break;
|
||||
case R_ARM_GOTPC:
|
||||
*(int *)ptr += s1->got->sh_addr - addr;
|
||||
break;
|
||||
case R_ARM_GOT32:
|
||||
/* we load the got offset */
|
||||
*(int *)ptr += s1->got_offsets[sym_index];
|
||||
break;
|
||||
case R_ARM_COPY:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"FIXME: handle reloc type %x at %lx [%.8x] to %lx\n",
|
||||
type,addr,(unsigned int )ptr,val);
|
||||
break;
|
||||
#elif defined(TCC_TARGET_C67)
|
||||
case R_C60_32:
|
||||
*(int *)ptr += val;
|
||||
break;
|
||||
case R_C60LO16:
|
||||
{
|
||||
uint32_t orig;
|
||||
|
||||
/* put the low 16 bits of the absolute address */
|
||||
// add to what is already there
|
||||
|
||||
orig = ((*(int *)(ptr )) >> 7) & 0xffff;
|
||||
orig |= (((*(int *)(ptr+4)) >> 7) & 0xffff) << 16;
|
||||
|
||||
//patch both at once - assumes always in pairs Low - High
|
||||
|
||||
*(int *) ptr = (*(int *) ptr & (~(0xffff << 7)) ) | (((val+orig) & 0xffff) << 7);
|
||||
*(int *)(ptr+4) = (*(int *)(ptr+4) & (~(0xffff << 7)) ) | ((((val+orig)>>16) & 0xffff) << 7);
|
||||
}
|
||||
break;
|
||||
case R_C60HI16:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"FIXME: handle reloc type %x at %lx [%.8x] to %lx\n",
|
||||
type,addr,(unsigned int )ptr,val);
|
||||
break;
|
||||
#else
|
||||
#error unsupported processor
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/* if the relocation is allocated, we change its symbol table */
|
||||
@@ -589,10 +665,12 @@ static void put32(unsigned char *p, uint32_t val)
|
||||
p[3] = val >> 24;
|
||||
}
|
||||
|
||||
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_ARM)
|
||||
static uint32_t get32(unsigned char *p)
|
||||
{
|
||||
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void build_got(TCCState *s1)
|
||||
{
|
||||
@@ -637,6 +715,7 @@ static void put_got_entry(TCCState *s1,
|
||||
sym = &((Elf32_Sym *)symtab_section->data)[sym_index];
|
||||
name = symtab_section->link->data + sym->st_name;
|
||||
offset = sym->st_value;
|
||||
#ifdef TCC_TARGET_I386
|
||||
if (reloc_type == R_386_JMP_SLOT) {
|
||||
Section *plt;
|
||||
uint8_t *p;
|
||||
@@ -675,6 +754,42 @@ static void put_got_entry(TCCState *s1,
|
||||
if (s1->output_type == TCC_OUTPUT_EXE)
|
||||
offset = plt->data_offset - 16;
|
||||
}
|
||||
#elif defined(TCC_TARGET_ARM)
|
||||
if (reloc_type == R_ARM_JUMP_SLOT) {
|
||||
Section *plt;
|
||||
uint8_t *p;
|
||||
|
||||
/* if we build a DLL, we add a %ebx offset */
|
||||
if (s1->output_type == TCC_OUTPUT_DLL)
|
||||
error("DLLs unimplemented!");
|
||||
|
||||
/* add a PLT entry */
|
||||
plt = s1->plt;
|
||||
if (plt->data_offset == 0) {
|
||||
/* first plt entry */
|
||||
p = section_ptr_add(plt, 16);
|
||||
put32(p , 0xe52de004);
|
||||
put32(p + 4, 0xe59fe010);
|
||||
put32(p + 8, 0xe08fe00e);
|
||||
put32(p + 12, 0xe5bef008);
|
||||
}
|
||||
|
||||
p = section_ptr_add(plt, 16);
|
||||
put32(p , 0xe59fc004);
|
||||
put32(p+4, 0xe08fc00c);
|
||||
put32(p+8, 0xe59cf000);
|
||||
put32(p+12, s1->got->data_offset);
|
||||
|
||||
/* the symbol is modified so that it will be relocated to
|
||||
the PLT */
|
||||
if (s1->output_type == TCC_OUTPUT_EXE)
|
||||
offset = plt->data_offset - 16;
|
||||
}
|
||||
#elif defined(TCC_TARGET_C67)
|
||||
error("C67 got not implemented");
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
index = put_elf_sym(s1->dynsym, offset,
|
||||
size, info, 0, sym->st_shndx, name);
|
||||
/* put a got entry */
|
||||
@@ -708,6 +823,7 @@ static void build_got_entries(TCCState *s1)
|
||||
rel++) {
|
||||
type = ELF32_R_TYPE(rel->r_info);
|
||||
switch(type) {
|
||||
#if defined(TCC_TARGET_I386)
|
||||
case R_386_GOT32:
|
||||
case R_386_GOTOFF:
|
||||
case R_386_GOTPC:
|
||||
@@ -726,6 +842,47 @@ static void build_got_entries(TCCState *s1)
|
||||
sym_index);
|
||||
}
|
||||
break;
|
||||
#elif defined(TCC_TARGET_ARM)
|
||||
case R_ARM_GOT32:
|
||||
case R_ARM_GOTOFF:
|
||||
case R_ARM_GOTPC:
|
||||
case R_ARM_PLT32:
|
||||
if (!s1->got)
|
||||
build_got(s1);
|
||||
if (type == R_ARM_GOT32 || type == R_ARM_PLT32) {
|
||||
sym_index = ELF32_R_SYM(rel->r_info);
|
||||
sym = &((Elf32_Sym *)symtab_section->data)[sym_index];
|
||||
/* look at the symbol got offset. If none, then add one */
|
||||
if (type == R_ARM_GOT32)
|
||||
reloc_type = R_ARM_GLOB_DAT;
|
||||
else
|
||||
reloc_type = R_ARM_JUMP_SLOT;
|
||||
put_got_entry(s1, reloc_type, sym->st_size, sym->st_info,
|
||||
sym_index);
|
||||
}
|
||||
break;
|
||||
#elif defined(TCC_TARGET_C67)
|
||||
case R_C60_GOT32:
|
||||
case R_C60_GOTOFF:
|
||||
case R_C60_GOTPC:
|
||||
case R_C60_PLT32:
|
||||
if (!s1->got)
|
||||
build_got(s1);
|
||||
if (type == R_C60_GOT32 || type == R_C60_PLT32) {
|
||||
sym_index = ELF32_R_SYM(rel->r_info);
|
||||
sym = &((Elf32_Sym *)symtab_section->data)[sym_index];
|
||||
/* look at the symbol got offset. If none, then add one */
|
||||
if (type == R_C60_GOT32)
|
||||
reloc_type = R_C60_GLOB_DAT;
|
||||
else
|
||||
reloc_type = R_C60_JMP_SLOT;
|
||||
put_got_entry(s1, reloc_type, sym->st_size, sym->st_info,
|
||||
sym_index);
|
||||
}
|
||||
break;
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -771,15 +928,39 @@ static void put_dt(Section *dynamic, int dt, unsigned long val)
|
||||
dyn->d_un.d_val = val;
|
||||
}
|
||||
|
||||
static void add_init_array_defines(TCCState *s1, const char *section_name)
|
||||
{
|
||||
Section *s;
|
||||
long end_offset;
|
||||
char sym_start[1024];
|
||||
char sym_end[1024];
|
||||
|
||||
snprintf(sym_start, sizeof(sym_start), "__%s_start", section_name + 1);
|
||||
snprintf(sym_end, sizeof(sym_end), "__%s_end", section_name + 1);
|
||||
|
||||
s = find_section(s1, section_name);
|
||||
if (!s) {
|
||||
end_offset = 0;
|
||||
s = data_section;
|
||||
} else {
|
||||
end_offset = s->data_offset;
|
||||
}
|
||||
|
||||
add_elf_sym(symtab_section,
|
||||
0, 0,
|
||||
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE),
|
||||
s->sh_num, sym_start);
|
||||
add_elf_sym(symtab_section,
|
||||
end_offset, 0,
|
||||
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE),
|
||||
s->sh_num, sym_end);
|
||||
}
|
||||
|
||||
/* add tcc runtime libraries */
|
||||
static void tcc_add_runtime(TCCState *s1)
|
||||
{
|
||||
char buf[1024];
|
||||
int i;
|
||||
Section *s;
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s/%s", tcc_lib_path, "libtcc1.o");
|
||||
tcc_add_file(s1, buf);
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (do_bounds_check) {
|
||||
unsigned long *ptr;
|
||||
@@ -810,12 +991,28 @@ static void tcc_add_runtime(TCCState *s1)
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
/* add libc if not memory output */
|
||||
if (s1->output_type != TCC_OUTPUT_MEMORY) {
|
||||
/* add libc */
|
||||
if (!s1->nostdlib) {
|
||||
tcc_add_library(s1, "c");
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s/%s", tcc_lib_path, "libtcc1.a");
|
||||
tcc_add_file(s1, buf);
|
||||
}
|
||||
/* add crt end if not memory output */
|
||||
if (s1->output_type != TCC_OUTPUT_MEMORY && !s1->nostdlib) {
|
||||
tcc_add_file(s1, CONFIG_TCC_CRT_PREFIX "/crtn.o");
|
||||
}
|
||||
/* add various standard linker symbols */
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
add_elf_sym(symtab_section,
|
||||
text_section->data_offset, 0,
|
||||
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE),
|
||||
@@ -828,6 +1025,11 @@ static void tcc_add_runtime(TCCState *s1)
|
||||
bss_section->data_offset, 0,
|
||||
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE),
|
||||
bss_section->sh_num, "_end");
|
||||
/* 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++) {
|
||||
@@ -869,8 +1071,27 @@ static char elf_interp[] = "/usr/libexec/ld-elf.so.1";
|
||||
static char elf_interp[] = "/lib/ld-linux.so.2";
|
||||
#endif
|
||||
|
||||
#define ELF_START_ADDR 0x08048000
|
||||
#define ELF_PAGE_SIZE 0x1000
|
||||
static void tcc_output_binary(TCCState *s1, FILE *f,
|
||||
const int *section_order)
|
||||
{
|
||||
Section *s;
|
||||
int i, offset, size;
|
||||
|
||||
offset = 0;
|
||||
for(i=1;i<s1->nb_sections;i++) {
|
||||
s = s1->sections[section_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* output an ELF file */
|
||||
/* XXX: suppress unneeded sections */
|
||||
@@ -894,8 +1115,9 @@ int tcc_output_file(TCCState *s1, const char *filename)
|
||||
file_type = s1->output_type;
|
||||
s1->nb_errors = 0;
|
||||
|
||||
if (file_type != TCC_OUTPUT_OBJ)
|
||||
if (file_type != TCC_OUTPUT_OBJ) {
|
||||
tcc_add_runtime(s1);
|
||||
}
|
||||
|
||||
phdr = NULL;
|
||||
section_order = NULL;
|
||||
@@ -905,9 +1127,10 @@ int tcc_output_file(TCCState *s1, const char *filename)
|
||||
saved_dynamic_data_offset = 0; /* avoid warning */
|
||||
|
||||
if (file_type != TCC_OUTPUT_OBJ) {
|
||||
|
||||
relocate_common_syms();
|
||||
|
||||
tcc_add_linker_symbols(s1);
|
||||
|
||||
if (!s1->static_link) {
|
||||
const char *name;
|
||||
int sym_index, index;
|
||||
@@ -958,19 +1181,19 @@ int tcc_output_file(TCCState *s1, const char *filename)
|
||||
esym = &((Elf32_Sym *)s1->dynsymtab_section->data)[sym_index];
|
||||
type = ELF32_ST_TYPE(esym->st_info);
|
||||
if (type == STT_FUNC) {
|
||||
put_got_entry(s1, R_386_JMP_SLOT, esym->st_size,
|
||||
put_got_entry(s1, R_JMP_SLOT, esym->st_size,
|
||||
esym->st_info,
|
||||
sym - (Elf32_Sym *)symtab_section->data);
|
||||
} else if (type == STT_OBJECT) {
|
||||
unsigned long offset;
|
||||
offset = bss_section->data_offset;
|
||||
/* XXX: which alignment ? */
|
||||
offset = (offset + 8 - 1) & -8;
|
||||
offset = (offset + 16 - 1) & -16;
|
||||
index = put_elf_sym(s1->dynsym, offset, esym->st_size,
|
||||
esym->st_info, 0,
|
||||
bss_section->sh_num, name);
|
||||
put_elf_reloc(s1->dynsym, bss_section,
|
||||
offset, R_386_COPY, index);
|
||||
offset, R_COPY, index);
|
||||
offset += esym->st_size;
|
||||
bss_section->data_offset = offset;
|
||||
}
|
||||
@@ -984,6 +1207,14 @@ int tcc_output_file(TCCState *s1, const char *filename)
|
||||
error_noabort("undefined symbol '%s'", name);
|
||||
}
|
||||
}
|
||||
} else if (s1->rdynamic &&
|
||||
ELF32_ST_BIND(sym->st_info) != STB_LOCAL) {
|
||||
/* if -rdynamic option, then export all non
|
||||
local symbols */
|
||||
name = symtab_section->link->data + sym->st_name;
|
||||
put_elf_sym(s1->dynsym, sym->st_value, sym->st_size,
|
||||
sym->st_info, 0,
|
||||
sym->st_shndx, name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1001,6 +1232,8 @@ int tcc_output_file(TCCState *s1, const char *filename)
|
||||
name = s1->dynsymtab_section->link->data + esym->st_name;
|
||||
sym_index = find_elf_sym(symtab_section, name);
|
||||
if (sym_index) {
|
||||
/* XXX: avoid adding a symbol if already
|
||||
present because of -rdynamic ? */
|
||||
sym = &((Elf32_Sym *)symtab_section->data)[sym_index];
|
||||
put_elf_sym(s1->dynsym, sym->st_value, sym->st_size,
|
||||
sym->st_info, 0,
|
||||
@@ -1112,21 +1345,36 @@ int tcc_output_file(TCCState *s1, const char *filename)
|
||||
/* allocate program segment headers */
|
||||
phdr = tcc_mallocz(phnum * sizeof(Elf32_Phdr));
|
||||
|
||||
file_offset = sizeof(Elf32_Ehdr) + phnum * sizeof(Elf32_Phdr);
|
||||
if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) {
|
||||
file_offset = sizeof(Elf32_Ehdr) + phnum * sizeof(Elf32_Phdr);
|
||||
} else {
|
||||
file_offset = 0;
|
||||
}
|
||||
if (phnum > 0) {
|
||||
/* compute section to program header mapping */
|
||||
if (file_type == TCC_OUTPUT_DLL)
|
||||
addr = 0;
|
||||
else
|
||||
addr = ELF_START_ADDR;
|
||||
|
||||
if (s1->has_text_addr) {
|
||||
int a_offset, p_offset;
|
||||
addr = s1->text_addr;
|
||||
/* we ensure that (addr % ELF_PAGE_SIZE) == file_offset %
|
||||
ELF_PAGE_SIZE */
|
||||
a_offset = addr & (ELF_PAGE_SIZE - 1);
|
||||
p_offset = file_offset & (ELF_PAGE_SIZE - 1);
|
||||
if (a_offset < p_offset)
|
||||
a_offset += ELF_PAGE_SIZE;
|
||||
file_offset += (a_offset - p_offset);
|
||||
} else {
|
||||
if (file_type == TCC_OUTPUT_DLL)
|
||||
addr = 0;
|
||||
else
|
||||
addr = ELF_START_ADDR;
|
||||
/* compute address after headers */
|
||||
addr += (file_offset & (ELF_PAGE_SIZE - 1));
|
||||
}
|
||||
|
||||
/* dynamic relocation table information, for .dynamic section */
|
||||
rel_size = 0;
|
||||
rel_addr = 0;
|
||||
|
||||
/* compute address after headers */
|
||||
addr += (file_offset & (ELF_PAGE_SIZE - 1));
|
||||
|
||||
/* leave one program header for the program interpreter */
|
||||
ph = &phdr[0];
|
||||
if (interp)
|
||||
@@ -1177,11 +1425,11 @@ int tcc_output_file(TCCState *s1, const char *filename)
|
||||
section_order[sh_order_index++] = i;
|
||||
|
||||
/* section matches: we align it and add its size */
|
||||
tmp = file_offset;
|
||||
file_offset = (file_offset + s->sh_addralign - 1) &
|
||||
tmp = addr;
|
||||
addr = (addr + s->sh_addralign - 1) &
|
||||
~(s->sh_addralign - 1);
|
||||
file_offset += addr - tmp;
|
||||
s->sh_offset = file_offset;
|
||||
addr += file_offset - tmp;
|
||||
s->sh_addr = addr;
|
||||
|
||||
/* update program header infos */
|
||||
@@ -1204,10 +1452,18 @@ int tcc_output_file(TCCState *s1, const char *filename)
|
||||
ph->p_filesz = file_offset - ph->p_offset;
|
||||
ph->p_memsz = addr - ph->p_vaddr;
|
||||
ph++;
|
||||
/* if in the middle of a page, we duplicate the page in
|
||||
memory so that one copy is RX and the other is RW */
|
||||
if ((addr & (ELF_PAGE_SIZE - 1)) != 0)
|
||||
addr += ELF_PAGE_SIZE;
|
||||
if (j == 0) {
|
||||
if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) {
|
||||
/* if in the middle of a page, we duplicate the page in
|
||||
memory so that one copy is RX and the other is RW */
|
||||
if ((addr & (ELF_PAGE_SIZE - 1)) != 0)
|
||||
addr += ELF_PAGE_SIZE;
|
||||
} else {
|
||||
addr = (addr + ELF_PAGE_SIZE - 1) & ~(ELF_PAGE_SIZE - 1);
|
||||
file_offset = (file_offset + ELF_PAGE_SIZE - 1) &
|
||||
~(ELF_PAGE_SIZE - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if interpreter, then add corresponing program header */
|
||||
@@ -1248,12 +1504,28 @@ int tcc_output_file(TCCState *s1, const char *filename)
|
||||
|
||||
p = s1->plt->data;
|
||||
p_end = p + s1->plt->data_offset;
|
||||
put32(p + 2, get32(p + 2) + s1->got->sh_addr);
|
||||
put32(p + 8, get32(p + 8) + s1->got->sh_addr);
|
||||
p += 16;
|
||||
while (p < p_end) {
|
||||
if (p < p_end) {
|
||||
#if defined(TCC_TARGET_I386)
|
||||
put32(p + 2, get32(p + 2) + s1->got->sh_addr);
|
||||
put32(p + 8, get32(p + 8) + s1->got->sh_addr);
|
||||
p += 16;
|
||||
while (p < p_end) {
|
||||
put32(p + 2, get32(p + 2) + s1->got->sh_addr);
|
||||
p += 16;
|
||||
}
|
||||
#elif defined(TCC_TARGET_ARM)
|
||||
int x;
|
||||
x=s1->got->sh_addr - s1->plt->sh_addr - 12;
|
||||
p +=16;
|
||||
while (p < p_end) {
|
||||
put32(p + 12, x + get32(p + 12) + s1->plt->data - p);
|
||||
p += 16;
|
||||
}
|
||||
#elif defined(TCC_TARGET_C67)
|
||||
/* XXX: TODO */
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1336,97 +1608,112 @@ int tcc_output_file(TCCState *s1, const char *filename)
|
||||
|
||||
/* get entry point address */
|
||||
if (file_type == TCC_OUTPUT_EXE)
|
||||
ehdr.e_entry = (unsigned long)tcc_get_symbol(s1, "_start");
|
||||
ehdr.e_entry = (unsigned long)tcc_get_symbol_err(s1, "_start");
|
||||
else
|
||||
ehdr.e_entry = text_section->sh_addr; /* XXX: is it correct ? */
|
||||
}
|
||||
|
||||
sort_syms(s1, symtab_section);
|
||||
|
||||
/* 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] = ELFCLASS32;
|
||||
ehdr.e_ident[5] = ELFDATA2LSB;
|
||||
ehdr.e_ident[6] = EV_CURRENT;
|
||||
#ifdef __FreeBSD__
|
||||
ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
|
||||
#endif
|
||||
switch(file_type) {
|
||||
default:
|
||||
case TCC_OUTPUT_EXE:
|
||||
ehdr.e_type = ET_EXEC;
|
||||
break;
|
||||
case TCC_OUTPUT_DLL:
|
||||
ehdr.e_type = ET_DYN;
|
||||
break;
|
||||
case TCC_OUTPUT_OBJ:
|
||||
ehdr.e_type = ET_REL;
|
||||
break;
|
||||
}
|
||||
ehdr.e_machine = EM_386;
|
||||
ehdr.e_version = EV_CURRENT;
|
||||
ehdr.e_shoff = file_offset;
|
||||
ehdr.e_ehsize = sizeof(Elf32_Ehdr);
|
||||
ehdr.e_shentsize = sizeof(Elf32_Shdr);
|
||||
ehdr.e_shnum = shnum;
|
||||
ehdr.e_shstrndx = shnum - 1;
|
||||
|
||||
/* write elf file */
|
||||
if (file_type == TCC_OUTPUT_OBJ)
|
||||
mode = 0666;
|
||||
else
|
||||
mode = 0777;
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, mode);
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode);
|
||||
if (fd < 0) {
|
||||
error_noabort("could not write '%s'", filename);
|
||||
goto fail;
|
||||
}
|
||||
f = fdopen(fd, "w");
|
||||
fwrite(&ehdr, 1, sizeof(Elf32_Ehdr), f);
|
||||
fwrite(phdr, 1, phnum * sizeof(Elf32_Phdr), f);
|
||||
offset = sizeof(Elf32_Ehdr) + phnum * sizeof(Elf32_Phdr);
|
||||
for(i=1;i<s1->nb_sections;i++) {
|
||||
s = s1->sections[section_order[i]];
|
||||
if (s->sh_type != SHT_NOBITS) {
|
||||
while (offset < s->sh_offset) {
|
||||
fputc(0, f);
|
||||
offset++;
|
||||
}
|
||||
size = s->sh_size;
|
||||
fwrite(s->data, 1, size, f);
|
||||
offset += size;
|
||||
}
|
||||
}
|
||||
while (offset < ehdr.e_shoff) {
|
||||
fputc(0, f);
|
||||
offset++;
|
||||
}
|
||||
f = fdopen(fd, "wb");
|
||||
|
||||
#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) {
|
||||
sort_syms(s1, symtab_section);
|
||||
|
||||
/* align to 4 */
|
||||
file_offset = (file_offset + 3) & -4;
|
||||
|
||||
/* output section headers */
|
||||
for(i=0;i<s1->nb_sections;i++) {
|
||||
sh = &shdr;
|
||||
memset(sh, 0, sizeof(Elf32_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;
|
||||
/* 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] = ELFCLASS32;
|
||||
ehdr.e_ident[5] = ELFDATA2LSB;
|
||||
ehdr.e_ident[6] = EV_CURRENT;
|
||||
#ifdef __FreeBSD__
|
||||
ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
|
||||
#endif
|
||||
#ifdef TCC_TARGET_ARM
|
||||
ehdr.e_ident[EI_OSABI] = ELFOSABI_ARM;
|
||||
#endif
|
||||
switch(file_type) {
|
||||
default:
|
||||
case TCC_OUTPUT_EXE:
|
||||
ehdr.e_type = ET_EXEC;
|
||||
break;
|
||||
case TCC_OUTPUT_DLL:
|
||||
ehdr.e_type = ET_DYN;
|
||||
break;
|
||||
case TCC_OUTPUT_OBJ:
|
||||
ehdr.e_type = ET_REL;
|
||||
break;
|
||||
}
|
||||
fwrite(sh, 1, sizeof(Elf32_Shdr), f);
|
||||
ehdr.e_machine = EM_TCC_TARGET;
|
||||
ehdr.e_version = EV_CURRENT;
|
||||
ehdr.e_shoff = file_offset;
|
||||
ehdr.e_ehsize = sizeof(Elf32_Ehdr);
|
||||
ehdr.e_shentsize = sizeof(Elf32_Shdr);
|
||||
ehdr.e_shnum = shnum;
|
||||
ehdr.e_shstrndx = shnum - 1;
|
||||
|
||||
fwrite(&ehdr, 1, sizeof(Elf32_Ehdr), f);
|
||||
fwrite(phdr, 1, phnum * sizeof(Elf32_Phdr), f);
|
||||
offset = sizeof(Elf32_Ehdr) + phnum * sizeof(Elf32_Phdr);
|
||||
|
||||
for(i=1;i<s1->nb_sections;i++) {
|
||||
s = s1->sections[section_order[i]];
|
||||
if (s->sh_type != SHT_NOBITS) {
|
||||
while (offset < s->sh_offset) {
|
||||
fputc(0, f);
|
||||
offset++;
|
||||
}
|
||||
size = s->sh_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<s1->nb_sections;i++) {
|
||||
sh = &shdr;
|
||||
memset(sh, 0, sizeof(Elf32_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(Elf32_Shdr), f);
|
||||
}
|
||||
} else {
|
||||
tcc_output_binary(s1, f, section_order);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
@@ -1452,7 +1739,8 @@ static void *load_data(int fd, unsigned long file_offset, unsigned long size)
|
||||
typedef struct SectionMergeInfo {
|
||||
Section *s; /* corresponding existing section */
|
||||
unsigned long offset; /* offset of the new section in the existing section */
|
||||
int new_section; /* true if section 's' was added */
|
||||
uint8_t new_section; /* true if section 's' was added */
|
||||
uint8_t link_once; /* true if link once section */
|
||||
} SectionMergeInfo;
|
||||
|
||||
/* load an object file and merge it with current files */
|
||||
@@ -1483,7 +1771,7 @@ static int tcc_load_object_file(TCCState *s1,
|
||||
goto fail1;
|
||||
/* test CPU specific stuff */
|
||||
if (ehdr.e_ident[5] != ELFDATA2LSB ||
|
||||
ehdr.e_machine != EM_386) {
|
||||
ehdr.e_machine != EM_TCC_TARGET) {
|
||||
fail1:
|
||||
error_noabort("invalid object file");
|
||||
return -1;
|
||||
@@ -1539,8 +1827,19 @@ static int tcc_load_object_file(TCCState *s1,
|
||||
/* find corresponding section, if any */
|
||||
for(j = 1; j < s1->nb_sections;j++) {
|
||||
s = s1->sections[j];
|
||||
if (!strcmp(s->name, sh_name))
|
||||
goto found;
|
||||
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;
|
||||
} else {
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* not found: create new section */
|
||||
s = new_section(s1, sh_name, sh->sh_type, sh->sh_flags);
|
||||
@@ -1574,6 +1873,7 @@ static int tcc_load_object_file(TCCState *s1,
|
||||
} else {
|
||||
s->data_offset += size;
|
||||
}
|
||||
next: ;
|
||||
}
|
||||
|
||||
/* second short pass to update sh_link and sh_info fields of new
|
||||
@@ -1601,6 +1901,18 @@ static int tcc_load_object_file(TCCState *s1,
|
||||
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 (ELF32_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;
|
||||
@@ -1678,6 +1990,55 @@ typedef struct ArchiveHeader {
|
||||
char ar_fmag[2]; /* should contain ARFMAG */
|
||||
} ArchiveHeader;
|
||||
|
||||
static int get_be32(const uint8_t *b)
|
||||
{
|
||||
return b[3] | (b[2] << 8) | (b[1] << 16) | (b[0] << 24);
|
||||
}
|
||||
|
||||
/* load only the objects which resolve undefined symbols */
|
||||
static int tcc_load_alacarte(TCCState *s1, int fd, int size)
|
||||
{
|
||||
int i, bound, nsyms, sym_index, off, ret;
|
||||
uint8_t *data;
|
||||
const char *ar_names, *p;
|
||||
const uint8_t *ar_index;
|
||||
Elf32_Sym *sym;
|
||||
|
||||
data = tcc_malloc(size);
|
||||
if (read(fd, data, size) != size)
|
||||
goto fail;
|
||||
nsyms = get_be32(data);
|
||||
ar_index = data + 4;
|
||||
ar_names = ar_index + nsyms * 4;
|
||||
|
||||
do {
|
||||
bound = 0;
|
||||
for(p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) {
|
||||
sym_index = find_elf_sym(symtab_section, p);
|
||||
if(sym_index) {
|
||||
sym = &((Elf32_Sym *)symtab_section->data)[sym_index];
|
||||
if(sym->st_shndx == SHN_UNDEF) {
|
||||
off = get_be32(ar_index + i * 4) + sizeof(ArchiveHeader);
|
||||
#if 0
|
||||
printf("%5d\t%s\t%08x\n", i, p, sym->st_shndx);
|
||||
#endif
|
||||
++bound;
|
||||
lseek(fd, off, SEEK_SET);
|
||||
if(tcc_load_object_file(s1, fd, off) < 0) {
|
||||
fail:
|
||||
ret = -1;
|
||||
goto the_end;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(bound);
|
||||
ret = 0;
|
||||
the_end:
|
||||
tcc_free(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* load a '.a' file */
|
||||
static int tcc_load_archive(TCCState *s1, int fd)
|
||||
{
|
||||
@@ -1710,18 +2071,21 @@ static int tcc_load_archive(TCCState *s1, int fd)
|
||||
ar_name[i + 1] = '\0';
|
||||
// printf("name='%s' size=%d %s\n", ar_name, size, ar_size);
|
||||
file_offset = lseek(fd, 0, SEEK_CUR);
|
||||
if (!strcmp(ar_name, "/") ||
|
||||
!strcmp(ar_name, "//") ||
|
||||
!strcmp(ar_name, "__.SYMDEF") ||
|
||||
!strcmp(ar_name, "__.SYMDEF/") ||
|
||||
!strcmp(ar_name, "ARFILENAMES/")) {
|
||||
/* align to even */
|
||||
size = (size + 1) & ~1;
|
||||
if (!strcmp(ar_name, "/")) {
|
||||
/* coff symbol table : we handle it */
|
||||
if(s1->alacarte_link)
|
||||
return tcc_load_alacarte(s1, fd, size);
|
||||
} else if (!strcmp(ar_name, "//") ||
|
||||
!strcmp(ar_name, "__.SYMDEF") ||
|
||||
!strcmp(ar_name, "__.SYMDEF/") ||
|
||||
!strcmp(ar_name, "ARFILENAMES/")) {
|
||||
/* skip symbol table or archive names */
|
||||
} else {
|
||||
if (tcc_load_object_file(s1, fd, file_offset) < 0)
|
||||
return -1;
|
||||
}
|
||||
/* align to even */
|
||||
size = (size + 1) & ~1;
|
||||
lseek(fd, file_offset + size, SEEK_SET);
|
||||
}
|
||||
return 0;
|
||||
@@ -1745,7 +2109,7 @@ static int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
|
||||
|
||||
/* test CPU specific stuff */
|
||||
if (ehdr.e_ident[5] != ELFDATA2LSB ||
|
||||
ehdr.e_machine != EM_386) {
|
||||
ehdr.e_machine != EM_TCC_TARGET) {
|
||||
error_noabort("bad architecture");
|
||||
return -1;
|
||||
}
|
||||
@@ -1954,6 +2318,21 @@ static int tcc_load_ldscript(TCCState *s1)
|
||||
t = ld_next(s1, filename, sizeof(filename));
|
||||
}
|
||||
}
|
||||
} else if (!strcmp(cmd, "OUTPUT_FORMAT") ||
|
||||
!strcmp(cmd, "TARGET")) {
|
||||
/* ignore some commands */
|
||||
t = ld_next(s1, cmd, sizeof(cmd));
|
||||
if (t != '(')
|
||||
expect("(");
|
||||
for(;;) {
|
||||
t = ld_next(s1, filename, sizeof(filename));
|
||||
if (t == LD_TOK_EOF) {
|
||||
error_noabort("unexpected end of file");
|
||||
return -1;
|
||||
} else if (t == ')') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
85
tcctest.c
85
tcctest.c
@@ -16,6 +16,9 @@
|
||||
|
||||
#endif
|
||||
|
||||
/* deprecated and no longer supported in gcc 3.3 */
|
||||
//#define ACCEPT_CR_IN_STRINGS
|
||||
|
||||
/* __VA_ARGS__ and __func__ support */
|
||||
#define C99_MACROS
|
||||
|
||||
@@ -76,6 +79,7 @@ void typeof_test(void);
|
||||
void local_label_test(void);
|
||||
void statement_expr_test(void);
|
||||
void asm_test(void);
|
||||
void builtin_test(void);
|
||||
|
||||
int fib(int n);
|
||||
void num(int n);
|
||||
@@ -122,6 +126,12 @@ int isid(int c);
|
||||
#define __INT64_C(c) c ## LL
|
||||
#define INT64_MIN (-__INT64_C(9223372036854775807)-1)
|
||||
|
||||
int qq(int x)
|
||||
{
|
||||
return x + 40;
|
||||
}
|
||||
#define qq(x) x
|
||||
|
||||
void macro_test(void)
|
||||
{
|
||||
printf("macro:\n");
|
||||
@@ -209,7 +219,7 @@ void macro_test(void)
|
||||
#line 203 "test"
|
||||
printf("__LINE__=%d __FILE__=%s\n",
|
||||
__LINE__, __FILE__);
|
||||
#line 206 "tcctest.c"
|
||||
#line 220 "tcctest.c"
|
||||
|
||||
/* not strictly preprocessor, but we test it there */
|
||||
#ifdef C99_MACROS
|
||||
@@ -243,6 +253,15 @@ void macro_test(void)
|
||||
MF_s("hi");
|
||||
MF_t("hi");
|
||||
|
||||
/* test macro substituion inside args (should not eat stream) */
|
||||
printf("qq=%d\n", qq(qq)(2));
|
||||
|
||||
/* test zero argument case. NOTE: gcc 2.95.x does not accept a
|
||||
null argument without a space. gcc 3.2 fixes that. */
|
||||
|
||||
#define qq1(x) 1
|
||||
printf("qq1=%d\n", qq1( ));
|
||||
|
||||
/* comment with stray handling *\
|
||||
/
|
||||
/* this is a valid *\/ comment */
|
||||
@@ -265,7 +284,7 @@ int ret(a)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ps(char *s)
|
||||
void ps(const char *s)
|
||||
{
|
||||
int c;
|
||||
while (1) {
|
||||
@@ -498,6 +517,7 @@ int main(int argc, char **argv)
|
||||
statement_expr_test();
|
||||
local_label_test();
|
||||
asm_test();
|
||||
builtin_test();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1286,6 +1306,16 @@ void bitfield_test(void)
|
||||
st1.f5++;
|
||||
printf("%d %d %d %d %d\n",
|
||||
st1.f1, st1.f2, st1.f3, st1.f4, st1.f5);
|
||||
|
||||
st1.f1 = 7;
|
||||
if (st1.f1 == -1)
|
||||
printf("st1.f1 == -1\n");
|
||||
else
|
||||
printf("st1.f1 != -1\n");
|
||||
if (st1.f2 == -1)
|
||||
printf("st1.f2 == -1\n");
|
||||
else
|
||||
printf("st1.f2 != -1\n");
|
||||
}
|
||||
|
||||
#define FTEST(prefix, type, fmt)\
|
||||
@@ -1572,6 +1602,15 @@ void longlong_test(void)
|
||||
printf("%lld\n", value(&a));
|
||||
}
|
||||
lloptest(0x80000000, 0);
|
||||
|
||||
/* another long long spill test */
|
||||
{
|
||||
long long *p, v;
|
||||
v = 1;
|
||||
p = &v;
|
||||
p[0]++;
|
||||
printf("%lld\n", *p);
|
||||
}
|
||||
}
|
||||
|
||||
void vprintf1(const char *fmt, ...)
|
||||
@@ -1643,6 +1682,8 @@ ntf("aaa=%d\n", 3);
|
||||
|
||||
pri\
|
||||
\
|
||||
ntf("min=%d\n", 4);
|
||||
|
||||
#ifdef ACCEPT_CR_IN_STRINGS
|
||||
printf("len1=%d\n", strlen("
|
||||
"));
|
||||
@@ -1652,6 +1693,7 @@ ntf("min=%d\n", 4);
|
||||
printf("len1=%d str[0]=%d\n", strlen(str), str[0]);
|
||||
#endif
|
||||
printf("len1=%d\n", strlen("
|
||||
a
|
||||
"));
|
||||
#endif /* ACCEPT_CR_IN_STRINGS */
|
||||
}
|
||||
@@ -1897,3 +1939,42 @@ void asm_test(void)
|
||||
void asm_test(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define COMPAT_TYPE(type1, type2) \
|
||||
{\
|
||||
printf("__builtin_types_compatible_p(%s, %s) = %d\n", #type1, #type2, \
|
||||
__builtin_types_compatible_p (type1, type2));\
|
||||
}
|
||||
|
||||
int constant_p_var;
|
||||
|
||||
void builtin_test(void)
|
||||
{
|
||||
#if GCC_MAJOR >= 3
|
||||
COMPAT_TYPE(int, int);
|
||||
COMPAT_TYPE(int, unsigned int);
|
||||
COMPAT_TYPE(int, char);
|
||||
COMPAT_TYPE(int, const int);
|
||||
COMPAT_TYPE(int, volatile int);
|
||||
COMPAT_TYPE(int *, int *);
|
||||
COMPAT_TYPE(int *, void *);
|
||||
COMPAT_TYPE(int *, const int *);
|
||||
COMPAT_TYPE(char *, unsigned char *);
|
||||
/* space is needed because tcc preprocessor introduces a space between each token */
|
||||
COMPAT_TYPE(char * *, void *);
|
||||
#endif
|
||||
printf("res = %d\n", __builtin_constant_p(1));
|
||||
printf("res = %d\n", __builtin_constant_p(1 + 2));
|
||||
printf("res = %d\n", __builtin_constant_p(&constant_p_var));
|
||||
printf("res = %d\n", __builtin_constant_p(constant_p_var));
|
||||
}
|
||||
|
||||
|
||||
void const_func(const int a)
|
||||
{
|
||||
}
|
||||
|
||||
void const_warn_test(void)
|
||||
{
|
||||
|
||||
48
tcctok.h
48
tcctok.h
@@ -90,6 +90,8 @@
|
||||
DEF(TOK_SECTION2, "__section__")
|
||||
DEF(TOK_ALIGNED1, "aligned")
|
||||
DEF(TOK_ALIGNED2, "__aligned__")
|
||||
DEF(TOK_PACKED1, "packed")
|
||||
DEF(TOK_PACKED2, "__packed__")
|
||||
DEF(TOK_UNUSED1, "unused")
|
||||
DEF(TOK_UNUSED2, "__unused__")
|
||||
DEF(TOK_CDECL1, "cdecl")
|
||||
@@ -100,6 +102,10 @@
|
||||
DEF(TOK_STDCALL3, "__stdcall__")
|
||||
DEF(TOK_NORETURN1, "noreturn")
|
||||
DEF(TOK_NORETURN2, "__noreturn__")
|
||||
DEF(TOK_builtin_types_compatible_p, "__builtin_types_compatible_p")
|
||||
DEF(TOK_builtin_constant_p, "__builtin_constant_p")
|
||||
DEF(TOK_REGPARM1, "regparm")
|
||||
DEF(TOK_REGPARM2, "__regparm__")
|
||||
|
||||
/* builtin functions or variables */
|
||||
DEF(TOK_memcpy, "memcpy")
|
||||
@@ -109,9 +115,37 @@
|
||||
DEF(TOK___moddi3, "__moddi3")
|
||||
DEF(TOK___udivdi3, "__udivdi3")
|
||||
DEF(TOK___umoddi3, "__umoddi3")
|
||||
#if defined(TCC_TARGET_ARM)
|
||||
DEF(TOK___divsi3, "__divsi3")
|
||||
DEF(TOK___modsi3, "__modsi3")
|
||||
DEF(TOK___udivsi3, "__udivsi3")
|
||||
DEF(TOK___umodsi3, "__umodsi3")
|
||||
DEF(TOK___sardi3, "__ashrdi3")
|
||||
DEF(TOK___shrdi3, "__lshrdi3")
|
||||
DEF(TOK___shldi3, "__ashldi3")
|
||||
DEF(TOK___slltold, "__slltold")
|
||||
DEF(TOK___fixunssfsi, "__fixunssfsi")
|
||||
DEF(TOK___fixunsdfsi, "__fixunsdfsi")
|
||||
DEF(TOK___fixunsxfsi, "__fixunsxfsi")
|
||||
DEF(TOK___fixsfdi, "__fixsfdi")
|
||||
DEF(TOK___fixdfdi, "__fixdfdi")
|
||||
DEF(TOK___fixxfdi, "__fixxfdi")
|
||||
#elif defined(TCC_TARGET_C67)
|
||||
DEF(TOK__divi, "_divi")
|
||||
DEF(TOK__divu, "_divu")
|
||||
DEF(TOK__divf, "_divf")
|
||||
DEF(TOK__divd, "_divd")
|
||||
DEF(TOK__remi, "_remi")
|
||||
DEF(TOK__remu, "_remu")
|
||||
DEF(TOK___sardi3, "__sardi3")
|
||||
DEF(TOK___shrdi3, "__shrdi3")
|
||||
DEF(TOK___shldi3, "__shldi3")
|
||||
#else
|
||||
/* XXX: same names on i386 ? */
|
||||
DEF(TOK___sardi3, "__sardi3")
|
||||
DEF(TOK___shrdi3, "__shrdi3")
|
||||
DEF(TOK___shldi3, "__shldi3")
|
||||
#endif
|
||||
DEF(TOK___tcc_int_fpu_control, "__tcc_int_fpu_control")
|
||||
DEF(TOK___tcc_fpu_control, "__tcc_fpu_control")
|
||||
DEF(TOK___ulltof, "__ulltof")
|
||||
@@ -142,12 +176,24 @@
|
||||
DEF(TOK_strcpy, "strcpy")
|
||||
#endif
|
||||
|
||||
/* Tiny Assembler for x86 */
|
||||
/* Tiny Assembler */
|
||||
|
||||
DEF_ASM(byte)
|
||||
DEF_ASM(align)
|
||||
DEF_ASM(skip)
|
||||
DEF_ASM(space)
|
||||
DEF_ASM(string)
|
||||
DEF_ASM(asciz)
|
||||
DEF_ASM(ascii)
|
||||
DEF_ASM(globl)
|
||||
DEF_ASM(global)
|
||||
DEF_ASM(text)
|
||||
DEF_ASM(data)
|
||||
DEF_ASM(bss)
|
||||
DEF_ASM(previous)
|
||||
DEF_ASM(fill)
|
||||
DEF_ASM(org)
|
||||
DEF_ASM(quad)
|
||||
|
||||
#ifdef TCC_TARGET_I386
|
||||
|
||||
|
||||
427
texi2pod.pl
Executable file
427
texi2pod.pl
Executable file
@@ -0,0 +1,427 @@
|
||||
#! /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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user