Compare commits

...

127 Commits

Author SHA1 Message Date
Jan Nieuwenhuizen cb08f119ca
README: Update to add info about GNU Mes and bootstrappable-tinycc.
* README: Add header on GNU Mes and bootstrappable-tinycc.
2020-02-22 16:31:18 +01:00
Christian Jullien adfcf3b1dd Temporary remove zfunc test on ARM which generates a relocation error. Waiting for a fix 2018-12-20 08:44:47 +01:00
Christian Jullien 8494f2c318 Fix Thomas commit 776aa0c093 which failedto build on Windows. 2018-12-17 17:05:05 +01:00
Petr Skocik 070646b790 Recognize C11' _Alignof 2018-12-12 20:12:03 +01:00
Michael Matz c4787e3626 Fix type completion for array types as well
like qualifier merging the array sizes are merged as well
for the operands of ?:, and they must not statically influence
the types of decls.

Also fix some style problems, spaces aren't stinky :)
2018-11-30 23:43:30 +01:00
Petr Skocik f7779efe58 Fix incorrect one-sided void handling in ?:
Also make the case when one side in ?: is a ptr
and the other is neither a ptr nor a null-ptr constant
fail cleanly instead of segfaulting.
2018-11-29 13:40:48 +01:00
Petr Skocik 49dfb5755a Make fn designators in ?: decay to ptrs
This
    _Generic((__typeof(1?f:f)*){0}, void (**)(void): (void)0);
should compile like it does in gcc and clang.
2018-11-29 12:43:01 +01:00
Petr Skocik 3058d4116e Fix (Cexpr?struct1:struct2).member
Tcc used to fail this with `lvalue expected`
if the expression was a compile-time constant.
2018-11-29 10:26:56 +01:00
Petr Skocik 9d44b02a49 Fix the fix on type combining (e0012c2)
char **argv;
	    _Generic(argv, char**: (void)0);
	    _Generic(0?(char const*)0:argv[0], char const*: (void)0);
	    _Generic(argv, char**: (void)0);

    would fail because the type of argv would get modified by the
    ternary. Now allocate a separate type on the value stack to
    prevent this error.
2018-11-29 10:26:35 +01:00
Petr Skocik e0012c2767 Fix ptr type combining inside the ternary operator
Make it match http://port70.net/~nsz/c/c99/n1256.html#6.5.15p6
(or http://port70.net/~nsz/c/c11/n1570.html#6.5.15p6).
2018-11-28 10:36:58 +01:00
Petr Skocik c81116e29a Make casts lose top-level qualifiers
TODO: also make them lose lvalue status
2018-11-20 19:24:24 +01:00
Petr Skocik f85b1e393f Always allow ({ }) in the ctrl-expr of _Generic
tcc would reject e.g.,
    void f(){ struct {_Bool x:_Generic(({0;}),default:1);} my_x; }
with `expected constant`. This patch makes it accept it.

(The patch also makes tcc's _Generic a little more "generic" than that
 of gcc and clang in that that tcc now also accepts
`struct {_Bool x:_Generic(({0;}),default:1);} my_x;` in file scope
while gcc and clang don't, but I think there's no harm in that
and gcc and clang might as well accept it in filescope too, given
that they have no problem with
e.g., `/*filescope:*/int x=1, y=2, z=_Generic(x+y, int:3);`)
2018-11-13 12:51:16 +01:00
Petr Skocik 1e2e5671f7 Make tcc accept `-l lib` as well as `-llib`.
The POSIX spec for `c99` specifically favors the space-containing version
(http://pubs.opengroup.org/onlinepubs/9699919799/utilities/c99.html)
and the `-l lib` syntax is also supported by gcc and clang.
2018-11-12 20:52:53 +01:00
Petr Skocik 314843ffc3 Fix how _Generic treats pointers to arrays.
_Generic should distinguish pointers to differently sized
arrays such as `int(*)[2]` and `int(*)[4]`.
2018-11-12 20:52:14 +01:00
Petr Skocik 73ca09ff32 Fix array pointer stringification.
`int (*)[4];` should not be stringified as `int *[4];`
Add stringification tests.
2018-11-12 20:50:51 +01:00
Petr Skocik 93a4ddfa63 Treat the - output as stdout. 2018-11-12 20:50:33 +01:00
Michael Matz 3b9c3fd186 Fix noreturn in main()
ISO C requires 'main' falling through the end without explicit
returns to implicitely return 0 (if declared as returning int).
2018-11-03 22:17:20 +01:00
Michael Matz 61ba9f2299 Check for void type in top-level decls
give an error message from the parser on things like "void x;" instead
of relying on codegen erroring out.
2018-08-03 22:51:35 +02:00
Michael Matz 22420ee1ee Fix misparsed type in presence of attributes
The type within the cast (int (__attribute__((foo)) *)(void))
was misparsed because of the presence of the attribute (parse_btype
prematurely concluded that (__attribute__() *) is a type.

Also see testcase.  This construct is used in sqlite it seems.
2018-07-28 18:55:54 +02:00
Jonathan Newman 0edbed1d52 Implement __attribute__((nodecorate))
Prevent any decoration that would otherwise affect an exported
PE function. For example, given the following:

__declspec(dllexport) __stdcall
int decorated(int arg) {
    return 0;
}

__declspec(dllexport) __stdcall __attribute__((nodecorate))
int undecorated(int arg) {
    return 0;
}

The following exported functions can now be seen in the DLL:
_decorated@4
undecorated

The attribute is recognised for all targets but only
affects PE codegen. I'm not sure whether this would be
useful for other targets; its intended use was to allow
the creation of a DLL matching an existing set of signatures.
2018-07-22 00:54:01 +01:00
Michael Matz d79caa9ff6 x86-64: Fix calls via absolute function pointers
linkers don't treat relocations using symindex 0 (undefined)
very well, it can't be misused as indicator for an absolute number.
Just don't bother with special casing this, rather emit an indirect
call/jump right away. ARM64 needs the same (and didn't handle
calls via constant absolute func pointers before).

The testcase as is doesn't fail without the patch, it actually
needs separate compilation (to -fPIC .o file, then to shared lib)
to fail.
2018-07-02 01:57:29 +02:00
Michael Matz 65c7f19deb Fix stored type of arguments on x86-64
the lvalue Syms for arguments didn't correctly reflect
their own types in all cases (a side-effect of the type being
stored in type->t and the ->r members (as VT_LVAL_xxx), so the below
used an int load (not a byte load) in the conditional.

extern void bar (void);
void foo (signed char c)
{
  signed char x = c;
  if (c)
    bar();
}
2018-06-24 20:12:51 +02:00
Andrey Gursky 91bdb5a4a3 Add linker's --export-dynamic flag alias
Since 9336fa7ae5 --export-dynamic is
supported. Add this conventional flag as alias.
2018-06-11 18:26:04 +02:00
grischka 8f6fcb709a misc fixes
misc fixes including:
- tcc.c: fix "tcc -vv" for libtcc1.a on win32/PE
- tccelf.c: fix a crash when GOT has no relocs (witn -nostdlib)
- tccelf.c: fix stab linkage for zero n_strx
- tccgen.c: fix stdcall decoration for array parameters
    int __stdcall func(char buf[10]) is _func@4 (was _func@12)
- tccgen.c: fix static variables with nocode/nodata_wanted
    see tests2/96_nodata_wanted.c
- tccrun.c: align sections using sh_addralign (for reliable function_alignment)
- tests2/Makefile sort 100 after 99
- win32/include/sys/stat.h fix _stat and _wstat
- x86_64-gen.c: win64/gfunc_call: fix a bug with xmmN register args
    previously overwrote valid other xmmN registers eventually
2018-06-01 12:52:01 +02:00
grischka 2b155a8c16 tccgen.c: fix warning for incompatible struct- and function pointers
see tests2/60_errors_and_warnings.c
2018-06-01 12:41:21 +02:00
grischka ace1225492 tcc_add_file(): preserve s->filetype
This is supposed to fix a bug where libtcc eventually was trying to
compile libtcc1.a as C source code.

Anyway, there is now only two functions that refer to s->filetype,
tcc_add_file() and tcc_add_library().
2018-06-01 12:41:17 +02:00
Michael Matz 671dcace82 Implement function alignment via attributes
which requires being able to emit an arbitrary number of NOP
instructions, which is also implemented here.  For x86 we
could emit other sequences but these are the easiest.
2018-04-06 23:02:42 +02:00
Petr Skocik ef668aae1e Don't fail on const/restrict/static/* inside []
This patch makes tcc ignore them.

Normally (as per the C standard), They should
be only applicable inside parameter arrays
and affect (const/restrict) the pointer the
array gets converted to.

[matz: fix formatting, add volatile handling, add testcase,
add comment about above deficiency]
2018-04-01 00:48:09 +02:00
Petr Skocik d6d3cf00ec patch type_to_str to handle complex function-ptr decls better
Code like:

    #include <signal.h>
    int main() { _Generic(signal, int: 0); }

should fail with
    error: type 'extern void (*(int, void (*)(int)))(int)' does not match any association
not
    error: type 'extern void *(int)(int, void *(int))' does not match any association

[matz: fix formatting, fix function-to-pointer decay for operands of
_Generic, add testcase for this]
2018-04-01 00:38:11 +02:00
Michael Matz f0a25ca263 Fix shortening casts of long long
see added testcase.
2018-03-31 21:52:20 +02:00
Thomas Preud'homme c41caac02d Select VFP if triplet is arm-linux-gnueabihf
A target triplet of arm-linux-gnueabihf indicates that the compiler
should use the VFP variant of the calling convention which as its name
implies requires VFP. This commit enables VFP when triplet is
arm-linux-gnueabihf.
2018-03-15 23:05:25 +00:00
Thomas Preud'homme e76058c478 Remove asm-c-connect-sep in tests clean target 2018-03-09 20:10:36 +00:00
Thomas Preud'homme 776aa0c093 Prevent dead code on !x86 in prepare_dynamic_rel
In prepare_dynamic_rel() on non x86 targets the count++ statements
appear before any case label and are therefore dead code. This triggers
build failure when building with -Werror. This patch adds an extra guard
around all the x86 case labels and their associated action, leaving just
the default case label for non x86 targets which builds fine.

Origin: vendor
Forwarded: no
Last-Updated: 2018-02-24
2018-02-24 19:35:15 +00:00
Michael Matz 3e6515b64f Add make testspp.all/testspp.20
like we have already make tests2.XX.
2018-01-05 02:19:26 +01:00
Michael Matz 7ad2cf8d68 Code suppression fixes
See adjusted testcase, a lone break; in a do while loop was
incorrectly disabling the exit test.
2018-01-05 02:19:26 +01:00
Michael Matz 8294285d8f Don't emit applied .rel sections
for a final link we shouldn't emit relocation sections that are applied
already.  For now we need to emit ALLOCed .rel sections as they contain
dynamic relocs, they should be put into their own (new) section instead.
2018-01-01 05:29:46 +01:00
foobar 988e2ff7fe fix debug info with musl on x86_64
http://lists.nongnu.org/archive/html/tinycc-devel/2017-12/msg00031.html
2017-12-28 15:05:27 +00:00
Michael Matz 414b224efa Accept more floating point constant expressions
the rules for constant expressions in static initializers are more
relaxed than for integer constant expressions.  We need to accept
0.0/0.0 in static initializers (in non-static initializers the potential
exceptions need to be raised though, so no translation-time calculation
then).
2017-12-25 12:44:29 +01:00
Michael Matz 9e47b18229 Make type of __nan__ __inf__ and __snan__ be float
so that those builtins can be used directly for the C99 NAN and
INFINITY math.h macros.
2017-12-24 13:16:09 +01:00
Michael Matz 3b27b3b1d1 Fix -pthread in a different way 2017-12-23 14:49:07 +01:00
Michael Matz 1b1b270f1e Revert "Fix -pthread option handling"
This reverts commit 3f8225509b.
It fixes the linking case but introduces an ugly error with -c
about adding a library.  To fix both uses the old code structure is
better.
2017-12-23 14:46:27 +01:00
Michael Matz 3f8225509b Fix -pthread option handling
adding -pthread confused option parsing as the number of file counting
came out wrong.  Simplify and fit it, can be handled purely within
option parsing, no need for a state flag.
2017-12-23 14:14:57 +01:00
grischka d348a9a51d final update for 0.9.27
tccgen.c:
- fix ldouble asm hack
- fix a VLA problem on Win64 (also x86_64-gen.c)
- patch_type(): make sure that no symbol ever changes
  from global to static

tcc.c:
- tcc -vv: print libtcc1.a path also on win32

tccpe.c, tcctools.c:
- use unix LF mode to for .def output files (that is for
  creating reproducible output trees)

Makefile:
- suppress some warnings when makeinfo is missing
- call 'which install' only on win32

tests/Makefile:
- change PATH only on WINNT systems (i.e. not if cross-compiling
  on linux for win32)
- asm-c-connect.test: slim output and do diff

tccrun.c tccpe.c *-link.c:
- integrate former 'pe_relocate_rva()' into normal relocation
  This also fixes linkage of the unwind data on WIN64 for -run
  (reported by Janus Lynggaard Thorborg)

tccasm.c, tests/tcctest.c:
- fix dot (sym_index of -1 crashed in put_elf_reloc)
- massage .set a bit (see test)

other:
- #define SECTION_ABS removed
- ST_DATA Section *strtab_section: removed
- put_extern_sym2(): take int section number

Conflicts:
	tccelf.c
	tccpe.c

Conflicts:
	tccelf.c
2017-12-12 17:57:20 +01:00
grischka 1a4d4b76e8 tccgen_begin/end_file
This is supposed to make compilation and linking with
multiple source files (tcc f1.c f2.S ...) behave just
the same as linking object files.

tccgen.c:put_extern_sym2():
- use put_elf_sym to enter new symbols unconditionally

tccelf.c:
- save section state before compilation
- disable symbol hashing during compilation
- merge symbols and update relocations after compilation

tccpe.c:
- re-create s1->uw_sym for each compilation (because it
  may change)
2017-12-12 17:33:37 +01:00
Michael Matz 8490c54dbd Fix some multi-file corner cases with asm
for this we have to create also asm symbols as VT_STATIC initially
except if there's an indication that it should be global (.globl
or undefined at end of unit).  For this to work we need to
be able to globalize symbols after they were local and enter them
into the ELF hash tables, and also adjust the symbols that were
potentially already used in relocs when they were still local.

The easiest is to do a proper symbol resolution step also in multi-file
mode, for regular symbols (the non-dynamic ones, i.e. not from shared
libs).
2017-12-10 06:50:58 +01:00
grischka 3ae1a2af1c tccgen: unify type redefinition checks
tccgen.c:
- improved function patch_storage() and added new function
  patch_type() for more consistent type redefinition and
  instance redefinition checks.
2017-12-05 02:06:26 +01:00
grischka 877e164d6a tccasm: use global(_symbol)_stack
* removed asm_label stack
* removed asm_free_labels() post-processing
* using "impossible C type" for asm labels (VT_ASM)
* tccgen.c:update_storage(): use it to refresh symbol attributes
* tccelf.c:find_elf_sym(): ignore STB_LOCAL symbols
* tccgen.c:unary(): asm symbols are supposed to be undeclared in C
2017-12-05 01:54:49 +01:00
Michael Matz cc6cb7f0e2 Fix another corner case with C/asm symtable
See testcase (from grischka).  If the asm has no .globl,
but there's a (non-static) C definition the symbol should
be exported, even if the first reference comes from asm.
2017-12-04 03:51:14 +01:00
Michael Matz 529b44c0d5 tccasm: Accept suffixed cmovCC
The length suffix for cmovCC isn't necessary as the required register
operands always allow length deduction.  But let's be nice to users
and accept them anyway.  Do that without blowing up tables, which means
we don't detect invalid suffixes for the given operands, but so be it.
2017-12-03 04:53:50 +01:00
Michael Matz 9e0d23cc47 tccasm: Unify C and asm symbol table
This makes the asm symbols use the same members as the C symbols
for global decls, e.g. using the ELF symbol to hold offset and
section.  That allows us to use only one symbol table for C and
asm symbols and to get rid of hacks to synch between them.

We still need some special handling for symbols that come purely
from asm sources.
2017-11-27 04:59:29 +01:00
Michael Matz 3494e5de3a Adjust asm-c-connect testcase for Windows
Calling conventions are different, let's use functions without
any arguments.
2017-11-27 01:09:50 +01:00
Michael Matz 4266ebd69c tccasm: Don't abuse dllexport/dllimport
For tracking if asm symbols are connected with a C symbol,
and if asm symbols need to be global use new flags, instead of
reusing dllimport/dllexport, which would cause unrequested exported
entries on Windows.

This is a stop-gap until the C and asm symtable are unified.
2017-11-25 19:41:03 +01:00
Michael Matz e7c71e2473 tccasm: synch C and asm symtab tighter
See testcase.  The C and asm symtab are still separate,
but integrated tighter: the asm labels are only synched at file
end, not after each asm snippet (this fixes references from one
to another asm block), the C and asm syms are synched both ways,
so defining things in asm and refering from C, or the other way
around works.  In effect this model reflects what happens with
GCC better.

For this the asm labels aren't using the C label namespace anymore,
but their own, which increases the size of each TokenSym by a pointer.
2017-11-22 17:57:43 +01:00
Michael Matz 330c01bfc6 Adjust testcase for PIE compilers
one some systems GCC defaults to PIC/PIE code which is incompatible
with a unannotated asm call to a function (getenv here).  TCC doesn't
support these PIC annotations (yet), so play some pre-processor games.
2017-11-19 15:36:47 +01:00
Michael Matz d0db21757a Fix forward asm labels differently
while last change fixed one part of label behaviour (undefined ones
must be global) it again broke a different aspect (forward defs
without .globl must stay local).  This fixes both aspects.
That a label is local instead of global is difficult to test without
resorting to look at the symbol table or using two-file testcases,
so we do without.  In essence the local/global-ness of symbols
should be the same between GAS and TCC for this input:

    .globl glob1
    glob1:
    call glob1

    .globl glob2
    call glob2
    glob2:

    glob3:
    .globl glob3
    call glob3

    glob4:
    call glob4
    .globl glob4

    call glob5
    .globl glob5
    glob5:

    call glob6
    glob6:
    .globl glob6

    locl1:
    call locl1

    call locl2
    locl2:

    unref1:
    unref2:
    .globl unref2
    .globl unref3
    unref3:
    call undef
2017-11-19 03:04:11 +01:00
Michael Matz a8ece0f2ce Don't make forard asm symbols static by default
fixes the problem in the testcase.  A symbolic reference
from asm, which remains undefined at the end of processing is
always a global reference, not a static (STB_LOCAL) one.
This also affected the linux kernel.
2017-11-16 13:29:59 +01:00
Michael Matz 348dd9f4a6 Fix absolute memory references
This properly fixes what 870271ea tried to fix.  Absolute memory
references can't use %rip relative addressing, and additionally,
if the address doesn't fit 32bit (signed) it must be loaded via
movabs.  No good testcase added, it would require catching signals
and still be unreliable.
2017-11-15 13:39:28 +01:00
Michael Matz 74463eb954 Revert "gen_addrpc32: absolute ptr needs *ABS* relocation"
This reverts commit 870271ea07.

The commit is broken, you can't unconditionally emit a PC-relative
relocation without a symbol.  And if there's a symbol the addend
need to be in the relocation, not the section.
2017-11-14 16:43:22 +01:00
janus.lt 32c9b51401 Win64/PE: Changed runtime function unwind info to be added after relocation, fixes SEH + long jmps 2017-11-04 00:18:37 +01:00
emekoi fc0188ffbc fixed dylib typo in libtcc.c 2017-10-19 00:55:42 -05:00
grischka da8c62f75d various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
  cygwin's "GCC for Win32 Toolchain"
      ./configure --cross-prefix=i686-w64-mingw32-
  or with an existing tcc:
      ./configure --cc=<old-tccdir>/tcc.exe

tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)

tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)

tests:
- remove -I "expr" diff option to allow tests with
  busybox-diff.

libtcc.c, tcc.c:
- removed -iwithprefix option.  It is supposed to be
  combined with -iprefix which we don't have either.

tccgen.c:
- fix assignments and return of 'void', as in
     void f() {
         void *p, *q;
         *p = *q:
         return *p;
     }
  This appears to be allowed but should do nothing.

tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
  This reverts commit 1d5e386b0a.

  The patch was giving tcc's system includes priority over -I which
  is not how it should be.

tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
  used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
  (weak) symbols

tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
  (it was so once except the RX mapping wasn't used at all).

tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.

tccasm.c:
- keep forward asm labels static, otherwise they will endup
  in dynsym eventually.

configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
      make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
  a cross compiler for example
      make cross-arm
      make install
- use name <target>-libtcc1.a

build-tcc.bat:
- add  options: -clean, -b bindir
2017-10-11 18:13:43 +02:00
YX Hao faa9744f5d Win: crt, initialize global __argc, __targv and _tenviron of msvcrt
_tenviron: as far as possible, not in ASC '-run' mode.
__argc and __targv are shortcuts for _tWinMain, when you want to use program parameters.
2017-10-10 20:39:05 +08:00
Steffen Nurpmeso 6f1860e200 Fix Windows++ compilation of previous (YX Hao, Joel Bodenmann) 2017-10-09 14:52:56 +02:00
Steffen Nurpmeso 1d5e386b0a Introduce VIP sysinclude paths which are always searched first 2017-10-03 17:58:45 +02:00
Steffen Nurpmeso a1c9051313 Adjust va_list to work with musl 2017-09-30 16:11:54 +02:00
Christian Jullien 2e5751caf1 tools directory no more exists, removed in win32 tarball Makefile target. 2017-09-29 07:26:21 +02:00
Larry Doolittle 8deb05c3e2 Use more conventional punctuation for sequential assignments 2017-09-25 22:16:23 -07:00
Avi Halachmi (:avih) abd1532ad4 freebsd: allow building tcc which targets windows
Currently tcc doesn't have a compile-time config indicating that the target
is freebsd, and as a result, the tcc binary adds freebsh stuff to elf headers
if the compile-time (of tcc) *host* is freebsd.

Test also that the target is not PE while generating an elf header.

This still likely fails (but untested) when tcc targets other non-freebsd
systems on a freebsd system, but for now fix it only when targetting windows.
2017-09-25 18:39:35 +03:00
Larry Doolittle 560188711d Fix some spelling in documentation 2017-09-24 18:22:42 -07:00
Larry Doolittle 1b6806e5bb Spelling fixes
Comments only, no change to functionality
2017-09-24 18:03:26 -07:00
Larry Doolittle 44d4da62bb Convert two .c files to LF line endings
... matching the other 157 .c files in the tree
2017-09-24 16:48:08 -07:00
grischka 1443039416 'long' review
add some features for more complete 'long' support

tcc.h:
- use LONG_SIZE=4/8 instead of TCC_LONG_ARE_64_BIT
tccgen.c:
- add ptrdiff_type, update size_type
- support shift and ?: operations
- support long enum types
- display 'long' from type_to_str
- nwchar_t is unsigned short on windows
- unrelated: use memcpy in init_putv for long doubles to avoid
  random bytes in the image (if tcc was compiled by gcc) for
  diff purposes.
tccpp.c:
- make parse_number return correct types
- improve multi-character-constants 'XX' 'abcd'
Changelog:
- update
2017-09-24 18:57:48 +02:00
Zdenek Pavlas 870271ea07 gen_addrpc32: absolute ptr needs *ABS* relocation
Dereferencing of absolute pointers is broken on x86_64, eg:

*(int*)NULL does not segfault but returns -4 instead
*(char*)(-10L << 20) does not return 0x55 (vsyscall page, push rbp)
2017-09-11 06:36:16 -07:00
Zhang Boyang 078d8c2c5a Add test case for fastcall calling convention 2017-09-10 18:22:48 +08:00
Zhang Boyang f406f63a38 Add test case for AL/AX extending problem 2017-09-10 17:03:34 +08:00
Zhang Boyang 978d1ecce0 Add test case for wide char handling in wide string literal 2017-09-10 16:50:19 +08:00
Zhang Boyang b39810ff78 Fix calling function pointers casted from intergers in DLL
The code generated for "((void (*)(void))0x12345678)()" will be a single "CALL 0x12345678" in previous code.
However, this will not work for DLLs, because "CALL imm" is PC related, DLL relocation will break the code.
This commit fixed the problem by forcing TCC generates indirect CALLs in this situation.
2017-09-09 21:11:56 +08:00
Zhang Boyang 02370acdc9 Fix AL/AX is not extended to EAX when calling indirectly
AL/AX should be extended to EAX when calling functions. However, the previous code did this only for direct calls, indirect calls were ignored.
New code also avoid redundant code when generating JMP instruction. (i.e. expanding code should be generated with CALL instruction only)
2017-09-09 21:01:42 +08:00
Zhang Boyang a82c11f4b4 Fix wide char handling in wide string literal
This commit fixed the problem that TCC directly cast each byte in wide string literal to wchar_t, which is wrong when wide string literal contains real wide chars.
It fixed the problem by assuming input charset is UTF-8, and wchar_t stores wide chars in UTF-16 (Windows) or UTF-32 (others).
The UTF-8 decoder is coded according to The Unicode Standard Version 10.
2017-09-09 20:37:43 +08:00
Zhang Boyang b8fe8fc210 called function should pop the arguments when using fastcall 2017-08-21 19:38:11 +08:00
Edmund Grimley Evans ac41e015f1 Convert from ISO-8859-1 to UTF-8. See aa812e8. 2017-07-26 13:07:14 +01:00
Matthias Gatto 4f15d08ea1 Revert "use int for ssize_t, (u)intptr_t instead of long in stddef.h"
This reverts commit 52622c3c03.

Because 28b7c9 was right.
2017-07-26 10:25:52 +02:00
matthias c18fc950d7 Revert "simplify VT_LONG parsing"
Too simple long parsion.
Take me a long long long time to see my mistake,
Sorry

(long long long wasn't see as an error)
This reverts commit a4cd2805f9.
2017-07-25 22:04:24 +02:00
Christian Jullien 023d4e0b59 Remove debug echo in Cygwin Makefile 2017-07-25 19:17:10 +02:00
Christian Jullien 421a1c48bb Update Cygwin Makefile to use -B. for bootstrap 2017-07-25 19:12:04 +02:00
Matthias Gatto 52622c3c03 use int for ssize_t, (u)intptr_t instead of long in stddef.h 2017-07-25 18:56:41 +02:00
Matthias Gatto 23064b1734 check that _Generic match 'signed long int' as 'long' 2017-07-25 18:56:41 +02:00
Matthias Gatto a4cd2805f9 simplify VT_LONG parsing 2017-07-25 18:56:41 +02:00
Christian Jullien 8258abeb80 Update Cygwin Makefile to work with recent changes about ONE_SOURCE and CONFG_TCCDIR 2017-07-25 17:50:28 +02:00
Matthias Gatto 28b7c9b34e define __SIZE_TYPE__ and __PTRDIFF_TYPE__ as unsigned int and int.
As long is now a qualifier, and because compare_type will notice
that variables are not the same type, we can't use long as int anymore.

So, I've redefine __SIZE_TYPE__ as unsigned int and __PTRDIFF_TYPE__ as int.
2017-07-25 16:25:27 +02:00
Matthias Gatto b72cddaa6e remove inside_generic hack
define uint64_t and int64_t as 'long' instead of 'long long'
when __LP64__ is define.
2017-07-24 11:52:15 +02:00
grischka 4b3c6e74ab tccgen: nodata_wanted fix, default ONE_SOURCE, etc...
tccgen.c:
  doubles need to be aligned, on ARM.  The section_reserve()
  in init_putv does not do that.
-D ONE_SOURCE: is now the default and not longer needed. Also,
  tcc.h now sets the default native target.  These both make
  compiling tcc simple as "gcc tcc.c -o tcc -ldl" again.
arm-asm.c:
  enable pseudo asm also for inline asm
tests/tests2/Makefile:
  disable bitfield tests except on windows and x86_64
  and don't generate-always
tcc.c:
  fix a loop with -dt on errors
configure:
  print compiler version (as recognized)
tccpp.c:
  actually define symbols for tcc -dt
  clear static variables (needed for -dt or libtcc usage)
96_nodata_wanted.c:
  use __label__ instead of asm
lib/files:
  use native symbols (__i386__ etc.) instead of TCC_TARGET_...
2017-07-23 21:24:11 +02:00
matthias fdc18d307a mutiples fix for _Generic
* check that _Generic don't match unsigned char * with char *
  this case is usefull as with -funsigned-char, 'char *' are unsigned

* change VT_LONG so it's now a qualifier

  VT_LONG are never use for code generation, but only durring parsing state,
  in _Generic we need to be able to make diference between
  'long' and 'long long'
  So VT_LONG is now use as a type qualifier, it's old behaviour is still
  here, but we can keep trace of what was a long and what wasn't

* add TOK_CLONG and TOK_CULONG

  tcc was directly converting value like '7171L' into TOK_CLLONG or
  TOK_CINT depending of the machine architecture.

  because of that, we was unable to make diference between a long and a
  long long, which doesn't work with _Generic.

  So now 7171L is a TOK_CLONG, and we can handle _Generic properly

* check that _Generic can make diference between long and long long

* uncomment "type match twice" as it should now pass tests on any platforms

* add inside_generic global

  the point of this variable is to use VT_LONG in comparaison only
  when we are evaluating a _Generic.
  problem is with my lastest patchs tcc can now make the diference between
  a 'long long' and a 'long', but in 64 bit stddef.h typedef uint64_t as
  typedef signed long long int int64_t and stdint.h as unsigned long int, so tcc
  break when stdint.h and stddef.h are include together.

  Another solution woud be to modifie include/stddef.h so it define uint64_t as
  unsigned long int when processor is 64 bit, but this could break some
  legacy code, so for now, VT_LONG are use only inside generc.

* check that _Generic parse first argument correctly

* check that _Generic evaluate correctly exresion like "f() / 2"
2017-07-21 19:30:31 +02:00
grischka 0cc24d0e84 tcc -dt -run ... : simpler is better
* -dt now with lowercase t

* test snippets now separated by real preprocessor statements
  which is valid C also for other compilers

    #if defined test_xxx
       < test snippet x >
    #elif defined test_yyy
       < test snippet y >
    #elif ...
    #endif

* simpler implementation, behaves like -run if no 'test_...' macros
  are seen, works with -E too

* for demonstration I combined some of the small tests for errors
  and warnings (56..63,74) in "60_errors_and_warnings.c"

Also:
* libtcc.c:
  put tcc_preprocess() and tcc_assemble() under the setjmp clause
  to let them return to caller after errors.  This is for -dt -E.
* tccgen.c:
  - get rid of save/restore_parse_state(), macro_ptr is saved
    by begin_macro anyway, now line_num too.
  - use expr_eq for parsing _Generic's controlling_type
  - set nocode_wanted with const_wanted. too, This is to keep
    VT_JMP on vtop when parsing preprocessor expressions.
* tccpp.c: tcc -E: suppress trailing whitespace from lines with
  comments (that -E removes) such as
       NO_GOTPLT_ENTRY,\t    /* never generate ... */
2017-07-20 22:21:27 +02:00
Matthias Gatto ba2b25e4ea fix typo sellector -> selector 2017-07-18 20:28:51 +02:00
matthias 2821644553 fix typo: march -> match 2017-07-18 20:28:51 +02:00
Matthias Gatto 2020a312ca unqualify volatile in _Generic type checking 2017-07-18 20:28:51 +02:00
Michael Matz 3f13e33872 Fix cross compilers
Only native compilers support -run and hence the new -dT.
2017-07-16 21:03:25 +02:00
grischka 7f1ab9b1e1 tccgen: nodata_wanted
The existing variable 'nocode_wanted' is now used to control
output of static data too. So...

(nocode_wanted == 0)
    code and data (normal within functions)
(nocode_wanted < 0)
    means: no code, but data (global or static data)
(nocode_wanted > 0)
    means: no code and no data (code and data suppressed)
(nocode_wanted & 0xC0000000)
    means:  we're in declaration of static data

Also: new option '-dT' to be used with -run
    tcc -dT -run file.c
This will look in file.c for certain comment-boundaries:
    /*-* test-xxx: ...some description */
and then for each test below run it from memory.  This way
various features and error messages can be tested with one
single file.  See 96_nodata_wanted.c for an example.

Also: tccgen.c: one more bitfield fix
2017-07-16 12:10:00 +02:00
grischka 69a137ff88 #pragma comment(option,"-..."), bitfields test, etc...
tccpp.c:
* #pragma comment(option,"-some-option")
  to set commandline option from C code.  May work only
  for some options.
libtcc.c:
* option "-d1..9": sets a 'g_debug' global variable.
  (for development)
tests2/Makefile:
* new make targets: tests2.37 / tests2.37+
  run single test from tests2,  optionally update .expect
* new variable GEN-ALWAYS to always generate certain .expects
* bitfields test
tccgen.c:
* bitfields: fix a bug and improve slightly more
* _Generic: ignore "type match twice"
2017-07-14 19:26:01 +02:00
Michael Matz 04418c7add Fix function types
various cases of function type uses were broken by recent
attribute refactoring, this fixes and adds testcases for them.
2017-07-14 17:42:48 +02:00
Michael Matz 2acb04f7f2 tccasm: Fix local statics referenced from asms
The assembler uses the ->sym_scope member to walk up the symbols
until finding a non-automatic symbol.  Since reordering the
members of Sym the sym_scope member contains a scope even for local
statics.  Formerly the use of asm_label for statics was implicitely
clearing sym_scope, now we have to do that explicitely.

Add a testcase for that, and one I encountered when moving the
clearing of sym_scope too deep into the call chain (into put_extern_sym).
2017-07-10 22:29:28 +02:00
Michael Matz 9bea88d616 Fix statement exprs returning a local label
Like returned local variables also labels local to a statement expression
can be returned, and so their symbols must not be immediately freed
(though they need to be removed from the symbol table).
2017-07-10 22:25:11 +02:00
Michael Matz 2240422da9 enums: Accept GNU extension
See testcase.  Happens e.g. in the linux kernel.
2017-07-10 22:20:34 +02:00
grischka a9e502cc3b refactor bitfields
Use 2 level strategy to access packed bitfields cleanly:

1) Allow to override the original declaration type with
   an auxilary "access type".  This solves cases such as

    struct {
        ...
        unsigned f1:1;
    };

    by using VT_BYTE to access f1.

2) Allow byte-wise split accesses using two new functions
   load/store_packed_bf. This solves any cases, also ones
   such as

    struct __attribute((packed)) _s {
        unsigned x : 12;
        unsigned char y : 7;
        unsigned z : 28;
        unsigned a: 3;
        unsigned b: 3;
        unsigned c: 3;
    };

    where for field 'z':
    - VT_INT access from offset 2 would be unaligned
    - VT_LLONG from offset 0 would go past the total
      struct size (7)

    and for field 'a' because it is in two bytes and
    aligned access with VT_SHORT/INT is not possible.

Also, static bitfield initializers are stored byte-wise always.
Also, cleanup the struct_layout function a bit.
2017-07-09 12:38:59 +02:00
grischka f87afa72e0 refactor enums
Eliminate VT_ENUM as a basic type.  Instead use the integral
types VT_InT/VT_LLONG with an additional flag to indicate
that it is an enum.
2017-07-09 12:38:25 +02:00
grischka 9ba76ac834 refactor sym & attributes
tcc.h:
* cleanup struct 'Sym'
* include some 'Attributes' into 'Sym'
* in turn get rid of VT_IM/EXPORT, VT_WEAK
* re-number VT_XXX flags
* replace some 'long' function args by 'int'

tccgen.c:
* refactor parse_btype()
2017-07-09 12:34:11 +02:00
grischka 9f79b62ec4 unsorted adjustments
- configure
  * use aarch64 instead of arm64

- Makefile
  * rename the custom include file to "config-extra.mak"
  * Also avoid "rm -r /*" if $(tccdir) is empty

- pp/Makefile
  * fix .expect generation with gcc

- tcc.h
  * cleanup #defines for _MSC_VER

- tccgen.c:
  * fix const-propagation for &,|
  * fix anonymous named struct (ms-extension) and enable
    -fms-extension by default

- i386-gen.c
  * clear VT_DEFSIGN

- x86_64-gen.c/win64:
  * fix passing structs in registers
  * fix alloca (need to keep "func_scratch" below each alloca area on stack)
    (This allows to compile a working gnu-make on win64)

- tccpp.c
  * alternative approach to 37999a4fbf
    This is to avoid some slowdown with ## token pasting.
  * get_tok_str() : return <eof> for TOK_EOF
  * -funsigned-char: apply to "string" literals as well

- tccpe/tools.c: -impdef: support both 32 and 64 bit dlls anyway
2017-07-09 12:07:40 +02:00
grischka 6c468c10f7 tccpp: allow "#define X defined Y ..."
That means: we do not macro-expand the argument of 'defined'

Also: store the last token position into the TokenString
structure in order to get rid of the tok_last function.
2017-07-09 11:46:14 +02:00
Michael Matz 824dcebe59 tccpp: Implement __COUNTER__
This requires one more change in how macro arguments are expanded:
the standard requires that macro args are expanded before substituting
into the replacement list.  This implies expanding them only once
even when they occur multiple times in the list.  TCC expanded
them repeatedly in that case.  Without __COUNTER__ that's harmless.

So, simply always expand arguments (when used without # and ##) once
and store the resulting tokens.
2017-07-09 05:30:47 +02:00
Michael Matz 1f3d3957c4 tccpp: Cleanup
With last change the can_read_stream flag is unneeded, so tidy this
a bit.
2017-07-09 04:53:24 +02:00
Michael Matz d8fdd380f3 tccpp: Fix corner case
See added testcase 19.c from a bug report.  The problem is reading outside
the arguments buffers, even though we aren't allowed to.  The single
can_read_stream variable is not enough, sometimes we need to be able
to pop into outer contexts but not into arbitrarily outside contexts.

The trick is to terminate argument tokens with a EOF (and not just with
0 that makes us pop contexts), and deal with that in the few places
we have to,

This enables some cleanups of the can_read_stream variable use.
2017-07-09 04:38:56 +02:00
Matthias Gatto 16d3dbf2d0 add _Generic test 2017-07-05 17:59:42 +02:00
Matthias Gatto 157bad52cd add C11's _Generic
Simple implementation, I'm not even sure to respect C standart here,
but it should work with most use case.

This add an case in unary(), and generate TokString depending of _Generic
controlling exression, use begin_macro to "push"
the generated TokString, then call unary() again before exiting the switch
so the just add token are reevaluate again.
2017-07-05 10:57:50 +02:00
Michael Matz 9ed8b54f6c Revert "String literals are always const"
This reverts commit d4fe9aba3f.
I was confused by the fact that string literals aren't writable.
Nevertheless the type isn't const.  As extension in GCC it's const
with -Wwrite-string, which is exactly what we had before.

GCC also wonders in a comment if it's really a good idea to change
expression types based on warning flags (IMHO it's not), but let's
be compatible.  So restore the state from before.
2017-07-04 16:37:49 +02:00
Michael Matz 580ad5f24c Extend skip_or_save_block
Make it stop also before outer level closing parens.  This way
we can now also skip/save the expression inside "foobar(42 + 41)".
2017-07-03 19:15:16 +02:00
Michael Matz 27ca303874 Improve skip_or_save_block
Stop at level 0 only for matching outer '}' (which is added).
Otherwise stop only at stop tokens (which aren't added).
2017-07-03 18:13:15 +02:00
Michael Matz d4fe9aba3f String literals are always const
Don't make the standard mandated types of string literals
depends on warning options.  Instead make them always const,
but limit the emission of the warning by that option.
2017-07-03 18:02:57 +02:00
Christian Jullien b68df809eb Align 'implicit-function-declaration' option comment with other comments (cosmetic change) 2017-06-10 06:45:51 +02:00
Christian Jullien 6d559d651f Add -O2 when compiling tcc on Windows. Not sure this flag is really used by tcc. 2017-06-10 06:35:11 +02:00
Emil 3e028af453 When creating a staticaly linked ELF program should not include
any dyn symbols. The if( !s1->static_link ) prevents tcc from
crashing when buiding a program linked to dietlibc.

The section header should not contain the number of local symbols when
the sh_size is null. This makes the header compliant and IDA will not
issue any warnings when an executable is disassembled.
2017-06-09 19:44:29 +01:00
U-NELSON\jullien 3e4b7693bf force i386-win32-tcc.exe to be a 32bit binary. Run tests in both 32/64 bits on Windows. 2017-06-05 08:18:11 +02:00
U-NELSON\jullien 2a348896dd Add more common tests to be run from win32/Makefile 2017-06-04 09:27:48 +02:00
Christian Jullien 0cc4e570bc Windows test Makefile target also test pp tests. 2017-05-28 07:12:57 +02:00
Michael Matz 31e5ad789a Limit access end-of-struct warning a bit
Only warn if the struct has a non-zero size.  You can't create objects
of zero-sized structs, but they can be used inside sizeof (e.g.
"sizeof (struct {int :0;})".  The warning would always trigger for these,
but as no objects can be created no accesses can ever happen.
2017-05-27 22:44:53 +02:00
Michael Matz 7cd1ae7710 x86-64: Fix psABI stdarg prologue
If there were more than 6 integer arguments before the ellipsis, or
there were used more than 8 slots used until the ellipsis (e.g. by
a large intermediate struct) we generated wrong code.  See testcase.
2017-05-27 22:42:18 +02:00
Michael Matz 53c5fc2246 x86-64: Rewrite linux parameter passing
This fixes two ABI testcases involving large arguments when there
are still registers available for later args.
2017-05-27 21:23:13 +02:00
115 changed files with 5367 additions and 2878 deletions

5
.gitignore vendored
View File

@ -41,16 +41,17 @@ win32/include/stddef.h
win32/include/varargs.h
win32/include/tcclib.h
tests/test.out*
tests/test*.out
tests/tcctest[1234]
tests/tcctest.gcc
tests/*.out*
tests/*.ref
tests/*.txt
tests/*.gcc
tests/*-cc*
tests/*-tcc*
tests/libtcc_test
tests/asm-c-connect
tests/asm-c-connect-sep
tests/vla_test
tests/hello
tests/tests2/fred.txt

View File

@ -9,11 +9,10 @@ User interface:
- -mno-sse on x86-64 disables use of SSE instructions
- @listfile support (Vlad Vissoultchev)
- tcc -ar/-impdef - formerly tiny_xxx tools integrated (grischka)
- CPATH, C_INCLUDE_PATH and LD_LIBRARY_PATH environment variables support
- CPATH, C_INCLUDE_PATH and LIBRARY_PATH environment variables support
(Andrew Aladjev, Urs Janssen)
Platforms:
- Bootstrap native Windows 32/64 compiler using Cygwin+gcc (Christian Jullien)
- new AARCH64 (arm64) target (Edmund Grimley Evans)
- vastly improved support for ARM hard float calling convention
(Thomas Preud'homme, Daniel Glöckner)
@ -22,6 +21,7 @@ Platforms:
- ABI tests with native compiler using libtcc (James Lyon)
- UNICODE startup code supports wmain and wWinMain (YX Hao)
- shared libraries for x86_64 (Michael Matz)
- Bootstrap native Windows 32/64 compiler using Cygwin+gcc (Christian Jullien)
Features:
- VLA (variable length array) improved (James Lyon, Pip Cet)
@ -35,6 +35,8 @@ Features:
- standard conforming (and GCC compatible) struct initialization
(Michael Matz)
- bit-field layout made compatible with GCC (Michael Matz)
- UTF8 in string literals supported (Zdenek Pavlas)
_ _Generic(...) supported (Matthias Gatto)
Licensing:
- TinyCC partly relicensed to MIT license (See RELICENSING file).

178
Makefile
View File

@ -98,16 +98,17 @@ TCC_X = i386 x86_64 i386-win32 x86_64-win32 x86_64-osx arm arm64 arm-wince c67
LIBTCC1_X = i386 x86_64 i386-win32 x86_64-win32 x86_64-osx arm arm64 arm-wince
PROGS_CROSS = $(foreach X,$(TCC_X),$X-tcc$(EXESUF))
LIBTCC1_CROSS = $(foreach X,$(LIBTCC1_X),libtcc1-$X.a)
LIBTCC1_CROSS = $(foreach X,$(LIBTCC1_X),$X-libtcc1.a)
# build cross compilers & libs
cross: $(LIBTCC1_CROSS) $(PROGS_CROSS)
# build specific cross compiler & lib
cross-%: %-tcc$(EXESUF) libtcc1-%.a ;
cross-%: %-tcc$(EXESUF) %-libtcc1.a ;
install: install$(CFGWIN)
uninstall: uninstall$(CFGWIN)
install: ; @$(MAKE) --no-print-directory install$(CFGWIN)
install-strip: ; @$(MAKE) --no-print-directory install$(CFGWIN) CONFIG_strip=yes
uninstall: ; @$(MAKE) --no-print-directory uninstall$(CFGWIN)
ifdef CONFIG_cross
all : cross
@ -143,16 +144,16 @@ DEFINES += $(DEF-$(or $(findstring win,$T),unx))
ifneq ($(X),)
ifeq ($(CONFIG_WIN32),yes)
DEF-win += -DTCC_LIBTCC1="\"libtcc1-$T.a\""
DEF-unx += -DTCC_LIBTCC1="\"lib/libtcc1-$T.a\""
DEF-win += -DTCC_LIBTCC1="\"$(X)libtcc1.a\""
DEF-unx += -DTCC_LIBTCC1="\"lib/$(X)libtcc1.a\""
else
DEF-all += -DTCC_LIBTCC1="\"libtcc1-$T.a\""
DEF-all += -DTCC_LIBTCC1="\"$(X)libtcc1.a\""
DEF-win += -DCONFIG_TCCDIR="\"$(tccdir)/win32\""
endif
endif
# include custom cross-compiler configuration (see make help)
-include config-cross.mak
# include custom configuration (see make help)
-include config-extra.mak
CORE_FILES = tcc.c tcctools.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c tccrun.c
CORE_FILES += tcc.h config.h libtcc.h tcctok.h
@ -173,11 +174,12 @@ ifeq ($(ONE_SOURCE),yes)
LIBTCC_OBJ = $(X)libtcc.o
LIBTCC_INC = $($T_FILES)
TCC_FILES = $(X)tcc.o
$(X)libtcc.o $T-tcc$(EXESUF) : DEFINES += -DONE_SOURCE
tcc.o : DEFINES += -DONE_SOURCE=0
else
LIBTCC_OBJ = $(patsubst %.c,$(X)%.o,$(LIBTCC_SRC))
LIBTCC_INC = $(filter %.h %-gen.c %-link.c,$($T_FILES))
TCC_FILES = $(X)tcc.o $(LIBTCC_OBJ)
$(TCC_FILES) : DEFINES += -DONE_SOURCE=0
endif
# target specific object rule
@ -200,7 +202,7 @@ $(CROSS_TARGET)-tcc$(EXESUF): $(TCC_FILES)
# profiling version
tcc_p$(EXESUF): $($T_FILES)
$(CC) -o $@ $< $(DEFINES) -DONE_SOURCE $(CFLAGS_P) $(LIBS_P) $(LDFLAGS_P)
$(CC) -o $@ $< $(DEFINES) $(CFLAGS_P) $(LIBS_P) $(LDFLAGS_P)
# static libtcc library
libtcc.a: $(LIBTCC_OBJ)
@ -216,34 +218,36 @@ libtcc.so: LDFLAGS+=-fPIC
# windows dynamic libtcc library
libtcc.dll : $(LIBTCC_OBJ)
$(CC) -shared -o $@ $^ $(LDFLAGS)
libtcc.def : libtcc.dll tcc$(EXESUF)
./tcc$(EXESUF) -impdef $< -o $@
libtcc.dll : DEFINES += -DLIBTCC_AS_DLL
# import file for windows libtcc.dll
libtcc.def : libtcc.dll tcc$(EXESUF)
$(XTCC) -impdef $< -o $@
XTCC ?= ./tcc$(EXESUF)
# TinyCC runtime libraries
libtcc1.a : tcc$(EXESUF) FORCE
@$(MAKE) -C lib DEFINES="$(DEF-$T)"
@$(MAKE) -C lib DEFINES='$(DEF-$T)'
# Cross libtcc1.a
libtcc1-%.a : %-tcc$(EXESUF) FORCE
@$(MAKE) -C lib DEFINES="$(DEF-$*)" CROSS_TARGET=$*
%-libtcc1.a : %-tcc$(EXESUF) FORCE
@$(MAKE) -C lib DEFINES='$(DEF-$*)' CROSS_TARGET=$*
.PRECIOUS: libtcc1-%.a
.PRECIOUS: %-libtcc1.a
FORCE:
# --------------------------------------------------------------------------
# documentation and man page
tcc-doc.html: tcc-doc.texi
-makeinfo --no-split --html --number-sections -o $@ $<
makeinfo --no-split --html --number-sections -o $@ $< || true
tcc.1: tcc-doc.texi
-$(TOPSRC)/texi2pod.pl $< tcc.pod
-pod2man --section=1 --center="Tiny C Compiler" --release="$(VERSION)" tcc.pod > $@
$(TOPSRC)/texi2pod.pl $< tcc.pod \
&& pod2man --section=1 --center="Tiny C Compiler" --release="$(VERSION)" tcc.pod >tmp.1 \
&& mv tmp.1 $@ || rm -f tmp.1
tcc-doc.info: tcc-doc.texi
-makeinfo $<
makeinfo $< || true
# --------------------------------------------------------------------------
# install
@ -251,35 +255,29 @@ tcc-doc.info: tcc-doc.texi
INSTALL = install -m644
INSTALLBIN = install -m755 $(STRIP_$(CONFIG_strip))
STRIP_yes = -s
install-strip: install
install-strip: CONFIG_strip = yes
TRY-INSTALL = $(if $(wildcard $1),mkdir -p $2 && $(INSTALL) $1 $2)
LIBTCC1_W = $(wildcard $(filter %-win32.a %-wince.a,$(LIBTCC1_CROSS)))
LIBTCC1_U = $(wildcard $(filter-out $(LIBTCC1_W),$(LIBTCC1_CROSS)))
PROGS_X = $(wildcard $(PROGS_CROSS))
LIBTCC1_W = $(filter %-win32-libtcc1.a %-wince-libtcc1.a,$(LIBTCC1_CROSS))
LIBTCC1_U = $(filter-out $(LIBTCC1_W),$(LIBTCC1_CROSS))
IB = $(if $1,mkdir -p $2 && $(INSTALLBIN) $1 $2)
IBw = $(call IB,$(wildcard $1),$2)
IF = $(if $1,mkdir -p $2 && $(INSTALL) $1 $2)
IFw = $(call IF,$(wildcard $1),$2)
IR = mkdir -p $2 && cp -r $1/. $2
# install progs & libs
install-unx:
mkdir -p "$(bindir)"
$(INSTALLBIN) $(PROGS) $(PROGS_X) "$(bindir)"
mkdir -p "$(tccdir)"
$(INSTALL) $(LIBTCC1) $(LIBTCC1_U) "$(tccdir)"
mkdir -p "$(tccdir)/include"
$(INSTALL) $(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h "$(tccdir)/include"
mkdir -p "$(libdir)"
$(INSTALL) $(LIBTCC) "$(libdir)"
mkdir -p "$(includedir)"
$(INSTALL) $(TOPSRC)/libtcc.h "$(includedir)"
$(call TRY-INSTALL,tcc.1,"$(mandir)/man1")
$(call TRY-INSTALL,tcc-doc.info,"$(infodir)")
$(call TRY-INSTALL,tcc-doc.html,"$(docdir)")
ifneq "$(LIBTCC1_W)" ""
mkdir -p "$(tccdir)/win32/lib"
$(INSTALL) $(TOPSRC)/win32/lib/*.def $(LIBTCC1_W) "$(tccdir)/win32/lib"
mkdir -p "$(tccdir)/win32/include"
cp -r $(TOPSRC)/win32/include/. "$(tccdir)/win32/include"
$(INSTALL) $(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h "$(tccdir)/win32/include"
$(call IBw,$(PROGS) $(PROGS_CROSS),"$(bindir)")
$(call IFw,$(LIBTCC1) $(LIBTCC1_U),"$(tccdir)")
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include")
$(call $(if $(findstring .so,$(LIBTCC)),IBw,IFw),$(LIBTCC),"$(libdir)")
$(call IF,$(TOPSRC)/libtcc.h,"$(includedir)")
$(call IFw,tcc.1,"$(mandir)/man1")
$(call IFw,tcc-doc.info,"$(infodir)")
$(call IFw,tcc-doc.html,"$(docdir)")
ifneq "$(wildcard $(LIBTCC1_W))" ""
$(call IFw,$(TOPSRC)/win32/lib/*.def $(LIBTCC1_W),"$(tccdir)/win32/lib")
$(call IR,$(TOPSRC)/win32/include,"$(tccdir)/win32/include")
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/win32/include")
endif
# uninstall
@ -292,33 +290,32 @@ uninstall-unx:
# install progs & libs on windows
install-win:
mkdir -p "$(tccdir)"
$(INSTALL) $(PROGS) $(subst libtcc.a,,$(LIBTCC)) $(PROGS_X) "$(tccdir)"
mkdir -p "$(tccdir)/lib"
$(INSTALL) $(TOPSRC)/win32/lib/*.def "$(tccdir)/lib"
$(INSTALL) libtcc1.a $(LIBTCC1_W) "$(tccdir)/lib"
mkdir -p "$(tccdir)/include"
cp -r $(TOPSRC)/win32/include/. "$(tccdir)/include"
$(INSTALL) $(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h "$(tccdir)/include"
mkdir -p "$(tccdir)/examples"
cp -r $(TOPSRC)/win32/examples/. "$(tccdir)/examples"
$(INSTALL) $(TOPSRC)/tests/libtcc_test.c "$(tccdir)/examples"
mkdir -p "$(tccdir)/libtcc"
$(INSTALL) $(TOPSRC)/libtcc.h $(subst .dll,.def,$(LIBTCC)) "$(tccdir)/libtcc"
mkdir -p "$(tccdir)/doc"
$(INSTALL) $(TOPSRC)/win32/tcc-win32.txt $(wildcard tcc-doc.html) "$(tccdir)/doc"
ifneq "$(LIBTCC1_U)" ""
$(INSTALL) $(LIBTCC1_U) "$(tccdir)/lib"
mkdir -p "$(tccdir)/lib/include";
$(INSTALL) $(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h "$(tccdir)/lib/include"
$(call IBw,$(PROGS) $(PROGS_CROSS) $(subst libtcc.a,,$(LIBTCC)),"$(bindir)")
$(call IF,$(TOPSRC)/win32/lib/*.def,"$(tccdir)/lib")
$(call IFw,libtcc1.a $(LIBTCC1_W),"$(tccdir)/lib")
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include")
$(call IR,$(TOPSRC)/win32/include,"$(tccdir)/include")
$(call IR,$(TOPSRC)/win32/examples,"$(tccdir)/examples")
$(call IF,$(TOPSRC)/tests/libtcc_test.c,"$(tccdir)/examples")
$(call IFw,$(TOPSRC)/libtcc.h $(subst .dll,.def,$(LIBTCC)),"$(libdir)")
$(call IFw,$(TOPSRC)/win32/tcc-win32.txt tcc-doc.html,"$(docdir)")
ifneq "$(wildcard $(LIBTCC1_U))" ""
$(call IFw,$(LIBTCC1_U),"$(tccdir)/lib")
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/lib/include")
endif
# the msys-git shell works to configure && make except it does not have install
ifeq "$(and $(CONFIG_WIN32),$(shell which install >/dev/null 2>&1 || echo no))" "no"
install-win : INSTALL = cp
install-win : INSTALLBIN = cp
endif
# uninstall on windows
uninstall-win:
rm -r "$(tccdir)/"*
@rm -fv $(foreach P,$(PROGS) $(PROGS_CROSS) libtcc.dll,"$(bindir)/$P")
@rm -fv $(foreach F,tcc-doc.html tcc-win32.txt,"$(docdir)/$F")
@rm -fv $(foreach F,libtcc.h libtcc.def libtcc.a,"$(libdir)/$F")
rm -r "$(tccdir)"
# --------------------------------------------------------------------------
# other stuff
@ -345,15 +342,21 @@ tar: tcc-doc.html
config.mak:
$(if $(wildcard $@),,@echo "Please run ./configure." && exit 1)
# in tests subdir
# run all tests
test:
$(MAKE) -C tests
# run test(s) from tests2 subdir (see make help)
tests2.%:
$(MAKE) -C tests/tests2 $@
testspp.%:
$(MAKE) -C tests/pp $@
clean:
rm -f $(PROGS) $(PROGS_CROSS) tcc_p$(EXESUF) tcc.pod
rm -f tcc$(EXESUF) tcc_p$(EXESUF) *-tcc$(EXESUF) tcc.pod
rm -f *~ *.o *.a *.so* *.out *.log lib*.def *.exe *.dll a.out tags TAGS
@$(MAKE) -C tests $@
@$(MAKE) -C lib $@
@$(MAKE) -C tests $@
distclean: clean
rm -f config.h config.mak config.texi tcc.1 tcc-doc.info tcc-doc.html
@ -374,19 +377,32 @@ help:
@echo " build one specific cross compiler for 'TARGET', as in"
@echo " $(TCC_X)"
@echo ""
@echo "Cross compiler configuration:"
@echo " make will read custom configuration for cross compilers from a file"
@echo " 'config-cross.mak' if present. For example for a windows->i386-linux"
@echo " cross-compiler that expects the linux files in <tccdir>/i386-linux:"
@echo "Custom configuration:"
@echo " The makefile includes a file 'config-extra.mak' if it is present."
@echo " This file may contain some custom configuration. For example:"
@echo ""
@echo " ROOT-i386 = {B}/i386-linux"
@echo " CRT-i386 = {B}/i386-linux/usr/lib"
@echo " LIB-i386 = {B}/i386-linux/lib:{B}/i386-linux/usr/lib"
@echo " INC-i386 = {B}/lib/include:{B}/i386-linux/usr/include"
@echo " DEF-i386 += -D__linux__"
@echo " NATIVE_DEFINES += -D..."
@echo ""
@echo " Or for example to configure the search paths for a cross-compiler"
@echo " that expects the linux files in <tccdir>/i386-linux:"
@echo ""
@echo " ROOT-i386 = {B}/i386-linux"
@echo " CRT-i386 = {B}/i386-linux/usr/lib"
@echo " LIB-i386 = {B}/i386-linux/lib:{B}/i386-linux/usr/lib"
@echo " INC-i386 = {B}/lib/include:{B}/i386-linux/usr/include"
@echo " DEF-i386 += -D__linux__"
@echo ""
@echo "make test"
@echo " run all tests"
@echo ""
@echo "make tests2.all / make tests2.37 / make tests2.37+"
@echo " run all/single test(s) from tests2, optionally update .expect"
@echo "make testspp.all / make testspp.17"
@echo " run all/single test(s) from tests/pp"
@echo ""
@echo "Other supported make targets:"
@echo " install install-strip test tags ETAGS tar clean distclean help"
@echo " install install-strip tags ETAGS tar clean distclean help"
@echo ""
# --------------------------------------------------------------------------
endif # ($(INCLUDED),no)

67
README
View File

@ -1,3 +1,70 @@
Bootstrappable TCC/TinyCC -- Tiny C Compiler's bootstrappable fork
------------------------------------------------------------------
Bootstrappable TCC is a fork from mainline TCC development, that
started spring 2017 from
commit 307b7b183d4ee56e74090b0e525d6a587840e31f
Author: Aron BARATH <baratharon@caesar.elte.hu>
Date: Tue May 16 07:03:26 2017 +0200
the R_X86_64_GOTOFF64 relocation was missing
and can be compiled by MesCC (https://gnu.org/s/mes).
Initially the plan was to make TinyCC itself "bootstrappable"
(https://bootstrappable.org).
The best way to do so would be to gradually simplify the
implementation of TinyCC by restricting the use of language constructs
to a well-defined subset of C. In bootstrapping each stage or
compiler adds functionality; a compiler that is written in itself --a
so-called `self-hosting' compiler--is not considered to be
bootstrappable.
At the time this vision was not received with much enthousiasm
https://lists.nongnu.org/archive/html/tinycc-devel/2017-09/msg00019.html
so I decided to fork TinyCC and instead grow MesCC (a bootstrappable
sub-C compiler in a subset of Guile Scheme) into a full C99 compiler.
Currently, the Reduced Binary Seed Bootstrap of the GNU Guix System
(https://guix.gnu.org/blog/2019/guix-reduces-bootstrap-seed-by-50/)
uses bootstrappable-tinycc.
The fork consists of about 12 patches
cee58e0 build: Support building from bootstrap-mes.
39de356 bootstrappable: Force static link.
2b6271d bootstrappable: Work around MesCC bug.
379c62d bootstrappable: add tcc.h include guards to include location.
274bd06 bootstrappable: Handle libtcc1.a.
6ae9aa4 bootstrappable: Skip tidy_section_headers.
a130ce1 bootstrappable: HAVE_FLOAT.
de906df bootstrappable: HAVE_BITFIELD.
540ba0b bootstrappable: HAVE_LONG_LONG.
306f677 bootstrappable: Work around Nyacc-0.80.42 bug.
9c97705 build: bootstrap build scripts.
584478f bootstrappable: Remove non-free grep test.
that work around bugs and missing C language features in MesCC. Only
three of these are really interesting: the HAVE_* patches that allow
for stepwise introduction of bitfields, doubles/floats and long longs.
In time, I hope we can remove the need for this fork; either by
upstreaming some bootstrappable work or else by maturing MesCC.
At the time of writing, mainline (non-bootstrappable) tinycc lives
here
https://repo.or.cz/tinycc.git
https://lists.nongnu.org/mailman/listinfo/tinycc-devel
--
janneke
Tiny C Compiler - C Scripting Everywhere - The Smallest ANSI C compiler
-----------------------------------------------------------------------

View File

@ -70,7 +70,6 @@ ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
uint8_t *clobber_regs,
int out_reg)
{
asm_error();
}
ST_FUNC void asm_compute_constraints(ASMOperand *operands,
@ -78,7 +77,6 @@ ST_FUNC void asm_compute_constraints(ASMOperand *operands,
const uint8_t *clobber_regs,
int *pout_reg)
{
asm_error();
}
ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str)

View File

@ -1221,7 +1221,7 @@ void gfunc_call(int nb_args)
int variadic;
if (float_abi == ARM_HARD_FLOAT) {
variadic = (vtop[-nb_args].type.ref->c == FUNC_ELLIPSIS);
variadic = (vtop[-nb_args].type.ref->f.func_type == FUNC_ELLIPSIS);
if (variadic || floats_in_core_regs(&vtop[-nb_args]))
float_abi = ARM_SOFTFP_FLOAT;
}
@ -1279,7 +1279,7 @@ void gfunc_prolog(CType *func_type)
sym = func_type->ref;
func_vt = sym->type;
func_var = (func_type->ref->c == FUNC_ELLIPSIS);
func_var = (func_type->ref->f.func_type == FUNC_ELLIPSIS);
n = nf = 0;
if ((func_vt.t & VT_BTYPE) == VT_STRUCT &&
@ -1410,6 +1410,16 @@ void gfunc_epilog(void)
}
}
ST_FUNC void gen_fill_nops(int bytes)
{
if ((bytes & 3))
tcc_error("alignment of code section not multiple of 4");
while (bytes > 0) {
o(0xE1A00000);
bytes -= 4;
}
}
/* generate a jump to a label */
int gjmp(int t)
{
@ -1783,7 +1793,7 @@ static uint32_t is_fconst()
}
/* generate a floating point operation 'v = t1 op t2' instruction. The
two operands are guaranted to have the same floating point type */
two operands are guaranteed to have the same floating point type */
void gen_opf(int op)
{
uint32_t x, r, r2, c1, c2;

View File

@ -382,6 +382,12 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
/* Nothing to do. Normally used to indicate a dependency
on a certain symbol (like for exception handling under EABI). */
return;
case R_ARM_RELATIVE:
#ifdef TCC_TARGET_PE
add32le(ptr, val - s1->pe_imagebase);
#endif
/* do nothing */
return;
default:
fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n",
type, (unsigned)addr, ptr, (unsigned)val);

View File

@ -249,7 +249,6 @@ static int arm64_type_size(int t)
case VT_BYTE: return 0;
case VT_SHORT: return 1;
case VT_PTR: return 3;
case VT_ENUM: return 2;
case VT_FUNC: return 3;
case VT_FLOAT: return 2;
case VT_DOUBLE: return 3;
@ -428,7 +427,7 @@ static void arm64_sym(int r, Sym *sym, unsigned long addend)
// relocation and use only relocations with unlimited range.
int avoid_adrp = 1;
if (avoid_adrp || (sym->type.t & VT_WEAK)) {
if (avoid_adrp || sym->a.weak) {
// (GCC uses a R_AARCH64_ABS64 in this case.)
greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G0_NC, addend);
o(0xd2800000 | r); // mov x(rt),#0,lsl #0
@ -581,8 +580,8 @@ ST_FUNC void store(int r, SValue *sv)
static void arm64_gen_bl_or_b(int b)
{
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
assert(!b && (vtop->r & VT_SYM));
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST && (vtop->r & VT_SYM)) {
assert(!b);
greloca(cur_text_section, vtop->sym, ind, R_AARCH64_CALL26, 0);
o(0x94000000); // bl .
}
@ -1277,6 +1276,16 @@ ST_FUNC void gfunc_epilog(void)
o(0xd65f03c0); // ret
}
ST_FUNC void gen_fill_nops(int bytes)
{
if ((bytes & 3))
tcc_error("alignment of code section not multiple of 4");
while (bytes > 0) {
o(0xd503201f); // nop
bytes -= 4;
}
}
// Generate forward branch to label:
ST_FUNC int gjmp(int t)
{

View File

@ -240,6 +240,12 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
#endif
write64le(ptr, val - rel->r_addend);
return;
case R_AARCH64_RELATIVE:
#ifdef TCC_TARGET_PE
add32le(ptr, val - s1->pe_imagebase);
#endif
/* do nothing */
return;
default:
fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n",
type, (unsigned)addr, ptr, (unsigned)val);

View File

@ -1951,12 +1951,12 @@ void gfunc_prolog(CType * func_type)
CType *type;
sym = func_type->ref;
func_call = sym->r;
func_call = sym->f.func_call;
addr = 8;
/* if the function returns a structure, then add an
implicit pointer parameter */
func_vt = sym->type;
func_var = (sym->c == FUNC_ELLIPSIS);
func_var = (sym->f.func_type == FUNC_ELLIPSIS);
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
func_vc = addr;
addr += 4;
@ -2035,6 +2035,16 @@ void gfunc_epilog(void)
}
}
ST_FUNC void gen_fill_nops(int bytes)
{
if ((bytes & 3))
tcc_error("alignment of code section not multiple of 4");
while (bytes > 0) {
C67_NOP(4);
bytes -= 4;
}
}
/* generate a jump to a label */
int gjmp(int t)
{

86
configure vendored
View File

@ -56,7 +56,6 @@ case $targetos in
DLLSUF=".dylib"
;;
MINGW*|MSYS*|CYGWIN*)
confvars="$confvars WIN32"
mingw32=yes
;;
DragonFly|OpenBSD|FreeBSD|NetBSD)
@ -126,8 +125,6 @@ for opt do
;;
--cpu=*) cpu=`echo $opt | cut -d '=' -f 2`
;;
--enable-mingw32) confvars="$confvars WIN32"; mingw32="yes"
;;
--enable-cross) confvars="$confvars cross"
;;
--disable-static) confvars="$confvars static=no"
@ -142,6 +139,8 @@ for opt do
;;
--with-selinux) confvars="$confvars selinux"
;;
--config-mingw32*) mingw32=$(echo "$opt=yes" | cut -d '=' -f 2)
;;
--config-*) confvars="$confvars ${opt#--config-}"; suggest="no"
;;
--help|-h) show_help="yes"
@ -161,7 +160,7 @@ fi
case "$cpu" in
x86|i386|i486|i586|i686|i86pc|BePC|i686-AT386)
cpu="x86"
cpu="i386"
;;
x86_64|amd64|x86-64)
cpu="x86_64"
@ -184,7 +183,7 @@ case "$cpu" in
cpu="arm"
;;
aarch64)
cpu="arm64"
cpu="aarch64"
;;
alpha)
cpu="alpha"
@ -216,22 +215,12 @@ if test "$mingw32" = "yes" ; then
if test "$cc" = gcc; then
test -z "$LDFLAGS" && LDFLAGS="-static"
fi
if test x"$tccdir" = x""; then
tccdir="tcc"
fi
if test -z "$prefix" ; then
prefix="C:/Program Files/${tccdir}"
fi
if test -z "$sharedir" ; then
sharedir="${prefix}"
fi
execprefix="$prefix"
bindir="${prefix}"
tccdir="${prefix}"
libdir="${prefix}/lib"
docdir="${sharedir}/doc"
mandir="${sharedir}/man"
infodir="${sharedir}/info"
test -z "$prefix" && prefix="C:/Program Files/tcc"
test -z "$tccdir" && tccdir="${prefix}"
test -z "$bindir" && bindir="${tccdir}"
test -z "$docdir" && docdir="${tccdir}/doc"
test -z "$libdir" && libdir="${tccdir}/libtcc"
confvars="$confvars WIN32"
LIBSUF=".lib"
EXESUF=".exe"
DLLSUF=".dll"
@ -263,12 +252,11 @@ else
if test x"$tccdir" = x""; then
tccdir="${libdir}/tcc"
fi
if test x"$includedir" = x""; then
includedir="${prefix}/include"
fi
fi # mingw32
if test x"$includedir" = x""; then
includedir="${prefix}/include"
fi
if test x"$show_help" = "xyes" ; then
cat << EOF
Usage: configure [options]
@ -301,8 +289,7 @@ Advanced options (experts only):
--disable-static make libtcc.so instead of libtcc.a
--enable-static make libtcc.a instead of libtcc.dll (win32)
--disable-rpath disable use of -rpath with the above
--with-libgcc use libgcc_s.so.1 instead of libtcc1.a in dynamic link
--enable-mingw32 build windows version on linux with mingw32
--with-libgcc use libgcc_s.so.1 instead of libtcc1.a
--enable-cross build cross compilers
--with-selinux use mmap for executable memory (with tcc -run)
--sysincludepaths=... specify system include paths, colon separated
@ -310,7 +297,7 @@ Advanced options (experts only):
--crtprefix=... specify locations of crt?.o, colon separated
--elfinterp=... specify elf interpreter
--triplet=... specify system library/include directory triplet
--config-uClibc,-musl... enable specific configuration for some systems
--config-uClibc,-musl,-mingw32... enable system specific configurations
EOF
#echo "NOTE: The object files are build at the place where configure is launched"
exit 1
@ -320,15 +307,14 @@ cc="${cross_prefix}${cc}"
ar="${cross_prefix}${ar}"
strip="${cross_prefix}${strip}"
CONFTEST=./conftest$EXESUF
if ! $cc -o $CONFTEST $source_path/conftest.c 2>/dev/null ; then
echo "configure: error: '$cc' failed to compile conftest.c."
else
gcc_major="$($CONFTEST version)"
gcc_minor="$($CONFTEST minor)"
fi
if test -z "$cross_prefix" ; then
CONFTEST=./conftest$EXESUF
if ! $cc -o $CONFTEST $source_path/conftest.c 2>/dev/null ; then
echo "configure: error: '$cc' failed to compile conftest.c."
else
gcc_major="$($CONFTEST version)"
gcc_minor="$($CONFTEST minor)"
fi
bigendian="$($CONFTEST bigendian)"
if test "$mingw32" = "no" ; then
@ -340,7 +326,7 @@ if test -z "$cross_prefix" ; then
fi
if test -z "$triplet"; then
if test $cpu = "x86_64" -o $cpu = "arm64" ; then
if test $cpu = "x86_64" -o $cpu = "aarch64" ; then
if test -f "/usr/lib64/crti.o" ; then
tcc_lddir="lib64"
fi
@ -349,7 +335,7 @@ if test -z "$cross_prefix" ; then
if test "$cpu" = "arm" ; then
if test "${triplet%eabihf}" != "$triplet" ; then
confvars="$confvars arm_eabihf"
confvars="$confvars arm_eabihf arm_vfp"
elif test "${triplet%eabi}" != "$triplet" ; then
confvars="$confvars arm_eabi"
fi
@ -401,16 +387,16 @@ fi
fcho() { if test -n "$2"; then echo "$1$2"; fi }
echo "Binary directory $bindir"
echo "TinyCC directory $tccdir"
echo "Library directory $libdir"
echo "Include directory $includedir"
echo "Manual directory $mandir"
echo "Info directory $infodir"
echo "Doc directory $docdir"
fcho "Binary directory " "$bindir"
fcho "TinyCC directory " "$tccdir"
fcho "Library directory " "$libdir"
fcho "Include directory " "$includedir"
fcho "Manual directory " "$mandir"
fcho "Info directory " "$infodir"
fcho "Doc directory " "$docdir"
fcho "Target root prefix " "$sysroot"
echo "Source path $source_path"
echo "C compiler $cc"
echo "C compiler $cc ($gcc_major.$gcc_minor)"
echo "Target OS $targetos"
echo "CPU $cpu"
fcho "Triplet " "$triplet"
@ -471,15 +457,11 @@ print_mak CONFIG_LDDIR "$tcc_lddir"
print_mak CONFIG_TRIPLET "$triplet"
print_mak_int TCC_CPU_VERSION "$cpuver"
echo "#define GCC_MAJOR $gcc_major" >> $TMPH
echo "#define GCC_MINOR $gcc_minor" >> $TMPH
if test "$cpu" = "x86" ; then
echo "ARCH=i386" >> config.mak
if test "$cpu" = "aarch64" ; then
echo "ARCH=arm64" >> config.mak
else
echo "ARCH=$cpu" >> config.mak
fi
echo "TARGETOS=$targetos" >> config.mak
for v in $confvars ; do

6
elf.h
View File

@ -232,7 +232,7 @@ typedef struct
#define EM_FX66 66 /* Siemens FX66 microcontroller */
#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */
#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */
#define EM_ST7 68 /* STMicroelectronics ST7 8 bit mc */
#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */
#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */
#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */
@ -817,7 +817,7 @@ typedef struct
#define DF_1_EDITED 0x00200000 /* Object is modified after built. */
#define DF_1_NORELOC 0x00400000
#define DF_1_SYMINTPOSE 0x00800000 /* Object has individual interposers. */
#define DF_1_GLOBAUDIT 0x01000000 /* Global auditin required. */
#define DF_1_GLOBAUDIT 0x01000000 /* Global auditing required. */
#define DF_1_SINGLETON 0x02000000 /* Singleton symbols are used. */
/* Flags for the feature selection in DT_FEATURE_1. */
@ -1313,7 +1313,7 @@ typedef struct
#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */
#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */
#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */
#define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */
#define R_SPARC_PC_LM22 39 /* Low middle 22 bits of ... */
#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */
#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */
#define R_SPARC_GLOB_JMP 42 /* was part of v9 ABI but was removed */

View File

@ -500,12 +500,13 @@ ST_FUNC void gen_expr64(ExprValue *pe)
static void gen_disp32(ExprValue *pe)
{
Sym *sym = pe->sym;
if (sym && sym->r == cur_text_section->sh_num) {
ElfSym *esym = elfsym(sym);
if (esym && esym->st_shndx == cur_text_section->sh_num) {
/* same section: we can output an absolute value. Note
that the TCC compiler behaves differently here because
it always outputs a relocation to ease (future) code
elimination in the linker */
gen_le32(pe->v + sym->jnext - ind - 4);
gen_le32(pe->v + esym->st_value - ind - 4);
} else {
if (sym && sym->type.t == VT_VOID) {
sym->type.t = VT_FUNC;
@ -726,6 +727,7 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
s = 0; /* avoid warning */
again:
/* optimize matching by using a lookup table (no hashing is needed
!) */
for(pa = asm_instrs; pa->sym != 0; pa++) {
@ -756,8 +758,9 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
if (!(opcode >= pa->sym && opcode < pa->sym + NB_TEST_OPCODES))
continue;
/* cmovxx is a test opcode but accepts multiple sizes.
TCC doesn't accept the suffixed mnemonic, instead we
simply force size autodetection always. */
The suffixes aren't encoded in the table, instead we
simply force size autodetection always and deal with suffixed
variants below when we don't find e.g. "cmovzl". */
if (pa->instr_type & OPC_WLX)
s = NBWLX - 1;
} else if (pa->instr_type & OPC_B) {
@ -843,8 +846,16 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
tcc_error("bad operand with opcode '%s'",
get_tok_str(opcode, NULL));
} else {
tcc_error("unknown opcode '%s'",
get_tok_str(opcode, NULL));
/* Special case for cmovcc, we accept size suffixes but ignore
them, but we don't want them to blow up our tables. */
TokenSym *ts = table_ident[opcode - TOK_IDENT];
if (ts->len >= 6
&& strchr("wlq", ts->str[ts->len-1])
&& !memcmp(ts->str, "cmov", 4)) {
opcode = tok_alloc(ts->str, ts->len-1)->tok;
goto again;
}
tcc_error("unknown opcode '%s'", ts->str);
}
}
/* if the size is unknown, then evaluate it (OPC_B or OPC_WL case) */
@ -1017,16 +1028,14 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
if (pa->instr_type & OPC_B)
v += s >= 1;
if (nb_ops == 1 && pa->op_type[0] == OPT_DISP8) {
Sym *sym;
ElfSym *esym;
int jmp_disp;
/* see if we can really generate the jump with a byte offset */
sym = ops[0].e.sym;
if (!sym)
esym = elfsym(ops[0].e.sym);
if (!esym || esym->st_shndx != cur_text_section->sh_num)
goto no_short_jump;
if (sym->r != cur_text_section->sh_num)
goto no_short_jump;
jmp_disp = ops[0].e.v + sym->jnext - ind - 2 - (v >= 0xff);
jmp_disp = ops[0].e.v + esym->st_value - ind - 2 - (v >= 0xff);
if (jmp_disp == (int8_t)jmp_disp) {
/* OK to generate jump */
ops[0].e.sym = 0;

View File

@ -157,25 +157,31 @@ static int oad(int c, int s)
return t;
}
ST_FUNC void gen_fill_nops(int bytes)
{
while (bytes--)
g(0x90);
}
/* generate jmp to a label */
#define gjmp2(instr,lbl) oad(instr,lbl)
/* output constant with relocation if 'r & VT_SYM' is true */
ST_FUNC void gen_addr32(int r, Sym *sym, long c)
ST_FUNC void gen_addr32(int r, Sym *sym, int c)
{
if (r & VT_SYM)
greloc(cur_text_section, sym, ind, R_386_32);
gen_le32(c);
}
ST_FUNC void gen_addrpc32(int r, Sym *sym, long c)
ST_FUNC void gen_addrpc32(int r, Sym *sym, int c)
{
if (r & VT_SYM)
greloc(cur_text_section, sym, ind, R_386_PC32);
gen_le32(c - 4);
}
/* generate a modrm reference. 'op_reg' contains the addtional 3
/* generate a modrm reference. 'op_reg' contains the additional 3
opcode bits */
static void gen_modrm(int op_reg, int r, Sym *sym, int c)
{
@ -210,7 +216,7 @@ ST_FUNC void load(int r, SValue *sv)
#endif
fr = sv->r;
ft = sv->type.t;
ft = sv->type.t & ~VT_DEFSIGN;
fc = sv->c.i;
ft &= ~(VT_VOLATILE | VT_CONSTANT);
@ -345,19 +351,18 @@ static void gen_static_call(int v)
static void gcall_or_jmp(int is_jmp)
{
int r;
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
int rt;
/* constant case */
if (vtop->r & VT_SYM) {
/* relocation case */
greloc(cur_text_section, vtop->sym,
ind + 1, R_386_PC32);
} else {
/* put an empty PC32 relocation */
put_elf_reloc(symtab_section, cur_text_section,
ind + 1, R_386_PC32, 0);
}
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST && (vtop->r & VT_SYM)) {
/* constant and relocation case */
greloc(cur_text_section, vtop->sym, ind + 1, R_386_PC32);
oad(0xe8 + is_jmp, vtop->c.i - 4); /* call/jmp im */
} else {
/* otherwise, indirect call */
r = gv(RC_INT);
o(0xff); /* call/jmp *r */
o(0xd0 + r + (is_jmp << 4));
}
if (!is_jmp) {
int rt;
/* extend the return value to the whole register if necessary
visual studio and gcc do not always set the whole eax register
when assigning the return value of a function */
@ -382,11 +387,6 @@ static void gcall_or_jmp(int is_jmp)
default:
break;
}
} else {
/* otherwise, indirect call */
r = gv(RC_INT);
o(0xff); /* call/jmp *r */
o(0xd0 + r + (is_jmp << 4));
}
}
@ -477,7 +477,7 @@ ST_FUNC void gfunc_call(int nb_args)
}
save_regs(0); /* save used temporary registers */
func_sym = vtop->type.ref;
func_call = func_sym->a.func_call;
func_call = func_sym->f.func_call;
/* fast call case */
if ((func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) ||
func_call == FUNC_FASTCALLW) {
@ -504,7 +504,7 @@ ST_FUNC void gfunc_call(int nb_args)
#endif
gcall_or_jmp(0);
if (args_size && func_call != FUNC_STDCALL)
if (args_size && func_call != FUNC_STDCALL && func_call != FUNC_FASTCALLW)
gadd_sp(args_size);
vtop--;
}
@ -525,7 +525,7 @@ ST_FUNC void gfunc_prolog(CType *func_type)
CType *type;
sym = func_type->ref;
func_call = sym->a.func_call;
func_call = sym->f.func_call;
addr = 8;
loc = 0;
func_vc = 0;
@ -547,7 +547,7 @@ ST_FUNC void gfunc_prolog(CType *func_type)
/* if the function returns a structure, then add an
implicit pointer parameter */
func_vt = sym->type;
func_var = (sym->c == FUNC_ELLIPSIS);
func_var = (sym->f.func_type == FUNC_ELLIPSIS);
#ifdef TCC_TARGET_PE
size = type_size(&func_vt,&align);
if (((func_vt.t & VT_BTYPE) == VT_STRUCT)
@ -586,8 +586,8 @@ ST_FUNC void gfunc_prolog(CType *func_type)
param_index++;
}
func_ret_sub = 0;
/* pascal type call ? */
if (func_call == FUNC_STDCALL)
/* pascal type call or fastcall ? */
if (func_call == FUNC_STDCALL || func_call == FUNC_FASTCALLW)
func_ret_sub = addr - 8;
#ifndef TCC_TARGET_PE
else if (func_vc)

View File

@ -226,6 +226,9 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
write16le(ptr, read16le(ptr) + val - addr);
return;
case R_386_RELATIVE:
#ifdef TCC_TARGET_PE
add32le(ptr, val - s1->pe_imagebase);
#endif
/* do nothing */
return;
case R_386_COPY:

View File

@ -16,11 +16,7 @@ typedef struct {
char *reg_save_area;
} __va_list_struct;
/* Avoid conflicting definition for va_list on musl libc */
#ifndef __DEFINED_va_list
typedef __va_list_struct va_list[1];
#define __DEFINED_va_list
#endif
void __va_start(__va_list_struct *ap, void *fp);
void *__va_arg(__va_list_struct *ap, int arg_type, int size, int align);

View File

@ -13,12 +13,20 @@ typedef __SIZE_TYPE__ uintptr_t;
typedef signed char int8_t;
typedef signed short int int16_t;
typedef signed int int32_t;
#ifdef __LP64__
typedef signed long int int64_t;
#else
typedef signed long long int int64_t;
#endif
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
#ifdef __LP64__
typedef unsigned long int uint64_t;
#else
typedef unsigned long long int uint64_t;
#endif
#endif
#ifndef NULL
#define NULL ((void*)0)

View File

@ -7,20 +7,20 @@ include $(TOP)/Makefile
VPATH = $(TOPSRC)/lib $(TOPSRC)/win32/lib
T = $(or $(CROSS_TARGET),$(NATIVE_TARGET),unknown)
X = $(if $(CROSS_TARGET),$(CROSS_TARGET)-)
BIN = $(TOP)/libtcc1$(if $(CROSS_TARGET),-$(CROSS_TARGET)).a
BIN = $(TOP)/$(X)libtcc1.a
TCC = $(TOP)/$(X)tcc$(EXESUF)
XCC = $(TCC)
XAR = $(TCC) -ar
XTCC ?= $(TOP)/$(X)tcc$(EXESUF)
XCC = $(XTCC)
XAR = $(XTCC) -ar
XFLAGS-unx = -B$(TOPSRC)
XFLAGS-win = -B$(TOPSRC)/win32 -I$(TOPSRC)/include
XFLAGS = $(XFLAGS$(XCFG))
XCFG = $(or $(findstring -win,$T),-unx)
# in order to use gcc, tyoe: make <target>lib-usegcc=yes
armlib-usegcc ?= no
# in order to use gcc, tyoe: make <target>-libtcc1-usegcc=yes
arm-libtcc1-usegcc ?= no
ifeq "$($(X)$(T)lib-usegcc)" "yes"
ifeq "$($(T)-libtcc1-usegcc)" "yes"
XCC = $(CC)
XAR = $(AR)
XFLAGS = $(CFLAGS) -fPIC
@ -29,7 +29,7 @@ endif
# only for native compiler
$(X)BCHECK_O = bcheck.o
ifeq ($(CONFIG_musl),yes)
ifeq ($(CONFIG_musl)$(CONFIG_uClibc),yes)
BCHECK_O =
endif
@ -61,10 +61,10 @@ $(BIN) : $(patsubst %.o,$(X)%.o,$(OBJ-$T))
$(XAR) rcs $@ $^
$(X)%.o : %.c
$(XCC) -c $< -o $@ $(DEFINES) $(XFLAGS)
$(XCC) -c $< -o $@ $(XFLAGS)
$(X)%.o : %.S
$(XCC) -c $< -o $@ $(DEFINES) $(XFLAGS)
$(XCC) -c $< -o $@ $(XFLAGS)
$(X)crt1w.o : crt1.c
$(X)wincrt1w.o : wincrt1.c

View File

@ -11,7 +11,7 @@ __bound_alloca:
and $-4,%eax
jz p6
#ifdef TCC_TARGET_PE
#ifdef _WIN32
p4:
cmp $4096,%eax
jbe p5

View File

@ -10,7 +10,7 @@ alloca:
and $-4,%eax
jz p3
#ifdef TCC_TARGET_PE
#ifdef _WIN32
p1:
cmp $4096,%eax
jbe p2

View File

@ -4,7 +4,7 @@
.globl __bound_alloca
__bound_alloca:
#ifdef TCC_TARGET_PE
#ifdef _WIN32
# bound checking is not implemented
pop %rdx
mov %rcx,%rax

View File

@ -5,7 +5,7 @@
alloca:
pop %rdx
#ifdef TCC_TARGET_PE
#ifdef _WIN32
mov %rcx,%rax
#else
mov %rdi,%rax
@ -14,7 +14,7 @@ alloca:
and $-16,%rax
jz p3
#ifdef TCC_TARGET_PE
#ifdef _WIN32
p1:
cmp $4096,%rax
jbe p2
@ -27,10 +27,6 @@ p2:
sub %rax,%rsp
mov %rsp,%rax
#ifdef TCC_TARGET_PE
add $32,%rax
#endif
p3:
push %rdx
ret

View File

@ -21,10 +21,15 @@
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) \
&& !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
#if !defined(__FreeBSD__) \
&& !defined(__FreeBSD_kernel__) \
&& !defined(__DragonFly__) \
&& !defined(__OpenBSD__) \
&& !defined(__NetBSD__)
#include <malloc.h>
#endif
#if !defined(_WIN32)
#include <unistd.h>
#endif
@ -45,10 +50,13 @@
#define CONFIG_TCC_MALLOC_HOOKS
#define HAVE_MEMALIGN
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
|| defined(__DragonFly__) || defined(__dietlibc__) \
|| defined(__UCLIBC__) || defined(__OpenBSD__) || defined(__NetBSD__) \
|| defined(_WIN32) || defined(TCC_UCLIBC) || defined(TCC_MUSL)
#if defined(__FreeBSD__) \
|| defined(__FreeBSD_kernel__) \
|| defined(__DragonFly__) \
|| defined(__OpenBSD__) \
|| defined(__NetBSD__) \
|| defined(__dietlibc__) \
|| defined(_WIN32)
//#warning Bound checking does not support malloc (etc.) in this environment.
#undef CONFIG_TCC_MALLOC_HOOKS
#undef HAVE_MEMALIGN
@ -236,7 +244,7 @@ BOUND_PTR_INDIR(16)
#if defined(__GNUC__) && (__GNUC__ >= 6)
/*
* At least gcc 6.2 complains when __builtin_frame_address is used whith
* At least gcc 6.2 complains when __builtin_frame_address is used with
* nonzero argument.
*/
#pragma GCC diagnostic push

View File

@ -107,10 +107,10 @@ union float_long {
};
/* XXX: we don't support several builtin supports for now */
#if !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_ARM)
#if !defined __x86_64__ && !defined __arm__
/* XXX: use gcc/tcc intrinsic ? */
#if defined(TCC_TARGET_I386)
#if defined __i386__
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("subl %5,%1\n\tsbbl %3,%0" \
: "=r" ((USItype) (sh)), \
@ -589,7 +589,7 @@ long long __fixdfdi (double a1)
return s ? ret : -ret;
}
#ifndef TCC_TARGET_ARM
#ifndef __arm__
unsigned long long __fixunsxfdi (long double a1)
{
register union ldouble_long dl1;

View File

@ -1,6 +1,6 @@
/* va_list.c - tinycc support for va_list on X86_64 */
#if defined TCC_TARGET_X86_64
#if defined __x86_64__
/* Avoid include files, they may not be available when cross compiling */
extern void *memset(void *s, int c, __SIZE_TYPE__ n);

219
libtcc.c
View File

@ -36,7 +36,7 @@ static int nb_states;
/********************************************************/
#ifdef ONE_SOURCE
#if ONE_SOURCE
#include "tccpp.c"
#include "tccgen.c"
#include "tccelf.c"
@ -58,6 +58,7 @@ static int nb_states;
#ifdef TCC_TARGET_C67
#include "c67-gen.c"
#include "c67-link.c"
#include "tcccoff.c"
#endif
#ifdef TCC_TARGET_X86_64
#include "x86_64-gen.c"
@ -67,9 +68,6 @@ static int nb_states;
#ifdef CONFIG_TCC_ASM
#include "tccasm.c"
#endif
#ifdef TCC_TARGET_COFF
#include "tcccoff.c"
#endif
#ifdef TCC_TARGET_PE
#include "tccpe.c"
#endif
@ -106,10 +104,8 @@ static void tcc_set_lib_path_w32(TCCState *s)
char path[1024], *p;
GetModuleFileNameA(tcc_module, path, sizeof path);
p = tcc_basename(normalize_slashes(strlwr(path)));
if (p - 5 > path && 0 == strncmp(p - 5, "/bin/", 5))
p -= 5;
else if (p > path)
p--;
if (p > path)
--p;
*p = 0;
tcc_set_lib_path(s, path);
}
@ -264,7 +260,7 @@ struct mem_debug_header {
int line_num;
char file_name[MEM_DEBUG_FILE_LEN + 1];
unsigned magic2;
__attribute__((aligned(16))) unsigned magic3;
ALIGNED(16) unsigned magic3;
};
typedef struct mem_debug_header mem_debug_header_t;
@ -442,7 +438,7 @@ static void tcc_split_path(TCCState *s, void *p_ary, int *p_nb_ary, const char *
CString str;
cstr_new(&str);
for (p = in; c = *p, c != '\0' && c != PATHSEP; ++p) {
for (p = in; c = *p, c != '\0' && c != PATHSEP[0]; ++p) {
if (c == '{' && p[1] && p[2] == '}') {
c = p[1], p += 2;
if (c == 'B')
@ -490,7 +486,7 @@ static void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap)
for(pf = s1->include_stack; pf < s1->include_stack_ptr; pf++)
strcat_printf(buf, sizeof(buf), "In file included from %s:%d:\n",
(*pf)->filename, (*pf)->line_num);
if (f->line_num > 0) {
if (s1->error_set_jmp_enabled) {
strcat_printf(buf, sizeof(buf), "%s:%d: ",
f->filename, f->line_num - !!(tok_flags & TOK_FLAG_BOL));
} else {
@ -508,8 +504,9 @@ static void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap)
if (!s1->error_func) {
/* default case: stderr */
if (s1->ppfp) /* print a newline during tcc -E */
fprintf(s1->ppfp, "\n"), fflush(s1->ppfp);
if (s1->output_type == TCC_OUTPUT_PREPROCESS && s1->ppfp == stdout)
/* print a newline during tcc -E */
printf("\n"), fflush(stdout);
fflush(stdout); /* flush -v output */
fprintf(stderr, "%s\n", buf);
fflush(stderr); /* print error/warning now (win32) */
@ -581,15 +578,13 @@ ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen)
bf->buf_end = bf->buffer + initlen;
bf->buf_end[0] = CH_EOB; /* put eob symbol */
pstrcpy(bf->filename, sizeof(bf->filename), filename);
pstrcpy(bf->filename2, sizeof(bf->filename2), filename);
#ifdef _WIN32
normalize_slashes(bf->filename);
#endif
bf->true_filename = bf->filename;
bf->line_num = 1;
bf->ifdef_stack_ptr = s1->ifdef_stack_ptr;
bf->fd = -1;
bf->prev = file;
file = bf;
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
}
ST_FUNC void tcc_close(void)
@ -599,6 +594,8 @@ ST_FUNC void tcc_close(void)
close(bf->fd);
total_lines += bf->line_num;
}
if (bf->true_filename != bf->filename)
tcc_free(bf->true_filename);
file = bf->prev;
tcc_free(bf);
}
@ -615,49 +612,50 @@ ST_FUNC int tcc_open(TCCState *s1, const char *filename)
(int)(s1->include_stack_ptr - s1->include_stack), "", filename);
if (fd < 0)
return -1;
tcc_open_bf(s1, filename, 0);
#ifdef _WIN32
normalize_slashes(file->filename);
#endif
file->fd = fd;
return fd;
}
/* compile the C file opened in 'file'. Return non zero if errors. */
static int tcc_compile(TCCState *s1)
/* compile the file opened in 'file'. Return non zero if errors. */
static int tcc_compile(TCCState *s1, int filetype)
{
Sym *define_start;
int is_asm;
define_start = define_stack;
is_asm = !!(filetype & (AFF_TYPE_ASM|AFF_TYPE_ASMPP));
tccelf_begin_file(s1);
if (setjmp(s1->error_jmp_buf) == 0) {
s1->nb_errors = 0;
s1->error_set_jmp_enabled = 1;
preprocess_start(s1);
tccgen_start(s1);
#ifdef INC_DEBUG
printf("%s: **** new file\n", file->filename);
preprocess_start(s1, is_asm);
if (s1->output_type == TCC_OUTPUT_PREPROCESS) {
tcc_preprocess(s1);
} else if (is_asm) {
#ifdef CONFIG_TCC_ASM
tcc_assemble(s1, !!(filetype & AFF_TYPE_ASMPP));
#else
tcc_error_noabort("asm not supported");
#endif
ch = file->buf_ptr[0];
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | PARSE_FLAG_TOK_STR;
next();
decl(VT_CONST);
if (tok != TOK_EOF)
expect("declaration");
/* free defines here already on behalf of of M.M.'s possibly existing
experimental preprocessor implementation. The normal call below
is still there to free after error-longjmp */
free_defines(define_start);
tccgen_end(s1);
} else {
tccgen_compile(s1);
}
}
s1->error_set_jmp_enabled = 0;
preprocess_end(s1);
free_inline_functions(s1);
/* reset define stack, but keep -D and built-ins */
free_defines(define_start);
sym_pop(&global_stack, NULL, 0);
sym_pop(&local_stack, NULL, 0);
tccelf_end_file(s1);
return s1->nb_errors != 0 ? -1 : 0;
}
@ -668,7 +666,7 @@ LIBTCCAPI int tcc_compile_string(TCCState *s, const char *str)
len = strlen(str);
tcc_open_bf(s, "<string>", len);
memcpy(file->buffer, str, len);
ret = tcc_compile(s);
ret = tcc_compile(s, s->filetype);
tcc_close();
return ret;
}
@ -690,10 +688,8 @@ LIBTCCAPI void tcc_define_symbol(TCCState *s1, const char *sym, const char *valu
memcpy(file->buffer + len1 + 1, value, len2);
/* parse with define parser */
ch = file->buf_ptr[0];
next_nomacro();
parse_define();
tcc_close();
}
@ -714,6 +710,8 @@ static void tcc_cleanup(void)
{
if (NULL == tcc_state)
return;
while (file)
tcc_close();
tccpp_delete(tcc_state);
tcc_state = NULL;
/* free sym_pools */
@ -734,9 +732,9 @@ LIBTCCAPI TCCState *tcc_new(void)
tcc_state = s;
++nb_states;
s->alacarte_link = 1;
s->nocommon = 1;
s->warn_implicit_function_declaration = 1;
s->ms_extensions = 1;
#ifdef CHAR_IS_UNSIGNED
s->char_is_unsigned = 1;
@ -762,6 +760,7 @@ LIBTCCAPI TCCState *tcc_new(void)
define_push(TOK___FILE__, MACRO_OBJ, NULL, NULL);
define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL);
define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL);
define_push(TOK___COUNTER__, MACRO_OBJ, NULL, NULL);
{
/* define __TINYC__ 92X */
char buffer[32]; int a,b,c;
@ -803,6 +802,8 @@ LIBTCCAPI TCCState *tcc_new(void)
#endif
#elif defined(TCC_TARGET_ARM64)
tcc_define_symbol(s, "__aarch64__", NULL);
#elif defined TCC_TARGET_C67
tcc_define_symbol(s, "__C67__", NULL);
#endif
#ifdef TCC_TARGET_PE
@ -826,36 +827,32 @@ LIBTCCAPI TCCState *tcc_new(void)
# if defined(__FreeBSD_kernel__)
tcc_define_symbol(s, "__FreeBSD_kernel__", NULL);
# endif
#endif
# if defined(__NetBSD__)
tcc_define_symbol(s, "__NetBSD__", "__NetBSD__");
# endif
# if defined(__OpenBSD__)
tcc_define_symbol(s, "__OpenBSD__", "__OpenBSD__");
# endif
#endif
/* TinyCC & gcc defines */
#if defined(TCC_TARGET_PE) && PTR_SIZE == 8
#if PTR_SIZE == 4
/* 32bit systems. */
tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned int");
tcc_define_symbol(s, "__PTRDIFF_TYPE__", "int");
tcc_define_symbol(s, "__ILP32__", NULL);
#elif LONG_SIZE == 4
/* 64bit Windows. */
tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long long");
tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long long");
tcc_define_symbol(s, "__LLP64__", NULL);
#elif PTR_SIZE == 8
#else
/* Other 64bit systems. */
tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long");
tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long");
tcc_define_symbol(s, "__LP64__", NULL);
#else
/* Other 32bit systems. */
tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long");
tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long");
tcc_define_symbol(s, "__ILP32__", NULL);
#endif
#if defined(TCC_MUSL)
tcc_define_symbol(s, "__builtin_va_list", "void *");
#endif /* TCC_MUSL */
#ifdef TCC_TARGET_PE
tcc_define_symbol(s, "__WCHAR_TYPE__", "unsigned short");
tcc_define_symbol(s, "__WINT_TYPE__", "unsigned short");
@ -882,6 +879,11 @@ LIBTCCAPI TCCState *tcc_new(void)
tcc_define_symbol(s, "__REDIRECT_NTH(name, proto, alias)",
"name proto __asm__ (#alias) __THROW");
# endif
# if defined(TCC_MUSL)
tcc_define_symbol(s, "__DEFINED_va_list", "");
tcc_define_symbol(s, "__DEFINED___isoc_va_list", "");
tcc_define_symbol(s, "__isoc_va_list", "void *");
# endif /* TCC_MUSL */
/* Some GCC builtins that are simple to express as macros. */
tcc_define_symbol(s, "__builtin_extract_return_addr(x)", "x");
#endif /* ndef TCC_TARGET_PE */
@ -992,26 +994,7 @@ LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname)
ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
{
int ret, filetype;
filetype = flags & 0x0F;
if (filetype == 0) {
/* use a file extension to detect a filetype */
const char *ext = tcc_fileextension(filename);
if (ext[0]) {
ext++;
if (!strcmp(ext, "S"))
filetype = AFF_TYPE_ASMPP;
else if (!strcmp(ext, "s"))
filetype = AFF_TYPE_ASM;
else if (!PATHCMP(ext, "c") || !PATHCMP(ext, "i"))
filetype = AFF_TYPE_C;
else
filetype = AFF_TYPE_BIN;
} else {
filetype = AFF_TYPE_C;
}
}
int ret;
/* open the file */
ret = tcc_open(s1, filename);
@ -1025,26 +1008,7 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
dynarray_add(&s1->target_deps, &s1->nb_target_deps,
tcc_strdup(filename));
parse_flags = 0;
/* if .S file, define __ASSEMBLER__ like gcc does */
if (filetype == AFF_TYPE_ASM || filetype == AFF_TYPE_ASMPP) {
tcc_define_symbol(s1, "__ASSEMBLER__", NULL);
parse_flags = PARSE_FLAG_ASM_FILE;
}
if (flags & AFF_PREPROCESS) {
ret = tcc_preprocess(s1);
} else if (filetype == AFF_TYPE_C) {
ret = tcc_compile(s1);
#ifdef CONFIG_TCC_ASM
} else if (filetype == AFF_TYPE_ASMPP) {
/* non preprocessed assembler */
ret = tcc_assemble(s1, 1);
} else if (filetype == AFF_TYPE_ASM) {
/* preprocessed assembler */
ret = tcc_assemble(s1, 0);
#endif
} else {
if (flags & AFF_TYPE_BIN) {
ElfW(Ehdr) ehdr;
int fd, obj_type;
@ -1052,11 +1016,8 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
obj_type = tcc_object_type(fd, &ehdr);
lseek(fd, 0, SEEK_SET);
/* do not display line number if error */
file->line_num = 0;
#ifdef TCC_TARGET_MACHO
if (0 == obj_type && 0 == strcmp(tcc_fileextension(filename), "dylib"))
if (0 == obj_type && 0 == strcmp(tcc_fileextension(filename), ".dylib"))
obj_type = AFF_BINTYPE_DYN;
#endif
@ -1079,7 +1040,7 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
break;
#endif
case AFF_BINTYPE_AR:
ret = tcc_load_archive(s1, fd);
ret = tcc_load_archive(s1, fd, !(flags & AFF_WHOLE_ARCHIVE));
break;
#ifdef TCC_TARGET_COFF
case AFF_BINTYPE_C67:
@ -1097,6 +1058,8 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
tcc_error_noabort("unrecognized file type");
break;
}
} else {
ret = tcc_compile(s1, flags);
}
tcc_close();
return ret;
@ -1104,10 +1067,25 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename)
{
if (s->output_type == TCC_OUTPUT_PREPROCESS)
return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR | AFF_PREPROCESS | s->filetype);
else
return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR | s->filetype);
int filetype = s->filetype;
if (0 == (filetype & AFF_TYPE_MASK)) {
/* use a file extension to detect a filetype */
const char *ext = tcc_fileextension(filename);
if (ext[0]) {
ext++;
if (!strcmp(ext, "S"))
filetype = AFF_TYPE_ASMPP;
else if (!strcmp(ext, "s"))
filetype = AFF_TYPE_ASM;
else if (!PATHCMP(ext, "c") || !PATHCMP(ext, "i"))
filetype = AFF_TYPE_C;
else
filetype |= AFF_TYPE_BIN;
} else {
filetype = AFF_TYPE_C;
}
}
return tcc_add_file_internal(s, filename, filetype | AFF_PRINT_ERROR);
}
LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname)
@ -1159,9 +1137,10 @@ LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname)
const char *libs[] = { "%s/lib%s.so", "%s/lib%s.a", NULL };
const char **pp = s->static_link ? libs + 1 : libs;
#endif
int flags = s->filetype & AFF_WHOLE_ARCHIVE;
while (*pp) {
if (0 == tcc_add_library_internal(s, *pp,
libraryname, 0, s->library_paths, s->nb_library_paths))
libraryname, flags, s->library_paths, s->nb_library_paths))
return 0;
++pp;
}
@ -1386,6 +1365,8 @@ static int tcc_set_linker(TCCState *s, const char *option)
ignoring = 1;
} else if (link_option(option, "export-all-symbols", &p)) {
s->rdynamic = 1;
} else if (link_option(option, "export-dynamic", &p)) {
s->rdynamic = 1;
} else if (link_option(option, "rpath=", &p)) {
copy_linker_arg(&s->rpath, p, ':');
} else if (link_option(option, "enable-new-dtags", &p)) {
@ -1427,7 +1408,10 @@ static int tcc_set_linker(TCCState *s, const char *option)
goto err;
#endif
} else if (ret = link_option(option, "?whole-archive", &p), ret) {
s->alacarte_link = ret < 0;
if (ret > 0)
s->filetype |= AFF_WHOLE_ARCHIVE;
else
s->filetype &= ~AFF_WHOLE_ARCHIVE;
} else if (p) {
return 0;
} else {
@ -1518,7 +1502,7 @@ static const TCCOption tcc_options[] = {
{ "P", TCC_OPTION_P, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "L", TCC_OPTION_L, TCC_OPTION_HAS_ARG },
{ "B", TCC_OPTION_B, TCC_OPTION_HAS_ARG },
{ "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG },
{ "bench", TCC_OPTION_bench, 0 },
#ifdef CONFIG_TCC_BACKTRACE
{ "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG },
@ -1553,7 +1537,6 @@ static const TCCOption tcc_options[] = {
{ "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "f", TCC_OPTION_f, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "isystem", TCC_OPTION_isystem, TCC_OPTION_HAS_ARG },
{ "iwithprefix", TCC_OPTION_iwithprefix, TCC_OPTION_HAS_ARG },
{ "include", TCC_OPTION_include, TCC_OPTION_HAS_ARG },
{ "nostdinc", TCC_OPTION_nostdinc, 0 },
{ "nostdlib", TCC_OPTION_nostdlib, 0 },
@ -1614,7 +1597,6 @@ static void args_parser_add_file(TCCState *s, const char* filename, int filetype
{
struct filespec *f = tcc_malloc(sizeof *f + strlen(filename));
f->type = filetype;
f->alacarte = s->alacarte_link;
strcpy(f->name, filename);
dynarray_add(&s->files, &s->nb_files, f);
}
@ -1688,7 +1670,6 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv, int optind)
int last_o = -1;
int x;
CString linker_arg; /* collect -Wl options */
char buf[1024];
int tool = 0, arg_start = 0, noaction = optind;
char **argv = *pargv;
int argc = *pargc;
@ -1762,7 +1743,7 @@ reparse:
tcc_set_lib_path(s, optarg);
break;
case TCC_OPTION_l:
args_parser_add_file(s, optarg, AFF_TYPE_LIB);
args_parser_add_file(s, optarg, AFF_TYPE_LIB | (s->filetype & ~AFF_TYPE_MASK));
s->nb_libraries++;
break;
case TCC_OPTION_pthread:
@ -1798,6 +1779,10 @@ reparse:
s->dflag = 3;
else if (*optarg == 'M')
s->dflag = 7;
else if (*optarg == 't')
s->dflag = 16;
else if (isnum(*optarg))
g_debug = atoi(optarg);
else
goto unsupported_option;
break;
@ -1829,10 +1814,6 @@ reparse:
case TCC_OPTION_isystem:
tcc_add_sysinclude_path(s, optarg);
break;
case TCC_OPTION_iwithprefix:
snprintf(buf, sizeof buf, "{B}/%s", optarg);
tcc_add_sysinclude_path(s, buf);
break;
case TCC_OPTION_include:
dynarray_add(&s->cmd_include_files,
&s->nb_cmd_include_files, tcc_strdup(optarg));
@ -1916,14 +1897,18 @@ reparse:
exit(0);
break;
case TCC_OPTION_x:
x = 0;
if (*optarg == 'c')
s->filetype = AFF_TYPE_C;
x = AFF_TYPE_C;
else if (*optarg == 'a')
s->filetype = AFF_TYPE_ASMPP;
x = AFF_TYPE_ASMPP;
else if (*optarg == 'b')
x = AFF_TYPE_BIN;
else if (*optarg == 'n')
s->filetype = AFF_TYPE_NONE;
x = AFF_TYPE_NONE;
else
tcc_warning("unsupported language '%s'", optarg);
s->filetype = x | (s->filetype & ~AFF_TYPE_MASK);
break;
case TCC_OPTION_O:
last_o = atoi(optarg);

View File

@ -322,6 +322,11 @@ Binary image (only for executable output)
COFF output format (only for executable output for TMS320C67xx target)
@end table
@item -Wl,--export-all-symbols
@item -Wl,--export-dynamic
Export global symbols to the dynamic linker. It is useful when a library
opened with @code{dlopen()} needs to access executable symbols.
@item -Wl,-subsystem=console/gui/wince/...
Set type for PE (Windows) executables.
@ -543,6 +548,7 @@ instead of
@cindex stdcall attribute
@cindex regparm attribute
@cindex dllexport attribute
@cindex nodecorate attribute
@item The keyword @code{__attribute__} is handled to specify variable or
function attributes. The following attributes are supported:
@ -570,6 +576,8 @@ registers @code{%eax}, @code{%edx} and @code{%ecx}.
@item @code{dllexport}: export function from dll/executable (win32 only)
@item @code{nodecorate}: do not apply any decorations that would otherwise be applied when exporting function from dll/executable (win32 only)
@end itemize
Here are some examples:
@ -669,7 +677,7 @@ are supported.
Since version 0.9.16, TinyCC integrates its own assembler. TinyCC
assembler supports a gas-like syntax (GNU assembler). You can
desactivate assembler support if you want a smaller TinyCC executable
deactivate assembler support if you want a smaller TinyCC executable
(the C compiler does not rely on the assembler).
TinyCC Assembler is used to handle files with @file{.S} (C
@ -1046,7 +1054,7 @@ All symbols are stored in hashed symbol stacks. Each symbol stack
contains @code{Sym} structures.
@code{Sym.v} contains the symbol name (remember
an idenfier is also a token, so a string is never necessary to store
an identifier is also a token, so a string is never necessary to store
it). @code{Sym.t} gives the type of the symbol. @code{Sym.r} is usually
the register in which the corresponding variable is stored. @code{Sym.c} is
usually a constant associated to the symbol like its address for normal
@ -1089,7 +1097,7 @@ global stack.
@section Sections
The generated code and datas are written in sections. The structure
The generated code and data are written in sections. The structure
@code{Section} contains all the necessary information for a given
section. @code{new_section()} creates a new section. ELF file semantics
is assumed for each section.
@ -1276,13 +1284,13 @@ should generate a function prolog/epilog.
@item gen_opi(op)
must generate the binary integer operation @var{op} on the two top
entries of the stack which are guaranted to contain integer types.
entries of the stack which are guaranteed to contain integer types.
The result value should be put on the stack.
@item gen_opf(op)
same as @code{gen_opi()} for floating point operations. The two top
entries of the stack are guaranted to contain floating point values of
entries of the stack are guaranteed to contain floating point values of
same types.
@item gen_cvt_itof()

67
tcc.c
View File

@ -18,10 +18,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef ONE_SOURCE
#include "libtcc.c"
#else
#include "tcc.h"
#if ONE_SOURCE
# include "libtcc.c"
#endif
#include "tcctools.c"
@ -63,7 +62,7 @@ static const char help[] =
" -bt N show N callers in stack traces\n"
#endif
"Misc. options:\n"
" -x[c|a|n] specify type of the next infile\n"
" -x[c|a|b|n] specify type of the next infile (C,ASM,BIN,NONE)\n"
" -nostdinc do not use standard system include paths\n"
" -nostdlib do not link with standard crt and libraries\n"
" -Bdir set tcc's private include/library dir\n"
@ -87,10 +86,10 @@ static const char help2[] =
" -Wp,-opt same as -opt\n"
" -include file include 'file' above each input file\n"
" -isystem dir add 'dir' to system include path\n"
" -iwithprefix dir set tcc's private include/library subdir\n"
" -static link to static libraries (not recommended)\n"
" -dumpversion print version\n"
" -print-search-dirs print search paths\n"
" -dt with -run/-E: auto-define 'test_...' macros\n"
"Ignored options:\n"
" --param -pedantic -pipe -s -std -traditional\n"
"-W... warnings:\n"
@ -98,7 +97,7 @@ static const char help2[] =
" error stop after first warning\n"
" unsupported warn about ignored options, pragmas, etc.\n"
" write-strings strings are const\n"
" implicit-function-declaration warn for missing prototype (*)\n"
" implicit-function-declaration warn for missing prototype (*)\n"
"-f[no-]... flags:\n"
" unsigned-char default char is unsigned\n"
" signed-char default char is signed\n"
@ -118,6 +117,7 @@ static const char help2[] =
" -nostdlib do not link with standard crt/libs\n"
" -[no-]whole-archive load lib(s) fully/only as needed\n"
" -export-all-symbols same as -rdynamic\n"
" -export-dynamic same as -rdynamic\n"
" -image-base= -Ttext= set base address of executable\n"
" -section-alignment= set section alignment in executable\n"
#ifdef TCC_TARGET_PE
@ -183,9 +183,11 @@ static void print_search_dirs(TCCState *s)
/* print_dirs("programs", NULL, 0); */
print_dirs("include", s->sysinclude_paths, s->nb_sysinclude_paths);
print_dirs("libraries", s->library_paths, s->nb_library_paths);
#ifndef TCC_TARGET_PE
print_dirs("crt", s->crt_paths, s->nb_crt_paths);
#ifdef TCC_TARGET_PE
printf("libtcc1:\n %s/lib/"TCC_LIBTCC1"\n", s->tcc_lib_path);
#else
printf("libtcc1:\n %s/"TCC_LIBTCC1"\n", s->tcc_lib_path);
print_dirs("crt", s->crt_paths, s->nb_crt_paths);
printf("elfinterp:\n %s\n", DEFAULT_ELFINTERP(s));
#endif
}
@ -196,7 +198,7 @@ static void set_environment(TCCState *s)
path = getenv("C_INCLUDE_PATH");
if(path != NULL) {
tcc_add_include_path(s, path);
tcc_add_sysinclude_path(s, path);
}
path = getenv("CPATH");
if(path != NULL) {
@ -244,18 +246,21 @@ static unsigned getclock_ms(void)
#endif
}
int main(int argc, char **argv)
int main(int argc0, char **argv0)
{
TCCState *s;
int ret, opt, n = 0;
int ret, opt, n = 0, t = 0;
unsigned start_time = 0;
const char *first_file;
int argc; char **argv;
FILE *ppfp = stdout;
redo:
argc = argc0, argv = argv0;
s = tcc_new();
opt = tcc_parse_args(s, &argc, &argv, 1);
if (n == 0) {
if ((n | t) == 0) {
if (opt == OPT_HELP)
return printf(help), 1;
if (opt == OPT_HELP2)
@ -274,6 +279,7 @@ redo:
return 0;
if (opt == OPT_PRINT_DIRS) {
/* initialize search dirs */
set_environment(s);
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
print_search_dirs(s);
return 0;
@ -284,11 +290,9 @@ redo:
tcc_error("no input files\n");
if (s->output_type == TCC_OUTPUT_PREPROCESS) {
if (!s->outfile) {
s->ppfp = stdout;
} else {
s->ppfp = fopen(s->outfile, "w");
if (!s->ppfp)
if (s->outfile && 0!=strcmp("-",s->outfile)) {
ppfp = fopen(s->outfile, "w");
if (!ppfp)
tcc_error("could not write '%s'", s->outfile);
}
} else if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) {
@ -297,8 +301,10 @@ redo:
if (n > 1 && s->outfile)
tcc_error("cannot specify output file with -c many files");
} else {
if (s->option_pthread)
if (s->option_pthread) {
tcc_set_options(s, "-lpthread");
n = s->nb_files;
}
}
if (s->do_bench)
@ -309,13 +315,17 @@ redo:
if (s->output_type == 0)
s->output_type = TCC_OUTPUT_EXE;
tcc_set_output_type(s, s->output_type);
s->ppfp = ppfp;
if ((s->output_type == TCC_OUTPUT_MEMORY
|| s->output_type == TCC_OUTPUT_PREPROCESS) && (s->dflag & 16))
s->dflag |= t ? 32 : 0, s->run_test = ++t, n = s->nb_files;
/* compile or add each files or library */
for (first_file = NULL, ret = 0;;) {
struct filespec *f = s->files[s->nb_files - n];
s->filetype = f->type;
s->alacarte_link = f->alacarte;
if (f->type == AFF_TYPE_LIB) {
if (f->type & AFF_TYPE_LIB) {
if (tcc_add_library_err(s, f->name) < 0)
ret = 1;
} else {
@ -326,16 +336,15 @@ redo:
if (tcc_add_file(s, f->name) < 0)
ret = 1;
}
s->filetype = 0;
s->alacarte_link = 1;
if (ret || --n == 0
if (--n == 0 || ret
|| (s->output_type == TCC_OUTPUT_OBJ && !s->option_r))
break;
}
if (s->output_type == TCC_OUTPUT_PREPROCESS) {
if (s->outfile)
fclose(s->ppfp);
if (s->run_test) {
t = 0;
} else if (s->output_type == TCC_OUTPUT_PREPROCESS) {
;
} else if (0 == ret) {
if (s->output_type == TCC_OUTPUT_MEMORY) {
#ifdef TCC_IS_NATIVE
@ -351,10 +360,14 @@ redo:
}
}
if (s->do_bench && ret == 0 && n == 0)
if (s->do_bench && (n | t | ret) == 0)
tcc_print_stats(s, getclock_ms() - start_time);
tcc_delete(s);
if (ret == 0 && n)
goto redo; /* compile more files with -c */
if (t)
goto redo; /* run more tests with -dt -run */
if (ppfp && ppfp != stdout)
fclose(ppfp);
return ret;
}

331
tcc.h
View File

@ -1,6 +1,6 @@
/*
* TCC - Tiny C Compiler
*
*
* Copyright (c) 2001-2004 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
@ -41,10 +41,11 @@
# include <dlfcn.h>
# endif
/* XXX: need to define this to use them in non ISOC99 context */
extern float strtof (const char *__nptr, char **__endptr);
extern long double strtold (const char *__nptr, char **__endptr);
extern float strtof (const char *__nptr, char **__endptr);
extern long double strtold (const char *__nptr, char **__endptr);
#endif
#else /* on _WIN32: */
#ifdef _WIN32
# include <windows.h>
# include <io.h> /* open, close etc. */
# include <direct.h> /* getcwd */
@ -52,7 +53,6 @@
# include <stdint.h>
# endif
# define inline __inline
# define inp next_inp /* inp is an intrinsic on msvc */
# define snprintf _snprintf
# define vsnprintf _vsnprintf
# ifndef __GNUC__
@ -65,6 +65,7 @@
# define LIBTCCAPI __declspec(dllexport)
# define PUB_FUNC LIBTCCAPI
# endif
# define inp next_inp /* inp is an intrinsic on msvc/mingw */
# ifdef _MSC_VER
# pragma warning (disable : 4244) // conversion from 'uint64_t' to 'int', possible loss of data
# pragma warning (disable : 4267) // conversion from 'size_t' to 'int', possible loss of data
@ -72,9 +73,6 @@
# pragma warning (disable : 4018) // signed/unsigned mismatch
# pragma warning (disable : 4146) // unary minus operator applied to unsigned type, result still unsigned
# define ssize_t intptr_t
# define __attribute__(x) __declspec x
# define aligned align
# else
# endif
# undef CONFIG_TCC_STATIC
#endif
@ -83,28 +81,32 @@
# define O_BINARY 0
#endif
#ifdef __GNUC__
# define NORETURN __attribute__ ((noreturn))
#elif defined _MSC_VER
#ifndef offsetof
#define offsetof(type, field) ((size_t) &((type *)0)->field)
#endif
#ifndef countof
#define countof(tab) (sizeof(tab) / sizeof((tab)[0]))
#endif
#ifdef _MSC_VER
# define NORETURN __declspec(noreturn)
# define ALIGNED(x) __declspec(align(x))
#else
# define NORETURN
# define NORETURN __attribute__((noreturn))
# define ALIGNED(x) __attribute__((aligned(x)))
#endif
#ifdef _WIN32
# define IS_DIRSEP(c) (c == '/' || c == '\\')
# define IS_ABSPATH(p) (IS_DIRSEP(p[0]) || (p[0] && p[1] == ':' && IS_DIRSEP(p[2])))
# define PATHCMP stricmp
# define PATHSEP ";"
#else
# define IS_DIRSEP(c) (c == '/')
# define IS_ABSPATH(p) IS_DIRSEP(p[0])
# define PATHCMP strcmp
#endif
#ifdef TCC_TARGET_PE
#define PATHSEP ';'
#else
#define PATHSEP ':'
# define PATHSEP ":"
#endif
/* -------------------------------------------- */
@ -131,12 +133,20 @@
#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_ARM) && \
!defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_C67) && \
!defined(TCC_TARGET_X86_64)
#define TCC_TARGET_I386
#endif
/* object format selection */
#if defined(TCC_TARGET_C67)
#define TCC_TARGET_COFF
# if defined __x86_64__ || defined _AMD64_
# define TCC_TARGET_X86_64
# elif defined __arm__
# define TCC_TARGET_ARM
# define TCC_ARM_EABI
# define TCC_ARM_HARDFLOAT
# elif defined __aarch64__
# define TCC_TARGET_ARM64
# else
# define TCC_TARGET_I386
# endif
# ifdef _WIN32
# define TCC_TARGET_PE 1
# endif
#endif
/* only native compiler supports -run */
@ -166,7 +176,7 @@
# define CONFIG_SYSROOT ""
#endif
#ifndef CONFIG_TCCDIR
# define CONFIG_TCCDIR "."
# define CONFIG_TCCDIR "/usr/local/lib/tcc"
#endif
#ifndef CONFIG_LDDIR
# define CONFIG_LDDIR "lib"
@ -189,7 +199,7 @@
/* system include paths */
#ifndef CONFIG_TCC_SYSINCLUDEPATHS
# ifdef TCC_TARGET_PE
# define CONFIG_TCC_SYSINCLUDEPATHS "{B}/include;{B}/include/winapi"
# define CONFIG_TCC_SYSINCLUDEPATHS "{B}/include"PATHSEP"{B}/include/winapi"
# else
# define CONFIG_TCC_SYSINCLUDEPATHS \
"{B}/include" \
@ -280,7 +290,11 @@
# define PUB_FUNC
#endif
#ifdef ONE_SOURCE
#ifndef ONE_SOURCE
# define ONE_SOURCE 1
#endif
#if ONE_SOURCE
#define ST_INLN static inline
#define ST_FUNC static
#define ST_DATA static
@ -316,6 +330,7 @@
# include "arm64-link.c"
#endif
#ifdef TCC_TARGET_C67
# define TCC_TARGET_COFF
# include "coff.h"
# include "c67-gen.c"
# include "c67-link.c"
@ -341,6 +356,13 @@
#endif
/* target address type */
#define addr_t ElfW(Addr)
#define ElfSym ElfW(Sym)
#if PTR_SIZE == 8 && !defined TCC_TARGET_PE
# define LONG_SIZE 8
#else
# define LONG_SIZE 4
#endif
/* -------------------------------------------- */
@ -409,63 +431,65 @@ typedef struct SValue {
result of unary() for an identifier. */
} SValue;
struct Attribute {
/* symbol attributes */
struct SymAttr {
unsigned short
aligned : 5, /* alignment as log2+1 (0 == unspecified) */
packed : 1,
weak : 1,
visibility : 2,
dllexport : 1,
nodecorate : 1,
dllimport : 1,
unused : 4;
};
/* function attributes or temporary attributes for parsing */
struct FuncAttr {
unsigned
func_call : 3, /* calling convention (0..5), see below */
aligned : 5, /* alignment as log2+1 (0 == unspecified) */
packed : 1,
func_export : 1,
func_import : 1,
func_args : 5,
func_body : 1,
mode : 4,
weak : 1,
visibility : 2,
unsigned_enum : 1,
fill : 7; // 7 bits left to fit well in union below
func_call : 3, /* calling convention (0..5), see below */
func_type : 2, /* FUNC_OLD/NEW/ELLIPSIS */
func_args : 8; /* PE __stdcall args */
};
/* GNUC attribute definition */
typedef struct AttributeDef {
struct Attribute a;
struct SymAttr a;
struct FuncAttr f;
struct Section *section;
int alias_target; /* token */
int asm_label; /* associated asm label */
int alias_target; /* token */
int asm_label; /* associated asm label */
char attr_mode; /* __attribute__((__mode__(...))) */
} AttributeDef;
/* symbol management */
typedef struct Sym {
int v; /* symbol token */
int v; /* symbol token */
unsigned short r; /* associated register or VT_CONST/VT_LOCAL and LVAL type */
struct SymAttr a; /* symbol attributes */
union {
int asm_label; /* associated asm label */
int scope; /* scope level for locals */
struct {
int c; /* associated number or Elf symbol index */
union {
int sym_scope; /* scope level for locals */
int jnext; /* next jump label */
struct FuncAttr f; /* function attributes */
int auxtype; /* bitfield access type */
};
};
long long enum_val; /* enum constant if IS_ENUM_VAL */
int *d; /* define token stream */
};
union {
long r; /* associated register or VT_CONST/VT_LOCAL and LVAL type */
struct Attribute a;
};
union {
long c; /* associated number */
int *d; /* define token stream */
};
CType type; /* associated type */
CType type; /* associated type */
union {
struct Sym *next; /* next related symbol (for fields and anoms) */
long jnext; /* next jump label */
int asm_label; /* associated asm label */
};
struct Sym *prev; /* prev symbol in stack */
struct Sym *prev_tok; /* previous symbol for this token */
} Sym;
/* section definition */
/* XXX: use directly ELF structure for parameters ? */
/* special flag to indicate that the section should not be linked to
the other ones */
#define SHF_PRIVATE 0x80000000
/* special flag, too */
#define SECTION_ABS ((void *)1)
typedef struct Section {
unsigned long data_offset; /* current data offset */
unsigned char *data; /* section data */
@ -500,12 +524,12 @@ typedef struct DLLReference {
#define SYM_FIELD 0x20000000 /* struct/union field symbol space */
#define SYM_FIRST_ANOM 0x10000000 /* first anonymous sym */
/* stored in 'Sym.c' field */
/* stored in 'Sym->f.func_type' field */
#define FUNC_NEW 1 /* ansi function prototype */
#define FUNC_OLD 2 /* old function prototype */
#define FUNC_ELLIPSIS 3 /* ansi function prototype with ... */
/* stored in 'Sym.r' field */
/* stored in 'Sym->f.func_call' field */
#define FUNC_CDECL 0 /* standard c call */
#define FUNC_STDCALL 1 /* pascal c call */
#define FUNC_FASTCALL1 2 /* first param in %eax */
@ -540,7 +564,7 @@ typedef struct BufferedFile {
int *ifdef_stack_ptr; /* ifdef_stack value at the start of the file */
int include_next_index; /* next search path */
char filename[1024]; /* filename */
char filename2[1024]; /* filename not modified by # line directive */
char *true_filename; /* filename not modified by # line directive */
unsigned char unget[4];
unsigned char buffer[1]; /* extra size for CH_EOB char */
} BufferedFile;
@ -548,21 +572,14 @@ typedef struct BufferedFile {
#define CH_EOB '\\' /* end of buffer or '\0' char in file */
#define CH_EOF (-1) /* end of file */
/* parsing state (used to save parser state to reparse part of the
source several times) */
typedef struct ParseState {
const int *macro_ptr;
int line_num;
int tok;
CValue tokc;
} ParseState;
/* used to record tokens */
typedef struct TokenString {
int *str;
int len;
int lastlen;
int allocated_len;
int last_line_num;
int save_line_num;
/* used to chain token-strings with begin/end_macro() */
struct TokenString *prev;
const int *prev_ptr;
@ -622,7 +639,6 @@ struct sym_attr {
};
struct TCCState {
int verbose; /* if true, display some information during compilation */
int nostdinc; /* if true, no standard headers are added */
int nostdlib; /* if true, no standard libraries are added */
@ -630,7 +646,7 @@ struct TCCState {
int static_link; /* if true, static linking is performed */
int rdynamic; /* if true, all symbols are exported */
int symbolic; /* if true, resolve symbols in the current module first */
int alacarte_link; /* if true, only link in referenced objects from archive */
int filetype; /* file type for compilation (NONE,C,ASM) */
char *tcc_lib_path; /* CONFIG_TCCDIR or -B option */
char *soname; /* as specified on the command line (-soname) */
@ -666,6 +682,7 @@ struct TCCState {
#ifdef TCC_TARGET_ARM
enum float_abi float_abi; /* float ABI of the generated code*/
#endif
int run_test; /* nth test to run with -dt -run */
addr_t text_addr; /* address of text section */
int has_text_addr;
@ -674,7 +691,7 @@ struct TCCState {
char *init_symbol; /* symbols to call at load-time (not used currently) */
char *fini_symbol; /* symbols to call at unload-time (not used currently) */
#ifdef TCC_TARGET_I386
int seg_size; /* 32. Can be 16 with i386 assembler (.code16) */
#endif
@ -769,8 +786,6 @@ struct TCCState {
/* extra attributes (eg. GOT/PLT value) for symtab symbols */
struct sym_attr *sym_attrs;
int nb_sym_attrs;
/* tiny assembler state */
Sym *asm_labels;
#ifdef TCC_TARGET_PE
/* PE info */
@ -778,6 +793,7 @@ struct TCCState {
unsigned pe_characteristics;
unsigned pe_file_align;
unsigned pe_stack_size;
addr_t pe_imagebase;
# ifdef TCC_TARGET_X86_64
Section *uw_pdata;
int uw_sym;
@ -795,7 +811,6 @@ struct TCCState {
struct filespec **files; /* files seen on command line */
int nb_files; /* number thereof */
int nb_libraries; /* number of libs thereof */
int filetype;
char *outfile; /* output filename */
int option_r; /* option -r */
int do_bench; /* option -bench */
@ -808,7 +823,6 @@ struct TCCState {
struct filespec {
char type;
char alacarte;
char name[1];
};
@ -835,53 +849,57 @@ struct filespec {
/* types */
#define VT_BTYPE 0x000f /* mask for basic type */
#define VT_INT 0 /* integer type */
#define VT_VOID 0 /* void type */
#define VT_BYTE 1 /* signed byte type */
#define VT_SHORT 2 /* short type */
#define VT_VOID 3 /* void type */
#define VT_PTR 4 /* pointer */
#define VT_ENUM 5 /* enum definition */
#define VT_INT 3 /* integer type */
#define VT_LLONG 4 /* 64 bit integer */
#define VT_PTR 5 /* pointer */
#define VT_FUNC 6 /* function type */
#define VT_STRUCT 7 /* struct/union definition */
#define VT_FLOAT 8 /* IEEE float */
#define VT_DOUBLE 9 /* IEEE double */
#define VT_LDOUBLE 10 /* IEEE long double */
#define VT_BOOL 11 /* ISOC99 boolean type */
#define VT_LLONG 12 /* 64 bit integer */
#define VT_LONG 13 /* long integer (NEVER USED as type, only
during parsing) */
#define VT_QLONG 14 /* 128-bit integer. Only used for x86-64 ABI */
#define VT_QFLOAT 15 /* 128-bit float. Only used for x86-64 ABI */
#define VT_QLONG 13 /* 128-bit integer. Only used for x86-64 ABI */
#define VT_QFLOAT 14 /* 128-bit float. Only used for x86-64 ABI */
#define VT_UNSIGNED 0x0010 /* unsigned type */
#define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */
#define VT_BITFIELD 0x0040 /* bitfield modifier */
#define VT_CONSTANT 0x0800 /* const modifier */
#define VT_VOLATILE 0x1000 /* volatile modifier */
#define VT_DEFSIGN 0x2000 /* signed type */
#define VT_VLA 0x00020000 /* VLA type (also has VT_PTR and VT_ARRAY) */
#define VT_DEFSIGN 0x0020 /* explicitly signed or unsigned */
#define VT_ARRAY 0x0040 /* array type (also has VT_PTR) */
#define VT_BITFIELD 0x0080 /* bitfield modifier */
#define VT_CONSTANT 0x0100 /* const modifier */
#define VT_VOLATILE 0x0200 /* volatile modifier */
#define VT_VLA 0x0400 /* VLA type (also has VT_PTR and VT_ARRAY) */
#define VT_LONG 0x0800 /* long type (also has VT_INT rsp. VT_LLONG) */
/* storage */
#define VT_EXTERN 0x00000080 /* extern definition */
#define VT_STATIC 0x00000100 /* static variable */
#define VT_TYPEDEF 0x00000200 /* typedef definition */
#define VT_INLINE 0x00000400 /* inline definition */
#define VT_IMPORT 0x00004000 /* win32: extern data imported from dll */
#define VT_EXPORT 0x00008000 /* win32: data exported from dll */
#define VT_WEAK 0x00010000 /* weak symbol */
#define VT_TLS 0x00040000 /* thread-local storage */
#define VT_VIS_SHIFT 19 /* shift for symbol visibility, overlapping
bitfield values, because bitfields never
have linkage and hence never have
visibility. */
#define VT_VIS_SIZE 2 /* We have four visibilities. */
#define VT_VIS_MASK (((1 << VT_VIS_SIZE)-1) << VT_VIS_SHIFT)
#define VT_EXTERN 0x00001000 /* extern definition */
#define VT_STATIC 0x00002000 /* static variable */
#define VT_TYPEDEF 0x00004000 /* typedef definition */
#define VT_INLINE 0x00008000 /* inline definition */
/* currently unused: 0x000[1248]0000 */
#define VT_STRUCT_SHIFT 19 /* shift for bitfield shift values (max: 32 - 2*6) */
#define VT_STRUCT_SHIFT 20 /* shift for bitfield shift values (32 - 2*6) */
#define VT_STRUCT_MASK (((1 << (6+6)) - 1) << VT_STRUCT_SHIFT | VT_BITFIELD)
#define BIT_POS(t) (((t) >> VT_STRUCT_SHIFT) & 0x3f)
#define BIT_SIZE(t) (((t) >> (VT_STRUCT_SHIFT + 6)) & 0x3f)
#define VT_UNION (1 << VT_STRUCT_SHIFT | VT_STRUCT)
#define VT_ENUM (2 << VT_STRUCT_SHIFT) /* integral type is an enum really */
#define VT_ENUM_VAL (3 << VT_STRUCT_SHIFT) /* integral type is an enum constant really */
#define IS_ENUM(t) ((t & VT_STRUCT_MASK) == VT_ENUM)
#define IS_ENUM_VAL(t) ((t & VT_STRUCT_MASK) == VT_ENUM_VAL)
#define IS_UNION(t) ((t & (VT_STRUCT_MASK|VT_BTYPE)) == VT_UNION)
/* type mask (except storage) */
#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE | VT_IMPORT | VT_EXPORT | VT_WEAK | VT_VIS_MASK)
#define VT_TYPE (~(VT_STORAGE))
#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE)
#define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK))
/* symbol was created by tccasm.c first */
#define VT_ASM (VT_VOID | VT_UNSIGNED)
#define IS_ASM_SYM(sym) (((sym)->type.t & (VT_BTYPE | VT_ASM)) == VT_ASM)
/* token values */
@ -923,6 +941,7 @@ struct filespec {
#define TOK_PPNUM 0xbe /* preprocessor number */
#define TOK_PPSTR 0xbf /* preprocessor string */
#define TOK_LINENUM 0xc0 /* line number info */
#define TOK_TWODOTS 0xa8 /* C++ token ? */
/* <-- */
#define TOK_UMULL 0xc2 /* unsigned 32x32 -> 64 mul */
@ -936,11 +955,13 @@ struct filespec {
#define TOK_TWOSHARPS 0xca /* ## preprocessing token */
#define TOK_PLCHLDR 0xcb /* placeholder token as defined in C99 */
#define TOK_NOSUBST 0xcc /* means following token has already been pp'd */
#define TOK_PPJOIN 0xce /* A '##' in the right position to mean pasting */
#define TOK_PPJOIN 0xcd /* A '##' in the right position to mean pasting */
#define TOK_CLONG 0xce /* long constant */
#define TOK_CULONG 0xcf /* unsigned long constant */
#define TOK_SHL 0x01 /* shift left */
#define TOK_SAR 0x02 /* signed shift right */
/* assignment operators : normal operator or 0x80 */
#define TOK_A_MOD 0xa5
#define TOK_A_AND 0xa6
@ -953,14 +974,6 @@ struct filespec {
#define TOK_A_SHL 0x81
#define TOK_A_SAR 0x82
#ifndef offsetof
#define offsetof(type, field) ((size_t) &((type *)0)->field)
#endif
#ifndef countof
#define countof(tab) (sizeof(tab) / sizeof((tab)[0]))
#endif
#define TOK_EOF (-1) /* end of file */
#define TOK_LINEFEED 10 /* line feed */
@ -1118,13 +1131,13 @@ ST_FUNC void cstr_free(CString *cstr);
ST_FUNC void cstr_reset(CString *cstr);
ST_INLN void sym_free(Sym *sym);
ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, long c);
ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, int c);
ST_FUNC Sym *sym_find2(Sym *s, int v);
ST_FUNC Sym *sym_push(int v, CType *type, int r, long c);
ST_FUNC Sym *sym_push(int v, CType *type, int r, int c);
ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep);
ST_INLN Sym *struct_find(int v);
ST_INLN Sym *sym_find(int v);
ST_FUNC Sym *global_identifier_push(int v, int t, long c);
ST_FUNC Sym *global_identifier_push(int v, int t, int c);
ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen);
ST_FUNC int tcc_open(TCCState *s1, const char *filename);
@ -1134,14 +1147,15 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
/* flags: */
#define AFF_PRINT_ERROR 0x10 /* print error if file not found */
#define AFF_REFERENCED_DLL 0x20 /* load a referenced dll from another dll */
#define AFF_PREPROCESS 0x40 /* preprocess file */
/* combined with: */
#define AFF_TYPE_BIN 0x40 /* file to add is binary */
#define AFF_WHOLE_ARCHIVE 0x80 /* load all objects from archive */
/* s->filetype: */
#define AFF_TYPE_NONE 0
#define AFF_TYPE_C 1
#define AFF_TYPE_ASM 2
#define AFF_TYPE_ASMPP 3
#define AFF_TYPE_BIN 4
#define AFF_TYPE_LIB 5
#define AFF_TYPE_ASMPP 4
#define AFF_TYPE_LIB 8
#define AFF_TYPE_MASK (15 | AFF_TYPE_BIN)
/* values from tcc_object_type(...) */
#define AFF_BINTYPE_REL 1
#define AFF_BINTYPE_DYN 2
@ -1209,9 +1223,7 @@ ST_FUNC TokenSym *tok_alloc(const char *str, int len);
ST_FUNC const char *get_tok_str(int v, CValue *cv);
ST_FUNC void begin_macro(TokenString *str, int alloc);
ST_FUNC void end_macro(void);
ST_FUNC void set_idnum(int c, int val);
ST_FUNC void save_parse_state(ParseState *s);
ST_FUNC void restore_parse_state(ParseState *s);
ST_FUNC int set_idnum(int c, int val);
ST_INLN void tok_str_new(TokenString *s);
ST_FUNC TokenString *tok_str_alloc(void);
ST_FUNC void tok_str_free(TokenString *s);
@ -1224,13 +1236,14 @@ ST_INLN Sym *define_find(int v);
ST_FUNC void free_defines(Sym *b);
ST_FUNC Sym *label_find(int v);
ST_FUNC Sym *label_push(Sym **ptop, int v, int flags);
ST_FUNC void label_pop(Sym **ptop, Sym *slast);
ST_FUNC void label_pop(Sym **ptop, Sym *slast, int keep);
ST_FUNC void parse_define(void);
ST_FUNC void preprocess(int is_bof);
ST_FUNC void next_nomacro(void);
ST_FUNC void next(void);
ST_INLN void unget_tok(int last_tok);
ST_FUNC void preprocess_start(TCCState *s1);
ST_FUNC void preprocess_start(TCCState *s1, int is_asm);
ST_FUNC void preprocess_end(TCCState *s1);
ST_FUNC void tccpp_new(TCCState *s);
ST_FUNC void tccpp_delete(TCCState *s);
ST_FUNC int tcc_preprocess(TCCState *s1);
@ -1279,6 +1292,7 @@ ST_DATA int func_var; /* true if current function is variadic */
ST_DATA int func_vc;
ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */
ST_DATA const char *funcname;
ST_DATA int g_debug;
ST_FUNC void tcc_debug_start(TCCState *s1);
ST_FUNC void tcc_debug_end(TCCState *s1);
@ -1286,9 +1300,7 @@ ST_FUNC void tcc_debug_funcstart(TCCState *s1, Sym *sym);
ST_FUNC void tcc_debug_funcend(TCCState *s1, int size);
ST_FUNC void tcc_debug_line(TCCState *s1);
ST_FUNC void tccgen_start(TCCState *s1);
ST_FUNC void tccgen_end(TCCState *s1);
ST_FUNC int tccgen_compile(TCCState *s1);
ST_FUNC void free_inline_functions(TCCState *s);
ST_FUNC void check_vstack(void);
@ -1296,8 +1308,10 @@ ST_INLN int is_float(int t);
ST_FUNC int ieee_finite(double d);
ST_FUNC void test_lvalue(void);
ST_FUNC void vpushi(int v);
ST_FUNC ElfSym *elfsym(Sym *);
ST_FUNC void update_storage(Sym *sym);
ST_FUNC Sym *external_global_sym(int v, CType *type, int r);
ST_FUNC void vset(CType *type, int r, long v);
ST_FUNC void vset(CType *type, int r, int v);
ST_FUNC void vswap(void);
ST_FUNC void vpush_global_sym(CType *type, int v);
ST_FUNC void vrote(SValue *e, int n);
@ -1330,7 +1344,6 @@ ST_FUNC void expr_prod(void);
ST_FUNC void expr_sum(void);
ST_FUNC void gexpr(void);
ST_FUNC int expr_const(void);
ST_FUNC void decl(int l);
#if defined CONFIG_TCC_BCHECK || defined TCC_TARGET_C67
ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsigned long size);
#endif
@ -1367,13 +1380,15 @@ ST_DATA Section *lbounds_section; /* contains local data bound description */
ST_FUNC void tccelf_bounds_new(TCCState *s);
#endif
/* symbol sections */
ST_DATA Section *symtab_section, *strtab_section;
ST_DATA Section *symtab_section;
/* debug sections */
ST_DATA Section *stab_section, *stabstr_section;
ST_FUNC void tccelf_new(TCCState *s);
ST_FUNC void tccelf_delete(TCCState *s);
ST_FUNC void tccelf_stab_new(TCCState *s);
ST_FUNC void tccelf_begin_file(TCCState *s1);
ST_FUNC void tccelf_end_file(TCCState *s1);
ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags);
ST_FUNC void section_realloc(Section *sec, unsigned long new_size);
@ -1383,7 +1398,7 @@ ST_FUNC void section_reserve(Section *sec, unsigned long size);
ST_FUNC Section *find_section(TCCState *s1, const char *name);
ST_FUNC Section *new_symtab(TCCState *s1, const char *symtab_name, int sh_type, int sh_flags, const char *strtab_name, const char *hash_name, int hash_sh_flags);
ST_FUNC void put_extern_sym2(Sym *sym, Section *section, addr_t value, unsigned long size, int can_add_underscore);
ST_FUNC void put_extern_sym2(Sym *sym, int sh_num, addr_t value, unsigned long size, int can_add_underscore);
ST_FUNC void put_extern_sym(Sym *sym, Section *section, addr_t value, unsigned long size);
#if PTR_SIZE == 4
ST_FUNC void greloc(Section *s, Sym *sym, unsigned long offset, int type);
@ -1402,14 +1417,13 @@ ST_FUNC void put_stabs_r(const char *str, int type, int other, int desc, unsigne
ST_FUNC void put_stabn(int type, int other, int desc, int value);
ST_FUNC void put_stabd(int type, int other, int desc);
ST_FUNC void relocate_common_syms(void);
ST_FUNC void resolve_common_syms(TCCState *s1);
ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve);
ST_FUNC void relocate_section(TCCState *s1, Section *s);
ST_FUNC void tcc_add_linker_symbols(TCCState *s1);
ST_FUNC int tcc_object_type(int fd, ElfW(Ehdr) *h);
ST_FUNC int tcc_load_object_file(TCCState *s1, int fd, unsigned long file_offset);
ST_FUNC int tcc_load_archive(TCCState *s1, int fd);
ST_FUNC int tcc_load_archive(TCCState *s1, int fd, int alacarte);
ST_FUNC void tcc_add_bcheck(TCCState *s1);
ST_FUNC void tcc_add_runtime(TCCState *s1);
@ -1433,7 +1447,7 @@ ST_FUNC int handle_eob(void);
/* ------------ xxx-link.c ------------ */
/* Wether to generate a GOT/PLT entry and when. NO_GOTPLT_ENTRY is first so
/* Whether to generate a GOT/PLT entry and when. NO_GOTPLT_ENTRY is first so
that unknown relocation don't create a GOT or PLT entry */
enum gotplt_entry {
NO_GOTPLT_ENTRY, /* never generate (eg. GLOB_DAT & JMP_SLOT relocs) */
@ -1461,6 +1475,7 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *reg
ST_FUNC void gfunc_call(int nb_args);
ST_FUNC void gfunc_prolog(CType *func_type);
ST_FUNC void gfunc_epilog(void);
ST_FUNC void gen_fill_nops(int);
ST_FUNC int gjmp(int t);
ST_FUNC void gjmp_addr(int a);
ST_FUNC int gtst(int inv, int t);
@ -1488,13 +1503,13 @@ static inline uint16_t read16le(unsigned char *p) {
return p[0] | (uint16_t)p[1] << 8;
}
static inline void write16le(unsigned char *p, uint16_t x) {
p[0] = x & 255, p[1] = x >> 8 & 255;
p[0] = x & 255; p[1] = x >> 8 & 255;
}
static inline uint32_t read32le(unsigned char *p) {
return read16le(p) | (uint32_t)read16le(p + 2) << 16;
}
static inline void write32le(unsigned char *p, uint32_t x) {
write16le(p, x), write16le(p + 2, x >> 16);
write16le(p, x); write16le(p + 2, x >> 16);
}
static inline void add32le(unsigned char *p, int32_t x) {
write32le(p, read32le(p) + x);
@ -1503,7 +1518,7 @@ static inline uint64_t read64le(unsigned char *p) {
return read32le(p) | (uint64_t)read32le(p + 4) << 32;
}
static inline void write64le(unsigned char *p, uint64_t x) {
write32le(p, x), write32le(p + 4, x >> 32);
write32le(p, x); write32le(p + 4, x >> 32);
}
static inline void add64le(unsigned char *p, int64_t x) {
write64le(p, read64le(p) + x);
@ -1514,8 +1529,8 @@ static inline void add64le(unsigned char *p, int64_t x) {
ST_FUNC void g(int c);
ST_FUNC void gen_le16(int c);
ST_FUNC void gen_le32(int c);
ST_FUNC void gen_addr32(int r, Sym *sym, long c);
ST_FUNC void gen_addrpc32(int r, Sym *sym, long c);
ST_FUNC void gen_addr32(int r, Sym *sym, int c);
ST_FUNC void gen_addrpc32(int r, Sym *sym, int c);
#endif
#ifdef CONFIG_TCC_BCHECK
@ -1527,6 +1542,9 @@ ST_FUNC void gen_bounded_ptr_deref(void);
#ifdef TCC_TARGET_X86_64
ST_FUNC void gen_addr64(int r, Sym *sym, int64_t c);
ST_FUNC void gen_opl(int op);
#ifdef TCC_TARGET_PE
ST_FUNC void gen_vla_result(int addr);
#endif
#endif
/* ------------ arm-gen.c ------------ */
@ -1586,7 +1604,7 @@ ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str);
ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd);
ST_FUNC int pe_output_file(TCCState * s1, const char *filename);
ST_FUNC int pe_putimport(TCCState *s1, int dllindex, const char *name, addr_t value);
#ifndef TCC_TARGET_ARM
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2);
#endif
#ifdef TCC_TARGET_X86_64
@ -1598,6 +1616,7 @@ PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp);
# define ST_PE_IMPORT 0x20
# define ST_PE_STDCALL 0x40
#endif
#define ST_ASM_SET 0x04
/* ------------ tccrun.c ----------------- */
#ifdef TCC_IS_NATIVE
@ -1633,7 +1652,7 @@ ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename)
/********************************************************/
#undef ST_DATA
#ifdef ONE_SOURCE
#if ONE_SOURCE
#define ST_DATA static
#else
#define ST_DATA

280
tccasm.c
View File

@ -31,55 +31,59 @@ ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n)
return ts->tok;
}
ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe);
static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global);
static Sym sym_dot;
static Sym* asm_new_label(TCCState *s1, int label, int is_local);
static Sym* asm_new_label1(TCCState *s1, int label, int is_local, int sh_num, int value);
static Sym *asm_label_find(int v)
{
Sym *sym = sym_find(v);
while (sym && sym->sym_scope)
sym = sym->prev_tok;
return sym;
}
static Sym *asm_label_push(int v)
{
/* We always add VT_EXTERN, for sym definition that's tentative
(for .set, removed for real defs), for mere references it's correct
as is. */
Sym *sym = global_identifier_push(v, VT_ASM | VT_EXTERN | VT_STATIC, 0);
sym->r = VT_CONST | VT_SYM;
return sym;
}
/* Return a symbol we can use inside the assembler, having name NAME.
The assembler symbol table is different from the C symbol table
(and the Sym members are used differently). But we must be able
to look up file-global C symbols from inside the assembler, e.g.
for global asm blocks to be able to refer to defined C symbols.
Symbols from asm and C source share a namespace. If we generate
an asm symbol it's also a (file-global) C symbol, but it's
either not accessible by name (like "L.123"), or its type information
is such that it's not usable without a proper C declaration.
This routine gives back either an existing asm-internal
symbol, or a new one. In the latter case the new asm-internal
symbol is initialized with info from the C symbol table.
If CSYM is non-null we take symbol info from it, otherwise
we look up NAME in the C symbol table and use that. */
Sometimes we need symbols accessible by name from asm, which
are anonymous in C, in this case CSYM can be used to transfer
all information from that symbol to the (possibly newly created)
asm symbol. */
ST_FUNC Sym* get_asm_sym(int name, Sym *csym)
{
Sym *sym = label_find(name);
Sym *sym = asm_label_find(name);
if (!sym) {
sym = label_push(&tcc_state->asm_labels, name, 0);
sym->type.t = VT_VOID | VT_EXTERN;
if (!csym) {
csym = sym_find(name);
/* We might be called for an asm block from inside a C routine
and so might have local decls on the identifier stack. Search
for the first global one. */
while (csym && csym->scope)
csym = csym->prev_tok;
}
/* Now, if we have a defined global symbol copy over
section and offset. */
if (csym &&
((csym->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST)) &&
csym->c) {
ElfW(Sym) *esym;
esym = &((ElfW(Sym) *)symtab_section->data)[csym->c];
sym->c = csym->c;
sym->r = esym->st_shndx;
sym->jnext = esym->st_value;
/* XXX can't yet store st_size anywhere. */
sym->type.t &= ~VT_EXTERN;
/* Mark that this asm symbol doesn't need to be fed back. */
sym->type.t |= VT_IMPORT;
}
sym = asm_label_push(name);
if (csym)
sym->c = csym->c;
}
return sym;
}
static Sym* asm_section_sym(TCCState *s1, Section *sec)
{
char buf[100];
int label = tok_alloc(buf,
snprintf(buf, sizeof buf, "L.%s", sec->name)
)->tok;
Sym *sym = asm_label_find(label);
return sym ? sym : asm_new_label1(s1, label, 1, sec->sh_num, 0);
}
/* We do not use the C expression parser to handle symbols. Maybe the
C expression parser could be tweaked to do so. */
@ -97,19 +101,18 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
if (*p == 'b' || *p == 'f') {
/* backward or forward label */
label = asm_get_local_label_name(s1, n);
sym = label_find(label);
sym = asm_label_find(label);
if (*p == 'b') {
/* backward : find the last corresponding defined label */
if (sym && sym->r == 0)
if (sym && (!sym->c || elfsym(sym)->st_shndx == SHN_UNDEF))
sym = sym->prev_tok;
if (!sym)
tcc_error("local label '%d' not found backward", n);
} else {
/* forward */
if (!sym || sym->r) {
if (!sym || (sym->c && elfsym(sym)->st_shndx != SHN_UNDEF)) {
/* if the last label is defined, then define a new one */
sym = label_push(&s1->asm_labels, label, 0);
sym->type.t = VT_STATIC | VT_VOID | VT_EXTERN;
sym = asm_label_push(label);
}
}
pe->v = 0;
@ -153,21 +156,20 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
skip(')');
break;
case '.':
pe->v = 0;
pe->sym = &sym_dot;
pe->pcrel = 0;
sym_dot.type.t = VT_VOID | VT_STATIC;
sym_dot.r = cur_text_section->sh_num;
sym_dot.jnext = ind;
pe->v = ind;
pe->sym = asm_section_sym(s1, cur_text_section);
pe->pcrel = 0;
next();
break;
default:
if (tok >= TOK_IDENT) {
ElfSym *esym;
/* label case : if the label was not found, add one */
sym = get_asm_sym(tok, NULL);
if (sym->r == SHN_ABS) {
esym = elfsym(sym);
if (esym && esym->st_shndx == SHN_ABS) {
/* if absolute symbol, no need to put a symbol value */
pe->v = sym->jnext;
pe->v = esym->st_value;
pe->sym = NULL;
pe->pcrel = 0;
} else {
@ -281,20 +283,26 @@ static inline void asm_expr_sum(TCCState *s1, ExprValue *pe)
} else if (pe->sym == e2.sym) {
/* OK */
pe->sym = NULL; /* same symbols can be subtracted to NULL */
} else if (pe->sym && pe->sym->r == e2.sym->r && pe->sym->r != 0) {
/* we also accept defined symbols in the same section */
pe->v += pe->sym->jnext - e2.sym->jnext;
pe->sym = NULL;
} else if (e2.sym->r == cur_text_section->sh_num) {
/* When subtracting a defined symbol in current section
this actually makes the value PC-relative. */
pe->v -= e2.sym->jnext - ind - 4;
pe->pcrel = 1;
e2.sym = NULL;
} else {
cannot_relocate:
tcc_error("invalid operation with label");
}
} else {
ElfSym *esym1, *esym2;
esym1 = elfsym(pe->sym);
esym2 = elfsym(e2.sym);
if (esym1 && esym1->st_shndx == esym2->st_shndx
&& esym1->st_shndx != SHN_UNDEF) {
/* we also accept defined symbols in the same section */
pe->v += esym1->st_value - esym2->st_value;
pe->sym = NULL;
} else if (esym2->st_shndx == cur_text_section->sh_num) {
/* When subtracting a defined symbol in current section
this actually makes the value PC-relative. */
pe->v -= esym2->st_value - ind - 4;
pe->pcrel = 1;
e2.sym = NULL;
} else {
cannot_relocate:
tcc_error("invalid operation with label");
}
}
}
}
}
@ -355,38 +363,38 @@ ST_FUNC int asm_int_expr(TCCState *s1)
return e.v;
}
/* NOTE: the same name space as C labels is used to avoid using too
much memory when storing labels in TokenStrings */
static Sym* asm_new_label1(TCCState *s1, int label, int is_local,
int sh_num, int value)
{
Sym *sym;
ElfSym *esym;
sym = label_find(label);
sym = asm_label_find(label);
if (sym) {
esym = elfsym(sym);
/* A VT_EXTERN symbol, even if it has a section is considered
overridable. This is how we "define" .set targets. Real
definitions won't have VT_EXTERN set. */
if (sym->r && !(sym->type.t & VT_EXTERN)) {
if (esym && esym->st_shndx != SHN_UNDEF) {
/* the label is already defined */
if (!is_local) {
tcc_error("assembler label '%s' already defined",
get_tok_str(label, NULL));
} else {
/* redefinition of local labels is possible */
if (IS_ASM_SYM(sym)
&& (is_local == 1 || (sym->type.t & VT_EXTERN)))
goto new_label;
}
if (!(sym->type.t & VT_EXTERN))
tcc_error("assembler label '%s' already defined",
get_tok_str(label, NULL));
}
} else {
new_label:
sym = label_push(&s1->asm_labels, label, 0);
/* If we need a symbol to hold a value, mark it as
tentative only (for .set). If this is for a real label
we'll remove VT_EXTERN. */
sym->type.t = VT_STATIC | VT_VOID | VT_EXTERN;
sym = asm_label_push(label);
}
sym->r = sh_num;
sym->jnext = value;
if (!sym->c)
put_extern_sym2(sym, SHN_UNDEF, 0, 0, 0);
esym = elfsym(sym);
esym->st_shndx = sh_num;
esym->st_value = value;
if (is_local != 2)
sym->type.t &= ~VT_EXTERN;
return sym;
}
@ -401,35 +409,17 @@ static Sym* set_symbol(TCCState *s1, int label)
{
long n;
ExprValue e;
Sym *sym;
ElfSym *esym;
next();
asm_expr(s1, &e);
n = e.v;
if (e.sym)
n += e.sym->jnext;
return asm_new_label1(s1, label, 0, e.sym ? e.sym->r : SHN_ABS, n);
}
static void asm_free_labels(TCCState *st)
{
Sym *s, *s1;
Section *sec;
for(s = st->asm_labels; s != NULL; s = s1) {
s1 = s->prev;
/* define symbol value in object file */
s->type.t &= ~VT_EXTERN;
if (s->r && !(s->type.t & VT_IMPORT)) {
if (s->r == SHN_ABS)
sec = SECTION_ABS;
else
sec = st->sections[s->r];
put_extern_sym2(s, sec, s->jnext, 0, 0);
}
/* remove label */
table_ident[s->v - TOK_IDENT]->sym_label = NULL;
sym_free(s);
}
st->asm_labels = NULL;
esym = elfsym(e.sym);
if (esym)
n += esym->st_value;
sym = asm_new_label1(s1, label, 2, esym ? esym->st_shndx : SHN_ABS, n);
elfsym(sym)->st_other |= ST_ASM_SET;
return sym;
}
static void use_section1(TCCState *s1, Section *sec)
@ -628,20 +618,16 @@ static void asm_parse_directive(TCCState *s1, int global)
{
int repeat;
TokenString *init_str;
ParseState saved_parse_state = {0};
next();
repeat = asm_int_expr(s1);
init_str = tok_str_alloc();
next();
while ((tok != TOK_ASMDIR_endr) && (tok != CH_EOF)) {
while (next(), tok != TOK_ASMDIR_endr) {
if (tok == CH_EOF)
tcc_error("we at end of file, .endr not found");
tok_str_add_tok(init_str);
next();
}
if (tok == CH_EOF) tcc_error("we at end of file, .endr not found");
next();
tok_str_add(init_str, -1);
tok_str_add(init_str, 0);
save_parse_state(&saved_parse_state);
begin_macro(init_str, 1);
while (repeat-- > 0) {
tcc_assemble_internal(s1, (parse_flags & PARSE_FLAG_PREPROCESS),
@ -649,20 +635,22 @@ static void asm_parse_directive(TCCState *s1, int global)
macro_ptr = init_str->str;
}
end_macro();
restore_parse_state(&saved_parse_state);
next();
break;
}
case TOK_ASMDIR_org:
{
unsigned long n;
ExprValue e;
ElfSym *esym;
next();
asm_expr(s1, &e);
n = e.v;
if (e.sym) {
if (e.sym->r != cur_text_section->sh_num)
esym = elfsym(e.sym);
if (esym) {
if (esym->st_shndx != cur_text_section->sh_num)
expect("constant or same-section symbol");
n += e.sym->jnext;
n += esym->st_value;
}
if (n < ind)
tcc_error("attempt to .org backwards");
@ -687,15 +675,15 @@ static void asm_parse_directive(TCCState *s1, int global)
tok1 = tok;
do {
Sym *sym;
next();
sym = get_asm_sym(tok, NULL);
if (tok1 != TOK_ASMDIR_hidden)
sym->type.t &= ~VT_STATIC;
if (tok1 == TOK_ASMDIR_weak)
sym->type.t |= VT_WEAK;
sym->a.weak = 1;
else if (tok1 == TOK_ASMDIR_hidden)
sym->type.t |= STV_HIDDEN << VT_VIS_SHIFT;
sym->a.visibility = STV_HIDDEN;
update_storage(sym);
next();
} while (tok == ',');
break;
@ -786,7 +774,7 @@ static void asm_parse_directive(TCCState *s1, int global)
Sym *sym;
next();
sym = label_find(tok);
sym = asm_label_find(tok);
if (!sym) {
tcc_error("label not found: %s", get_tok_str(tok, NULL));
}
@ -917,13 +905,9 @@ static void asm_parse_directive(TCCState *s1, int global)
static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
{
int opcode;
int saved_parse_flags = parse_flags;
/* XXX: undefine C labels */
ch = file->buf_ptr[0];
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
parse_flags = PARSE_FLAG_ASM_FILE | PARSE_FLAG_TOK_STR;
set_idnum('.', IS_ID);
if (do_preprocess)
parse_flags |= PARSE_FLAG_PREPROCESS;
for(;;) {
@ -942,7 +926,6 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
} else if (tok >= TOK_ASMDIR_FIRST && tok <= TOK_ASMDIR_LAST) {
asm_parse_directive(s1, global);
} else if (tok == TOK_PPNUM) {
Sym *sym;
const char *p;
int n;
p = tokc.str.data;
@ -950,9 +933,7 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
if (*p != '\0')
expect("':'");
/* new local label */
sym = asm_new_label(s1, asm_get_local_label_name(s1, n), 1);
/* Remove the marker for tentative definitions. */
sym->type.t &= ~VT_EXTERN;
asm_new_label(s1, asm_get_local_label_name(s1, n), 1);
next();
skip(':');
goto redo;
@ -961,19 +942,8 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
opcode = tok;
next();
if (tok == ':') {
/* handle "extern void vide(void); __asm__("vide: ret");" as
"__asm__("globl vide\nvide: ret");" */
Sym *sym = sym_find(opcode);
if (sym && (sym->type.t & VT_EXTERN) && global) {
sym = label_find(opcode);
if (!sym) {
sym = label_push(&s1->asm_labels, opcode, 0);
sym->type.t = VT_VOID | VT_EXTERN;
}
}
/* new label */
sym = asm_new_label(s1, opcode, 0);
sym->type.t &= ~VT_EXTERN;
asm_new_label(s1, opcode, 0);
next();
goto redo;
} else if (tok == '=') {
@ -989,31 +959,22 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
parse_flags &= ~PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
}
asm_free_labels(s1);
parse_flags = saved_parse_flags;
return 0;
}
/* Assemble the current file */
ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess)
{
Sym *define_start;
int ret;
define_start = define_stack;
preprocess_start(s1);
tcc_debug_start(s1);
/* default section is text */
cur_text_section = text_section;
ind = cur_text_section->data_offset;
nocode_wanted = 0;
ret = tcc_assemble_internal(s1, do_preprocess, 1);
cur_text_section->data_offset = ind;
tcc_debug_end(s1);
free_defines(define_start);
return ret;
}
@ -1025,21 +986,16 @@ ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess)
end */
static void tcc_assemble_inline(TCCState *s1, char *str, int len, int global)
{
int saved_parse_flags;
const int *saved_macro_ptr;
saved_parse_flags = parse_flags;
saved_macro_ptr = macro_ptr;
const int *saved_macro_ptr = macro_ptr;
int dotid = set_idnum('.', IS_ID);
tcc_open_bf(s1, ":asm:", len);
memcpy(file->buffer, str, len);
macro_ptr = NULL;
tcc_assemble_internal(s1, 0, global);
tcc_close();
parse_flags = saved_parse_flags;
set_idnum('.', (parse_flags & PARSE_FLAG_ASM_FILE) ? IS_ID : 0);
set_idnum('.', dotid);
macro_ptr = saved_macro_ptr;
}

406
tccelf.c
View File

@ -38,13 +38,18 @@ ST_DATA Section *bounds_section; /* contains global data bound description */
ST_DATA Section *lbounds_section; /* contains local data bound description */
#endif
/* symbol sections */
ST_DATA Section *symtab_section, *strtab_section;
ST_DATA Section *symtab_section;
/* debug sections */
ST_DATA Section *stab_section, *stabstr_section;
/* XXX: avoid static variable */
static int new_undef_sym = 0; /* Is there a new undefined sym since last new_undef_sym() */
/* special flag to indicate that the section should not be linked to the other ones */
#define SHF_PRIVATE 0x80000000
/* section is dynsymtab_section */
#define SHF_DYNSYM 0x40000000
/* ------------------------------------------------------------------------- */
ST_FUNC void tccelf_new(TCCState *s)
@ -63,11 +68,10 @@ ST_FUNC void tccelf_new(TCCState *s)
symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0,
".strtab",
".hashtab", SHF_PRIVATE);
strtab_section = symtab_section->link;
s->symtab = symtab_section;
/* private symbol table for dynamic symbols */
s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE,
s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE|SHF_DYNSYM,
".dynstrtab",
".dynhashtab", SHF_PRIVATE);
get_sym_attr(s, 0, 1);
@ -128,6 +132,61 @@ ST_FUNC void tccelf_delete(TCCState *s1)
/* free loaded dlls array */
dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls);
tcc_free(s1->sym_attrs);
symtab_section = NULL; /* for tccrun.c:rt_printline() */
}
/* save section data state */
ST_FUNC void tccelf_begin_file(TCCState *s1)
{
Section *s; int i;
for (i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
s->sh_offset = s->data_offset;
}
/* disable symbol hashing during compilation */
s = s1->symtab, s->reloc = s->hash, s->hash = NULL;
#if defined TCC_TARGET_X86_64 && defined TCC_TARGET_PE
s1->uw_sym = 0;
#endif
}
/* At the end of compilation, convert any UNDEF syms to global, and merge
with previously existing symbols */
ST_FUNC void tccelf_end_file(TCCState *s1)
{
Section *s = s1->symtab;
int first_sym, nb_syms, *tr, i;
first_sym = s->sh_offset / sizeof (ElfSym);
nb_syms = s->data_offset / sizeof (ElfSym) - first_sym;
s->data_offset = s->sh_offset;
s->link->data_offset = s->link->sh_offset;
s->hash = s->reloc, s->reloc = NULL;
tr = tcc_mallocz(nb_syms * sizeof *tr);
for (i = 0; i < nb_syms; ++i) {
ElfSym *sym = (ElfSym*)s->data + first_sym + i;
if (sym->st_shndx == SHN_UNDEF
&& ELFW(ST_BIND)(sym->st_info) == STB_LOCAL)
sym->st_info = ELFW(ST_INFO)(STB_GLOBAL, ELFW(ST_TYPE)(sym->st_info));
tr[i] = set_elf_sym(s, sym->st_value, sym->st_size, sym->st_info,
sym->st_other, sym->st_shndx, s->link->data + sym->st_name);
}
/* now update relocations */
for (i = 1; i < s1->nb_sections; i++) {
Section *sr = s1->sections[i];
if (sr->sh_type == SHT_RELX && sr->link == s) {
ElfW_Rel *rel = (ElfW_Rel*)(sr->data + sr->sh_offset);
ElfW_Rel *rel_end = (ElfW_Rel*)(sr->data + sr->data_offset);
for (; rel < rel_end; ++rel) {
int n = ELFW(R_SYM)(rel->r_info) - first_sym;
//if (n < 0) tcc_error("internal: invalid symbol index in relocation");
rel->r_info = ELFW(R_INFO)(tr[n], ELFW(R_TYPE)(rel->r_info));
}
}
}
tcc_free(tr);
}
ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags)
@ -269,7 +328,7 @@ ST_FUNC int put_elf_str(Section *s, const char *sym)
len = strlen(sym) + 1;
offset = s->data_offset;
ptr = section_ptr_add(s, len);
memcpy(ptr, sym, len);
memmove(ptr, sym, len);
return offset;
}
@ -299,6 +358,9 @@ static void rebuild_hash(Section *s, unsigned int nb_buckets)
strtab = s->link->data;
nb_syms = s->data_offset / sizeof(ElfW(Sym));
if (!nb_buckets)
nb_buckets = ((int*)s->hash->data)[0];
s->hash->data_offset = 0;
ptr = section_ptr_add(s->hash, (2 + nb_buckets + nb_syms) * sizeof(int));
ptr[0] = nb_buckets;
@ -332,7 +394,7 @@ ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size,
Section *hs;
sym = section_ptr_add(s, sizeof(ElfW(Sym)));
if (name)
if (name && name[0])
name_offset = put_elf_str(s->link, name);
else
name_offset = 0;
@ -349,11 +411,11 @@ ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size,
int *ptr, *base;
ptr = section_ptr_add(hs, sizeof(int));
base = (int *)hs->data;
/* only add global or weak symbols */
/* only add global or weak symbols. */
if (ELFW(ST_BIND)(info) != STB_LOCAL) {
/* add another hashing entry */
nbuckets = base[0];
h = elf_hash((unsigned char *) name) % nbuckets;
h = elf_hash((unsigned char *)s->link->data + name_offset) % nbuckets;
*ptr = base[2 + h];
base[2 + h] = sym_index;
base[1]++;
@ -370,8 +432,6 @@ ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size,
return sym_index;
}
/* find global ELF symbol 'name' and return its index. Return 0 if not
found. */
ST_FUNC int find_elf_sym(Section *s, const char *name)
{
ElfW(Sym) *sym;
@ -438,17 +498,15 @@ ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size,
sym_type = ELFW(ST_TYPE)(info);
sym_vis = ELFW(ST_VISIBILITY)(other);
sym_index = find_elf_sym(s, name);
esym = &((ElfW(Sym) *)s->data)[sym_index];
if (sym_index && esym->st_value == value && esym->st_size == size
&& esym->st_info == info && esym->st_other == other
&& esym->st_shndx == shndx)
return sym_index;
if (sym_bind != STB_LOCAL) {
/* we search global or weak symbols */
sym_index = find_elf_sym(s, name);
if (!sym_index)
goto do_def;
esym = &((ElfW(Sym) *)s->data)[sym_index];
if (esym->st_value == value && esym->st_size == size && esym->st_info == info
&& esym->st_other == other && esym->st_shndx == shndx)
return sym_index;
if (esym->st_shndx != SHN_UNDEF) {
esym_bind = ELFW(ST_BIND)(esym->st_info);
/* propagate the most constraining visibility */
@ -484,8 +542,12 @@ ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size,
goto do_patch;
} else if (shndx == SHN_COMMON || shndx == bss_section->sh_num) {
/* data symbol keeps precedence over common/bss */
} else if (s == tcc_state->dynsymtab_section) {
} else if (s->sh_flags & SHF_DYNSYM) {
/* we accept that two DLL define the same symbol */
} else if (esym->st_other & ST_ASM_SET) {
/* If the existing symbol came from an asm .set
we can override. */
goto do_patch;
} else {
#if 0
printf("new_bind=%x new_shndx=%x new_vis=%x old_bind=%x old_shndx=%x old_vis=%x\n",
@ -679,7 +741,8 @@ static void sort_syms(TCCState *s1, Section *s)
p++;
}
/* save the number of local symbols in section header */
s->sh_info = q - new_syms;
if( s->sh_size ) /* this 'if' makes IDA happy */
s->sh_info = q - new_syms;
/* then second pass for non local symbols */
p = (ElfW(Sym) *)s->data;
@ -711,21 +774,6 @@ static void sort_syms(TCCState *s1, Section *s)
tcc_free(old_to_new_syms);
}
/* relocate common symbols in the .bss section */
ST_FUNC void relocate_common_syms(void)
{
ElfW(Sym) *sym;
for_each_elem(symtab_section, 1, sym, ElfW(Sym)) {
if (sym->st_shndx == SHN_COMMON) {
/* symbol alignment is in st_value for SHN_COMMONs */
sym->st_value = section_add(bss_section, sym->st_size,
sym->st_value);
sym->st_shndx = bss_section->sh_num;
}
}
}
/* relocate symbol table, resolve undefined symbols if do_resolve is
true and output error if undefined symbol. */
ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve)
@ -737,7 +785,7 @@ ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve)
for_each_elem(symtab, 1, sym, ElfW(Sym)) {
sh_num = sym->st_shndx;
if (sh_num == SHN_UNDEF) {
name = (char *) strtab_section->data + sym->st_name;
name = (char *) s1->symtab->link->data + sym->st_name;
/* Use ld.so to resolve symbol for us (for tcc -run) */
if (do_resolve) {
#if defined TCC_IS_NATIVE && !defined TCC_TARGET_PE
@ -818,15 +866,24 @@ static void relocate_rel(TCCState *s1, Section *sr)
static int prepare_dynamic_rel(TCCState *s1, Section *sr)
{
ElfW_Rel *rel;
int sym_index, type, count;
int type, count;
count = 0;
for_each_elem(sr, 0, rel, ElfW_Rel) {
sym_index = ELFW(R_SYM)(rel->r_info);
type = ELFW(R_TYPE)(rel->r_info);
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
int sym_index = ELFW(R_SYM)(rel->r_info);
#endif
switch(type) {
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
#if defined(TCC_TARGET_I386)
case R_386_32:
if (!get_sym_attr(s1, sym_index, 0)->dyn_index
&& ((ElfW(Sym)*)symtab_section->data + sym_index)->st_shndx == SHN_UNDEF) {
/* don't fixup unresolved (weak) symbols */
rel->r_info = ELFW(R_INFO)(sym_index, R_386_RELATIVE);
break;
}
#elif defined(TCC_TARGET_X86_64)
case R_X86_64_32:
case R_X86_64_32S:
@ -842,6 +899,7 @@ static int prepare_dynamic_rel(TCCState *s1, Section *sr)
if (get_sym_attr(s1, sym_index, 0)->dyn_index)
count++;
break;
#endif
default:
break;
}
@ -1090,7 +1148,6 @@ static void add_init_array_defines(TCCState *s1, const char *section_name)
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
s->sh_num, sym_end);
}
#endif
static int tcc_add_support(TCCState *s1, const char *filename)
{
@ -1098,6 +1155,7 @@ static int tcc_add_support(TCCState *s1, const char *filename)
snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, filename);
return tcc_add_file(s1, buf);
}
#endif
ST_FUNC void tcc_add_bcheck(TCCState *s1)
{
@ -1133,8 +1191,10 @@ ST_FUNC void tcc_add_bcheck(TCCState *s1)
/* add tcc runtime libraries */
ST_FUNC void tcc_add_runtime(TCCState *s1)
{
s1->filetype = 0;
tcc_add_bcheck(s1);
tcc_add_pragma_libs(s1);
#ifndef TCC_TARGET_PE
/* add libc */
if (!s1->nostdlib) {
tcc_add_library_err(s1, "c");
@ -1151,12 +1211,13 @@ ST_FUNC void tcc_add_runtime(TCCState *s1)
if (s1->output_type != TCC_OUTPUT_MEMORY)
tcc_add_crt(s1, "crtn.o");
}
#endif
}
/* add various standard linker symbols (must be done after the
sections are filled (for example after allocating common
symbols)) */
ST_FUNC void tcc_add_linker_symbols(TCCState *s1)
static void tcc_add_linker_symbols(TCCState *s1)
{
char buf[1024];
int i;
@ -1215,6 +1276,24 @@ ST_FUNC void tcc_add_linker_symbols(TCCState *s1)
}
}
ST_FUNC void resolve_common_syms(TCCState *s1)
{
ElfW(Sym) *sym;
/* Allocate common symbols in BSS. */
for_each_elem(symtab_section, 1, sym, ElfW(Sym)) {
if (sym->st_shndx == SHN_COMMON) {
/* symbol alignment is in st_value for SHN_COMMONs */
sym->st_value = section_add(bss_section, sym->st_size,
sym->st_value);
sym->st_shndx = bss_section->sh_num;
}
}
/* Now assign linker provided symbols their value. */
tcc_add_linker_symbols(s1);
}
static void tcc_output_binary(TCCState *s1, FILE *f,
const int *sec_order)
{
@ -1237,14 +1316,6 @@ static void tcc_output_binary(TCCState *s1, FILE *f,
}
}
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#define HAVE_PHDR 1
#define EXTRA_RELITEMS 14
#else
#define HAVE_PHDR 1
#define EXTRA_RELITEMS 9
#endif
ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel)
{
int sym_index = ELFW(R_SYM) (rel->r_info);
@ -1295,6 +1366,8 @@ ST_FUNC void fill_got(TCCState *s1)
static void fill_local_got_entries(TCCState *s1)
{
ElfW_Rel *rel;
if (!s1->got->reloc)
return;
for_each_elem(s1->got->reloc, 0, rel, ElfW_Rel) {
if (ELFW(R_TYPE)(rel->r_info) == R_RELATIVE) {
int sym_index = ELFW(R_SYM) (rel->r_info);
@ -1412,13 +1485,12 @@ static void bind_libs_dynsyms(TCCState *s1)
for_each_elem(s1->dynsymtab_section, 1, esym, ElfW(Sym)) {
name = (char *) s1->dynsymtab_section->link->data + esym->st_name;
sym_index = find_elf_sym(symtab_section, name);
/* XXX: avoid adding a symbol if already present because of
-rdynamic ? */
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
if (sym_index && sym->st_shndx != SHN_UNDEF)
set_elf_sym(s1->dynsym, sym->st_value, sym->st_size, sym->st_info,
0, sym->st_shndx, name);
else if (esym->st_shndx == SHN_UNDEF) {
if (sym_index && sym->st_shndx != SHN_UNDEF
&& ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
set_elf_sym(s1->dynsym, sym->st_value, sym->st_size,
sym->st_info, 0, sym->st_shndx, name);
} else if (esym->st_shndx == SHN_UNDEF) {
/* weak symbols can stay undefined */
if (ELFW(ST_BIND)(esym->st_info) != STB_WEAK)
tcc_warning("undefined dynamic symbol '%s'", name);
@ -1450,10 +1522,11 @@ static void export_global_syms(TCCState *s1)
/* Allocate strings for section names and decide if an unallocated section
should be output.
NOTE: the strsec section comes last, so its size is also correct ! */
static void alloc_sec_names(TCCState *s1, int file_type, Section *strsec)
static int alloc_sec_names(TCCState *s1, int file_type, Section *strsec)
{
int i;
Section *s;
int textrel = 0;
/* Allocate strings for section names */
for(i = 1; i < s1->nb_sections; i++) {
@ -1462,13 +1535,12 @@ static void alloc_sec_names(TCCState *s1, int file_type, Section *strsec)
patch them */
if (file_type == TCC_OUTPUT_DLL &&
s->sh_type == SHT_RELX &&
!(s->sh_flags & SHF_ALLOC)) {
/* gr: avoid bogus relocs for empty (debug) sections */
if (s1->sections[s->sh_info]->sh_flags & SHF_ALLOC)
prepare_dynamic_rel(s1, s);
else if (s1->do_debug)
s->sh_size = s->data_offset;
} else if (s1->do_debug ||
!(s->sh_flags & SHF_ALLOC) &&
(s1->sections[s->sh_info]->sh_flags & SHF_ALLOC) &&
prepare_dynamic_rel(s1, s)) {
if (s1->sections[s->sh_info]->sh_flags & SHF_EXECINSTR)
textrel = 1;
} else if ((s1->do_debug && s->sh_type != SHT_RELX) ||
file_type == TCC_OUTPUT_OBJ ||
(s->sh_flags & SHF_ALLOC) ||
i == (s1->nb_sections - 1)) {
@ -1479,13 +1551,14 @@ static void alloc_sec_names(TCCState *s1, int file_type, Section *strsec)
s->sh_name = put_elf_str(strsec, s->name);
}
strsec->sh_size = strsec->data_offset;
return textrel;
}
/* Info to be copied in dynamic section */
struct dyn_inf {
Section *dynamic;
Section *dynstr;
unsigned long dyn_rel_off;
unsigned long data_offset;
addr_t rel_addr;
addr_t rel_size;
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
@ -1541,7 +1614,7 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum,
the program header table itself if needed. These are done later as
they require section layout to be done first. */
if (interp)
ph += 1 + HAVE_PHDR;
ph += 2;
/* dynamic relocation table information, for .dynamic section */
dyninf->rel_addr = dyninf->rel_size = 0;
@ -1683,19 +1756,14 @@ static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp,
if (interp) {
ph = &phdr[0];
if (HAVE_PHDR)
{
int len = phnum * sizeof(ElfW(Phdr));
ph->p_type = PT_PHDR;
ph->p_offset = sizeof(ElfW(Ehdr));
ph->p_vaddr = interp->sh_addr - len;
ph->p_paddr = ph->p_vaddr;
ph->p_filesz = ph->p_memsz = len;
ph->p_flags = PF_R | PF_X;
ph->p_align = 4; /* interp->sh_addralign; */
ph++;
}
ph->p_type = PT_PHDR;
ph->p_offset = sizeof(ElfW(Ehdr));
ph->p_filesz = ph->p_memsz = phnum * sizeof(ElfW(Phdr));
ph->p_vaddr = interp->sh_addr - ph->p_filesz;
ph->p_paddr = ph->p_vaddr;
ph->p_flags = PF_R | PF_X;
ph->p_align = 4; /* interp->sh_addralign; */
ph++;
ph->p_type = PT_INTERP;
ph->p_offset = interp->sh_offset;
@ -1726,12 +1794,9 @@ static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp,
sections */
static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf)
{
Section *dynamic;
dynamic = dyninf->dynamic;
Section *dynamic = dyninf->dynamic;
/* put dynamic section entries */
dynamic->data_offset = dyninf->dyn_rel_off;
put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr);
put_dt(dynamic, DT_STRTAB, dyninf->dynstr->sh_addr);
put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr);
@ -1776,14 +1841,7 @@ static int final_sections_reloc(TCCState *s1)
/* XXX: ignore sections with allocated relocations ? */
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
#if defined(TCC_TARGET_I386) || defined(TCC_MUSL)
if (s->reloc && s != s1->got && (s->sh_flags & SHF_ALLOC)) //gr
/* On X86 gdb 7.3 works in any case but gdb 6.6 will crash if SHF_ALLOC
checking is removed */
#else
if (s->reloc && s != s1->got)
/* On X86_64 gdb 7.3 will crash if SHF_ALLOC checking is present */
#endif
relocate_section(s1, s);
}
@ -1831,7 +1889,8 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr,
ehdr.e_ident[4] = ELFCLASSW;
ehdr.e_ident[5] = ELFDATA2LSB;
ehdr.e_ident[6] = EV_CURRENT;
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#if !defined(TCC_TARGET_PE) && (defined(__FreeBSD__) || defined(__FreeBSD_kernel__))
/* FIXME: should set only for freebsd _target_, but we exclude only PE target */
ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
#endif
#ifdef TCC_TARGET_ARM
@ -1985,10 +2044,11 @@ static void tidy_section_headers(TCCState *s1, int *sec_order)
for_each_elem(symtab_section, 1, sym, ElfW(Sym))
if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE)
sym->st_shndx = backmap[sym->st_shndx];
for_each_elem(s1->dynsym, 1, sym, ElfW(Sym))
if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE)
sym->st_shndx = backmap[sym->st_shndx];
if( !s1->static_link ) {
for_each_elem(s1->dynsym, 1, sym, ElfW(Sym))
if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE)
sym->st_shndx = backmap[sym->st_shndx];
}
for (i = 0; i < s1->nb_sections; i++)
sec_order[i] = i;
tcc_free(s1->sections);
@ -2006,23 +2066,20 @@ static int elf_output_file(TCCState *s1, const char *filename)
ElfW(Phdr) *phdr;
ElfW(Sym) *sym;
Section *strsec, *interp, *dynamic, *dynstr;
int textrel;
file_type = s1->output_type;
s1->nb_errors = 0;
/* if linking, also link in runtime libraries (libc, libgcc, etc.) */
if (file_type != TCC_OUTPUT_OBJ) {
tcc_add_runtime(s1);
}
ret = -1;
phdr = NULL;
sec_order = NULL;
interp = dynamic = dynstr = NULL; /* avoid warning */
textrel = 0;
if (file_type != TCC_OUTPUT_OBJ) {
relocate_common_syms();
tcc_add_linker_symbols(s1);
/* if linking, also link in runtime libraries (libc, libgcc, etc.) */
tcc_add_runtime(s1);
resolve_common_syms(s1);
if (!s1->static_link) {
if (file_type == TCC_OUTPUT_EXE) {
@ -2054,53 +2111,70 @@ static int elf_output_file(TCCState *s1, const char *filename)
if (file_type == TCC_OUTPUT_EXE) {
bind_exe_dynsyms(s1);
if (s1->nb_errors) {
ret = -1;
if (s1->nb_errors)
goto the_end;
}
bind_libs_dynsyms(s1);
} else /* shared library case: simply export all global symbols */
} else {
/* shared library case: simply export all global symbols */
export_global_syms(s1);
build_got_entries(s1);
/* add a list of needed dlls */
for(i = 0; i < s1->nb_loaded_dlls; i++) {
DLLReference *dllref = s1->loaded_dlls[i];
if (dllref->level == 0)
put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, dllref->name));
}
if (s1->rpath)
put_dt(dynamic, s1->enable_new_dtags ? DT_RUNPATH : DT_RPATH,
put_elf_str(dynstr, s1->rpath));
/* XXX: currently, since we do not handle PIC code, we
must relocate the readonly segments */
if (file_type == TCC_OUTPUT_DLL) {
if (s1->soname)
put_dt(dynamic, DT_SONAME, put_elf_str(dynstr, s1->soname));
put_dt(dynamic, DT_TEXTREL, 0);
}
if (s1->symbolic)
put_dt(dynamic, DT_SYMBOLIC, 0);
/* add necessary space for other entries */
dyninf.dyn_rel_off = dynamic->data_offset;
dynamic->data_offset += sizeof(ElfW(Dyn)) * EXTRA_RELITEMS;
} else {
/* still need to build got entries in case of static link */
build_got_entries(s1);
}
build_got_entries(s1);
}
/* we add a section for symbols */
strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0);
put_elf_str(strsec, "");
/* Allocate strings for section names */
textrel = alloc_sec_names(s1, file_type, strsec);
if (dynamic) {
/* add a list of needed dlls */
for(i = 0; i < s1->nb_loaded_dlls; i++) {
DLLReference *dllref = s1->loaded_dlls[i];
if (dllref->level == 0)
put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, dllref->name));
}
if (s1->rpath)
put_dt(dynamic, s1->enable_new_dtags ? DT_RUNPATH : DT_RPATH,
put_elf_str(dynstr, s1->rpath));
if (file_type == TCC_OUTPUT_DLL) {
if (s1->soname)
put_dt(dynamic, DT_SONAME, put_elf_str(dynstr, s1->soname));
/* XXX: currently, since we do not handle PIC code, we
must relocate the readonly segments */
if (textrel)
put_dt(dynamic, DT_TEXTREL, 0);
}
if (s1->symbolic)
put_dt(dynamic, DT_SYMBOLIC, 0);
dyninf.dynamic = dynamic;
dyninf.dynstr = dynstr;
/* remember offset and reserve space for 2nd call below */
dyninf.data_offset = dynamic->data_offset;
fill_dynamic(s1, &dyninf);
dynamic->sh_size = dynamic->data_offset;
dynstr->sh_size = dynstr->data_offset;
}
/* compute number of program headers */
if (file_type == TCC_OUTPUT_OBJ)
phnum = 0;
else if (file_type == TCC_OUTPUT_DLL)
phnum = 3;
else if (s1->static_link)
phnum = 2;
else
phnum = 5;
/* allocate program segment headers */
phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr)));
/* compute number of sections */
shnum = s1->nb_sections;
@ -2108,41 +2182,16 @@ static int elf_output_file(TCCState *s1, const char *filename)
sec_order = tcc_malloc(sizeof(int) * shnum);
sec_order[0] = 0;
/* compute number of program headers */
switch(file_type) {
default:
case TCC_OUTPUT_OBJ:
phnum = 0;
break;
case TCC_OUTPUT_EXE:
if (!s1->static_link)
phnum = 4 + HAVE_PHDR;
else
phnum = 2;
break;
case TCC_OUTPUT_DLL:
phnum = 3;
break;
}
/* Allocate strings for section names */
alloc_sec_names(s1, file_type, strsec);
/* allocate program segment headers */
phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr)));
/* compute section to program header mapping */
file_offset = layout_sections(s1, phdr, phnum, interp, strsec, &dyninf,
sec_order);
/* Fill remaining program header and finalize relocation related to dynamic
linking. */
if (phnum > 0) {
if (file_type != TCC_OUTPUT_OBJ) {
fill_unloadable_phdr(phdr, phnum, interp, dynamic);
if (dynamic) {
dyninf.dynamic = dynamic;
dyninf.dynstr = dynstr;
dynamic->data_offset = dyninf.data_offset;
fill_dynamic(s1, &dyninf);
/* put in GOT the dynamic section address and relocate PLT */
@ -2159,22 +2208,20 @@ static int elf_output_file(TCCState *s1, const char *filename)
}
}
}
}
/* if building executable or DLL, then relocate each section
except the GOT which is already relocated */
if (file_type != TCC_OUTPUT_OBJ) {
/* if building executable or DLL, then relocate each section
except the GOT which is already relocated */
ret = final_sections_reloc(s1);
if (ret)
goto the_end;
tidy_section_headers(s1, sec_order);
}
/* Perform relocation to GOT or PLT entries */
if (file_type == TCC_OUTPUT_EXE && s1->static_link)
fill_got(s1);
else if (s1->got)
fill_local_got_entries(s1);
/* Perform relocation to GOT or PLT entries */
if (file_type == TCC_OUTPUT_EXE && s1->static_link)
fill_got(s1);
else if (s1->got)
fill_local_got_entries(s1);
}
/* Create the ELF file with name 'filename' */
ret = tcc_write_elf_file(s1, filename, phnum, phdr, file_offset, sec_order);
@ -2400,8 +2447,11 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
a = (Stab_Sym *)(s->data + sm_table[stab_index].offset);
b = (Stab_Sym *)(s->data + s->data_offset);
o = sm_table[stabstr_index].offset;
while (a < b)
a->n_strx += o, a++;
while (a < b) {
if (a->n_strx)
a->n_strx += o;
a++;
}
}
/* second short pass to update sh_link and sh_info fields of new
@ -2588,7 +2638,7 @@ static int tcc_load_alacarte(TCCState *s1, int fd, int size, int entrysize)
}
/* load a '.a' file */
ST_FUNC int tcc_load_archive(TCCState *s1, int fd)
ST_FUNC int tcc_load_archive(TCCState *s1, int fd, int alacarte)
{
ArchiveHeader hdr;
char ar_size[11];
@ -2622,10 +2672,10 @@ ST_FUNC int tcc_load_archive(TCCState *s1, int fd)
size = (size + 1) & ~1;
if (!strcmp(ar_name, "/")) {
/* coff symbol table : we handle it */
if(s1->alacarte_link)
if (alacarte)
return tcc_load_alacarte(s1, fd, size, 4);
} else if (!strcmp(ar_name, "/SYM64/")) {
if(s1->alacarte_link)
if (alacarte)
return tcc_load_alacarte(s1, fd, size, 8);
} else {
ElfW(Ehdr) ehdr;

1991
tccgen.c

File diff suppressed because it is too large Load Diff

124
tccpe.c
View File

@ -26,10 +26,12 @@
#ifndef _WIN32
#define stricmp strcasecmp
#define strnicmp strncasecmp
#include <sys/stat.h> /* chmod() */
#endif
#ifdef TCC_TARGET_X86_64
# define ADDR3264 ULONGLONG
# define PE_IMAGE_REL IMAGE_REL_BASED_DIR64
# define REL_TYPE_DIRECT R_X86_64_64
# define R_XXX_THUNKFIX R_X86_64_PC32
# define R_XXX_RELATIVE R_X86_64_RELATIVE
@ -38,6 +40,7 @@
#elif defined TCC_TARGET_ARM
# define ADDR3264 DWORD
# define PE_IMAGE_REL IMAGE_REL_BASED_HIGHLOW
# define REL_TYPE_DIRECT R_ARM_ABS32
# define R_XXX_THUNKFIX R_ARM_ABS32
# define R_XXX_RELATIVE R_ARM_RELATIVE
@ -46,6 +49,7 @@
#elif defined TCC_TARGET_I386
# define ADDR3264 DWORD
# define PE_IMAGE_REL IMAGE_REL_BASED_HIGHLOW
# define REL_TYPE_DIRECT R_386_32
# define R_XXX_THUNKFIX R_386_32
# define R_XXX_RELATIVE R_386_RELATIVE
@ -54,22 +58,6 @@
#endif
#if 0
#ifdef _WIN32
void dbg_printf (const char *fmt, ...)
{
char buffer[4000];
va_list arg;
int x;
va_start(arg, fmt);
x = vsprintf (buffer, fmt, arg);
strcpy(buffer+x, "\n");
OutputDebugString(buffer);
}
#endif
#endif
/* ----------------------------------------------------------- */
#ifndef IMAGE_NT_SIGNATURE
/* ----------------------------------------------------------- */
/* definitions below are from winnt.h */
@ -241,14 +229,19 @@ typedef struct _IMAGE_BASE_RELOCATION {
#define IMAGE_REL_BASED_MIPS_JMPADDR 5
#define IMAGE_REL_BASED_SECTION 6
#define IMAGE_REL_BASED_REL32 7
#define IMAGE_REL_BASED_DIR64 10
#pragma pack(pop)
/* ----------------------------------------------------------- */
#endif /* ndef IMAGE_NT_SIGNATURE */
/* ----------------------------------------------------------- */
#pragma pack(push, 1)
#ifndef IMAGE_REL_BASED_DIR64
# define IMAGE_REL_BASED_DIR64 10
#endif
#pragma pack(push, 1)
struct pe_header
{
IMAGE_DOS_HEADER doshdr;
@ -281,7 +274,6 @@ struct pe_rsrc_reloc {
DWORD size;
WORD type;
};
#pragma pack(pop)
/* ------------------------------------------------------------- */
@ -732,6 +724,9 @@ static int pe_write(struct pe_info *pe)
fseek(op, offsetof(struct pe_header, opthdr.CheckSum), SEEK_SET);
pe_fwrite(&pe_header.opthdr.CheckSum, sizeof pe_header.opthdr.CheckSum, op, NULL);
fclose (op);
#ifndef _WIN32
chmod(pe->filename, 0777);
#endif
if (2 == pe->s1->verbose)
printf("-------------------------------\n");
@ -959,7 +954,7 @@ static void pe_build_exports(struct pe_info *pe)
/* automatically write exports to <output-filename>.def */
pstrcpy(buf, sizeof buf, pe->filename);
strcpy(tcc_fileextension(buf), ".def");
op = fopen(buf, "w");
op = fopen(buf, "wb");
if (NULL == op) {
tcc_error_noabort("could not create '%s': %s", buf, strerror(errno));
} else {
@ -972,7 +967,7 @@ static void pe_build_exports(struct pe_info *pe)
for (ord = 0; ord < sym_count; ++ord)
{
p = sorted[ord], sym_index = p->index, name = p->name;
/* insert actual address later in pe_relocate_rva */
/* insert actual address later in relocate_section() */
put_elf_reloc(symtab_section, pe->thunk,
func_o, R_XXX_RELATIVE, sym_index);
*(DWORD*)(pe->thunk->data + name_o)
@ -1017,7 +1012,7 @@ static void pe_build_reloc (struct pe_info *pe)
}
if ((addr -= offset) < (1<<12)) { /* one block spans 4k addresses */
WORD *wp = section_ptr_add(pe->reloc, sizeof (WORD));
*wp = addr | IMAGE_REL_BASED_HIGHLOW<<12;
*wp = addr | PE_IMAGE_REL<<12;
++count;
continue;
}
@ -1186,26 +1181,6 @@ static int pe_assign_addresses (struct pe_info *pe)
return 0;
}
/* ------------------------------------------------------------- */
static void pe_relocate_rva (struct pe_info *pe, Section *s)
{
Section *sr = s->reloc;
ElfW_Rel *rel, *rel_end;
rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
for(rel = (ElfW_Rel *)sr->data; rel < rel_end; rel++) {
if (ELFW(R_TYPE)(rel->r_info) == R_XXX_RELATIVE) {
int sym_index = ELFW(R_SYM)(rel->r_info);
DWORD addr = s->sh_addr;
if (sym_index) {
ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index;
addr = sym->st_value;
}
// printf("reloc rva %08x %08x %s\n", (DWORD)rel->r_offset, addr, s->name);
*(DWORD*)(s->data + rel->r_offset) += addr - pe->imagebase;
}
}
}
/*----------------------------------------------------------------------------*/
static int pe_isafunc(int sym_index)
@ -1471,13 +1446,13 @@ static void pe_print_sections(TCCState *s1, const char *fname)
/* ------------------------------------------------------------- */
/* helper function for load/store to insert one more indirection */
#ifndef TCC_TARGET_ARM
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2)
{
int r2;
if ((sv->r & (VT_VALMASK|VT_SYM)) != (VT_CONST|VT_SYM) || (sv->r2 != VT_CONST))
return sv;
if (!(sv->sym->type.t & VT_IMPORT))
if (!sv->sym->a.dllimport)
return sv;
// printf("import %04x %04x %04x %s\n", sv->type.t, sv->sym->type.t, sv->r, get_tok_str(sv->sym->v, NULL));
memset(v2, 0, sizeof *v2);
@ -1547,11 +1522,7 @@ PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp)
IMAGE_DOS_HEADER dh;
IMAGE_FILE_HEADER ih;
DWORD sig, ref, addr, ptr, namep;
#ifdef TCC_TARGET_X86_64
IMAGE_OPTIONAL_HEADER64 oh;
#else
IMAGE_OPTIONAL_HEADER32 oh;
#endif
int pef_hdroffset, opt_hdroffset, sec_hdroffset;
n = n0 = 0;
@ -1562,7 +1533,6 @@ PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp)
if (fd < 0)
goto the_end_1;
ret = 1;
if (!read_mem(fd, 0, &dh, sizeof dh))
goto the_end;
if (!read_mem(fd, dh.e_lfanew, &sig, sizeof sig))
@ -1572,22 +1542,26 @@ PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp)
pef_hdroffset = dh.e_lfanew + sizeof sig;
if (!read_mem(fd, pef_hdroffset, &ih, sizeof ih))
goto the_end;
if (IMAGE_FILE_MACHINE != ih.Machine) {
if (ih.Machine == 0x014C)
ret = 32;
else if (ih.Machine == 0x8664)
ret = 64;
goto the_end;
}
opt_hdroffset = pef_hdroffset + sizeof ih;
sec_hdroffset = opt_hdroffset + sizeof oh;
if (!read_mem(fd, opt_hdroffset, &oh, sizeof oh))
if (ih.Machine == 0x014C) {
IMAGE_OPTIONAL_HEADER32 oh;
sec_hdroffset = opt_hdroffset + sizeof oh;
if (!read_mem(fd, opt_hdroffset, &oh, sizeof oh))
goto the_end;
if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes)
goto the_end_0;
addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
} else if (ih.Machine == 0x8664) {
IMAGE_OPTIONAL_HEADER64 oh;
sec_hdroffset = opt_hdroffset + sizeof oh;
if (!read_mem(fd, opt_hdroffset, &oh, sizeof oh))
goto the_end;
if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes)
goto the_end_0;
addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
} else
goto the_end;
if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes)
goto the_end_0;
addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
//printf("addr: %08x\n", addr);
for (i = 0; i < ih.NumberOfSections; ++i) {
if (!read_mem(fd, sec_hdroffset + i * sizeof ish, &ish, sizeof ish))
@ -1639,7 +1613,7 @@ static int pe_load_res(TCCState *s1, int fd)
{
struct pe_rsrc_header hdr;
Section *rsrc_section;
int i, ret = -1;
int i, ret = -1, sym_index;
BYTE *ptr;
unsigned offs;
@ -1657,8 +1631,8 @@ static int pe_load_res(TCCState *s1, int fd)
if (!read_mem(fd, offs, ptr, hdr.sectionhdr.SizeOfRawData))
goto quit;
offs = hdr.sectionhdr.PointerToRelocations;
for (i = 0; i < hdr.sectionhdr.NumberOfRelocations; ++i)
{
sym_index = put_elf_sym(symtab_section, 0, 0, 0, 0, rsrc_section->sh_num, ".rsrc");
for (i = 0; i < hdr.sectionhdr.NumberOfRelocations; ++i) {
struct pe_rsrc_reloc rel;
if (!read_mem(fd, offs, &rel, sizeof rel))
goto quit;
@ -1666,7 +1640,7 @@ static int pe_load_res(TCCState *s1, int fd)
if (rel.type != RSRC_RELTYPE)
goto quit;
put_elf_reloc(symtab_section, rsrc_section,
rel.offset, R_XXX_RELATIVE, 0);
rel.offset, R_XXX_RELATIVE, sym_index);
offs += sizeof rel;
}
ret = 0;
@ -1785,9 +1759,9 @@ static unsigned pe_add_uwwind_info(TCCState *s1)
if (NULL == s1->uw_pdata) {
s1->uw_pdata = find_section(tcc_state, ".pdata");
s1->uw_pdata->sh_addralign = 4;
s1->uw_sym = put_elf_sym(symtab_section, 0, 0, 0, 0, text_section->sh_num, NULL);
}
if (0 == s1->uw_sym)
s1->uw_sym = put_elf_sym(symtab_section, 0, 0, 0, 0, text_section->sh_num, ".uw_base");
if (0 == s1->uw_offs) {
/* As our functions all have the same stackframe, we use one entry for all */
static const unsigned char uw_info[] = {
@ -1836,7 +1810,7 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack)
/* put relocations on it */
for (n = o + sizeof *p; o < n; o += sizeof p->BeginAddress)
put_elf_reloc(symtab_section, pd, o, R_X86_64_RELATIVE, s1->uw_sym);
put_elf_reloc(symtab_section, pd, o, R_XXX_RELATIVE, s1->uw_sym);
}
#endif
/* ------------------------------------------------------------- */
@ -1892,8 +1866,6 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
SHN_UNDEF, start_symbol);
tcc_add_pragma_libs(s1);
if (0 == s1->nostdlib) {
static const char *libs[] = {
TCC_LIBTCC1, "msvcrt", "kernel32", "", "user32", "gdi32", NULL
@ -1974,10 +1946,9 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
pe.filename = filename;
pe.s1 = s1;
tcc_add_bcheck(s1);
tcc_add_runtime(s1);
pe_add_runtime(s1, &pe);
relocate_common_syms(); /* assign bss addresses */
tcc_add_linker_symbols(s1);
resolve_common_syms(s1);
pe_set_options(s1, &pe);
ret = pe_check_symbols(&pe);
@ -1986,11 +1957,11 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
else if (filename) {
pe_assign_addresses(&pe);
relocate_syms(s1, s1->symtab, 0);
s1->pe_imagebase = pe.imagebase;
for (i = 1; i < s1->nb_sections; ++i) {
Section *s = s1->sections[i];
if (s->reloc) {
relocate_section(s1, s);
pe_relocate_rva(&pe, s);
}
}
pe.start_addr = (DWORD)
@ -2006,6 +1977,9 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
pe.thunk = data_section;
pe_build_imports(&pe);
s1->runtime_main = pe.start_symbol;
#ifdef TCC_TARGET_X86_64
s1->uw_pdata = find_section(s1, ".pdata");
#endif
#endif
}

985
tccpp.c

File diff suppressed because it is too large Load Diff

109
tccrun.c
View File

@ -45,15 +45,13 @@ static void set_exception_handler(void);
#endif
static void set_pages_executable(void *ptr, unsigned long length);
static int tcc_relocate_ex(TCCState *s1, void *ptr);
static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff);
#ifdef _WIN64
static void *win64_add_function_table(TCCState *s1);
static void win64_del_function_table(void *);
#endif
// #define HAVE_SELINUX
/* ------------------------------------------------------------- */
/* Do all relocations (needed before using tcc_get_symbol())
Returns -1 on error. */
@ -61,25 +59,36 @@ static void win64_del_function_table(void *);
LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr)
{
int size;
addr_t ptr_diff = 0;
if (TCC_RELOCATE_AUTO != ptr)
return tcc_relocate_ex(s1, ptr);
return tcc_relocate_ex(s1, ptr, 0);
size = tcc_relocate_ex(s1, NULL);
size = tcc_relocate_ex(s1, NULL, 0);
if (size < 0)
return -1;
#ifdef HAVE_SELINUX
/* Use mmap instead of malloc for Selinux. */
ptr = mmap (NULL, size, PROT_READ|PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (ptr == MAP_FAILED)
tcc_error("tccrun: could not map memory");
{
/* Using mmap instead of malloc */
void *prx;
char tmpfname[] = "/tmp/.tccrunXXXXXX";
int fd = mkstemp(tmpfname);
unlink(tmpfname);
ftruncate(fd, size);
ptr = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
prx = mmap (NULL, size, PROT_READ|PROT_EXEC, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED || prx == MAP_FAILED)
tcc_error("tccrun: could not map memory");
dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, (void*)(addr_t)size);
dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, prx);
ptr_diff = (char*)prx - (char*)ptr;
}
#else
ptr = tcc_malloc(size);
#endif
tcc_relocate_ex(s1, ptr); /* no more errors expected */
tcc_relocate_ex(s1, ptr, ptr_diff); /* no more errors expected */
dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, ptr);
return 0;
}
@ -91,6 +100,7 @@ ST_FUNC void tcc_run_free(TCCState *s1)
for (i = 0; i < s1->nb_runtime_mem; ++i) {
#ifdef HAVE_SELINUX
unsigned size = (unsigned)(addr_t)s1->runtime_mem[i++];
munmap(s1->runtime_mem[i++], size);
munmap(s1->runtime_mem[i], size);
#else
#ifdef _WIN64
@ -108,6 +118,8 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
int (*prog_main)(int, char **);
s1->runtime_main = "main";
if ((s1->dflag & 16) && !find_elf_sym(s1->symtab, s1->runtime_main))
return 0;
if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
return -1;
prog_main = tcc_get_symbol_err(s1, s1->runtime_main);
@ -157,18 +169,21 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
}
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
/* To avoid that x86 processors would reload cached instructions
each time when data is written in the near, we need to make
sure that code and data do not share the same 64 byte unit */
#define RUN_SECTION_ALIGNMENT 63
#else
#define RUN_SECTION_ALIGNMENT 15
#define RUN_SECTION_ALIGNMENT 0
#endif
/* relocate code. Return -1 on error, required size if ptr is NULL,
otherwise copy code into buffer passed by the caller */
static int tcc_relocate_ex(TCCState *s1, void *ptr)
static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff)
{
Section *s;
unsigned offset, length, fill, i, k;
addr_t mem;
unsigned offset, length, align, max_align, i, k, f;
addr_t mem, addr;
if (NULL == ptr) {
s1->nb_errors = 0;
@ -176,42 +191,39 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr)
pe_output_file(s1, NULL);
#else
tcc_add_runtime(s1);
relocate_common_syms();
tcc_add_linker_symbols(s1);
resolve_common_syms(s1);
build_got_entries(s1);
#endif
if (s1->nb_errors)
return -1;
}
offset = 0, mem = (addr_t)ptr;
fill = -mem & RUN_SECTION_ALIGNMENT;
offset = max_align = 0, mem = (addr_t)ptr;
#ifdef _WIN64
offset += sizeof (void*);
offset += sizeof (void*); /* space for function_table pointer */
#endif
for (k = 0; k < 2; ++k) {
f = 0, addr = k ? mem : mem + ptr_diff;
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if (0 == (s->sh_flags & SHF_ALLOC))
continue;
if (k != !(s->sh_flags & SHF_EXECINSTR))
continue;
offset += fill;
s->sh_addr = mem ? mem + offset : 0;
align = s->sh_addralign - 1;
if (++f == 1 && align < RUN_SECTION_ALIGNMENT)
align = RUN_SECTION_ALIGNMENT;
if (max_align < align)
max_align = align;
offset += -(addr + offset) & align;
s->sh_addr = mem ? addr + offset : 0;
offset += s->data_offset;
#if 0
if (mem)
printf("%-16s +%02lx %p %04x\n",
s->name, fill, (void*)s->sh_addr, (unsigned)s->data_offset);
printf("%-16s %p len %04x align %2d\n",
s->name, (void*)s->sh_addr, (unsigned)s->data_offset, align + 1);
#endif
offset += s->data_offset;
fill = -(mem + offset) & 15;
}
#if RUN_SECTION_ALIGNMENT > 15
/* To avoid that x86 processors would reload cached instructions each time
when data is written in the near, we need to make sure that code and data
do not share the same 64 byte unit */
fill = -(mem + offset) & RUN_SECTION_ALIGNMENT;
#endif
}
/* relocate symbols */
@ -220,7 +232,11 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr)
return -1;
if (0 == mem)
return offset + RUN_SECTION_ALIGNMENT;
return offset + max_align;
#ifdef TCC_TARGET_PE
s1->pe_imagebase = mem;
#endif
/* relocate each section */
for(i = 1; i < s1->nb_sections; i++) {
@ -230,24 +246,27 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr)
}
relocate_plt(s1);
#ifdef _WIN64
*(void**)ptr = win64_add_function_table(s1);
#endif
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if (0 == (s->sh_flags & SHF_ALLOC))
continue;
length = s->data_offset;
ptr = (void*)s->sh_addr;
if (s->sh_flags & SHF_EXECINSTR)
ptr = (char*)ptr - ptr_diff;
if (NULL == s->data || s->sh_type == SHT_NOBITS)
memset(ptr, 0, length);
else
memcpy(ptr, s->data, length);
/* mark executable sections as executable in memory */
if (s->sh_flags & SHF_EXECINSTR)
set_pages_executable(ptr, length);
set_pages_executable((char*)ptr + ptr_diff, length);
}
#ifdef _WIN64
*(void**)mem = win64_add_function_table(s1);
#endif
return 0;
}
@ -261,15 +280,17 @@ static void set_pages_executable(void *ptr, unsigned long length)
VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect);
#else
void __clear_cache(void *beginning, void *end);
# ifndef HAVE_SELINUX
addr_t start, end;
#ifndef PAGESIZE
# define PAGESIZE 4096
#endif
# ifndef PAGESIZE
# define PAGESIZE 4096
# endif
start = (addr_t)ptr & ~(PAGESIZE - 1);
end = (addr_t)ptr + length;
end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1);
if (mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC))
tcc_error("mprotect failed: did you mean to configure --with-selinux?");
# endif
# if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64
__clear_cache(ptr, (char *)ptr + length);
# endif
@ -285,11 +306,11 @@ static void *win64_add_function_table(TCCState *s1)
RtlAddFunctionTable(
(RUNTIME_FUNCTION*)p,
s1->uw_pdata->data_offset / sizeof (RUNTIME_FUNCTION),
text_section->sh_addr
s1->pe_imagebase
);
s1->uw_pdata = NULL;
}
return p;;
return p;
}
static void win64_del_function_table(void *p)
@ -418,7 +439,7 @@ no_stabs:
if (wanted_pc >= sym->st_value &&
wanted_pc < sym->st_value + sym->st_size) {
pstrcpy(last_func_name, sizeof(last_func_name),
(char *) strtab_section->data + sym->st_name);
(char *) symtab_section->link->data + sym->st_name);
func_addr = sym->st_value;
goto found;
}

View File

@ -36,7 +36,9 @@
DEF(TOK_RESTRICT2, "__restrict")
DEF(TOK_RESTRICT3, "__restrict__")
DEF(TOK_EXTENSION, "__extension__") /* gcc keyword */
DEF(TOK_GENERIC, "_Generic")
DEF(TOK_FLOAT, "float")
DEF(TOK_DOUBLE, "double")
DEF(TOK_BOOL, "_Bool")
@ -51,6 +53,7 @@
DEF(TOK_ATTRIBUTE2, "__attribute__")
DEF(TOK_ALIGNOF1, "__alignof")
DEF(TOK_ALIGNOF2, "__alignof__")
DEF(TOK_ALIGNOF3, "_Alignof")
DEF(TOK_TYPEOF1, "typeof")
DEF(TOK_TYPEOF2, "__typeof")
DEF(TOK_TYPEOF3, "__typeof__")
@ -85,6 +88,7 @@
DEF(TOK___TIME__, "__TIME__")
DEF(TOK___FUNCTION__, "__FUNCTION__")
DEF(TOK___VA_ARGS__, "__VA_ARGS__")
DEF(TOK___COUNTER__, "__COUNTER__")
/* special identifiers */
DEF(TOK___FUNC__, "__func__")
@ -117,6 +121,8 @@
DEF(TOK_FASTCALL1, "fastcall")
DEF(TOK_FASTCALL2, "__fastcall")
DEF(TOK_FASTCALL3, "__fastcall__")
DEF(TOK_REGPARM1, "regparm")
DEF(TOK_REGPARM2, "__regparm__")
DEF(TOK_MODE, "__mode__")
DEF(TOK_MODE_QI, "__QI__")
@ -127,27 +133,24 @@
DEF(TOK_DLLEXPORT, "dllexport")
DEF(TOK_DLLIMPORT, "dllimport")
DEF(TOK_NODECORATE, "nodecorate")
DEF(TOK_NORETURN1, "noreturn")
DEF(TOK_NORETURN2, "__noreturn__")
DEF(TOK_VISIBILITY1, "visibility")
DEF(TOK_VISIBILITY2, "__visibility__")
DEF(TOK_builtin_types_compatible_p, "__builtin_types_compatible_p")
DEF(TOK_builtin_choose_expr, "__builtin_choose_expr")
DEF(TOK_builtin_constant_p, "__builtin_constant_p")
DEF(TOK_builtin_frame_address, "__builtin_frame_address")
DEF(TOK_builtin_return_address, "__builtin_return_address")
DEF(TOK_builtin_expect, "__builtin_expect")
#ifdef TCC_TARGET_X86_64
#ifdef TCC_TARGET_PE
/*DEF(TOK_builtin_va_list, "__builtin_va_list")*/
#if defined TCC_TARGET_PE && defined TCC_TARGET_X86_64
DEF(TOK_builtin_va_start, "__builtin_va_start")
#else
#elif defined TCC_TARGET_X86_64
DEF(TOK_builtin_va_arg_types, "__builtin_va_arg_types")
#endif
#endif
DEF(TOK_REGPARM1, "regparm")
DEF(TOK_REGPARM2, "__regparm__")
#ifdef TCC_TARGET_ARM64
#elif defined TCC_TARGET_ARM64
DEF(TOK___va_start, "__va_start")
DEF(TOK___va_arg, "__va_arg")
#endif
@ -164,6 +167,7 @@
DEF(TOK_push_macro, "push_macro")
DEF(TOK_pop_macro, "pop_macro")
DEF(TOK_once, "once")
DEF(TOK_option, "option")
/* builtin functions or variables */
#ifndef TCC_ARM_EABI

View File

@ -363,9 +363,8 @@ usage:
ret = tcc_get_dllexports(file, &p);
if (ret || !p) {
fprintf(stderr, "tcc: impdef: %s '%s'\n",
ret == 32 ? "can't read symbols from 32bit" :
ret == 64 ? "can't read symbols from 64bit" :
ret == -1 ? "can't find file" :
ret == 1 ? "can't read symbols" :
ret == 0 ? "no symbols found in" :
"unknown file type", file);
ret = 1;
@ -375,7 +374,7 @@ usage:
if (v)
printf("-> %s\n", file);
op = fopen(outfile, "w");
op = fopen(outfile, "wb");
if (NULL == op) {
fprintf(stderr, "tcc: impdef: could not create output file: %s\n", outfile);
goto the_end;

View File

@ -16,6 +16,7 @@ TESTS = \
memtest \
dlltest \
abitest \
asm-c-connect-test \
vla_test-run \
cross-test \
tests2-dir \
@ -44,18 +45,17 @@ ifeq ($(CONFIG_arm_eabi),yes)
TESTS := $(filter-out test3,$(TESTS))
endif
ifeq (,$(filter i386 x86_64,$(ARCH)))
TESTS := $(filter-out dlltest,$(TESTS))
TESTS := $(filter-out dlltest asm-c-connect-test,$(TESTS))
endif
ifndef CONFIG_cross
TESTS := $(filter-out cross-%,$(TESTS))
endif
ifdef CONFIG_WIN32
SEP = $(if $(findstring :\,$(PATH)),;,:)
PATH := $(CURDIR)/$(TOP)$(SEP)$(PATH) # for libtcc_test to find libtcc.dll
ifeq ($(OS),Windows_NT) # for libtcc_test to find libtcc.dll
PATH := $(CURDIR)/$(TOP)$(if $(findstring :\,$(PATH)),;,:)$(PATH)
endif
RUN_TCC = $(NATIVE_DEFINES) -DONE_SOURCE -run $(TOPSRC)/tcc.c $(TCCFLAGS)
RUN_TCC = $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS)
DISAS = objdump -d
DUMPTCC = (set -x; $(TOP)/tcc -vv; ldd $(TOP)/tcc; exit 1)
@ -129,23 +129,23 @@ test4: tcctest.c test.ref
# use tcc to create libtcc.so/.dll and the tcc(.exe) frontend and run them
dlltest:
@echo ------------ $@ ------------
$(TCC) -DONE_SOURCE $(NATIVE_DEFINES) -DLIBTCC_AS_DLL $(TOPSRC)/libtcc.c $(LIBS) -shared -o libtcc2$(DLLSUF)
$(TCC) $(NATIVE_DEFINES) $(TOPSRC)/tcc.c libtcc2$(DLLSUF) $(LIBS) -Wl,-rpath=. -o tcc2$(EXESUF)
$(TCC) $(NATIVE_DEFINES) -DLIBTCC_AS_DLL $(TOPSRC)/libtcc.c $(LIBS) -shared -o libtcc2$(DLLSUF)
$(TCC) $(NATIVE_DEFINES) -DONE_SOURCE=0 $(TOPSRC)/tcc.c libtcc2$(DLLSUF) $(LIBS) -Wl,-rpath=. -o tcc2$(EXESUF)
./tcc2$(EXESUF) $(TCCFLAGS) $(RUN_TCC) -run $(TOPSRC)/examples/ex1.c
ifndef CONFIG_WIN32
@echo ------------ $@ with PIC ------------
$(CC) $(CFLAGS) -fPIC -DONE_SOURCE $(NATIVE_DEFINES) -DLIBTCC_AS_DLL -c $(TOPSRC)/libtcc.c
$(CC) $(CFLAGS) -fPIC $(NATIVE_DEFINES) -DLIBTCC_AS_DLL -c $(TOPSRC)/libtcc.c
$(TCC) libtcc.o $(LIBS) -shared -o libtcc2$(DLLSUF)
$(TCC) $(NATIVE_DEFINES) $(TOPSRC)/tcc.c libtcc2$(DLLSUF) $(LIBS) -Wl,-rpath=. -o tcc2$(EXESUF)
$(TCC) $(NATIVE_DEFINES) -DONE_SOURCE=0 $(TOPSRC)/tcc.c libtcc2$(DLLSUF) $(LIBS) -Wl,-rpath=. -o tcc2$(EXESUF)
./tcc2$(EXESUF) $(TCCFLAGS) $(RUN_TCC) -run $(TOPSRC)/examples/ex1.c
endif
@rm tcc2$(EXESUF) libtcc2$(DLLSUF)
memtest:
@echo ------------ $@ ------------
$(CC) $(CFLAGS) $(NATIVE_DEFINES) -DONE_SOURCE -DMEM_DEBUG=2 $(TOPSRC)/tcc.c $(LIBS) -o memtest-tcc$(EXESUF)
./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -DONE_SOURCE $(TOPSRC)/tcc.c $(LIBS)
./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -DONE_SOURCE -run $(TOPSRC)/tcc.c $(TCCFLAGS) $(TOPSRC)/tests/tcctest.c
$(CC) $(CFLAGS) $(NATIVE_DEFINES) -DMEM_DEBUG=2 $(TOPSRC)/tcc.c $(LIBS) -o memtest-tcc$(EXESUF)
./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) $(TOPSRC)/tcc.c $(LIBS)
./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS) $(TOPSRC)/tests/tcctest.c
# memory and bound check auto test
@ -210,7 +210,7 @@ abitest-cc$(EXESUF): abitest.c $(LIBTCC)
$(CC) -o $@ $^ $(CFLAGS) $(LIBS) -w
abitest-tcc$(EXESUF): abitest.c libtcc.c
$(TCC) -o $@ $^ $(NATIVE_DEFINES) -DONE_SOURCE $(LIBS)
$(TCC) -o $@ $^ $(NATIVE_DEFINES) $(LIBS)
ABITESTS := abitest-cc$(EXESUF)
ifneq ($(CONFIG_arm_eabi),yes) # not ARM soft-float
@ -231,11 +231,30 @@ vla_test-run: vla_test$(EXESUF)
@echo ------------ $@ ------------
./vla_test$(EXESUF)
asm-c-connect$(EXESUF): asm-c-connect-1.c asm-c-connect-2.c
$(TCC) -o $@ $^
asm-c-connect-%.o: asm-c-connect-%.c
$(TCC) -c -o $@ $<
asm-c-connect-sep$(EXESUF): asm-c-connect-1.o asm-c-connect-2.o
$(TCC) -o $@ $^
asm-c-connect-test: asm-c-connect$(EXESUF) asm-c-connect-sep$(EXESUF)
@echo ------------ $@ ------------
./asm-c-connect$(EXESUF) > asm-c-connect.out1 && cat asm-c-connect.out1
./asm-c-connect-sep$(EXESUF) > asm-c-connect.out2 && cat asm-c-connect.out2
@diff -u asm-c-connect.out1 asm-c-connect.out2 && echo "ok"
cross-test :
@echo ------------ $@ ------------
$(TOP)/i386-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
$(TOP)/i386-win32-tcc$(EXESUF) $(TCCFLAGS-win) $(TOPSRC)/examples/ex3.c && echo "ok"
$(TOP)/x86_64-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
$(TOP)/x86_64-win32-tcc$(EXESUF) $(TCCFLAGS-win) $(TOPSRC)/examples/ex3.c && echo "ok"
$(TOP)/arm-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
$(TOP)/arm-wince-tcc$(EXESUF) $(TCCFLAGS-win) -c $(TOPSRC)/examples/ex3.c && echo "ok"
$(TOP)/arm64-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
$(TOP)/c67-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
$(TOP)/i386-win32-tcc$(EXESUF) $(TCCFLAGS-win) $(TOPSRC)/win32/examples/hello_win.c && echo "ok"
$(TOP)/x86_64-win32-tcc$(EXESUF) $(TCCFLAGS-win) $(TOPSRC)/win32/examples/hello_win.c && echo "ok"
@ -260,6 +279,7 @@ cache: tcc_g
clean:
rm -f *~ *.o *.a *.bin *.i *.ref *.out *.out? *.out?b *.cc *.gcc
rm -f *-cc *-gcc *-tcc *.exe hello libtcc_test vla_test tcctest[1234]
rm -f asm-c-connect$(EXESUF) asm-c-connect-sep$(EXESUF)
rm -f ex? tcc_g weaktest.*.txt *.def
@$(MAKE) -C tests2 $@
@$(MAKE) -C pp $@

View File

@ -425,7 +425,7 @@ static int two_member_union_test(void) {
}
/*
* Win64 calling convetntion test.
* Win64 calling convention test.
*/
typedef struct many_struct_test_type_s {long long a, b, c;} many_struct_test_type;
@ -558,6 +558,36 @@ static int stdarg_test(void) {
return run_callback(src, stdarg_test_callback);
}
typedef struct {long long a, b;} stdarg_many_test_struct_type;
typedef void (*stdarg_many_test_function_type) (int, int, int, int, int,
stdarg_many_test_struct_type,
int, int, ...);
static int stdarg_many_test_callback(void *ptr)
{
stdarg_many_test_function_type f = (stdarg_many_test_function_type)ptr;
int x;
stdarg_many_test_struct_type l = {10, 11};
f(1, 2, 3, 4, 5, l, 6, 7, &x, 44);
return x == 44 ? 0 : -1;
}
static int stdarg_many_test(void)
{
const char *src =
"#include <stdarg.h>\n"
"typedef struct {long long a, b;} stdarg_many_test_struct_type;\n"
"void f (int a, int b, int c, int d, int e, stdarg_many_test_struct_type l, int f, int g, ...){\n"
" va_list ap;\n"
" int *p;\n"
" va_start (ap, g);\n"
" p = va_arg(ap, int*);\n"
" *p = va_arg(ap, int);\n"
" va_end (ap);\n"
"}\n";
return run_callback(src, stdarg_many_test_callback);
}
/*
* Test Win32 stdarg handling, since the calling convention will pass a pointer
* to the struct and the stdarg pointer must point to that pointer initially.
@ -637,10 +667,10 @@ int main(int argc, char **argv) {
RUN_TEST(ret_longdouble_test);
RUN_TEST(ret_2float_test);
RUN_TEST(ret_2double_test);
#if !defined __x86_64__ || defined _WIN32
/* currently broken on x86_64 linux */
RUN_TEST(ret_8plus2double_test);
RUN_TEST(ret_6plus2longlong_test);
#if !defined __x86_64__ || defined _WIN32
/* currently broken on x86_64 linux */
RUN_TEST(ret_mixed_test);
RUN_TEST(ret_mixed2_test);
#endif
@ -654,6 +684,7 @@ int main(int argc, char **argv) {
RUN_TEST(many_struct_test_2);
RUN_TEST(many_struct_test_3);
RUN_TEST(stdarg_test);
RUN_TEST(stdarg_many_test);
RUN_TEST(stdarg_struct_test);
RUN_TEST(arg_align_test);
return retval;

57
tests/asm-c-connect-1.c Normal file
View File

@ -0,0 +1,57 @@
#include <stdio.h>
#if defined _WIN32 && !defined __TINYC__
# define _ "_"
#else
# define _
#endif
static int x1_c(void)
{
printf(" x1");
return 1;
}
asm(".text;"_"x1: call "_"x1_c; ret");
void callx4(void);
void callx5_again(void);
void x6()
{
printf(" x6-1");
}
int main(int argc, char *argv[])
{
printf("*");
asm("call "_"x1");
asm("call "_"x2");
asm("call "_"x3");
callx4();
asm("call "_"x5");
callx5_again();
x6();
printf(" *\n");
return 0;
}
static
int x2(void)
{
printf(" x2");
return 2;
}
extern int x3(void);
void x4(void)
{
printf(" x4");
}
void x5(void);
void x5(void)
{
printf(" x5");
}

36
tests/asm-c-connect-2.c Normal file
View File

@ -0,0 +1,36 @@
#include <stdio.h>
#if defined _WIN32 && !defined __TINYC__
# define _ "_"
#else
# define _
#endif
int x3(void)
{
printf(" x3");
return 3;
}
/* That callx4 is defined globally (as if ".globl callx4")
is a TCC extension. GCC doesn't behave like this. */
void callx4(void);
__asm__(_"callx4: call "_"x4; ret;"
#ifndef __TINYC__
" .global "_"callx4"
#endif
);
extern void x5(void);
void callx5_again(void);
void callx5_again(void)
{
x5();
asm("call "_"x6");
}
static void x6()
{
printf(" x6-2");
}

View File

@ -577,10 +577,13 @@ fucomip %st(5), %st
cmovs 0x1000, %eax
cmovns %edx, %edi
cmovne %ax, %si
cmovbw %ax, %di
cmovnbel %edx, %ecx
#ifdef __x86_64__
bswapq %rsi
bswapq %r10
cmovz %rdi,%rbx
cmovpeq %rsi, %rdx
#endif
int $3

View File

@ -1,3 +1,2 @@
# `modelist' label. Each video mode record looks like:
.text
endtext:

View File

@ -12,7 +12,7 @@ return n(A)n(++)n(+)n(+)n(B);
return n(0x1E)n(-1);
// unlike gcc but correct
XXX: return n(x)+n(x)-n(1)+n(1)-2;
// XXX: return n(x)+n(x)-n(1)+n(1)-2;
// unlile gcc, but cannot appear in valid C
XXX: return n(x)n(x)n(1)n(2)n(x);
// unlike gcc, but cannot appear in valid C
// XXX: return n(x)n(x)n(1)n(2)n(x);

View File

@ -3,5 +3,3 @@ return A+++B;
return A+ ++B;
return A+++ +B;
return 0x1E -1;
XXX: return x+x-1 +1 -2;
XXX: return x x 1 2 x;

101
tests/pp/19.c Normal file
View File

@ -0,0 +1,101 @@
#define M_C2I(a, ...) a ## __VA_ARGS__
#define M_C(a, ...) M_C2I(a, __VA_ARGS__)
#define M_C3I(a, b, ...) a ## b ## __VA_ARGS__
#define M_C3(a, b, ...) M_C3I(a ,b, __VA_ARGS__)
#define M_RETI_ARG2(a, b, ...) b
#define M_RET_ARG2(...) M_RETI_ARG2(__VA_ARGS__)
#define M_RETI_ARG27(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,aa, ...) aa
#define M_RET_ARG27(...) M_RETI_ARG27(__VA_ARGS__)
#define M_TOBOOLI_0 1, 0,
#define M_BOOL(x) M_RET_ARG2(M_C(M_TOBOOLI_, x), 1, useless)
#define M_IFI_0(true_macro, ...) __VA_ARGS__
#define M_IFI_1(true_macro, ...) true_macro
#define M_IF(c) M_C(M_IFI_, M_BOOL(c))
#define M_FLAT(...) __VA_ARGS__
#define M_INVI_0 1
#define M_INVI_1 0
#define M_INV(x) M_C(M_INVI_, x)
#define M_ANDI_00 0
#define M_ANDI_01 0
#define M_ANDI_10 0
#define M_ANDI_11 1
#define M_AND(x,y) M_C3(M_ANDI_, x, y)
#define M_ORI_00 0
#define M_ORI_01 1
#define M_ORI_10 1
#define M_ORI_11 1
#define M_OR(x,y) M_C3(M_ORI_, x, y)
#define M_COMMA_P(...) M_RET_ARG27(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, useless)
#define M_EMPTYI_DETECT(...) 0, 1,
#define M_EMPTYI_P_C1(...) M_COMMA_P(M_EMPTYI_DETECT __VA_ARGS__ ())
#define M_EMPTYI_P_C2(...) M_COMMA_P(M_EMPTYI_DETECT __VA_ARGS__)
#define M_EMPTYI_P_C3(...) M_COMMA_P(__VA_ARGS__ () )
#define M_EMPTY_P(...) M_AND(M_EMPTYI_P_C1(__VA_ARGS__), M_INV(M_OR(M_OR(M_EMPTYI_P_C2(__VA_ARGS__), M_COMMA_P(__VA_ARGS__)),M_EMPTYI_P_C3(__VA_ARGS__))))
#define M_APPLY_FUNC2B(func, arg1, arg2) \
M_IF(M_EMPTY_P(arg2))(,func(arg1, arg2))
#define M_MAP2B_0(func, data, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z,...) \
M_APPLY_FUNC2B(func, data, a) M_APPLY_FUNC2B(func, data, b) M_APPLY_FUNC2B(func, data, c) \
M_APPLY_FUNC2B(func, data, d) M_APPLY_FUNC2B(func, data, e) M_APPLY_FUNC2B(func, data, f) \
M_APPLY_FUNC2B(func, data, g) M_APPLY_FUNC2B(func, data, h) M_APPLY_FUNC2B(func, data, i) \
M_APPLY_FUNC2B(func, data, j) M_APPLY_FUNC2B(func, data, k) M_APPLY_FUNC2B(func, data, l) \
M_APPLY_FUNC2B(func, data, m) M_APPLY_FUNC2B(func, data, n) M_APPLY_FUNC2B(func, data, o) \
M_APPLY_FUNC2B(func, data, p) M_APPLY_FUNC2B(func, data, q) M_APPLY_FUNC2B(func, data, r) \
M_APPLY_FUNC2B(func, data, s) M_APPLY_FUNC2B(func, data, t) M_APPLY_FUNC2B(func, data, u) \
M_APPLY_FUNC2B(func, data, v) M_APPLY_FUNC2B(func, data, w) M_APPLY_FUNC2B(func, data, x) \
M_APPLY_FUNC2B(func, data, y) M_APPLY_FUNC2B(func, data, z)
#define M_MAP2B(f, ...) M_MAP2B_0(f, __VA_ARGS__, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , )
#define M_INIT_INIT(a) ,a,
#define M_GET_METHOD(method, method_default, ...) \
M_RET_ARG2 (M_MAP2B(M_C, M_C3(M_, method, _), __VA_ARGS__), method_default,)
#define M_TEST_METHOD_P(method, oplist) \
M_BOOL(M_GET_METHOD (method, 0, M_FLAT oplist))
#define TRUE 1
#define TEST1(n) \
M_IF(n)(ok,nok)
#define TEST2(op) \
M_TEST_METHOD_P(INIT, op)
#define TEST3(op) \
M_IF(M_TEST_METHOD_P(INIT, op))(ok, nok)
#define TEST4(op) \
TEST1(TEST2(op))
#define KO(a) ((void)1)
/* This checks that the various expansions that ultimately lead to
something like 'KO(arg,arg)', where 'KO' comes from a macro
expansion reducing from a large macro chain do not are regarded
as funclike macro invocation of KO. E.g. X93 and X94 expand to 'KO',
but X95 must not consume the (a,b) arguments outside the M_IF()
invocation to reduce the 'KO' macro to an invocation. Instead
X95 should reduce via M_IF(KO)(a,b) to 'a'.
The other lines here are variations on this scheme, with X1 to
X6 coming from the bug report at
http://lists.nongnu.org/archive/html/tinycc-devel/2017-07/msg00017.html */
X92 M_IF(KO)
X93 M_GET_METHOD(INIT, 0, INIT(KO))
X94 M_GET_METHOD(INIT, 0, M_FLAT (INIT(KO)))
X95 M_IF(M_GET_METHOD(INIT, 0, INIT(KO)))(a,b)
X96 M_IF(M_GET_METHOD(INIT, 0, M_FLAT (INIT(KO))))
X97 M_IF(M_GET_METHOD(INIT, 0, M_FLAT (INIT(KO))))(ok,nok)
X98 (M_TEST_METHOD_P(INIT, (INIT(KO))))(ok, nok)
X99 M_IF(M_TEST_METHOD_P(INIT, (INIT(KO))))(ok, nok)
// test begins
X1 TEST1(TRUE) // ==> expect ok, get ok
// First test with a token which is not a macro
X2 TEST2((INIT(ok))) // ==> expect 1, get 1
X3 TEST3((INIT(ok))) // ==> expect ok, get ok
// Then test with a token which is a macro, but should not be expanded.
X4 TEST2((INIT(KO))) // ==> expect 1, get 1
X5 TEST4(INIT(KO))
X6 TEST3((INIT(KO))) // ==> expect ok, get "error: macro 'KO' used with too many args"

14
tests/pp/19.expect Normal file
View File

@ -0,0 +1,14 @@
X92 M_IFI_1
X93 KO
X94 KO
X95 a
X96 M_IFI_1
X97 ok
X98 (1)(ok, nok)
X99 ok
X1 ok
X2 1
X3 ok
X4 1
X5 nok
X6 ok

13
tests/pp/20.c Normal file
View File

@ -0,0 +1,13 @@
/* Various things I encountered while hacking the pre processor */
#define wrap(x) x
#define pr_warning(fmt, ...) printk(KERN_WARNING fmt, ##__VA_ARGS__)
#define pr_warn(x,y) pr_warning(x,y)
#define net_ratelimited_function(function, ...) function(__VA_ARGS__)
X1 net_ratelimited_function(pr_warn, "pipapo", bla);
X2 net_ratelimited_function(wrap(pr_warn), "bla", foo);
#define two m n
#define chain4(a,b,c,d) a ## b ## c ## d
X2 chain4(two,o,p,q)
X3 chain4(o,two,p,q)
X4 chain4(o,p,two,q)
X5 chain4(o,p,q,two)

6
tests/pp/20.expect Normal file
View File

@ -0,0 +1,6 @@
X1 printk(KERN_WARNING "pipapo",bla);
X2 printk(KERN_WARNING "bla",foo);
X2 twoopq
X3 otwopq
X4 optwoq
X5 opqtwo

36
tests/pp/21.c Normal file
View File

@ -0,0 +1,36 @@
/* accept 'defined' as result of substitution */
----- 1 ------
#define AAA 2
#define BBB
#define CCC (defined ( AAA ) && AAA > 1 && !defined BBB)
#if !CCC
OK
#else
NOT OK
#endif
----- 2 ------
#undef BBB
#if CCC
OK
#else
NOT OK
#endif
----- 3 ------
#define DEFINED defined
#define DDD (DEFINED ( AAA ) && AAA > 1 && !DEFINED BBB)
#if (DDD)
OK
#else
NOT OK
#endif
----- 4 ------
#undef AAA
#if !(DDD)
OK
#else
NOT OK
#endif

8
tests/pp/21.expect Normal file
View File

@ -0,0 +1,8 @@
----- 1 ------
OK
----- 2 ------
OK
----- 3 ------
OK
----- 4 ------
OK

View File

@ -10,9 +10,9 @@ VPATH = $(SRC)
files = $(patsubst %.$1,%.test,$(notdir $(wildcard $(SRC)/*.$1)))
TESTS = $(call files,c) $(call files,S)
all test : $(sort $(TESTS))
all test testspp.all: $(sort $(TESTS))
DIFF_OPTS = -Nu -b -B -I "^\#"
DIFF_OPTS = -Nu -b -B
# Filter source directory in warnings/errors (out-of-tree builds)
FILTER = 2>&1 | sed 's,$(SRC)/,,g'
@ -29,12 +29,11 @@ FILTER = 2>&1 | sed 's,$(SRC)/,,g'
diff $(DIFF_OPTS) $(SRC)/$*.expect $*.output \
&& rm -f $*.output
testspp.%: %.test ;
# automatically generate .expect files with gcc:
%.expect: # %.c
gcc -E -P $< >$*.expect 2>&1
%.expect: # %.S
gcc -E -P $< >$*.expect 2>&1
gcc -E -P $*.[cS] >$*.expect 2>&1
# tell make not to delete
.PRECIOUS: %.expect
@ -43,7 +42,7 @@ clean:
rm -f *.output
02.test : DIFF_OPTS += -w
15.test : DIFF_OPTS += -I"^XXX:"
# 15.test : DIFF_OPTS += -I"^XXX:"
# diff options:
# -b ighore space changes

27
tests/pp/pp-counter.c Normal file
View File

@ -0,0 +1,27 @@
X1 __COUNTER__
X2 __COUNTER__
#if __COUNTER__
X3 __COUNTER__
#endif
#define pass(x) x
#define a x __COUNTER__ y
#define a2 pass(__COUNTER__)
#define f(c) c __COUNTER__
#define apply(d) d d __COUNTER__ x2 f(d) y2 __COUNTER__
#define _paste(a,b) a ## b
#define paste(a,b) _paste(a,b)
#define _paste3(a,b,c) a ## b ## c
#define doublepaste(a,b) _paste3(a,b,b)
#define str(x) #x
X4 a
X5 f(a)
X6 f(b)
X7 f(__COUNTER__)
X8 apply(a)
X9 apply(f(a))
X10 apply(__COUNTER__)
X11 apply(a2)
X12 str(__COUNTER__)
X13 paste(x,__COUNTER__)
X14 _paste(x,__COUNTER__)
X15 doublepaste(x,__COUNTER__)

View File

@ -0,0 +1,15 @@
X1 0
X2 1
X3 3
X4 x 4 y
X5 x 5 y 6
X6 b 7
X7 8 9
X8 x 10 y x 10 y 11 x2 x 10 y 12 y2 13
X9 x 14 y 15 x 14 y 15 16 x2 x 14 y 15 17 y2 18
X10 19 19 20 x2 19 21 y2 22
X11 23 23 24 x2 23 25 y2 26
X12 "__COUNTER__"
X13 x27
X14 x__COUNTER__
X15 x2828

View File

@ -384,7 +384,7 @@ void macro_test(void)
MF_s("hi");
MF_t("hi");
/* test macro substituion inside args (should not eat stream) */
/* test macro substitution 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
@ -404,7 +404,7 @@ comment
substituted */
TEST2();
/* And again when the name and parenthes are separated by a
/* And again when the name and parentheses are separated by a
comment. */
TEST2 /* the comment */ ();
@ -1050,8 +1050,8 @@ int pad1;
but __alignof__ returns the wrong result (4) because we
can't store the alignment yet when specified on symbols
directly (it's stored in the type so we'd need to make
a copy of it).
struct aligntest7 altest7[2] __attribute__((aligned(16)));*/
a copy of it). -- FIXED */
struct aligntest7 altest7[2] __attribute__((aligned(16)));
struct aligntest8
{
@ -1161,8 +1161,8 @@ void struct_test()
sizeof(altest5), __alignof__(altest5));
printf("altest6 sizeof=%d alignof=%d\n",
sizeof(altest6), __alignof__(altest6));
/*printf("altest7 sizeof=%d alignof=%d\n",
sizeof(altest7), __alignof__(altest7));*/
printf("altest7 sizeof=%d alignof=%d\n",
sizeof(altest7), __alignof__(altest7));
/* empty structures (GCC extension) */
printf("sizeof(struct empty) = %d\n", sizeof(struct empty));
@ -2234,6 +2234,9 @@ void float_test(void)
double da, db;
int a;
unsigned int b;
static double nan2 = 0.0/0.0;
static double inf1 = 1.0/0.0;
static double inf2 = 1e5000;
printf("float_test:\n");
printf("sizeof(float) = %d\n", sizeof(float));
@ -2255,6 +2258,7 @@ void float_test(void)
b = 4000000000;
db = b;
printf("db = %f\n", db);
printf("nan != nan = %d, inf1 = %f, inf2 = %f\n", nan2 != nan2, inf1, inf2);
#endif
}
@ -2266,6 +2270,8 @@ int fib(int n)
return fib(n-1) + fib(n-2);
}
void __attribute__((aligned(16))) aligned_function(int i) {}
void funcptr_test()
{
void (*func)(int);
@ -2296,6 +2302,10 @@ void funcptr_test()
func(42);
(func + diff)(42);
(num + a)(43);
/* Check that we can align functions */
func = aligned_function;
printf("aligned_function (should be zero): %d\n", ((int)func) & 15);
}
void lloptest(long long a, long long b)
@ -2487,6 +2497,11 @@ void longlong_test(void)
a = 0x123;
long long *p = &a;
llshift(*p, 5);
/* shortening followed by widening */
unsigned long long u = 0x8000000000000001ULL;
u = (unsigned)(u + 1);
printf("long long u=" ULONG_LONG_FORMAT "\n", u);
}
void manyarg_test(void)
@ -2899,6 +2914,11 @@ struct hlist_head {
struct hlist_node *first, *last;
};
void consume_ulong (unsigned long i)
{
i = 0;
}
void statement_expr_test(void)
{
int a, i;
@ -2954,6 +2974,9 @@ void statement_expr_test(void)
});
printf ("stmtexpr: %d %d %d\n", t, b, c);
printf ("stmtexpr: %ld %ld\n", (long)h.first, (long)h.last);
/* Test that we can give out addresses of local labels. */
consume_ulong(({ __label__ __here; __here: (unsigned long)&&__here; }));
}
void local_label_test(void)
@ -3109,7 +3132,7 @@ static __inline__ unsigned long long inc64(unsigned long long a)
unsigned long long res;
#ifdef __x86_64__
/* Using the A constraint is wrong, and increments are tested
elsewere. */
elsewhere. */
res = a + 1;
#else
__asm__("addl $1, %%eax ; adcl $0, %%edx" : "=A" (res) : "A" (a));
@ -3197,8 +3220,37 @@ char * get_asm_string (void)
char * str = ((char*)bug_table) + bug_table[1];
return str;
}
/* This checks another constructs with local labels. */
extern unsigned char alld_stuff[];
asm(".data\n"
".byte 41\n"
"alld_stuff:\n"
"661:\n"
".byte 42\n"
"662:\n"
".pushsection .data.ignore\n"
".long 661b - .\n" /* This reference to 661 generates an external sym
which shouldn't somehow overwrite the offset that's
already determined for it. */
".popsection\n"
".byte 662b - 661b\n" /* So that this value is undeniably 1. */);
void asm_local_label_diff (void)
{
printf ("asm_local_label_diff: %d %d\n", alld_stuff[0], alld_stuff[1]);
}
/* This checks that static local variables are available from assembler. */
void asm_local_statics (void)
{
static int localint = 41;
asm("incl %0" : "+m" (localint));
printf ("asm_local_statics: %d\n", localint);
}
#endif
static
unsigned int set;
void fancy_copy (unsigned *in, unsigned *out)
@ -3211,7 +3263,7 @@ void fancy_copy2 (unsigned *in, unsigned *out)
asm volatile ("mov %0,(%1)" : : "r" (*in), "r" (out) : "memory");
}
#ifdef __x86_64__
#if defined __x86_64__ && !defined _WIN64
void clobber_r12(void)
{
asm volatile("mov $1, %%r12" ::: "r12");
@ -3220,7 +3272,7 @@ void clobber_r12(void)
void test_high_clobbers(void)
{
#ifdef __x86_64__
#if defined __x86_64__ && !defined _WIN64
register long val asm("r12");
long val2;
/* This tests if asm clobbers correctly save/restore callee saved
@ -3229,11 +3281,9 @@ void test_high_clobbers(void)
correctly capture the data flow, but good enough for us. */
asm volatile("mov $0x4542, %%r12" : "=r" (val):: "memory");
clobber_r12();
#ifndef _WIN64
asm volatile("mov %%r12, %0" : "=r" (val2) : "r" (val): "memory");
printf("asmhc: 0x%x\n", val2);
#endif
#endif
}
static long cpu_number;
@ -3310,6 +3360,62 @@ void test_asm_dead_code(void)
}));
}
void test_asm_call(void)
{
#if defined __x86_64__ && !defined _WIN64
static char str[] = "PATH";
char *s;
/* This tests if a reference to an undefined symbol from an asm
block, which isn't otherwise referenced in this file, is correctly
regarded as global symbol, so that it's resolved by other object files
or libraries. We chose getenv here, which isn't used anywhere else
in this file. (If we used e.g. printf, which is used we already
would have a global symbol entry, not triggering the bug which is
tested here). */
/* two pushes so stack remains aligned */
asm volatile ("push %%rdi; push %%rdi; mov %0, %%rdi;"
#if 1 && !defined(__TINYC__) && (defined(__PIC__) || defined(__PIE__))
"call getenv@plt;"
#else
"call getenv;"
#endif
"pop %%rdi; pop %%rdi"
: "=a" (s) : "r" (str));
printf("asmd: %s\n", s);
#endif
}
#if defined __x86_64__
# define RX "(%rip)"
#else
# define RX
#endif
void asm_dot_test(void)
{
int x;
for (x = 1;; ++x) {
int r = x;
switch (x) {
case 1:
asm(".text; lea S"RX",%eax; lea ."RX",%ecx; sub %ecx,%eax; S=.; jmp p0");
case 2:
asm(".text; jmp .+6; .int 123; mov .-4"RX",%eax; jmp p0");
case 3:
asm(".data; Y=.; .int 999; X=Y; .int 456; X=.-4");
asm(".text; mov X"RX",%eax; jmp p0");
case 4:
asm(".data; X=.; .int 789; Y=.; .int 999");
asm(".text; mov X"RX",%eax; X=Y; jmp p0");
case 0:
asm(".text; p0=.; mov %%eax,%0;" : "=m"(r)); break;
}
if (r == x)
break;
printf("asm_dot_test %d: %d\n", x, r);
}
}
void asm_test(void)
{
char buf[128];
@ -3370,6 +3476,8 @@ void asm_test(void)
asm volatile(".weak override_func3\n.set override_func3, base_func");
override_func3();
printf("asmstr: %s\n", get_asm_string());
asm_local_label_diff();
asm_local_statics();
#endif
/* Check that we can also load structs of appropriate layout
into registers. */
@ -3394,6 +3502,8 @@ void asm_test(void)
test_high_clobbers();
trace_console(8, 8);
test_asm_dead_code();
test_asm_call();
asm_dot_test();
return;
label1:
goto label2;

View File

@ -15,6 +15,19 @@ void qfunc()
printf("qfunc()\n");
}
#if !defined(__ARMEL__)
/*
* At least on ARM (like RPi), zfunc below fails with something like:
* +tcc: error: can't relocate value at 1ef93bc,1
* Test is temporary removed for this architecture until ARM maintainers
* see what happens with this test.
*/
void zfunc()
{
((void (*)(void))0) ();
}
#endif
int main()
{
printf("%d\n", myfunc(3));

View File

@ -0,0 +1,34 @@
void foo(int [5]);
void fooc(int x[const 5]);
void foos(int x[static 5]);
void foov(int x[volatile 5]);
void foor(int x[restrict 5]);
void fooc(int [const 5]);
void foos(int [static 5]);
void foov(int [volatile 5]);
void foor(int [restrict 5]);
void fooc(int (* const x));
void foos(int *x);
void foov(int * volatile x);
void foor(int * restrict x);
void fooc(int x[volatile 5])
{
x[3] = 42;
#ifdef INVALID
x = 0;
#endif
}
void foovm(int x[const *]);
void foovm(int * const x);
#ifdef INVALID
void wrongc(int x[3][const 4]);
void wrongvm(int x[static *]);
void foovm(int x[const *])
{
x[2] = 1;
}
#endif
int main()
{
return 0;
}

View File

@ -12,9 +12,49 @@ enum fred
h
};
/* All following uses of enum efoo should compile
without warning. While forward enums aren't ISO C,
it's accepted by GCC also in strict mode, and only warned
about with -pedantic. This happens in the real world. */
/* Strict ISO C doesn't allow this kind of forward declaration of
enums, but GCC accepts it (and gives only pedantic warning), and
it occurs in the wild. */
enum efoo;
struct Sforward_use {
int (*fmember) (enum efoo x);
};
extern enum efoo it_real_fn(void);
enum efoo {
ONE,
TWO,
};
struct S2 {
enum efoo (*f2) (void);
};
void should_compile(struct S2 *s)
{
s->f2 = it_real_fn;
}
enum efoo it_real_fn(void)
{
return TWO;
}
static unsigned int deref_uintptr(unsigned int *p)
{
return *p;
}
enum Epositive {
epos_one, epos_two
};
int main()
{
enum fred frod;
enum Epositive epos = epos_two;
printf("%d %d %d %d %d %d %d %d\n", a, b, c, d, e, f, g, h);
/* printf("%d\n", frod); */
@ -23,6 +63,9 @@ int main()
frod = e;
printf("%d\n", frod);
/* Following should compile without warning. */
printf ("enum to int: %u\n", deref_uintptr(&epos));
return 0;
}

View File

@ -1,3 +1,4 @@
0 1 2 3 54 73 74 75
12
54
enum to int: 1

View File

@ -1,4 +1,30 @@
#include <stdio.h>
#include <assert.h>
char arr[1];
static void f (void){}
void (*fp)(void) = f;
void call_fp()
{
(fp?f:f)();
(fp?fp:fp)();
(fp?fp:&f)();
(fp?&f:fp)();
(fp?&f:&f)();
_Generic(0?arr:arr, char*: (void)0);
_Generic(0?&arr[0]:arr, char*: (void)0);
_Generic(0?arr:&arr[0], char*: (void)0);
_Generic(1?arr:arr, char*: (void)0);
_Generic(1?&arr[0]:arr, char*: (void)0);
_Generic(1?arr:&arr[0], char*: (void)0);
_Generic((__typeof(1?f:f)*){0}, void (**)(void): (void)0);
(fp?&f:f)();
(fp?f:&f)();
_Generic((__typeof(fp?0L:(void)0)*){0}, void*: (void)0);
//Should cleanly fail, not segfault:
/*(fp?f:1);*/
}
int main()
{
@ -9,6 +35,19 @@ int main()
printf("%d\n", (Count < 5) ? (Count*Count) : (Count * 3));
}
{
int c = 0;
#define ASSERT(X) assert(X)
static struct stru { int x; } a={'A'},b={'B'};
ASSERT('A'==(*(1?&a:&b)).x);
ASSERT('A'==(1?a:b).x);
ASSERT('A'==(c?b:a).x);
ASSERT('A'==(0?b:a).x);
c=1;
ASSERT('A'==(c?a:b).x);
}
return 0;
}

View File

@ -44,4 +44,22 @@ extern const int cb[1][2][3];
extern B b;
extern int b[1][2][3];
/* Funny but valid function declaration. */
typedef int functype (int);
extern functype func;
int func(int i)
{
return i + 1;
}
/* Even funnier function decl and definition using typeof. */
int set_anon_super(void);
int set_anon_super(void)
{
return 42;
}
typedef int sas_type (void);
extern typeof(set_anon_super) set_anon_super;
extern sas_type set_anon_super;
/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/

View File

@ -1 +0,0 @@
struct A {} int i;

View File

@ -1 +0,0 @@
56_btype_excess-1.c:1: error: too many basic types

View File

@ -1 +0,0 @@
char int i;

View File

@ -1 +0,0 @@
57_btype_excess-2.c:1: error: too many basic types

View File

@ -1,9 +0,0 @@
int f(void)
{
return 0;
}
int f(void)
{
return 1;
}

View File

@ -1 +0,0 @@
58_function_redefinition.c:7: error: redefinition of 'f'

View File

@ -1 +0,0 @@
int (*fct)[42](int x);

View File

@ -1 +0,0 @@
59_function_array.c:1: error: declaration of an array of functions

View File

@ -1,4 +0,0 @@
enum color {RED, GREEN, BLUE};
enum color {R, G, B};
enum color c;

View File

@ -1 +0,0 @@
60_enum_redefinition.c:2: error: struct/union/enum already defined

View File

@ -0,0 +1,127 @@
#if defined test_56_btype_excess_1
struct A {} int i;
#elif defined test_57_btype_excess_2
char int i;
#elif defined test_58_function_redefinition
int f(void) { return 0; }
int f(void) { return 1; }
#elif defined test_global_redefinition
int xxx = 1;
int xxx;
int xxx = 2;
#elif defined test_59_function_array
int (*fct)[42](int x);
#elif defined test_60_enum_redefinition
enum color { RED, GREEN, BLUE };
enum color { R, G, B };
enum color c;
#elif defined test_62_enumerator_redefinition
enum color { RED, GREEN, BLUE };
enum rgb { RED, G, B};
enum color c = RED;
#elif defined test_63_local_enumerator_redefinition
enum {
FOO,
BAR
};
int main(void)
{
enum {
FOO = 2,
BAR
};
return BAR - FOO;
}
#elif defined test_61_undefined_enum
enum rgb3 c = 42;
#elif defined test_74_non_const_init
int i = i++;
#elif defined test_pointer_assignment
void (*f1)(void);
void f2(void) {}
struct s1 *ps1;
struct s2 *ps2;
void *v1, **v2, ***v3;
enum e1 { a = 4 } e10, *e11, *e12;
enum e2 { b = -4 } e20, *e21;
enum e3 { c = 5000000000LL } e30;
int *ip;
unsigned int *up;
long *lp;
long long *llp;
char **c1;
char const **c2;
unsigned char **u1;
int no_main ()
{
// function
f1 = f2;
// struct
ps1 = ps2;
// void*
v1 = v3;
v2 = v3;
// enum
e11 = e12;
e11 = e21;
e11 = &e10;
ip = &e10;
ip = &e20;
up = &e10;
up = &e20;
up = &e30;
lp = ip;
lp = llp;
// constness
c1 = c2;
*c1 = *c2;
**c1 = **c2;
// unsigned = signed
u1 = c2;
*u1 = *c2;
**u1 = **c2;
c2 = c1;
*c2 = *c1;
**c2 = **c1;
return 0;
}
#elif defined test_enum_compat
enum e4;
enum e5;
void f3(enum e4 e);
void f3(enum e5 e);
#elif defined test_ptr_to_str
void f() { _Generic((int const *[]){0}, int:0); }
#elif defined test_fnptr_to_str
void f() { _Generic((int (*(*)(float,char))(double,int)){0}, int:0); }
#elif defined test_array_to_str
void f() { _Generic((int(*)[3]){0}, int:0); }
#endif

View File

@ -0,0 +1,55 @@
[test_56_btype_excess_1]
60_errors_and_warnings.c:2: error: too many basic types
[test_57_btype_excess_2]
60_errors_and_warnings.c:5: error: too many basic types
[test_58_function_redefinition]
60_errors_and_warnings.c:9: error: redefinition of 'f'
[test_global_redefinition]
60_errors_and_warnings.c:14: error: redefinition of 'xxx'
[test_59_function_array]
60_errors_and_warnings.c:17: error: declaration of an array of functions
[test_60_enum_redefinition]
60_errors_and_warnings.c:21: error: struct/union/enum already defined
[test_62_enumerator_redefinition]
60_errors_and_warnings.c:26: error: redefinition of enumerator 'RED'
[test_63_local_enumerator_redefinition]
[test_61_undefined_enum]
60_errors_and_warnings.c:46: error: unknown type size
[test_74_non_const_init]
60_errors_and_warnings.c:49: error: initializer element is not constant
[test_pointer_assignment]
60_errors_and_warnings.c:79: warning: assignment from incompatible pointer type
60_errors_and_warnings.c:82: warning: assignment from incompatible pointer type
60_errors_and_warnings.c:86: warning: assignment from incompatible pointer type
60_errors_and_warnings.c:88: warning: assignment from incompatible pointer type
60_errors_and_warnings.c:91: warning: assignment from incompatible pointer type
60_errors_and_warnings.c:92: warning: assignment from incompatible pointer type
60_errors_and_warnings.c:94: warning: assignment from incompatible pointer type
60_errors_and_warnings.c:95: warning: assignment from incompatible pointer type
60_errors_and_warnings.c:98: warning: assignment discards qualifiers from pointer target type
60_errors_and_warnings.c:99: warning: assignment discards qualifiers from pointer target type
60_errors_and_warnings.c:103: warning: assignment discards qualifiers from pointer target type
60_errors_and_warnings.c:104: warning: assignment discards qualifiers from pointer target type
60_errors_and_warnings.c:109: warning: assignment of read-only location
[test_enum_compat]
60_errors_and_warnings.c:119: error: incompatible types for redefinition of 'f3'
[test_ptr_to_str]
60_errors_and_warnings.c:122: error: type 'const int **' does not match any association
[test_fnptr_to_str]
60_errors_and_warnings.c:124: error: type 'int (*(*)(float, char))(double, int)' does not match any association
[test_array_to_str]
60_errors_and_warnings.c:126: error: type 'int (*)[3]' does not match any association

View File

@ -1 +0,0 @@
enum rgb c = 42;

View File

@ -1 +0,0 @@
61_undefined_enum.c:1: error: unknown type size

View File

@ -1,4 +0,0 @@
enum color {RED, GREEN, BLUE};
enum rgb {RED, G, B};
enum color c = RED;

View File

@ -1 +0,0 @@
62_enumerator_redefinition.c:2: error: redefinition of enumerator 'RED'

View File

@ -1,14 +0,0 @@
enum {
FOO,
BAR
};
int main(void)
{
enum {
FOO = 2,
BAR
};
return BAR - FOO;
}

View File

@ -1 +0,0 @@
int i = i++;

View File

@ -1 +0,0 @@
74_nocode_wanted.c:1: error: initializer element is not constant

View File

@ -11,4 +11,30 @@ typedef union __attribute__((packed)) Unaligned16b {
uint8_t b[2];
} Unaligned16b;
int main () { return 0; }
extern void foo (void) __attribute__((stdcall));
void __attribute__((stdcall)) foo (void)
{
}
/* The actual attribute isn't important, must just be
parsable. */
#define ATTR __attribute__((__noinline__))
int ATTR actual_function() {
return 42;
}
extern int printf (const char *, ...);
int main()
{
void *function_pointer = &actual_function;
int a = ((ATTR int(*) (void)) function_pointer)();
printf("%i\n", a);
/* In the following we once misparsed 'ATTR *' is a btype
and hence the whole type was garbled. */
int b = ( (int(ATTR *)(void)) function_pointer)();
printf("%i\n", b);
return 0;
}

View File

@ -0,0 +1,2 @@
42
42

View File

@ -9,7 +9,7 @@ static void kb_wait_1(void)
/* Here the else arm is a statement expression that's supposed
to be suppressed. The label inside the while would unsuppress
code generation again if not handled correctly. And that
would wreak havok to the cond-expression because there's no
would wreak havoc to the cond-expression because there's no
jump-around emitted, the whole statement expression really
needs to not generate code (perhaps except useless forward jumps). */
(1 ?
@ -26,6 +26,36 @@ static void kb_wait_1(void)
timeout--;
} while (timeout);
}
static int global;
static void foo(int i)
{
global+=i;
printf ("g=%d\n", global);
}
static int check(void)
{
printf ("check %d\n", global);
return 1;
}
static void dowhile(void)
{
do {
foo(1);
if (global == 1) {
continue;
} else if (global == 2) {
continue;
}
/* The following break shouldn't disable the check() call,
as it's reachable by the continues above. */
break;
} while (check());
}
int main (void)
{
int i = 1;
@ -118,5 +148,8 @@ enterloop3:
printf ("error4\n");
}
}
dowhile();
return 0;
}

View File

@ -16,3 +16,8 @@ once3
twice3
caseok
caseok2
g=1
check 1
g=2
check 2
g=3

View File

@ -60,7 +60,7 @@ struct U gu4 = { 3, {5,6,7,}, 5, { "bla", {44}} };
struct S gs3 = { (1), {(2)}, {(((3))), {4}}};
/* Superfluous braces, and leaving out braces for V.t, plus cast */
struct V gv = {{{3},4,{5,6}}, "haha", (u8)45, 46};
/* Compund literal */
/* Compound literal */
struct V gv2 = {(struct S){7,8,{9,10}}, {"hihi", 47}, 48};
/* Parens around compound literal */
struct V gv3 = {((struct S){7,8,{9,10}}), {"hoho", 49}, 50};
@ -157,7 +157,7 @@ void foo (struct W *w, struct pkthdr *phdr_)
struct S ls3 = { (1), (2), {(((3))), 4}};
/* Superfluous braces, and leaving out braces for V.t, plus cast */
struct V lv = {{3,4,{5,6}}, "haha", (u8)45, 46};
/* Compund literal */
/* Compound literal */
struct V lv2 = {(struct S)w->t.s, {"hihi", 47}, 48};
/* Parens around compound literal */
struct V lv3 = {((struct S){7,8,{9,10}}), ((const struct W *)w)->t.t, 50};

115
tests/tests2/94_generic.c Normal file
View File

@ -0,0 +1,115 @@
#include <stdio.h>
const int a = 0;
struct a {
int a;
};
struct b {
int a;
};
int a_f()
{
return 20;
}
int b_f()
{
return 10;
}
typedef int (*fptr)(int);
int foo(int i)
{
return i;
}
typedef int int_type1;
#define gen_sw(a) _Generic(a, const char *: 1, default: 8, int: 123);
int main()
{
int i = 0;
signed long int l = 2;
struct b titi;
const int * const ptr;
const char *ti;
int_type1 i2;
i = _Generic(a, int: a_f, const int: b_f)();
printf("%d\n", i);
i = _Generic(a, int: a_f() / 2, const int: b_f() / 2);
printf("%d\n", i);
i = _Generic(ptr, int *:1, int * const:2, default:20);
printf("%d\n", i);
i = gen_sw(a);
printf("%d\n", i);
i = _Generic(titi, struct a:1, struct b:2, default:20);
printf("%d\n", i);
i = _Generic(i2, char: 1, int : 0);
printf("%d\n", i);
i = _Generic(a, char:1, int[4]:2, default:5);
printf("%d\n", i);
i = _Generic(17, int :1, int **:2);
printf("%d\n", i);
i = _Generic(17L, int :1, long :2, long long : 3);
printf("%d\n", i);
i = _Generic("17, io", char *: 3, const char *: 1);
printf("%d\n", i);
i = _Generic(ti, const unsigned char *:1, const char *:4, char *:3,
const signed char *:2);
printf("%d\n", i);
printf("%s\n", _Generic(i + 2L, long: "long", int: "int",
long long: "long long"));
i = _Generic(l, long: 1, int: 2);
printf("%d\n", i);
i = _Generic(foo, fptr: 3, int: 4);
printf("%d\n", i);
(void)_Generic((int(*)[2]){0}, int(*)[2]:0, int(*)[4]:0); //shouldn't match twice
//should accept ({ }) in the controlling expr of _Generic even in const_wanted contexts
struct { _Bool x_0: _Generic(({0;}),default:1); } my_x;
_Generic((__typeof((float const)((float const){42}))*){0}, float*: 0); //casts lose top-level qualifiers
int const x = 42; __typeof((__typeof(x))x) *xp = 0; (void)_Generic(xp, int*: 0); //casts lose top-level qualifiers
//TEST TERNARY:
//Same type
_Generic( 0?(long*)0:(long*)0, long*: (void)0);
//combining of qualifiers
_Generic( 0?(long volatile*)0:(long const*)0, long const volatile*: (void)0);
//nul-ptr constant selects other type
_Generic( 0?(long*)0:0, long*: (void)0);
_Generic( 0?(long*)0:(void*)0, long*: (void)0);
//void ptrs get chosen preferentially; qualifs still combine
_Generic( 0?(int volatile*)0: (void const*)1, void volatile const*: (void)0);
//like gcc but not clang, don't treat (void* const as the null-ptr constant)
_Generic( 0?(int volatile*)0: (void const*)0, void volatile const*: (void)0);
//ptrs to incomplete types get completed
(void)(sizeof(struct { int x:_Generic( 0?(int (*)[4])0 : (int (*)[])0, int (*)[4]:+1, int (*)[5]:(void)0); }));
(void)(sizeof(struct { int x:_Generic( 0?(int (*)[])0 : (int (*)[4])0, int (*)[4]:+1, int (*)[5]:(void)0); }));
{
/* completion shouldn't affect the type of decl */
char **argv;
_Generic(argv, char**: (void)0);
_Generic(0?(char const*)0:argv[0], char const*: (void)0);
_Generic(argv, char**: (void)0);
}
{
extern int (*ar)[];
(void)(sizeof(struct { int x:_Generic( 0?(int (*)[4])0 : (int (*)[])0, int (*)[4]:+1, int (*)[5]:(void)0); }));
(void)(sizeof(struct { int x:_Generic( 0?(int (*)[])0 : (int (*)[4])0, int (*)[4]:+1, int (*)[5]:(void)0); }));
(void)(sizeof(struct { int x:_Generic( 0?ar : (int (*)[4])0, int (*)[4]:+1, int (*)[5]:(void)0); }));
(void)(sizeof(struct { int x:_Generic( 0?(int (*)[4])0 : ar, int (*)[4]:+1, int (*)[5]:(void)0); }));
(void)(sizeof(struct { int x:_Generic( 0?(int (*)[5])0 : ar, int (*)[5]:+1, int (*)[4]:(void)0); }));
}
return 0;
}

View File

@ -0,0 +1,14 @@
20
10
20
123
2
0
5
1
2
3
4
long
1
3

218
tests/tests2/95_bitfields.c Normal file
View File

@ -0,0 +1,218 @@
/* ----------------------------------------------------------------------- */
#if TEST == 1
{
struct M P A __s
{
unsigned x : 12;
unsigned char y : 7;
unsigned z : 28;
unsigned a: 4;
unsigned b: 5;
};
TEST_STRUCT(0x333,0x44,0x555555,6,7);
}
/* ----------------------------------------------------------------------- */
#elif TEST == 2
{
struct M P __s
{
int x: 12;
char y: 6;
long long z:63;
A char a:4;
long long b:2;
};
TEST_STRUCT(3,30,0x123456789abcdef0LL,5,2);
}
/* ----------------------------------------------------------------------- */
#elif TEST == 3
{
struct M P __s
{
unsigned x:5, y:5, :0, z:5; char a:5; A short b:5;
};
TEST_STRUCT(21,23,25,6,14);
}
/* ----------------------------------------------------------------------- */
#elif TEST == 4
{
struct M P __s {
int x : 3;
int : 2;
int y : 1;
int : 0;
int z : 5;
int a : 7;
unsigned int b : 7;
};
TEST_STRUCT(3,1,15,120,120);
}
/* ----------------------------------------------------------------------- */
#elif TEST == 5
{
struct M P __s {
long long x : 45;
long long : 2;
long long y : 30;
unsigned long long z : 38;
char a; short b;
};
TEST_STRUCT(0x123456789ULL, 120<<25, 120, 0x44, 0x77);
}
/* ----------------------------------------------------------------------- */
#elif TEST == 6
{
struct M P __s {
int a;
signed char b;
int x : 12, y : 4, : 0, : 4, z : 3;
char d;
};
TEST_STRUCT(1,2,3,4,-3);
}
/* ----------------------------------------------------------------------- */
#elif defined PACK
#if PACK
# pragma pack(push,1)
# define P //_P
#else
# define P
#endif
printf("\n\n" + 2*top);
#define TEST 1
#include SELF
top = 0;
#define TEST 2
#include SELF
#define TEST 3
#include SELF
#define TEST 4
#include SELF
#define TEST 5
#include SELF
#define TEST 6
#include SELF
#if PACK
# pragma pack(pop)
#endif
#undef P
#undef PACK
/* ----------------------------------------------------------------------- */
#elif defined ALIGN
#if ALIGN
# define A _A(16)
#else
# define A
#endif
#define PACK 0
#include SELF
#define PACK 1
#include SELF
#undef A
#undef ALIGN
/* ----------------------------------------------------------------------- */
#elif defined MS_BF
#if MS_BF
# ifdef __TINYC__
# pragma comment(option, "-mms-bitfields")
# elif defined __GNUC__
# define M __attribute__((ms_struct))
# endif
#else
# ifdef __TINYC__
# pragma comment(option, "-mno-ms-bitfields")
# elif defined __GNUC__
# define M __attribute__((gcc_struct))
# endif
#endif
#ifndef M
# define M
#endif
#define ALIGN 0
#include SELF
#define ALIGN 1
#include SELF
#undef M
#undef MS_BF
/* ----------------------------------------------------------------------- */
#else
#include <stdio.h>
#include <string.h>
/* some gcc headers #define __attribute__ to empty if it's not gcc */
#undef __attribute__
void dump(void *p, int s)
{
int i;
for (i = s; --i >= 0;)
printf("%02X", ((unsigned char*)p)[i]);
printf("\n");
}
#define pv(m) \
printf(sizeof (s->m + 0) == 8 ? " %016llx" : " %02x", s->m)
#define TEST_STRUCT(v1,v2,v3,v4,v5) { \
struct __s _s, *s = & _s; \
printf("\n---- TEST %d%s%s%s ----\n" + top, \
TEST, MS_BF?" - MS-BITFIELDS":"", \
PACK?" - PACKED":"", \
ALIGN?" - WITH ALIGN":""); \
memset(s, 0, sizeof *s); \
s->x = -1, s->y = -1, s->z = -1, s->a = -1, s->b = -1; \
printf("bits in use : "), dump(s, sizeof *s); \
s->x = v1, s->y = v2, s->z = v3, s->a += v4, ++s->a, s->b = v5; \
printf("bits as set : "), dump(s, sizeof *s); \
printf("values :"), pv(x), pv(y), pv(z), pv(a), pv(b), printf("\n"); \
printf("align/size : %d %d\n", alignof(struct __s),sizeof(struct __s)); \
}
#ifdef _MSC_VER
# define _A(n) __declspec(align(n))
# define _P
# define alignof(x) __alignof(x)
#else
# define _A(n) __attribute__((aligned(n)))
# define _P __attribute__((packed))
# define alignof(x) __alignof__(x)
#endif
#ifndef MS_BITFIELDS
# define MS_BITFIELDS 0
#endif
#define SELF "95_bitfields.c"
int top = 1;
int main()
{
#define MS_BF MS_BITFIELDS
#include SELF
return 0;
}
/* ----------------------------------------------------------------------- */
#endif
#undef TEST

View File

@ -0,0 +1,149 @@
---- TEST 1 ----
bits in use : 0000001FFFFFFFFF007F0FFF
bits as set : 000000076055555500440333
values : 333 44 555555 06 07
align/size : 4 12
---- TEST 2 ----
bits in use : 000000000000003F7FFFFFFFFFFFFFFF00000000003F0FFF
bits as set : 0000000000000025123456789ABCDEF000000000001E0003
values : 03 1e 123456789abcdef0 05 fffffffe
align/size : 8 24
---- TEST 3 ----
bits in use : 001F1F1F000003FF
bits as set : 000E0619000002F5
values : 15 17 19 06 0e
align/size : 4 8
---- TEST 4 ----
bits in use : 0007FFFF00000027
bits as set : 00078F0F00000023
values : 03 ffffffff 0f fffffff8 78
align/size : 4 8
---- TEST 5 ----
bits in use : FFFFFF3FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF
bits as set : 007744000000007800000000300000000000000123456789
values : 0000000123456789 f0000000 0000000000000078 44 77
align/size : 8 24
---- TEST 6 ----
bits in use : 0000007000FFFFFFFFFFFFFF
bits as set : 00000030002001FD00000004
values : 01 02 03 04 fffffffd
align/size : 4 12
---- TEST 1 - PACKED ----
bits in use : FFFFFFFFFFFFFF
bits as set : 3B02AAAAAC4333
values : 333 44 555555 06 07
align/size : 1 7
---- TEST 2 - PACKED ----
bits in use : 7FFFFFFFFFFFFFFFFFFFFF
bits as set : 4A48D159E26AF37BC1E003
values : 03 1e 123456789abcdef0 05 fffffffe
align/size : 1 11
---- TEST 3 - PACKED ----
bits in use : 7FFF000003FF
bits as set : 38D9000002F5
values : 15 17 19 06 0e
align/size : 1 6
---- TEST 4 - PACKED ----
bits in use : 07FFFF00000027
bits as set : 078F0F00000023
values : 03 ffffffff 0f fffffff8 78
align/size : 1 7
---- TEST 5 - PACKED ----
bits in use : FFFFFF07FFFFFFFFFFFFFFFF9FFFFFFFFFFF
bits as set : 007744000000000F18000000000123456789
values : 0000000123456789 f0000000 0000000000000078 44 77
align/size : 1 18
---- TEST 6 - PACKED ----
bits in use : 007000FFFFFFFFFFFFFF
bits as set : 0030002001FD00000004
values : 01 02 03 04 fffffffd
align/size : 1 10
---- TEST 1 - WITH ALIGN ----
bits in use : 000000000000001FFFFFFFFF007F0FFF
bits as set : 00000000000000076055555500440333
values : 333 44 555555 06 07
align/size : 16 16
---- TEST 2 - WITH ALIGN ----
bits in use : 0000000000000000000000000000003F7FFFFFFFFFFFFFFF00000000003F0FFF
bits as set : 00000000000000000000000000000025123456789ABCDEF000000000001E0003
values : 03 1e 123456789abcdef0 05 fffffffe
align/size : 16 32
---- TEST 3 - WITH ALIGN ----
bits in use : 0000000000000000000000000000001F000000000000000000001F1F000003FF
bits as set : 0000000000000000000000000000000E000000000000000000000619000002F5
values : 15 17 19 06 0e
align/size : 16 32
---- TEST 4 - WITH ALIGN ----
bits in use : 0007FFFF00000027
bits as set : 00078F0F00000023
values : 03 ffffffff 0f fffffff8 78
align/size : 4 8
---- TEST 5 - WITH ALIGN ----
bits in use : FFFFFF3FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF
bits as set : 007744000000007800000000300000000000000123456789
values : 0000000123456789 f0000000 0000000000000078 44 77
align/size : 8 24
---- TEST 6 - WITH ALIGN ----
bits in use : 0000007000FFFFFFFFFFFFFF
bits as set : 00000030002001FD00000004
values : 01 02 03 04 fffffffd
align/size : 4 12
---- TEST 1 - PACKED - WITH ALIGN ----
bits in use : 000000000000000000FFFFFFFFFFFFFF
bits as set : 0000000000000000003B02AAAAAC4333
values : 333 44 555555 06 07
align/size : 16 16
---- TEST 2 - PACKED - WITH ALIGN ----
bits in use : 3F01FFFFFFFFFFFFFFFFFFFF
bits as set : 250048D159E26AF37BC1E003
values : 03 1e 123456789abcdef0 05 fffffffe
align/size : 1 12
---- TEST 3 - PACKED - WITH ALIGN ----
bits in use : 1F03FF000003FF
bits as set : 0E00D9000002F5
values : 15 17 19 06 0e
align/size : 1 7
---- TEST 4 - PACKED - WITH ALIGN ----
bits in use : 07FFFF00000027
bits as set : 078F0F00000023
values : 03 ffffffff 0f fffffff8 78
align/size : 1 7
---- TEST 5 - PACKED - WITH ALIGN ----
bits in use : FFFFFF07FFFFFFFFFFFFFFFF9FFFFFFFFFFF
bits as set : 007744000000000F18000000000123456789
values : 0000000123456789 f0000000 0000000000000078 44 77
align/size : 1 18
---- TEST 6 - PACKED - WITH ALIGN ----
bits in use : 007000FFFFFFFFFFFFFF
bits as set : 0030002001FD00000004
values : 01 02 03 04 fffffffd
align/size : 1 10

View File

@ -0,0 +1,2 @@
#define MS_BITFIELDS 1
#include "95_bitfields.c"

View File

@ -0,0 +1,149 @@
---- TEST 1 - MS-BITFIELDS ----
bits in use : 0000001FFFFFFFFF0000007F00000FFF
bits as set : 00000007605555550000004400000333
values : 333 44 555555 06 07
align/size : 4 16
---- TEST 2 - MS-BITFIELDS ----
bits in use : 0000000000000003000000000000000F7FFFFFFFFFFFFFFF0000003F00000FFF
bits as set : 00000000000000020000000000000005123456789ABCDEF00000001E00000003
values : 03 1e 123456789abcdef0 05 fffffffffffffffe
align/size : 8 32
---- TEST 3 - MS-BITFIELDS ----
bits in use : 001F001F0000001F000003FF
bits as set : 000E000600000019000002F5
values : 15 17 19 06 0e
align/size : 4 12
---- TEST 4 - MS-BITFIELDS ----
bits in use : 0007FFFF00000027
bits as set : 00078F0F00000023
values : 03 ffffffff 0f fffffff8 78
align/size : 4 8
---- TEST 5 - MS-BITFIELDS ----
bits in use : 00000000FFFF00FF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF
bits as set : 0000000000770044000000000000007800000000300000000000000123456789
values : 0000000123456789 fffffffff0000000 0000000000000078 44 77
align/size : 8 32
---- TEST 6 - MS-BITFIELDS ----
bits in use : 00000000000000700000FFFF000000FFFFFFFFFF
bits as set : 000000000000003000002001000000FD00000004
values : 01 02 03 04 fffffffd
align/size : 4 20
---- TEST 1 - MS-BITFIELDS - PACKED ----
bits in use : 0000001FFFFFFFFF7F00000FFF
bits as set : 00000007605555554400000333
values : 333 44 555555 06 07
align/size : 1 13
---- TEST 2 - MS-BITFIELDS - PACKED ----
bits in use : 00000000000000030F7FFFFFFFFFFFFFFF3F00000FFF
bits as set : 000000000000000205123456789ABCDEF01E00000003
values : 03 1e 123456789abcdef0 05 fffffffffffffffe
align/size : 1 22
---- TEST 3 - MS-BITFIELDS - PACKED ----
bits in use : 001F1F0000001F000003FF
bits as set : 000E0600000019000002F5
values : 15 17 19 06 0e
align/size : 1 11
---- TEST 4 - MS-BITFIELDS - PACKED ----
bits in use : 0007FFFF00000027
bits as set : 00078F0F00000023
values : 03 ffffffff 0f fffffff8 78
align/size : 1 8
---- TEST 5 - MS-BITFIELDS - PACKED ----
bits in use : FFFFFF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF
bits as set : 007744000000000000007800000000300000000000000123456789
values : 0000000123456789 fffffffff0000000 0000000000000078 44 77
align/size : 1 27
---- TEST 6 - MS-BITFIELDS - PACKED ----
bits in use : 00000000700000FFFFFFFFFFFFFF
bits as set : 000000003000002001FD00000004
values : 01 02 03 04 fffffffd
align/size : 1 14
---- TEST 1 - MS-BITFIELDS - WITH ALIGN ----
bits in use : 0000001FFFFFFFFF0000007F00000FFF
bits as set : 00000007605555550000004400000333
values : 333 44 555555 06 07
align/size : 16 16
---- TEST 2 - MS-BITFIELDS - WITH ALIGN ----
bits in use : 0000000000000003000000000000000F7FFFFFFFFFFFFFFF0000003F00000FFF
bits as set : 00000000000000020000000000000005123456789ABCDEF00000001E00000003
values : 03 1e 123456789abcdef0 05 fffffffffffffffe
align/size : 16 32
---- TEST 3 - MS-BITFIELDS - WITH ALIGN ----
bits in use : 0000000000000000000000000000001F000000000000001F0000001F000003FF
bits as set : 0000000000000000000000000000000E000000000000000600000019000002F5
values : 15 17 19 06 0e
align/size : 16 32
---- TEST 4 - MS-BITFIELDS - WITH ALIGN ----
bits in use : 0007FFFF00000027
bits as set : 00078F0F00000023
values : 03 ffffffff 0f fffffff8 78
align/size : 4 8
---- TEST 5 - MS-BITFIELDS - WITH ALIGN ----
bits in use : 00000000FFFF00FF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF
bits as set : 0000000000770044000000000000007800000000300000000000000123456789
values : 0000000123456789 fffffffff0000000 0000000000000078 44 77
align/size : 8 32
---- TEST 6 - MS-BITFIELDS - WITH ALIGN ----
bits in use : 00000000000000700000FFFF000000FFFFFFFFFF
bits as set : 000000000000003000002001000000FD00000004
values : 01 02 03 04 fffffffd
align/size : 4 20
---- TEST 1 - MS-BITFIELDS - PACKED - WITH ALIGN ----
bits in use : 0000000000001FFFFFFFFF7F00000FFF
bits as set : 00000000000007605555554400000333
values : 333 44 555555 06 07
align/size : 16 16
---- TEST 2 - MS-BITFIELDS - PACKED - WITH ALIGN ----
bits in use : 00000000000000030F0000007FFFFFFFFFFFFFFF3F00000FFF
bits as set : 000000000000000205000000123456789ABCDEF01E00000003
values : 03 1e 123456789abcdef0 05 fffffffffffffffe
align/size : 16 25
---- TEST 3 - MS-BITFIELDS - PACKED - WITH ALIGN ----
bits in use : 001F000000000000001F0000001F000003FF
bits as set : 000E000000000000000600000019000002F5
values : 15 17 19 06 0e
align/size : 16 18
---- TEST 4 - MS-BITFIELDS - PACKED - WITH ALIGN ----
bits in use : 0007FFFF00000027
bits as set : 00078F0F00000023
values : 03 ffffffff 0f fffffff8 78
align/size : 1 8
---- TEST 5 - MS-BITFIELDS - PACKED - WITH ALIGN ----
bits in use : FFFFFF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF
bits as set : 007744000000000000007800000000300000000000000123456789
values : 0000000123456789 fffffffff0000000 0000000000000078 44 77
align/size : 1 27
---- TEST 6 - MS-BITFIELDS - PACKED - WITH ALIGN ----
bits in use : 00000000700000FFFFFFFFFFFFFF
bits as set : 000000003000002001FD00000004
values : 01 02 03 04 fffffffd
align/size : 1 14

View File

@ -0,0 +1,98 @@
/*****************************************************************************/
/* test 'nodata_wanted' data output suppression */
#if defined test_static_data_error
void foo() {
if (1) {
static short w = (int)&foo; /* initializer not computable */
}
}
#elif defined test_static_nodata_error
void foo() {
if (0) {
static short w = (int)&foo; /* initializer not computable */
}
}
#elif defined test_global_data_error
void foo();
static short w = (int)&foo; /* initializer not computable */
#elif defined test_local_data_noerror
void foo() {
short w = &foo; /* 2 cast warnings */
}
#elif defined test_data_suppression_off || defined test_data_suppression_on
#if defined test_data_suppression_on
# define SKIP 1
#else
# define SKIP 0
#endif
#include <stdio.h>
/* some gcc headers #define __attribute__ to empty if it's not gcc */
#undef __attribute__
int main()
{
__label__ ts0, te0, ts1, te1;
int tl, dl;
static char ds0 = 0;
static char de0 = 0;
/* get reference size of empty jmp */
ts0:;
if (!SKIP) {}
te0:;
dl = -(&de0 - &ds0);
tl = -(&&te0 - &&ts0);
/* test data and code suppression */
static char ds1 = 0;
ts1:;
if (!SKIP) {
void *p = (void*)&main;
char cc[] = "static string";
double d = 8.0;
struct __attribute__((packed)) {
unsigned x : 12;
unsigned char y : 7;
unsigned z : 28, a: 4, b: 5;
} s = { 0x333,0x44,0x555555,6,7 };
printf("data:\n");
printf(" %d - %.1f - %.1f - %s - %s\n",
sizeof 8.0, 8.0, d, __FUNCTION__, cc);
printf(" %x %x %x %x %x\n",
s.x, s.y, s.z, s.a, s.b);
}
te1:;
static char de1 = 0;
dl += &de1 - &ds1;
tl += &&te1 - &&ts1;
printf("size of data/text:\n %s/%s\n",
dl ? "non-zero":"zero", tl ? "non-zero":"zero");
/*printf("# %d/%d\n", dl, tl);*/
}
#elif defined test_static_data
#include <stdio.h>
int main(int argc, char **argv)
{
goto there;
if (0) {
static int a = 1;
printf("hello\n"); /* the "hello\n" string is still suppressed */
there:
printf("a = %d\n", a);
}
return 0;
}
#endif

View File

@ -0,0 +1,26 @@
[test_static_data_error]
96_nodata_wanted.c:7: error: initializer element is not computable at load time
[test_static_nodata_error]
96_nodata_wanted.c:14: error: initializer element is not computable at load time
[test_global_data_error]
96_nodata_wanted.c:20: error: initializer element is not computable at load time
[test_local_data_noerror]
96_nodata_wanted.c:25: warning: assignment makes integer from pointer without a cast
96_nodata_wanted.c:25: warning: nonportable conversion from pointer to char/short
[test_data_suppression_off]
data:
8 - 8.0 - 8.0 - main - static string
333 44 555555 6 7
size of data/text:
non-zero/non-zero
[test_data_suppression_on]
size of data/text:
zero/zero
[test_static_data]
a = 1

View File

@ -0,0 +1,12 @@
// this file contains BMP chars encoded in UTF-8
#include <stdio.h>
#include <wchar.h>
int main()
{
wchar_t s[] = L"hello$$你好¢¢世界€€world";
wchar_t *p;
for (p = s; *p; p++) printf("%04X ", (unsigned) *p);
printf("\n");
return 0;
}

View File

@ -0,0 +1 @@
0068 0065 006C 006C 006F 0024 0024 4F60 597D 00A2 00A2 4E16 754C 20AC 20AC 0077 006F 0072 006C 0064

View File

@ -0,0 +1,41 @@
#include <stdio.h>
#include <stdlib.h>
asm (
".text;"
".globl _us;.globl _ss;.globl _uc;.globl _sc;"
"_us:;_ss:;_uc:;_sc:;"
"movl $0x1234ABCD, %eax;"
"ret;"
);
#if 1
#define us _us
#define ss _ss
#define uc _uc
#define sc _sc
#endif
int main()
{
unsigned short us(void);
short ss(void);
unsigned char uc(void);
signed char sc(void);
unsigned short (*fpus)(void) = us;
short (*fpss)(void) = ss;
unsigned char (*fpuc)(void) = uc;
signed char (*fpsc)(void) = sc;
printf("%08X %08X\n", us() + 1, fpus() + 1);
printf("%08X %08X\n", ss() + 1, fpss() + 1);
printf("%08X %08X\n", uc() + 1, fpuc() + 1);
printf("%08X %08X\n", sc() + 1, fpsc() + 1);
printf("\n");
printf("%08X %08X\n", fpus() + 1, us() + 1);
printf("%08X %08X\n", fpss() + 1, ss() + 1);
printf("%08X %08X\n", fpuc() + 1, uc() + 1);
printf("%08X %08X\n", fpsc() + 1, sc() + 1);
return 0;
}

View File

@ -0,0 +1,9 @@
0000ABCE 0000ABCE
FFFFABCE FFFFABCE
000000CE 000000CE
FFFFFFCE FFFFFFCE
0000ABCE 0000ABCE
FFFFABCE FFFFABCE
000000CE 000000CE
FFFFFFCE FFFFFFCE

276
tests/tests2/99_fastcall.c Normal file
View File

@ -0,0 +1,276 @@
#include <stdio.h>
#include <assert.h>
#ifndef _WIN32
#define __fastcall __attribute((fastcall))
#endif
#if 1
#define SYMBOL(x) _##x
#else
#define SYMBOL(x) x
#endif
/////////////////////////////////////////////////////////////////////////
////////// TRAP FRAMEWORK
/////////////////////////////////////////////////////////////////////////
// if you cast 'TRAP' to a function pointer and call it,
// it will save all 8 registers,
// and jump into C-code (previously set using 'SET_TRAP_HANDLER(x)'),
// in C-code you can pop DWORDs from stack and modify registers
//
void *SYMBOL(trap_handler);
extern unsigned char SYMBOL(trap)[];
asm (
".text;"
"_trap:;"
"pushl %esp;"
"pusha;"
"addl $0x4, 0xc(%esp);"
"pushl %esp;"
"call *_trap_handler;"
"addl $0x4, %esp;"
"movl 0xc(%esp), %eax;"
"movl %eax, 0x20(%esp);"
"popa;"
"popl %esp;"
"ret;"
);
struct trapframe {
unsigned edi, esi, ebp, esp, ebx, edx, ecx, eax;
};
#define M_FLOAT(addr) (*(float *)(addr))
#define M_DWORD(addr) (*(unsigned *)(addr))
#define M_WORD(addr) (*(unsigned short *)(addr))
#define M_BYTE(addr) (*(unsigned char *)(addr))
#define R_EAX ((tf)->eax)
#define R_ECX ((tf)->ecx)
#define R_EDX ((tf)->edx)
#define R_EBX ((tf)->ebx)
#define R_ESP ((tf)->esp)
#define R_EBP ((tf)->ebp)
#define R_ESI ((tf)->esi)
#define R_EDI ((tf)->edi)
#define ARG(x) (M_DWORD(R_ESP + (x) * 4))
#define RETN(x) do { \
M_DWORD(R_ESP + (x)) = M_DWORD(R_ESP); \
R_ESP += (x); \
} while (0)
#define DUMP() do { \
unsigned i; \
printf("EAX: %08X\n", R_EAX); \
printf("ECX: %08X\n", R_ECX); \
printf("EDX: %08X\n", R_EDX); \
printf("EBX: %08X\n", R_EBX); \
printf("ESP: %08X\n", R_ESP); \
printf("EBP: %08X\n", R_EBP); \
printf("ESI: %08X\n", R_ESI); \
printf("EDI: %08X\n", R_EDI); \
printf("\n"); \
printf("[RETADDR]: %08X\n", M_DWORD(R_ESP)); \
for (i = 1; i <= 8; i++) { \
printf("[ARG%4d]: %08X\n", i, ARG(i)); \
} \
} while (0)
#define SET_TRAP_HANDLER(x) ((SYMBOL(trap_handler)) = (x))
#define TRAP ((void *) &SYMBOL(trap))
/////////////////////////////////////////////////////////////////////////
////////// SAFECALL FRAMEWORK
/////////////////////////////////////////////////////////////////////////
// this framework will convert any calling convention to cdecl
// usage: first set call target with 'SET_SAFECALL_TARGET(x)'
// then cast 'SAFECALL' to target function pointer type and invoke it
// after calling, 'ESPDIFF' is the difference of old and new esp
void *SYMBOL(sc_call_target);
unsigned SYMBOL(sc_retn_addr);
unsigned SYMBOL(sc_old_esp);
unsigned SYMBOL(sc_new_esp);
extern unsigned char SYMBOL(safecall)[];
asm (
".text;"
"_safecall:;"
"popl _sc_retn_addr;"
"movl %esp, _sc_old_esp;"
"call *_sc_call_target;"
"movl %esp, _sc_new_esp;"
"movl _sc_old_esp, %esp;"
"jmp *_sc_retn_addr;"
);
#define SET_SAFECALL_TARGET(x) ((SYMBOL(sc_call_target)) = (x))
#define SAFECALL ((void *) &SYMBOL(safecall))
#define ESPDIFF (SYMBOL(sc_new_esp) - SYMBOL(sc_old_esp))
/////////////////////////////////////////////////////////////////////////
////////// TEST FASTCALL INVOKE
/////////////////////////////////////////////////////////////////////////
void check_fastcall_invoke_0(struct trapframe *tf)
{
//DUMP();
RETN(0);
}
void check_fastcall_invoke_1(struct trapframe *tf)
{
//DUMP();
assert(R_ECX == 0x11111111);
RETN(0);
}
void check_fastcall_invoke_2(struct trapframe *tf)
{
//DUMP();
assert(R_ECX == 0x11111111);
assert(R_EDX == 0x22222222);
RETN(0);
}
void check_fastcall_invoke_3(struct trapframe *tf)
{
//DUMP();
assert(R_ECX == 0x11111111);
assert(R_EDX == 0x22222222);
assert(ARG(1) == 0x33333333);
RETN(1*4);
}
void check_fastcall_invoke_4(struct trapframe *tf)
{
//DUMP();
assert(R_ECX == 0x11111111);
assert(R_EDX == 0x22222222);
assert(ARG(1) == 0x33333333);
assert(ARG(2) == 0x44444444);
RETN(2*4);
}
void check_fastcall_invoke_5(struct trapframe *tf)
{
//DUMP();
assert(R_ECX == 0x11111111);
assert(R_EDX == 0x22222222);
assert(ARG(1) == 0x33333333);
assert(ARG(2) == 0x44444444);
assert(ARG(3) == 0x55555555);
RETN(3*4);
}
void test_fastcall_invoke()
{
SET_TRAP_HANDLER(check_fastcall_invoke_0);
((void __fastcall (*)(void)) TRAP)();
SET_TRAP_HANDLER(check_fastcall_invoke_1);
((void __fastcall (*)(unsigned)) TRAP)(0x11111111);
SET_TRAP_HANDLER(check_fastcall_invoke_2);
((void __fastcall (*)(unsigned, unsigned)) TRAP)(0x11111111, 0x22222222);
SET_TRAP_HANDLER(check_fastcall_invoke_3);
((void __fastcall (*)(unsigned, unsigned, unsigned)) TRAP)(0x11111111, 0x22222222, 0x33333333);
SET_TRAP_HANDLER(check_fastcall_invoke_4);
((void __fastcall (*)(unsigned, unsigned, unsigned, unsigned)) TRAP)(0x11111111, 0x22222222, 0x33333333, 0x44444444);
SET_TRAP_HANDLER(check_fastcall_invoke_5);
((void __fastcall (*)(unsigned, unsigned, unsigned, unsigned, unsigned)) TRAP)(0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555);
}
/////////////////////////////////////////////////////////////////////////
////////// TEST FUNCTION CODE GENERATION
/////////////////////////////////////////////////////////////////////////
int __fastcall check_fastcall_espdiff_0(void)
{
return 0;
}
int __fastcall check_fastcall_espdiff_1(int a)
{
return a;
}
int __fastcall check_fastcall_espdiff_2(int a, int b)
{
return a + b;
}
int __fastcall check_fastcall_espdiff_3(int a, int b, int c)
{
return a + b + c;
}
int __fastcall check_fastcall_espdiff_4(int a, int b, int c, int d)
{
return a + b + c + d;
}
int __fastcall check_fastcall_espdiff_5(int a, int b, int c, int d, int e)
{
return a + b + c + d + e;
}
void test_fastcall_espdiff()
{
int x;
SET_SAFECALL_TARGET(check_fastcall_espdiff_0);
x = ((typeof(&check_fastcall_espdiff_0))SAFECALL)();
assert(x == 0);
assert(ESPDIFF == 0);
SET_SAFECALL_TARGET(check_fastcall_espdiff_1);
x = ((typeof(&check_fastcall_espdiff_1))SAFECALL)(1);
assert(x == 1);
assert(ESPDIFF == 0);
SET_SAFECALL_TARGET(check_fastcall_espdiff_2);
x = ((typeof(&check_fastcall_espdiff_2))SAFECALL)(1, 2);
assert(x == 1 + 2);
assert(ESPDIFF == 0);
SET_SAFECALL_TARGET(check_fastcall_espdiff_3);
x = ((typeof(&check_fastcall_espdiff_3))SAFECALL)(1, 2, 3);
assert(x == 1 + 2 + 3);
assert(ESPDIFF == 1*4);
SET_SAFECALL_TARGET(check_fastcall_espdiff_4);
x = ((typeof(&check_fastcall_espdiff_4))SAFECALL)(1, 2, 3, 4);
assert(x == 1 + 2 + 3 + 4);
assert(ESPDIFF == 2*4);
SET_SAFECALL_TARGET(check_fastcall_espdiff_5);
x = ((typeof(&check_fastcall_espdiff_5))SAFECALL)(1, 2, 3, 4, 5);
assert(x == 1 + 2 + 3 + 4 + 5);
assert(ESPDIFF == 3*4);
}
int main()
{
#define N 10000
int i;
for (i = 1; i <= N; i++) {
test_fastcall_espdiff();
}
for (i = 1; i <= N; i++) {
test_fastcall_invoke();
}
puts("TEST OK");
return 0;
}

View File

@ -0,0 +1 @@
TEST OK

Some files were not shown because too many files have changed in this diff Show More