Compare commits

...

313 Commits
meesbs ... mob

Author SHA1 Message Date
grischka 4429cef9f6 tccgen.c: merge more function attributes
Merge function attributes with those given given for the
prototype, also handle post-decl appearance such as

    void func() __attribute__((noreturn))
    {
    }

Also, some test fixes (unrelated).
2020-05-13 11:39:39 +02:00
grischka 7bb5454ef3 make SILENT=yes
This allows to run make more silently.

Also, turns off debug info for binaries by default,
but adds a switch to get it back easily

    ./configure --debug
2020-05-12 20:35:43 +02:00
Christian Jullien 92236bfe1d Rework help messages: split --version -v and -vv, display -m32/64 only when available on current plateform. 2020-05-11 16:23:48 +02:00
grischka 9c28349757 tccgen.c: cleanup debug support
from 3e731e3a78

tccgen.c:
- make 'struct default_debug' const
- pass TCCState* as parameter to tcc_debug_xxx functions
- always check tcc_state->do_debug before calling functions
- factor out tcc_debug_extern_sym()
- remove formats "%lld"/"%llu" (not reliable on windows)

xxx-gen files:
- set func_vt/var from caller
2020-05-11 11:41:56 +02:00
grischka 5bc1720776 tccgen.c: move 'alloca_used' complication to *-gen files
related to commit 8370bc03a1
2020-05-11 11:41:56 +02:00
Michael Matz 8de7c092f0 Support --version cmdline arg
for simplicity handles like -v (verbose), but enables the usual idiom
of configure scripts to use '$CC --version' to find out the compiler
variant and version.
2020-05-10 22:47:53 +02:00
herman ten brugge 29ba50da29 Fix some printf like functions 2020-05-05 09:00:24 +02:00
herman ten brugge 8370bc03a1 Allow signal handlers when bound checking
Disable generating bound_local_new/bound_local_delete when not needed.
Add new testcase 114_bound_signal.
2020-05-05 08:31:57 +02:00
herman ten brugge 973a14bb2f Fix symbolic debugging for -g -dt -run 2020-05-04 08:13:41 +02:00
herman ten brugge 3e731e3a78 Add symbolic debug support
This allows debugging with variables/structs/unions/enums/bitfields.

Add new functions:
- tcc_debug_stabs: store stabs debug info
- tcc_debug_stabn: store stabn debug info
- tcc_get_debug_info: generate stabs debug info
- tcc_debug_finish: store debug info in debug section
- tcc_add_debug_info: Add function debug info

Update functions:
- tcc_debug_end: free debug hash
- tcc_debug_funcstart: Generate correct function debug info
- tcc_debug_funcend: Finish debug info
- put_extern_sym2: Generate debug info for symbols
- pop_local_syms: Add debug info
- prev_scope: Add local symbols
2020-05-03 11:59:57 +02:00
Michael Matz fb1fb8219c riscv64: fcvt.d.s doesn't need a rounding mode
it doesn't round so the RM field can be zero.  According to some
sourcs it should be set to zero by software in these cases, and
the binutils disassembler doesn't like us setting it to 7.

This shouldn't matter in practice, but who knows.
2020-04-16 00:02:32 +02:00
Michael Matz 2f94390223 musl: disable boundcheck tests
for now that doesn't work with musl libc.
2020-04-15 22:08:18 +02:00
Michael Matz 245f6a0d13 stdarg: always have the __builtin_va_* available
This makes available the __builtin_va_list type and __builtin variants
of va_start, va_arg, va_copy and va_end.  We do this via a header file
that's prepended to all compilations always (except if merely
preprocessing): tcc_predefs.h.  That header could also be used
for predefining other builtins in the future.

We don't need the define hacks for musl anymore with this.

Also fix x86_64 gfunc_prologue to reserve enoug space for the
full va_list structure, not just 16 bytes.
2020-04-15 22:06:52 +02:00
Michael Matz 8c6143d86f Fix stdarg on x86-64
this partly reverts 1803762e3 to fix stdarg on x86-64 again.  I've tried
to retain the apple specific changes from that commit.
Also include stdarg.h first in tcc.h, maybe that helps as well.
2020-04-15 04:49:34 +02:00
Robert Hoelzl 1803762e3f Make tcclib1.a compile on macOS again
When compiling on macOS (at least in version 10.12) the TCC compiler failed
to compile libtcc1.a. Three problems were solved:
 - The predefined macro "__APPLE__" is now available, as it is tested in the
   libc darwin header files
 - the libtcc1 Makefile defined _ANSI_SOURCE, although it used signals
 - stdargs.h defined va_list differently from the darwin libc.
   If the darwin standard library was included BEFORE stdargs this caused
   problems.
 - the darwin libc generated a warning if GCC < 4 was used
 - additional defines are predefined now to make darwin libc headers compile.
2020-04-15 02:56:24 +02:00
Michael Matz 38ab621b55 Factor out common type combination
as there's overlap between handling types for binary and ternay
operations.  Factor this into a single routine (combine_types).
This uses the structure that gen_op was following, and expr_cond
was using as well in the past, which I find easier to reconvene
with the standard language.  But it reuses the new functions for
diagnostics to improve (a little) on what GCC or clang produce :)
2020-04-15 02:44:12 +02:00
Michael Matz c085645f98 Expect c99 support in tcctest.c
the support for the macro GCC_MAJOR is gone since 2017, and it's
fairly doubtful that anyone serious is using gcc 2.95.

Also adds a test for the ternary ops typing rules: 'x?bool:bool' has
to promote to int.
2020-04-15 02:28:23 +02:00
Michael Matz 00fbf65524 Move type_incompatibility_error earlier
also move type_incompatibility_warning and type_to_str.
2020-04-15 02:11:05 +02:00
Michael Matz 096c93c0c6 Fix interaction of (local) labels and stmt exprs
as per testcase.  We must not reset token.sym_label twice with
kept symbols.  This is no problem for non-label symbols because those
aren't generated on demand when mentioning them.
2020-04-14 22:43:13 +02:00
grischka 6696da2f61 win32: long double as distinct C-type
On windows. there is no long double really IOW it is the
same as double.  However setting the VT_LONG flag in
combination with VT_DOUBLE allows to keep track of the
original type for the purpose of '_Generic() or more
accurate type warnings.
2020-04-11 22:03:09 +02:00
grischka d019586378 win32/include/math.h: rint/trunc: pop fp stack
... in order to avoid fp stack overflow (see test below).

#include <math.h>
#include <stdio.h>
int main()
{
   printf("%f %f %f %f\n", trunc(1.2), rint(1.2), trunc(1.2), rint(1.2));
   printf("%f %f %f %f\n", trunc(1.2), rint(1.2), trunc(1.2), rint(1.2));
   printf("%f %f %f %f\n", trunc(1.2), rint(1.2), trunc(1.2), rintl(1.2));
}

Also in rintl:
- 'long double' is not a ten-byte float on windows.
2020-04-11 21:45:57 +02:00
Tyge 024214af2d Finalizing math.h fixes:
- Updated msvcrt.def with symbols from 64bit version of dll - it contains the float math functions missing in the 32bit dll.
- Made sure this patch only apply to to WIN32 and WIN64. For WIN32 float functions calls the double variants, on 64bit they are called natively.
2020-04-11 02:29:51 +02:00
Tyge df67d8617b Minimum changes to make all float variants of math.h functions work,
by calling the double functions and removing unsupported __asm implementations using "=t".
This patch also enables the double version of logb(double).

Note: None of the 'long double' variants works though - could easily be fixed
by aliasing the double equvalents for completeness/compability.
2020-04-07 20:18:51 +02:00
wanjochan c386ca91c6 OSX: libtcc.dylib Makefile fix 2020-03-22 20:36:14 +08:00
Christian Jullien 5ade19c421 Add a test function which verifies we can pass a struct ptr to va_arg for all supported architectures. The bug has been identify by trying to compile FFTW-3.3.8. 2020-03-22 08:40:35 +01:00
Christian Jullien ec0e93616f Fix arm64-gen.c when passing a struct ptr to va_arg. 2020-03-22 08:26:03 +01:00
wanjochan 6fa78a3635 OSX: make libtcc.dylib 2020-03-21 23:57:00 +08:00
wanjochan 4caa9a4cc7 relocate_syms() should using !(nostdlib) for parameter "int do_resolve" 2020-03-14 16:17:39 +08:00
matthias 704b602184 instruduce C2x _Static_assert syntaxe 2020-03-04 11:35:34 +01:00
matthias cb041f11f6 improve _Static_assert
Fix static assert to support literal string instead of just printing
the sring of the current token as it use to be

so we can now use _Static_assert(0, "0" "1") which will print
__FILE__ __LINE__ error: 01
2020-03-04 11:35:34 +01:00
Sizhe Zhao e050ae845e win32/build-tcc.bat: clean .o in win32/lib
commit ef42295fe8 intrduced 4 .o files to
win32/lib. But they (bcheck.o, bt-dll.o, bt-exe.o and bt-log.o) are not
removed by "win32/build-tcc.bat -clean". This commit should fix it.
2020-02-19 00:43:41 +01:00
Udo 923100c498 Better follow spacing style. (only changed formatting) 2020-02-18 21:11:49 +01:00
Udo 9272fac7c4 rework type coercion in ternary expr (a bit) and uncomment previously failing test. Be more explicit in diagnostic messages. 2020-02-17 18:25:43 +01:00
Udo a9e7fe19c7 extend test 03_struct for attr. __cleanup__ 2020-02-09 18:31:19 +01:00
Udo 89b3cf0b87 warn if attr. __cleanup__ is given in type decl. (Allow this as an extension?) 2020-02-09 18:21:59 +01:00
Udo c092f2ed61 Check if symbol given for attr. cleanup is actually a function 2020-02-07 23:23:31 +01:00
grischka 7e901299bf Rework expr_infix
- revert const-folding in gvtst() and put it back into
  expr_landor().  Although it did make sense, one reason
  not to do it is __builtin_constant_p() which may return
  true when it shouldn't because of nocode_wanted, see test.

- tccgen_init() can do init_prec(), also for tcc -E.

- for nostalgic reasons, keep the original expression parser
  functions in the source.

- Makefile: remove stale stuff
2020-01-22 21:57:19 +01:00
Michael Matz aeac24de98 Rework expr_landor
so that it also is called from the precedence parser.  This
is complicated by the fact that something needs to be done before
the second operand is parsed in a single pass compiler, so it
doesn't quite fit into expr_infix itself.  It turns out the smallest
code changes result when expr_landor remains separate.  But it can
be tidied a bit.
2020-01-20 05:48:48 +01:00
Michael Matz 23a8bac7b5 Use precedence parser for expressions
This is smaller and uses less stack depth per expression (eight function
calls from expr_or to get down to a unary).  It's a tiny bit faster
depending on how good the branch predictor is, on my machine a wash.
2020-01-20 05:48:48 +01:00
Michael Matz fdeeb62e28 Fix symbol versions with shared libs
ELF files that refer to shared libs containing sym-versions, but
don't refer to any dynamic symbols with symbol versions (should happen
only with very simple shared libs) would generate an empty .gnu.version_r
section.  Some dynamic linker contain bugs in that they don't check
the section size or DT_VERNEEDNUM (which are both zero for such files
we generate) before accessing the first entry, and then bail out with
a message like

./a.exe: error while loading shared libraries: ./a1.so: unsupported
 version 25960 of Verneed record

(where the "version number" actually comes from neighboring bytes
from different sections).

So, there's not much choice, we simply must not generate such section.
2020-01-20 05:31:09 +01:00
grischka d79e1dee8c backtrace: test with DLLs
- tests2/113_btdll.c: test handling multiple stabs infos
Also:
- libtcc.c: remove _ISOC99_SOURCE pre-defines.  It is causing
  strange warnings such as 'strdup not declared'

- i386/x86_64-gen.c cleanup bounds_pro/epilog.  This discards
  the extra code for main's argv.  If needed, __argv might be
  processed instead.

- tccgen.c:block(): reduce stackspace usage.  For example with
  code like "if (..) ... else if (..) ... else if (..)... "
  considerable numbers of nested block() calls may occur.

  Before that most stack space used when compiling itself was
  for libtcc.c:tcc_set_linker().

  Now it's rather this construct at tccpp.c:2765: in next_nomacro1():

  if (!((isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM))
        || c == '.'
        || ((c == '+' || c == '-')
        ...
2020-01-19 11:46:07 +01:00
Michael Matz a5f6e6189e Make 112_backtrace/bcheck_123 more robust
the strcat checker first checks dest for overlap, then src.
If the padding byte between b[] and the pad[] arrays happens to be zero
the dest check would have succeeded and the src test failed.  If that
padding byte would be zero the dest check would trigger first.
As we can't influence the padding byte (only the b[] and pad[] arrays)
it was random if the dest or src checks triggered.

This makes it reliably trigger the dest check first.
2020-01-18 03:06:44 +01:00
grischka 2b7cffac74 fixes for previous commit 2020-01-18 01:22:28 +01:00
gr ef42295fe8 tccrun.c: standalone backtraces with -bt[N] or -b
This makes it possible to get backtraces with executables
(including DLLs/SOs) like we had it already with -g -run.

Option -b includes -bt, and -bt includes -g.

- new file lib/bt-exe.c: used to link rt_printline and the
  exception handler from tccrun.c into executables/DLLs.

- new file lib/bt-log.c: provides a function that may be
  called from user code to print out a backtrace with a
  message (currently for i386/x86_64 only):

     int (*tcc_backtrace)(const char *fmt, ...);

  As an extra hack, if 'fmt' is prefixed like "^file.c^..."
  then the backtrace will skip calls from within 'file.c'.

- new file lib/bt-dll.c:  used on win32 to link the backtrace
  and bcheck functions with the main module at runtime

- bcheck.c: now uses the tcc_backtrace function from above

- tccgen.c: minor cleanups

- tccelf.c: stab sections get SHF_ALLOC for easy access.
  Also in relocate_section(): 64bit relocations for stabs
  in DLLs cannot work.  To find DLL addresses, the DLL base
  is added manually in tccrun.c via rc.prog_base instead.

- tccpe.c: there are some changes to allow merging sections,
  used to merge .finit_array into .data in the first place.

- tccpp.c: tcc -run now #defines __TCC_RUN__
  also: refactor a line in tal_realloc that was incompatible
  with bcheck

- tcctest.c: fixed a problem with r12 which tcc cannot preserve
  as well as gcc does.

- tests2/112_backtrace.c: test the feature and the bcheck test18
  that previously was in boundtest.c
2020-01-17 22:58:39 +01:00
herman ten brugge 4092b05068 Exclude ellipsis functions from bounds checking.
This fails on i386.
2020-01-16 09:40:33 +01:00
Christian Jullien c2976962da Merge branch 'mob' of git://repo.or.cz/tinycc into mypatch 2020-01-16 09:00:26 +01:00
Christian Jullien c7e3d5d7a3 Add _ISOCxx_SOURCE glibc compatible macros. 2020-01-16 08:58:43 +01:00
herman ten brugge 0d7c40b948 Call pop_local_syms before gfunc_epilog 2020-01-16 08:24:17 +01:00
Michael Matz 65f2fe390c Cleanup new bound checking code
remove quadratic loops by not using side tables; address-taken
can simply be a flag per local sym, and the lbounds section can
be filled after symbols go out of scope at which point we know
if the address was taken, so that there's no need to compress it
again after the funcion is done.
2020-01-16 01:19:59 +01:00
Michael Matz 4a70b2bc2d Fix handling of unevaluated subexpression of const
we were emitting error messages for something like
'static int i = 2 || 1/0', even though the exception would be in
the unevaluated part.  This doesn't destroy const-ness, so we must
accept it.  This requires splitting the nocode_wanted values a bit more,
so that nocode_wanted due to const_wanted can be differentiated from
nocode_wanted due to non-evaluation.
2020-01-15 23:32:40 +01:00
herman ten brugge 3877618785 Update bound checking code.
Add __attribute__((constructor)) to __bounds_init.
- remove tcc_add_bcheck from i386-link.c and x86_64-link.c
- add simplified tcc_add_bcheck to tccelf.c
- Update tccrun.c to call constructor/destructor.
Set dynsym sh_info to number of local symbols in tccelf.c
Reduce stack size when bounds checking is enabled.
Added variable TCC_LIBBCHECK for windows support.
Add signal stack to detect stack overflow.
Add all & parameters in lbound_section and remove them if not used.
Close fd in tcc_relocate in tccrun.c
Fix section type constructor/destructor in tccelf.c
Add check code in tests/boundtest.c for mem/str functions.
Remove -ba from documentation.
Add bounds check signal info in documentation.

bcheck.c:
- Fix initial_pool alignment.
. Fix printf statements.
. Add prototypes for all external interface functions.
- Add TCC_BOUNDS_WARN_POINTER_ADD environment variable.
. Add ctype and errno data.
- Fix alloca when multithreading is used.
- Add lock for __bound_checking and __bound_never_fatal.
- Catch pthread_create and use locks when called.
- Detect in loaded in shared lib and use locks when found
- Use spin locks instead of semaphore locks.
- Make spin locked code as small as possible.
- Fix mem/str functions checking.
- Fix overlap checking mem/str functions.
2020-01-15 08:53:19 +01:00
Christian Jullien 0d6801b130 C11, section 7.2: The macro static_assert expands to _Static_assert. This macro was missing on Windows 2020-01-14 07:41:58 +01:00
herman ten brugge 269042503e Fix sellinux pointer code in tccrun.
Free all memory on exit in __bound_exit.
2019-12-23 20:23:18 +01:00
Michael Matz f150f93854 Fix the get_asm_string fail on i386 in another way
the problem is that new debian GCC enabled -fPIC or -fPIE by
default, causing the mentioned compile error.
2019-12-17 17:54:54 +01:00
Giovanni Mascellani 43fb5a72e7
tcctest: explain why i386 is not tested 2019-12-17 12:36:02 +01:00
Michael Matz 1d4d74d6d0 Use explicit signed char in char_short_test
as 'char' is unsigned on some architectures, so the tests weren't
testing what they were supposed to.
2019-12-17 04:56:54 +01:00
Michael Matz c8ca64d28b Adjust return value promotion for some archs
this is a bit complicated: for i386 and x86-64 we really need to
extend return values ourself, as the common code now does.  For arm64
this at least preserves old behaviour.  For riscv64 we don't have to
extend ourself but can expect things to be extended up to int (this
matters for var-args tests, when the sign-extension to int64 needs to
happen explicitely).  As the extensions are useless, don't do them.

And for arm32 we actually can't express GCC behaviour: the callee side
expects the return value to be correctly extended to int32, but
remembers the original type.  In case the ultimate target type for the
call result is only int, no further extension is done.  But in case
the target type is e.g. int64 an extension happens, but not from int32
but from the original type.  We don't know the ultimate target type,
so we have to choose a type to put into vtop:
* original type (plus VT_MUSTCAST) - this looses when the ultimate
  target is int (GCC: no cast, TCC: a cast)
* int (without MUSTCAST) - this looses when the ultimate target is
  int64 (GCC: cast from original type, TCC: cast from int)
This difference can only be seen with undefined sources, like the
testcases, so it doesn't seem worthwhile to try an make it work, just
disable the test on arm and choose the second variant as that generates
less code.
2019-12-17 01:46:06 +01:00
Michael Matz 2d17e5a6c4 riscv64: adjust for cast changes
gfunc_call plays with types and needs to retain the unsignedness
now (this was a latent problem before commit 35475b5).
2019-12-17 00:48:57 +01:00
grischka d30d68d738 #pragma comment(option, "file.c")
This allows adding files or libraries from
   #pragma comment(option, ...)

Also, {f}/file.c will be expanded with the directory of
the current source, that is the file that has the #pragma
2019-12-16 22:48:31 +01:00
grischka a64353ce71 tccgen.c: generic char/short promotion for function return values 2019-12-16 21:58:32 +01:00
grischka 89372dc482 update gen_cast 2019-12-16 21:37:44 +01:00
grischka 35475b5423 remove VT_LVAL_BYTE etc.
For some reason there was no point for that anymore.
2019-12-16 20:59:23 +01:00
grischka 5914f4d57d tccgen.c: cleanup reg classes
wrap some copy&paste code into functions
2019-12-16 20:44:48 +01:00
grischka ff3b5ee91c -bench fix
Put total_lines etc. into TCCState.  Also, initialize
the predefined compiler types for the preprocessor too.
tccpe.c: fix BaseOfCode if .init section present (with tcc -b)
2019-12-16 20:17:10 +01:00
Michael Matz b476a5f478 Readd lost error on local static function decls
see testcase: block scope decls for functions can't use static
(allowed is only extern or none).  This got lost in commit 85690480.
2019-12-16 07:00:26 +01:00
Michael Matz 6cb68c3a17 arm64: fix some casts
in the new common backtrace/context code.
2019-12-15 00:05:30 +01:00
Michael Matz 2fb79a6326 Fix some races
protect some more accesses to global data with the semaphore.
(And for the testcase: don't just write into global data, use local
copies; it's not important for speed here).
2019-12-14 23:58:45 +01:00
grischka 65f74a4df0 tccrun.c: better stab debug support
* a major revision of the rt_printline() feature in
  tccrun.c to report file:linenumber more correctly.

* minor changes to the stab info produced by the
  compiler in tccgen.c

However stab addresses are limited to 32 bits.  I added
a work around:

    if (sizeof pc == 8)
        pc |= wanted_pc & 0xffffffff00000000ULL;

However GDB has problems with that too.
2019-12-14 17:48:50 +01:00
grischka 56db092ab7 bcheck cleanup
- revert Makefiles to state before last bcheck additions
  Instead, just load bcheck.o explicitly if that is
  what is wanted.

- move tcc_add_bcheck() to the <target>-link.c files and
  remove revently added arguments.  This function is to
  support tccelf.c with linking, not for tccgen.c to
  support compilation.

- remove -ba option:  It said:
  "-ba  Enable better address checking with bounds checker"
  Okay, if it is better then to have it is not an option.

- remove va_copy. It is C99 and we try to stay C89 in tinycc
  when possible.  For example, MS compilers do not have va_copy.

- win64: revert any 'fixes' to alloca
  It was correct as it was before, except for bound_checking
  where it was not implemented.  This should now work too.

- remove parasitic filename:linenum features
  Such feature is already present with rt_printline in
  tccrun.c.  If it doesn't work it can be fixed.

- revert changes to gen_bounded_ptr_add()
  gen_bounded_ptr_add() was working as it should before
  (mostly).  For the sake of simplicity I switched it to
  CDECL.  Anyway, FASTCALL means SLOWCALL with tinycc.

In exchange you get one addition which is required for
bounds_cnecking function arguments.  The important thing
is to check them *BEFORE* they are loaded into registers.
New function gbound_args() does that.

In any case, code instrumentation with the bounds-check
functions as such now seems to work flawlessly again,
which means when they are inserted as NOPs, any code that
tcc can compile, seems to behave just the same as without
them.

What these functions then do when fully enabled, is a
differnt story.  I did not touch this.
2019-12-14 13:26:18 +01:00
herman ten brugge a86f47889c Fix debug info 2019-12-13 15:07:02 +01:00
herman ten brugge 87639aae7c Add linenumber filename support for bounds checking. 2019-12-13 13:45:09 +01:00
herman ten brugge 56e70bfa31 Fix bounds checking new functions.
There was a problem with strncpy and strncmp.
Made bound_ptr_add and bound_ptr_indir a little bit faster.
Fix statistic counter types. Change long into long long.
2019-12-13 10:02:20 +01:00
herman ten brugge 39c0ff311d Add new bounds checking functions.
The following functions are now also bounds checked:
memcmp, strncpy, strcmp, strncmp, strcat, strchr, strdup.

Add statistics code for bounds checking functions.
The statistics can be printed by settings environment variable
"TCC_BOUNDS_PRINT_STATISTIC".

Enabled more tests in test/Makefile.
2019-12-12 20:49:35 +01:00
herman ten brugge 35512be1ee Fix typo with -ba option 2019-12-12 14:21:07 +01:00
herman ten brugge 75145ddc1a Add -ba option for bounds_checking 2019-12-12 13:29:45 +01:00
herman ten brugge 4a2e33d160 Update bounds checking.
The bounds checking code has now enabled gen_bounded_ptr_add tests.
This makes the code slower but finds more errors.
I had to correct some things in tcc to make it work.
- Fixed off by one in lib/bcheck.c
- Corrected tccelf.c sym_versions.
- Disabled USE_TAL when using bounds checking.
- Fixed cstr_printf va_start.
- Fixed tests/tests2/46_grep.c off by one error.
- Updated gen_bounded_ptr_add in x86_64-gen.c
- Fixed x86_64-link.c pointer diff.
For gen_vla_alloc now always use alloca call when bounds checking.
Added line/filename in %rax before bound calls to find location of error.
2019-12-12 12:56:06 +01:00
Michael Matz ce4eafb34f Include some headers in new multi-thread test
for usleep and gettimeofday.
2019-12-12 03:31:21 +01:00
Michael Matz 11fc58fa13 Fix parallel make targets
my last patch here fixed a missing dependency, but in the wrong
way.  It would build some object files twice, which could race.
The lib/all target already builds both libtcc{,b}1.a libs, so
a simple dependency is enough.
2019-12-12 02:00:13 +01:00
Michael Matz 90e09ed75f Disable thumb code generation on tcctest.gcc
this breaks getting the alignment of functions via bit masking
which we assume to work in one test.
2019-12-12 01:52:50 +01:00
Michael Matz 83f822d0cd Also parse -Dfoo in libtcc_test_mt
otherwise the -DTCC_ARM_VFP doesn't get through.
2019-12-12 01:39:58 +01:00
Michael Matz 8b23662d53 Fix libtcc_test_mt with lib64
we need to pass NATIVE_DEFINES, and we need to actually parse
and pass them into the state.
2019-12-11 17:57:43 +01:00
herman ten brugge b3893baa45 Fix3 alloca on x86_64 windows 2019-12-11 14:26:27 +01:00
herman ten brugge b45a8d456d Fix2 alloca on x86_64 windows 2019-12-11 14:22:01 +01:00
herman ten brugge 426d32af23 Fix alloca on x86_64 windows 2019-12-11 14:06:15 +01:00
herman ten brugge a0bc149b0c Fix bounds checking after concurrently commit 2019-12-11 12:07:48 +01:00
grischka 72729d8e36 allow libtcc states to be used concurrently
This allows creation of TCCStates and operation with API
calls independently from each other, even from threads.

Frontend (option parsing/libtcc.c) and backend (linker/tccelf.c)
now depend only on the TCCState (s1) argument.

Compilation per se (tccpp.c, tccgen.c) is still using
globals for convenience.  There is only one entry point
to this section which is tcc_compile() which is protected
by a semaphore.

There are some hacks involved to avoid too many changes,
as well as some changes in order to avoid too many hacks ;)

The test libtcc_test_mt.c shows the feature.  Except this
new file the patch adds 87 lines overall.
2019-12-11 02:36:19 +01:00
grischka 6082dd62bb tcc -vv ... : show objects loaded from archives 2019-12-10 20:55:57 +01:00
grischka df349ddc43 versym cleanup
get rid of some globals, in the first place.  Also, for the
PE target, ifdef out ELF executable creation.
2019-12-10 20:41:35 +01:00
herman ten brugge 4d297d354c Add bound checking print heap 2019-12-10 19:47:33 +01:00
Michael Matz fb22e0c12d Fix type/r/r2 confusion differently
on i386 111_conversion.c breaks when save_reg_upstack isn't careful
about r2 and type mismatches.  The bcheck patches fixed this by
enlarging the stack slot beyond the natural type, this variant simply
avoids saving the second register is the type indicates that it isn't
needed.

Adds also a comment how this should ideally work, namely that type
and r/r2 entries in the vstack are consistent.  In the 111_conversion
testcase it's specifically gen_cast via gen_cvt_ftoi that breaks
this, but there more general code broken as well, so that would deserve
a careful fixup based on some additional asserts.
2019-12-10 17:49:04 +01:00
Michael Matz ac2a61d1b3 Add dependency on libtccb1.a
otherwise parallel makes might throw errors.
2019-12-10 17:48:23 +01:00
Michael Matz 353db307ed Fix compile warning with cross compilers
'make i386-tcc' on a x86-64 host gave a warning about the
unconditionally declared static tcc_add_bcheck function.
2019-12-10 16:56:10 +01:00
herman ten brugge 88dd577302 Disable bounds_check1_test on arm 2019-12-10 09:39:45 +01:00
herman ten brugge 17850a51f5 Fix bounds checking on targets with no bcheck.c 2019-12-10 08:44:44 +01:00
herman ten brugge 4461f38a9e Fix bounds checking for linux/windows 2019-12-10 08:07:25 +01:00
Michael Matz 474f95dda8 Fix setting of options
now that the type of boolean options is uchar set_flag() needs
an accompanying change.
2019-12-05 17:04:04 +01:00
Michael Matz 1dc92f8ff8 Fix indentation and run_test type
tcc_state.run_test is used as counter, not flag, so int is appropriate.
Also fix indentation garbled by last patch.
2019-12-02 19:20:56 +01:00
Sergey Sushilin 4873f6fada use uchar instead of int to save memory 2019-12-01 23:22:57 +03:00
Sergey Sushilin 14fc6b6dcb use size_t instead of int when work with strings 2019-12-01 22:45:42 +03:00
herman ten brugge df72b8d487 Add windows constructor/destructor support 2019-11-27 18:29:12 +01:00
Michael Matz 4e9ce59fe8 Workaround false positive warning 2019-11-27 17:35:24 +01:00
Michael Matz 8a93ce106a elf: rewrite version support
so it isn't quadratic in number of symbols.  It's still quadratic
in number of lib/version combinations (at library load time the
sym versions are internalized), but that's much less a problem as
in practice only glibc uses sym versioning.
2019-11-25 21:06:07 +01:00
Christian Jullien 25781e4552 Fix float conversion in arm64 backend 2019-11-08 07:55:05 +01:00
Jookia f420259ee5 arm: Don't override syscall implementation 2019-11-06 01:01:56 +11:00
herman ten brugge 96f1fb1da0 rename testcase 2019-10-29 12:02:58 +01:00
herman ten brugge fadfc118e5 Fix sse calling bug 2019-10-29 07:19:42 +01:00
herman ten brugge 800c3a5e0b Add constructor/destructor support 2019-10-29 07:02:58 +01:00
herman ten brugge c4c5ea4381 remove wine 2019-10-25 07:40:37 +02:00
herman ten brugge b84ab23011 Add wine support 2019-10-24 22:10:04 +02:00
herman ten brugge 588dd6827a Fix elf version info 2019-10-24 20:47:02 +02:00
Pursuer2 a7b37f9c63 Fix bug in gen_cvt_ftoi1. Add test 107_stack_safe for this fix.
(Thanks to the support of herman ten brugge)
2019-10-24 00:57:59 +08:00
herman ten brugge 749dd15ee8 Fix testcase for elf version 2019-10-23 13:14:41 +02:00
herman ten brugge 66a14a1e33 Add testcase for elf_version 2019-10-22 20:45:03 +02:00
herman ten brugge b073a9c103 Add testcase for elf_version 2019-10-22 20:43:30 +02:00
herman ten brugge 7268fe7239 Add elf version support 2019-10-22 16:55:20 +02:00
Luc Everse 491773ac58
Add error_func and error_opaque getters to libtcc 2019-10-14 09:36:14 +02:00
Jan Boon 944c4003bd Add function to list all symbols, for purpose of linking separate in-memory compilations 2019-09-16 15:24:16 +08:00
Øyvind A. Holm c6635504fe README: Fix typo and remove trailing whitespace 2019-09-14 15:37:20 +02:00
Sergey Sushilin 53a1521c2e fix _Noreturn keyword 2019-09-08 18:35:15 +03:00
grischka 7b8799e5ff tccgen.c: local extern decls: copy s->ref for VT_PTR too
This fixes the issue

    int main() { extern char *x; }
    void main1() { extern char *x; }
    t2.c:5: error: incompatible types for redefinition of 'x'

(reported by Giovanni Mascellani 2019/07/16)
2019-09-08 16:59:17 +02:00
Sergey Sushilin 9298555eb6 add C11 stdalign.h header 2019-09-08 15:04:06 +03:00
Siddhesh Poyarekar 7d4a71fc8b arm64: Increase page size
Fedora, RHEL and Centos have a default page size of 64K for arm64, so
bump up the page size so that ELF sections of the generated inary are
correctly aligned for 64K pages too.
2019-09-03 12:39:05 +05:30
Michael Matz 9264f06efe Improve ?: expansion a little
there's no need to prematurely convert the condition into registers
before emitting the test.
2019-09-01 23:13:21 +02:00
Michael Matz 91e297acd3 riscv: Optimize compares
don't convert to 1/0 prematurely, we can save enough info
in the VT_CMP metadata to be usable for the gtst branch expansion.
2019-09-01 23:13:21 +02:00
Michael Matz 48ba22c744 riscv: Replace RR insn emitter with specific one
instead of using o() directly.  Makes the code a little easier
to read.
2019-09-01 23:13:21 +02:00
Michael Matz d5bb407cc4 riscv: Add special cases for const operands
RISC-V supports small immediates for some operations, let's
use them.
2019-09-01 23:13:21 +02:00
Michael Matz f8d80464a9 riscv: factor load/store code
split out common code and tidy result.
2019-09-01 23:13:21 +02:00
Michael Matz 83cf5bf17f riscv: TLC of param passing
factor and cleanup the param passing code somewhat.
2019-09-01 23:13:21 +02:00
Michael Matz c505074a9f riscv: rewrite parameter passing
this fixes the ret_mixed_test of abitest.c, now everything of the
testsuite works.

The generic code for returns is good enough for our use, except in
the specific case of a mixed int/float structures returned in registers,
so instead of duplicating the whole generic gfunc_return function, add
another modus for gfunc_sret: returning -1 makes the actual register
transfer by a new backend function.
2019-09-01 23:13:21 +02:00
Michael Matz 9b0efa9346 riscv: Make PLT reloc be AUTO_GOT
relocs against defined symbols are replaced by relative
relocs, when a GOT slot is created.  But code relocs (usually
calls via PLT) use the plt_offset member of attr, not the got_offset
member, so the "huh" warning was triggered in the case of calls to
static functions (the code still worked).

So, for now just use the AUTO_GOT_PLT mechanism.  We could also
emit a non-PLT reloc in the backend for calls to VT_STATIC functions
(like the x86-64 backend does) and do the same as for x86-64 in
build_got_entries (which transforms PLT32 into PC32 relocs, riscv
would transform CALL_PLT into CALL relocs).  Maybe later.
2019-09-01 23:13:21 +02:00
Michael Matz 0cb6e3fff8 riscv: Fix mixed2 and mixed3 abi tests
this was caused by a simple bug, not by the current inability
to pass a {float,int} struct per psABI.  So now only ret_mixed_test
is still broken.
2019-09-01 23:13:21 +02:00
Michael Matz 98f1b83ffe riscv: Start fixing float struct passing/returnig
this fixes ret_2float_test, ret_2double_test and
ret_8plus2double_test of abitest.c.  The common gfunc_return
actually works for these cases, so let's use that for now.

The ret_mixed_test (as well as mixed2 and mixed3) are left
broken, and tccgen.c:gfunc_return can't be used for that as is,
so I'll leave the gfunc_return implementation in riscv64-gen.c for
now, I'll have to think about this some more.
2019-09-01 23:13:20 +02:00
Michael Matz 98dc4c123d riscv: Fix stdarg_many_test
if named params are passed on stack, the va_arg area begins after
that, not at sp+0.  Fixes abitest:stdarg_many_test.
2019-09-01 23:13:20 +02:00
Michael Matz e9c2a1996a riscv: Fix tcctest.c
this is it!  With this tcctest.c works, as well as compiling
TCC with itself.  abitest.c doesn't yet work due to known
problems, all the rest does.  There are still warnings during
linking.
2019-09-01 23:13:20 +02:00
Michael Matz 509f561823 riscv: fix more sign/zero-extension problems
see the testcase.  For the signed case this problably does
the wrong thing, and it should break other archs.  Rework once
there are testcases for this.
2019-09-01 23:13:20 +02:00
Michael Matz 1ada32900b riscv: Fix ftoi and ftof(long double->float)
float to int must be truncations, not normal rounding.
And ftof was typoed to select the wrong conversion function.

This fixes tcctest.c completely.  (make -C tests test1)
2019-09-01 23:13:20 +02:00
Michael Matz 06184aec53 riscv: fix relocs for global syms
loads and stores to global symbols need to go via the
GOT (at least for weaks), otherwise -run doesn't work.
Ideally we'd generate GOT relocs (and loads) always and replace
them with PCREL relocs and adds during linking.
2019-09-01 23:13:20 +02:00
Michael Matz 69c77d1597 riscv: Fix unsigned 32bit loads
the invariant for the risc-v codegen is, that 64bit regs
generally contain the sign-extension of a 32bit value.
This wasn't heeded by loads of 32bit values from memory, which
used lwu and ultimately caused a miscompilation in string_test
of tcctest.c.

Now most of tcctest.c works (not with -run, but with linking
a real executable), except some ftoi/ftof conversions.
2019-09-01 23:13:20 +02:00
Michael Matz 2668eda595 riscv: Implement long double support
for the implementation of operations we can reuse the ones
from lib/lib-arm64.c, risc-v long double is also float128.
Also implement ggoto, and PDIV, and use t0 in load/store as
temporary register if necessary, not one given by get_reg
(the latter can destroy assignments of long double parameters
in function calls that are already set up).

This let's us compile tcc.c and tcctest.c, though both
don't yet work.
2019-09-01 23:13:20 +02:00
Michael Matz 2616c6b230 riscv: Fix 73_arm.c
some constants were loaded wrong (e.g. 0xffffabcdU), and
risc-v needs to do explicit zero-extensions for widening from
32bit (not sign-extensions like the other 64bit targets).

This makes the whole tests2.all testsuite work.

Parameter passing is still not psABI-compliant, but internally
consistent.  (e.g. structs of two floats/doubles are passed
in integer registers, but should sit in float regs).
2019-09-01 23:13:20 +02:00
Michael Matz 982de78e8d riscv: implement stdarg functions
this also fixes passing of params > 16 bytes.  In riscv
they aren't passed by value on stack, but via reference (and
because callees are allowed to modify by-ref params the caller must
allocate an own copy per call).

This fixes the stdarg parts of 73_arm.c.
2019-09-01 23:13:20 +02:00
Michael Matz f44df9d85b riscv: some work on large function arguments
like long double (16 bytes) and structs.  Not completely
correct, but 73_arm64 somewhat works now (when the stdarg part
is disabled), though with some errors.  What's definitely incorrect
is arguments of a mixed int/float struct.  I'm using VT_LDOUBLE
(which conveniently has to be placed in a int-reg-pair) to load/store
structure arguments of size > 8 and <= 16, and that can lead to
overreads.
2019-09-01 23:13:20 +02:00
Michael Matz ddb0c2de92 riscv: support large stack and far jumps
for 101_cleanup we need 256kb stack (with the associated problem
of needing a larger prologue/epilogue) as well as jumps out of
range for the 21bit offsets (exactly for second part of the prologue).
2019-09-01 23:13:19 +02:00
Michael Matz b69c2ea2cf riscv: fix 90_struct-init
indirect calls were broken.
2019-09-01 23:13:19 +02:00
Michael Matz 31ecaa7c28 riscv: GOT loads, signed remainder, ELF flags
* support loading sym addresses from GOT: important for weak syms,
  fixes 104_inline.  This is still incomplete, it only works
  for taking the sym address, not for directly loading/storing into
  such symbols (i.e. not for VT_LVAL)
* another op: '%'
* ELF flags: add EF_RISCV_FLOAT_ABI_DOUBLE, which is our ABI.
2019-09-01 23:13:19 +02:00
Michael Matz b0329ac081 riscv: predefine more macros
RISC-V uses some more control macros for features (e.g. used
int <setjmp.h> to declare the jumpbuf contents).
2019-09-01 23:13:19 +02:00
Michael Matz 5390a729d9 riscv: Implement VLA stuff
makes 78_vla_label and 79_vla_continue work.
2019-09-01 23:13:19 +02:00
Michael Matz 9164594d1f riscv: load 64bit constants, and 32bit shifts
fixes 95_bitfields.  loading 64bit constants is suboptimal
right now.  int32_t shifts really need to use the W form,
otherwise 'x << 24 >> 24' doesn't extract the low 8 bits.
2019-09-01 23:13:19 +02:00
Michael Matz 215bc1aab4 riscv: Add sar, shr insn
fixes 92_enum_bitfield.
2019-09-01 23:13:19 +02:00
Michael Matz f64d460d29 riscv: fix 72_long_long_constant
32bit signed constants larger than 0x7ffff800 were handled wrongly.
2019-09-01 23:13:19 +02:00
Michael Matz 5fcb87138d riscv: Handle more relocs
those happen on SUSE systems.
2019-09-01 23:13:19 +02:00
Michael Matz 9309585dbe riscv: some long double support
long double on risc-v is 128bit, but there are no registers
for that type (without the Q ISA extension).  They are passed
like two 64bit integers values (with an exception for varargs,
where it's an aligned register pair).  This all requires some
hacks in generic code as otherwise RC_FLOAT regs are tried for
holding values of long double type, but we need a RC_INT register
pair.  This really could all use some cleanup for all archs.

This doesn't implement any conversions of operations for long
double, but it's enough to get 70_floating_point_literals working.
2019-09-01 23:13:19 +02:00
Michael Matz 9c1b17407f riscv: Make 32_leds work
* more ops: umod and udiv
* large immediates: suboptimal code, e.g. when loading
  0xffffffffU (which is what a cast from long to int does).

tests2 work up to 67_macro_concat.
2019-09-01 23:13:19 +02:00
Michael Matz 02c8e69a07 riscv: fp parameters
makes 23_type_coercion work.  (clean up to 31_args)
2019-09-01 23:13:19 +02:00
Michael Matz 0d3db83f16 riscv: float ops
* compares
* add/sub/mul/div
* float-float converts

makes 22_floating_point work.
2019-09-01 23:13:19 +02:00
Michael Matz 9214087259 riscv: More insns, operands and arg slots
* load/store of FP ops
* load/store from symbols, VT_LLOCAL, some with large addend
* load of VT_JMP result
* calls with many args (stack slots)
* calls with FP args
* more operations: and/or/xor/div
2019-09-01 23:13:19 +02:00
Michael Matz b1c7520886 riscv: more insns
* register indirect loads and stores
* load of local addresses
* indirect calls (uses ra as temporary reg if necessary)
* operations *, -, <<
* gen_cvt_sxtw: is not needed in most cases, let's see

tests2 runs until (incl) 09_do_while.
2019-09-01 23:13:18 +02:00
Michael Matz 16edda58b7 riscv: Add more ops and fixes
* implement compares, gtst and gsym/gjmp and add
* implement stores (simple cases)
* fix arg passing with more than one register arg, fix
  loads to not always use 8byte loads
* add some predefined macros: __riscv, __riscv_xlen,
  __SIZEOF_POINTER__ (needed by glibc header)

The first 5 tests of tests2 run now.
2019-09-01 23:13:08 +02:00
Michael Matz 55040845f3 riscv: Handle JUMP_SLOT reloc
so that -run works.
2019-08-14 18:22:21 +02:00
Michael Matz ef7c1a4e96 riscv: Implement some loads and calls
so that a hello world works.
2019-08-14 18:22:18 +02:00
Michael Matz 35d7b5934e riscv: hacky prolog, epilog and return
this now allows to compile a simple working example:

  int main(void) { return 0; }
2019-08-14 18:22:14 +02:00
Michael Matz 1353ccd9e2 riscv: Handle some usual relocs
this is enough to let me link a tcctest.c compiled by GCC
using some current debian sid riscv64 system.  It needs
linking against libgcc.a for various floating point TFmode
routines.  The result runs.
2019-08-14 18:19:00 +02:00
Michael Matz 0676d5bc23 riscv64: Add skeleton target 2019-08-14 18:18:46 +02:00
Michael Matz 9e429dbef0 Fix invalid size with GNU designated initializers
the uninitialized cumofs was leading to random sizes for
the memset when initializing local structures, potentially
leading to segfaults from it.  Only a problem with GNU
designated initializers, which we didn't test very well.
See testcase.
2019-07-21 21:14:58 +02:00
grischka ce1ef5b8fc some smaller fixes
- libtcc.c/tccpp.c: fix -U option for multiple input files
- libtcc: remove decl of tcc_add_crt() for PE
- tcc.h: define __i386__ and __x86_64__ for msvc
- tcc.h: undef __attribute__ for __TINYC__ on gnu/linux platforms
- tccelf.c: disable prepare_dynamic_rel unless x86/x64
- tccpe.c: construct rather than predefine PE section flags
- tccpp.c: (alt.) fix access of dead stack variable after error/longjmp
- x86_64-gen.c: fix func_alloca chain for nocode_wanted
- tccpp.c/tccgen.c: improve file:line info for inline functions
- winapi/winnt.h: correct position for DECLSPEC_ALIGN attribute
- win32/lib/crt: simplify top exception handler (needed for signal)
- arm64-gen.c: remove dprintf left from VT_CMP commit
- tccgen.c: limit binary scan with gcase to > 8 (= smaller code)
- tccgen.c: call save_regs(4) in gen_opl for cmp-ops (see test in tcctest.c)
2019-07-14 22:46:19 +02:00
Christian Jullien 4bb5bc4401 Add Windows WSAPool declaration, associated struct and constants. It allows 100% poll compatible POSIX API on Windows. 2019-07-09 18:02:59 +02:00
YX Hao 756e766295 win: ignore dllimport/dllexport for typedef with warning instead of error
Keep the same as gcc and clang.
The usage exists in MinGW-w64 headers.
2019-07-02 18:19:24 +08:00
Christian Jullien a4997bf3d9 Inverse last intr test so that function always returns. This prevents warning as found with gcc 8.3 and it matches other function styles doing the same in ARM generator. 2019-06-26 05:43:47 +02:00
Christian Jullien a9340dd325 Applying grischka proposed patch fixes error reported on 93_integer_promotion test as found on Debian buster / gcc 8.3 for ARM plateform 2019-06-26 05:26:20 +02:00
Avi Halachmi (:avih) a7eef33859 configure: conftest win32: don't translate LF to CRLF
This removes a spurious \r at $gcc_{major,minor} in configure on cygwin.

Details:

The EOL output of conftest.exe for windows was \r\n . Now it's only \n .
The output of conftest is used with sh command substitutions which trim
trailing newlines, but not all windows shells consider \r\n as newline.

E.g. msys2 and busybox (for windows) were designed for tight integration
with windows apps and their shells do trim \r\n, but cygwin sh is closer
to POSIX and trims only \n - leaving \r at the string.
2019-06-25 16:44:43 +03:00
Avi Halachmi (:avih) 84779b2b84 configure: allow cc tests even if cross compiling, test i386/x86-64
Adds a tool `ppif` at configure which can test preprocessor conditions
even when $cc is a cross compiler to any foreign platform.

Currently used only to identify i386 or x86_64 (including when cross
compiling) as a mini-demonstration.

Hopefully will be used in the future to test more compiler features
and/or replace uname-related tests with more accurate results.
2019-06-25 16:44:43 +03:00
grischka 3d78918e63 introduce scopes for VLA & attribute cleanup 2019-06-24 11:40:01 +02:00
grischka 8227db3a23 jump optimizations
This unifies VT_CMP with VT_JMP(i) by using mostly VT_CMP
with both a positive and a negative jump target list.

Such we can delay putting the non-inverted or inverted jump
until we can see which one is nore suitable (in most cases).

example:
    if (a && b || c && d)
        e = 0;

before this patch:
   a:	8b 45 fc             	mov    0xfffffffc(%ebp),%eax
   d:	83 f8 00             	cmp    $0x0,%eax
  10:	0f 84 11 00 00 00    	je     27 <main+0x27>
  16:	8b 45 f8             	mov    0xfffffff8(%ebp),%eax
  19:	83 f8 00             	cmp    $0x0,%eax
  1c:	0f 84 05 00 00 00    	je     27 <main+0x27>
  22:	e9 22 00 00 00       	jmp    49 <main+0x49>
  27:	8b 45 f4             	mov    0xfffffff4(%ebp),%eax
  2a:	83 f8 00             	cmp    $0x0,%eax
  2d:	0f 84 11 00 00 00    	je     44 <main+0x44>
  33:	8b 45 f0             	mov    0xfffffff0(%ebp),%eax
  36:	83 f8 00             	cmp    $0x0,%eax
  39:	0f 84 05 00 00 00    	je     44 <main+0x44>
  3f:	e9 05 00 00 00       	jmp    49 <main+0x49>
  44:	e9 08 00 00 00       	jmp    51 <main+0x51>
  49:	b8 00 00 00 00       	mov    $0x0,%eax
  4e:	89 45 ec             	mov    %eax,0xffffffec(%ebp)
  51:   ...

with this patch:
   a:	8b 45 fc             	mov    0xfffffffc(%ebp),%eax
   d:	83 f8 00             	cmp    $0x0,%eax
  10:	0f 84 0c 00 00 00    	je     22 <main+0x22>
  16:	8b 45 f8             	mov    0xfffffff8(%ebp),%eax
  19:	83 f8 00             	cmp    $0x0,%eax
  1c:	0f 85 18 00 00 00    	jne    3a <main+0x3a>
  22:	8b 45 f4             	mov    0xfffffff4(%ebp),%eax
  25:	83 f8 00             	cmp    $0x0,%eax
  28:	0f 84 14 00 00 00    	je     42 <main+0x42>
  2e:	8b 45 f0             	mov    0xfffffff0(%ebp),%eax
  31:	83 f8 00             	cmp    $0x0,%eax
  34:	0f 84 08 00 00 00    	je     42 <main+0x42>
  3a:	b8 00 00 00 00       	mov    $0x0,%eax
  3f:	89 45 ec             	mov    %eax,0xffffffec(%ebp)
  42:   ...
2019-06-24 11:40:01 +02:00
grischka 1b57560502 nocode, noreturn
A more automatic approach to code suppression (aka. nocode_wanted)

The simple rules are:
- Clear 'nocode_wanted' at (im/explicit) label IF it was used
- Set 'nocode_wanted' after unconditional jumps

Also in order to test this then I did add the "function might
return no value" warning, and then to make that work again I
did add the __attribute__((noreturn)).

Also moved the look ahead label check into the type parser
to gain a little speed.
2019-06-24 11:40:01 +02:00
grischka 8569048031 work on local extern declarations
Example:
    int a = 1;
    void f(void)
    {
        int a = 2;
        {
             extern int a; // = 1 !!
             ....

To get this (more) correctly there is a new function to copy
syms between local to global stacks.

Also, this patch changes the meaning of VT_EXTERN back
to the simpler and IMO more useful notion of
    DECLARED but not (yet) DEFINED.
and that for both variables and functions.  That is, VT_EXTERN
in tcc doesn't have to do with the keyword 'extern' necessarily.

Also this patch does allow
    int x[];
as alias for
    extern int x[];
(as do gcc and msvc)
2019-06-24 11:38:32 +02:00
Pascal Cuoq cbbba01b46 reject invalid arrays in post_type() 2019-06-24 10:28:44 +02:00
Michael Matz 942b73bbbb Try fixing asm_dot_test on Windows
its GAS lacks .pushsection/.popsection and .previous, so
we must manually switch back to .text in the snippets on
that platform.
2019-06-24 05:18:08 +02:00
Avi Halachmi (:avih) 6599483304 test 104: fix out-of-tree build+test
This was broken, and now works again:
mkdir build && cd build && ../configure && make && make test
2019-06-22 09:47:57 +03:00
Michael Matz dd60b20c6e Define __dso_handle in libtcc1.a
new glibc really can't avoid it anymore, so let's provide it.
I've tried doing it only on systems that possibly are glibc
based.  (For others it would be harmless as it simply wouldn't
be picked up from libtcc1.a)
2019-06-22 01:38:43 +02:00
Michael Matz 7894f39e65 Make VT_STRUCT_MASK unsigned
avoids a (overly anal, but correct) undefined behaviour warning
about shifting 4095 as int by 20.
2019-06-22 00:42:24 +02:00
grischka e6d8f9a8bb test 104: adjust to (unwritten) tests2 suite conventions
... which IMO are:

1) files don't need a _test suffix because all files in
   the directory are tests ;)

2) we test the BEHAVIOR of the program, rather than its
   binary bit contents.

Ok, but nobody said a test can't use two files ;)

(where the 104+_ construct is meant to prevent the file
from being picked up by the makefile as a test on its own).
2019-06-22 00:26:31 +02:00
Avi Halachmi (:avih) 5dfcc7506c test 104: simplify, ensure sort locale, parametric tcc
Previously test 104 used a combination of *nix tools and system() calls
to emulate a `sh` script, which required split code paths for windows
due to different shell and different absolute path representation.

Also, it used a hardcoded tcc binary path, didn't set locale for sort.

Now the tools are used from a `sh` script which the program generates
and invokes, tmp files are at CWD and no conversion is required, tcc
path is taken from Makefile (exported), and `sort` uses LC_ALL=C.
2019-06-21 22:36:09 +03:00
Pascal Cuoq 944fe7036c x86-64 codegen: avoid allocating VLA of size 0 2019-06-19 20:43:10 +02:00
Christian Jullien d39c49db2d Remove empty conditional _WIN32 code 2019-06-18 15:05:46 +02:00
Christian Jullien d052f609fe Remove \r in win32/include/uchar.h 2019-06-18 14:39:54 +02:00
Christian Jullien 21841cb622 Add win32/include/uchar.h which is a C11 standard header. It makes Windows standalone port more C11 compliant 2019-06-18 14:38:16 +02:00
Christian Jullien 78ee3eb7c7 Add Windows support for tests of inline functions - test 104 2019-06-18 14:29:58 +02:00
Michael Matz cb73be5346 Fix last commit
it wasn't complete.
2019-06-17 20:52:09 +02:00
Michael Matz c3f0937012 Don't emit unreferenced static inlines
there's no need to emit unreferenced static function, even
if they are forced.
2019-06-17 19:36:59 +02:00
Michael Matz 3980e4a5b9 Add testcase for 69a46b0
that fixed mingw but also fixed the problem for which the testcase
is now added.
2019-06-17 19:08:08 +02:00
Michael Matz fe23a14ebb Deal with more tentative definitions
see testcase.
2019-06-17 18:52:49 +02:00
Michael Matz 69a46b0c53 Make mingw work again
my last inline changes caused parameter names to be overwritten
always (as VT_EXTERN now doesn't mark the current def anymore),
leading to a compile error when including windows.h.  Rework this.

Also silence a warning that currently happens for mingw, which is
written with gnu-inline behaviour in mind.  Our work-arounds
of using "static inline" actually create invalid C (which we warn
about).  Until we implement this properly, just silence the warning.
2019-06-17 18:28:56 +02:00
Michael Matz cb8bbf1ab9 TLC for C99 inline implementation
there's no need for two new flags in type.t .  We just can't use
VT_EXTERN as marker if functions are defined or not (like we can
for objects), and then can simply implement the rules of C99/C11
by not overwriting VT_STATIC/VT_EXTERN at all but rather only
look at them.  A function already on the inline list can be
forced by removing the VT_INLINE flag, and then linkage
follows from some combination of VT_STATIC, VT_EXTERN and VT_INLINE.
2019-06-17 03:34:03 +02:00
Michael Matz 4dfc27b101 Stricter C99 inline tests
these three functions are external definitions, and so need
to be emitted even without any references.
2019-06-17 03:33:52 +02:00
Michael Matz 7ed2d15345 Revert "Fix relocs of unwanted sections"
This reverts commit fef838db2d,
should not be necessary anymore.
2019-06-16 22:50:06 +02:00
Michael Matz eaf5f3fa52 Ignore relocs to ignored sections as well
relocs to sections which we ignore should be ignored as well,
they have no meaning and currently would segfault.
2019-06-16 22:48:15 +02:00
Michael Matz 4c2b55f962 Fix use-after-free in tccelf.c
build_got might realloc the symbol table (for the _GLOBAL_OFFSET_TABLE_
symbol), so we can't reuse sym (a pointer into it) after build_got.
Using it isn't necessary, as we pass the sym_index to put_got_entry,
and that recomputes sym.
2019-06-16 22:06:07 +02:00
Petr Skocik 47722a8c2e fix windows errors uncovered by the inline patch
By always instantiating extern inlines, the patch has discovered
2 assembly errors, which were fixed in the original mingw64 in 2009.

This fixes those errors.

Additionally it changes __CRT_INLINE in win32/include/_mingw.h
from `extern __inline__` to `static __inline__`.

__CRT_INLINE is used exclusively in header files and as such
it should not create externally visible instantiations like a `extern
inline` would (as per the C standard).
2019-06-12 15:37:59 +02:00
Petr Skocik 587e1f5598 standard conformant inline functions
- add tests for standard conformant inline functions
- implement it

The  old tinycc failed to provide a conforming implementation
of non-static inlines.  It would expose external symbols where it
shouldn't and hide them where it should expose them.

This commit provides a hopefully comprehensive test suite
for how things should be done. The .expect file can be obtained
by compiling the example c file (embedded in the test)
with a conforming compiler such as gcc, clang or icc and then
printing the exported symbols (e.g., with nm+awk+sort).

(The implementation currently reserves two new VT_ flags.
If anyone can provide an implementation without reserving
two extra flags, please replace mine.)
2019-06-11 16:29:24 +02:00
Petr Skocik f2fd56a27d turn -fdollars-in-identifiers on by default
gcc and clang do it too
2019-06-11 13:45:22 +02:00
Petr Skocik 60ceab1453 in c11 mode, skip __STDC_ISO_10646__
The macro conflicts (=> redef warnings in a simple hello world)
with a definition introduced by glibc headers and
it's probably not "necessary" anyway since clang doesn't use it.
2019-06-11 13:43:24 +02:00
Petr Skocik 18a2ed2936 make -h|-hh succeed if the output is successfully written 2019-06-11 12:42:26 +02:00
Michael Matz d04ce7772c Don't allow section switches in local asm instructions
GCC wouldn't be able to implement this either (due to the separate
phases of compilation and assembly).  We could allow it but it
makes not much sense and actively can confuse broken code into
segfaulting TCC.  At least we can warn.

Warning exposes a problem in tcctest, and fixing that gives us
an opportunity to also test .pushsection/.popsection and .previous
directive support.
2019-05-30 21:31:35 +02:00
Vlad Vissoultchev 1dd6842654
Don't drop asm_label hack on external symbols for win32 DLL exports 2019-05-14 22:37:13 +03:00
matthias cf3d23741f add tests for cleanup loop
- Also fix some gcc warning
2019-05-03 12:32:55 +02:00
matthias 14be3a1dc1 fix cleanup with for loop initialisation
Signed-off-by: matthias <uso.cosmo.ray@gmail.com>
2019-05-03 12:32:55 +02:00
matthias 0d54946dec fix cleanup with break and continue
fix cleanup
2019-05-03 12:32:55 +02:00
Michael Matz d30bc6d00a _Static_assert must be followed by semicolon
as per the C11 grammar.
2019-05-03 00:22:35 +02:00
matthias gatto e371642e6b _Static_assert test 2019-04-28 08:27:33 +02:00
matthias 5a0101856b add C11 _Static_assert support 2019-04-28 01:07:21 +02:00
Michael Matz 85483f321d Add 103_implicit_memmove testcase
which checks that a declaration after TCC implicitely declares
an internally used function (memmove here) doesn't create any problem.
2019-04-18 03:42:23 +02:00
Michael Matz c07e81b087 Tidy some code
the real difference is in decl0 where we can use external_sym
just fine also for function definitions, we don't have to use
external_global_sym.  Setting VT_EXTERN in external_sym isn't
necessary either (the type will have it set if necessary).
The rest is tidying: removing unused arguments and moving
some code around.
2019-04-18 03:42:23 +02:00
Christian Jullien f2461096b1 Add minimal includes and .def files to support, by default, BSD socket programming on Windows. 2019-04-16 07:26:04 +02:00
Michael Matz c16dadbb97 win64: make signal handlers work somewhat
we can register a top-level exception filter which does
nothing else than call into _XcptFilter (provided by
the default C runtime environment) and signal handlers
for the few POSIX signals that Windows can handle start
working (that includes e.g. SEGV).
2019-04-15 20:02:45 +02:00
Michael Matz 105107124d Make 102_alignas independend of architecture
alignment of double is of course depending on the target,
so the .expect file was arch dependend.  Fix this by simply doing
some comparison tests.
2019-04-11 00:37:07 +02:00
Michael Matz 0344c0b6a0 Fix more struct inits
anonymous struct members were somewhat broken as the testcase
demonstrates.  The reason is the jumping through hoops to fiddle
with the offsets I once introduced to avoid having to track
a cumulative offset.  That's now not necessary anymore and actively
harmful, doing the obvious thing is now better.
2019-04-11 00:30:41 +02:00
Michael Matz 94846d3eef Some types testcases
during some rework I tripped over some more obscure but valid declarators.
Let's not loose them.
2019-04-09 04:39:38 +02:00
Michael Matz ce4aea2478 Fix last commit's expected output
I forgot to regenerate the expected output of 102_alignas.c
just before committing and pushing :-/  This rectifies that.
2019-04-09 03:58:17 +02:00
Michael Matz 38a6aba468 Fix _Alignas
* don't accept _Alignas as type qualifier (after pointer '*').
* accept type-names within _Alignas
* add testcases
2019-04-08 22:06:51 +02:00
Ziga Lenarcic fa0ef91a24 With -run -nostdlib use "_start" as the entry symbol. 2019-04-07 13:44:07 +02:00
Michael Matz 2a417b50ee Detect invalid VLA decls
see testcase, when the inner array dimension of multi-dimensional
VLAs isn't given TCC was generating invalid vstack accesses.
Those are actually invalid, so just diagnose them.
2019-04-07 04:09:25 +02:00
Michael Matz 5ac2a26666 Don't endlessly recurse on invalid nested typedefs
see testcase.
2019-04-07 03:15:05 +02:00
Michael Matz d00f98a7a5 Fix 98_al_ax_extend.c compile error
this test is run only on i386 so its failing went unnoticed for
a while, since 1fd3709379.  IS_ASM_SYMs should not be tested
for conflicting types, the C typing overrides.
2019-04-07 02:44:32 +02:00
Devin Hussey 9382a3ad58 C11 conformance: Add _Noreturn, stdnoreturn.h, and partial _Alignas support
_Noreturn, just like __attribute__((noreturn)), is ignored.
I also added stdnoreturn.h, in all its glorious uselessness.

_Alignas only works for integer expressions right now. In order
to comply, we need:
 - _Alignas(type) -> _Alignas(_Alignof(type)).
 - stdalign.h as soon as it is done.

Note: DR 444 is supported; it works on struct members.

Signed-off-by: Devin Hussey <husseydevin@gmail.com>
2019-03-20 15:03:27 -04:00
Michael Matz 1fd3709379 Fix local extern vardecl
see testcases.  A local 'extern int i' declaration needs to
refer to the global declaration, not to a local one it might
be shadowing.  Doesn't seem to happen in the wild very often as
this was broken forever.
2019-03-18 05:53:03 +01:00
Michael Matz e6980f6cc7 Detect more invalid initializers
in presence of invalid source code we can't rely on the
next token to determine if we have or haven't already parsed
an initializer element, we really have to track it in some separate
state; it's a flag, so merge it with the other two we have (size_only
and first).  Also add some syntax checks for situations which
formerly lead to vstack leaks, see the added testcases.
2019-03-18 03:31:11 +01:00
Michael Matz d72b877e45 Fix invalid memory access in preprocess_end
when an error is thrown macro_stack might point to
unwound local variables, we can't access them.
2019-03-15 13:17:58 +01:00
Vincent Lefevre be7c870718 Fix va_end() definition: must be an expression of type void
Also added a test yielding a failure with the previous definition,
i.e. when using: (va_end(ap));

The test also checks potentially incorrect va_start() definition.
2019-03-14 15:39:52 +01:00
Vincent Lefevre 920f773a81 Fix "make -j test"
The clean-s rule must be run before the tests, not at the same time!
2019-03-14 14:59:27 +01:00
Michael Matz 4b46e0ec63 Handle corner case for abstract decls
sometimes abstract decls in parameter lists left the returned name
uninitialized potentially leading to segfaults, like in

  int f(int ()) {
    return 0;
  }

Deal with this.
2019-03-12 17:27:15 +01:00
Michael Matz ef0397cf3d Fix crash on invalid code
like on 'enum myenum { L = -1 } L;'.  It's a bit tedious as
there are two paths (for global vs local symbols), and because
the scope and enum_val share same storage.
2019-03-08 17:58:25 +01:00
matthias b082659f19 fix segv in "{,}" combound literal 2019-03-06 18:51:13 +01:00
Michael Matz fef838db2d Fix relocs of unwanted sections
relocation sections to sections we don't want to handle lead
to segfaults, handle this situation (by ignoring the relocs
as well).
2019-03-04 16:53:24 +01:00
Michael Matz 749d19d70b Fix sub-int returns on x86-64 and i386
the ABIs (and other compilers) extend sub-int return values in the
caller.  TCC extends them in the callee.  For compatibility with
those other compilers we have extend them in the caller as well.
That introduces a useless double extension in pure TCC-compiled code,
but fixing that generally requires that the code generator of TCC would
understand sub-int types.  For the time being bite the bullet.
2019-02-10 18:27:41 +01:00
Michael Matz 5f737fb4d3 tidy code 2019-01-31 01:04:55 +01:00
Michael Matz 5c862a08b4 suppress code after continue as well
fix an oversight in code suppression
2019-01-31 00:37:49 +01:00
matthias d27ea5155f remove incr/decr_local_scope functions 2019-01-29 21:32:38 +01:00
Michael Matz 08e22d8ad2 More cleanup tests
test3 wasn't working originally.
2019-01-28 05:54:19 +01:00
Michael Matz 4cc802a88e Tidy new support for cleanups
encode most things in Syms, do only as much work as necessary
(e.g. pending cleanups), don't track scopes in a large
structure (instead encode the scopes with cleanups directly
in the cleanups tree).  Removes ca. 120 lines of code.
2019-01-28 05:54:19 +01:00
Detlef Riekenberg 5d805a90e3 tcc.c: Fix outdated help info for the std option
the std option is no longer ignored

--
bye bye ... Detlef

Signed-off-by: Detlef Riekenberg <tcc.dev@web.de>
2019-01-27 17:32:11 +01:00
matthias 46145af4a1 remove C99 'for' loop initial declarations 2019-01-23 19:42:04 +01:00
matthias 5010023428 remove outdated comment 2019-01-23 17:21:14 +01:00
matthias de92fbee7e add a cleanup test that use a lot of scope 2019-01-23 17:21:14 +01:00
matthias 26f0cf0708 Fix scope limit for cleanup attribute
old implementation use only a global static array for storing
ScopeTracker which have the advantage to be fast, but you can't
use cleanup in a function that have move than SCOPE_TCK_STORE_SIZE
scopes.

I don't want to use only dynarray_* as it would slow down tcc for
every functions, so I keep both stores.
2019-01-23 17:21:14 +01:00
matthias ff38d90d5d Add attribute cleanup test 2019-01-23 17:21:14 +01:00
matthias 0d91ba749c Add gcc attribute cleanup support
The major difficulty was to handle cleanup when a goto happen
to do so, I've had a "ScopeTracker" struct.
I can't use local_scope because that would not work with code like below
as local_scope would be at the same level:

{
    char * __attribute__ ((cleanup(clean_function))) str = "hej";
    goto next;
}
{
    next:
}
2019-01-23 17:21:14 +01:00
Giovanni Mascellani f6be0d483b
Fix read() usage in tccelf.c.
read() is allowed to short-read, and return less bytes then requested.
The caller must restart read() when this happens (and they want more
bytes).

This patch is still buggy, because errors are not always checked.
Still, less buggy than before.
2019-01-13 15:20:39 +01:00
Christian Jullien acac38afb2 Add C99 compiliant iso646.h header 2019-01-13 10:24:50 +01:00
Michael Matz 45b8b0e57d Revert 337dc84b (other -static fix)
this should work now with 05f6aa1a.
2019-01-13 06:01:59 +01:00
Michael Matz 05f6aa1ade Fix -static linking with uClibc
symbols are local when defined and referred to from the executable.
Also, we need to relocate the .got section when this is a static link
(our static linking effectively generates code as if this were a dynamic
link with PLT and GOT, and then emulates the runtime loader).
2019-01-13 06:00:51 +01:00
Michael Matz adbe794a46 Properly access sym_attrs
in corner cases the direct access to the sym_attrs[] array in the
backends is out of bounds and replacec garbage symindices into
the relocs.
2019-01-13 02:55:44 +01:00
Christian Jullien d44d8cdf60 Add more STDC_ C11 compatible constants 2019-01-12 10:41:56 +01:00
Pursuer ecb90de4cc FIX:Revert commit 3f05d88d5b
The function should to be saved to stack in some cases (fastcall on i386, struct argument on arm etc.). But I neglected. So I revert this commit.
2019-01-12 01:54:24 +08:00
Christian Jullien 8482f9e54b Add __STDC_xxx test features related to ISO/IEC C11 when -std=c11 is passed. 2019-01-11 14:26:17 +01:00
Petr Skocik 065a3b35fc Make stddef.h expose max_align_t with -std= >= c11 2019-01-11 11:17:49 +01:00
Matthias Gatto 2b94c0c3b1 Revert "allow c11 feature only when -std=c11 is use"
This reverts commit 756988e8f9.
2019-01-11 10:35:44 +01:00
matthias gatto 756988e8f9 allow c11 feature only when -std=c11 is use 2019-01-10 23:42:45 +01:00
Christian Jullien a3a291784a Add -std=c11 option which sets __STDC_VERSION__ to 201112L and allows to implement c11 features conditionally 2019-01-11 02:32:48 +08:00
Kurt Nalty 337dc84b57 Fixed -static linking on x86_64 Linux 2019-01-11 02:32:48 +08:00
Petr Skocik 51f6e52dd3 Support multiple __label__ declarations
Support multiple __label__ declarations at the beginning of a block
as long as they're contiguous.

gcc and clang accept:
    { __label__ a,b; __label__ c;  /*...*/ }
.
Tcc would fail it. This patch makes it accept it.

The patch:
-        if (tok == TOK_LABEL) {
+        while (tok == TOK_LABEL) {
2019-01-11 02:32:47 +08:00
Pursuer 3f05d88d5b optimize the generated code when save_reg is required (2)
In gfunc_call, regisger will be saved before gcall_or_jmp. The register
stored the function will be saved too, though in some generator the SValue
of this function will be immediately poped after gcall_or_jmp, and no need to be saved. So I modify some generator to avoid save redundant SValue before gcall_or_jmp.
2019-01-11 02:32:12 +08:00
Pursuer b3b685d92a optimize the generated code when save_reg is required
Before this patch, save_reg can't reuse the temporary local variable
created before to save register. It may consume a lot of stack memory. this patch make save_reg reuse the temporary local variable.
2019-01-10 13:17:14 +08:00
Pursuer 0c313f491b Insert arm-xxx_FILES into Makefile to suport CROSS_TARGET and Remove duplicate function lexpand_nr 2019-01-09 02:06:26 +08:00
Petr Skocik 7369cfc490 Revert "Add max_align_t to stddef.h"
max_align_t is C11 not C99 and the name is not reserved by C99.

This reverts commit 7eceba178d.
2019-01-08 12:32:18 +01:00
Petr Skocik 7eceba178d Add max_align_t to stddef.h 2019-01-04 14:56:37 +01:00
Christian Jullien f21b53b5ed Add winnls.h to allow SQLite compile ROOTB on Windows 2019-01-01 08:58:09 +01:00
Michael Matz 3e007193a2 Fix more attribute placements
when parsing the type in this cast:
  (int (__attribute__(X) *)(int))foo
we ignored the attribute, which matters if it's e.g. a 'stdcall'
attribute on the function pointer.  Only this particular placement
was misparsed.  Putting the attribute after the '*' or outside the inner
parens worked.  This idiom seems to be used on SQLite, perhaps this
fixes a compilation problem on win32 with that.
2018-12-31 22:00:31 +01:00
Christian Jullien 325241c0de zfunc works again on ARM after Pursuer fix 2018-12-22 19:14:22 +01:00
general bf09349f8e fix arm-gen.c -> gcall_or_jmp to VT_CONST 2018-12-22 19:48:56 +08:00
Theodore Dubois 82abfd75f3 Fix ELF interpreter of i386 musl target 2018-12-22 04:29:06 +00:00
Michael Matz 63f69c2bdd Disable -Wformat-truncation
this new gcc 8 warning triggers here, but is useless for our
purposes.
2018-12-21 01:03:38 +01:00
Michael Matz f68a1f50fd Don't use C99 decls
we're consciously trying to write C90 compatible code, hence
no mixed declaration and code.
2018-12-21 01:03:05 +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
131 changed files with 14960 additions and 5512 deletions

2
.gitignore vendored
View File

@ -50,8 +50,10 @@ tests/*.gcc
tests/*-cc*
tests/*-tcc*
tests/libtcc_test
tests/libtcc_test_mt
tests/asm-c-connect
tests/asm-c-connect-sep
tests/vla_test
tests/hello
tests/tests2/fred.txt
libtcc.dylib

172
Makefile
View File

@ -8,9 +8,11 @@ ifndef TOP
INCLUDED = no
endif
include $(TOP)/config.mak
ifeq ($(findstring $(MAKECMDGOALS),clean distclean),)
include $(TOP)/config.mak
endif
ifeq (-$(CC)-$(GCC_MAJOR)-$(findstring $(GCC_MINOR),56789)-,-gcc-4--)
ifeq (-$(GCC_MAJOR)-$(findstring $(GCC_MINOR),56789)-,-4--)
CFLAGS += -D_FORTIFY_SOURCE=0
endif
@ -30,7 +32,7 @@ ifdef CONFIG_WIN32
CFGWIN = -win
NATIVE_TARGET = $(ARCH)-win$(if $(findstring arm,$(ARCH)),ce,32)
else
LIBS=-lm
LIBS=-lm -lpthread
ifneq ($(CONFIG_ldl),no)
LIBS+=-ldl
endif
@ -47,7 +49,7 @@ else
ifdef CONFIG_OSX
NATIVE_TARGET = $(ARCH)-osx
LDFLAGS += -flat_namespace -undefined warning
export MACOSX_DEPLOYMENT_TARGET := 10.2
export MACOSX_DEPLOYMENT_TARGET := 10.4
endif
endif
@ -60,6 +62,11 @@ ifdef CONFIG_OSX
TCCFLAGS += -D_ANSI_SOURCE
endif
# cross compiler targets to build
TCC_X = i386 x86_64 i386-win32 x86_64-win32 x86_64-osx arm arm64 arm-wince c67
TCC_X += riscv64
# TCC_X += arm-fpa arm-fpa-ld arm-vfp arm-eabi
CFLAGS_P = $(CFLAGS) -pg -static -DCONFIG_TCC_STATIC -DTCC_PROFILE
LIBS_P = $(LIBS)
LDFLAGS_P = $(LDFLAGS)
@ -78,6 +85,7 @@ NATIVE_DEFINES_$(CONFIG_arm_eabihf) += -DTCC_ARM_EABI -DTCC_ARM_HARDFLOAT
NATIVE_DEFINES_$(CONFIG_arm_eabi) += -DTCC_ARM_EABI
NATIVE_DEFINES_$(CONFIG_arm_vfp) += -DTCC_ARM_VFP
NATIVE_DEFINES_$(CONFIG_arm64) += -DTCC_TARGET_ARM64
NATIVE_DEFINES_$(CONFIG_riscv64) += -DTCC_TARGET_RISCV64
NATIVE_DEFINES += $(NATIVE_DEFINES_yes)
ifeq ($(INCLUDED),no)
@ -85,17 +93,14 @@ ifeq ($(INCLUDED),no)
# running top Makefile
PROGS = tcc$(EXESUF)
TCCLIBS = $(LIBTCC1) $(LIBTCC) $(LIBTCCDEF)
TCCLIBS = $(LIBTCCDEF) $(LIBTCC) $(LIBTCC1)
TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info
all: $(PROGS) $(TCCLIBS) $(TCCDOCS)
# cross compiler targets to build
TCC_X = i386 x86_64 i386-win32 x86_64-win32 x86_64-osx arm arm64 arm-wince c67
# TCC_X += arm-fpa arm-fpa-ld arm-vfp arm-eabi
# cross libtcc1.a targets to build
LIBTCC1_X = i386 x86_64 i386-win32 x86_64-win32 x86_64-osx arm arm64 arm-wince
LIBTCC1_X += riscv64
PROGS_CROSS = $(foreach X,$(TCC_X),$X-tcc$(EXESUF))
LIBTCC1_CROSS = $(foreach X,$(LIBTCC1_X),$X-libtcc1.a)
@ -106,8 +111,8 @@ cross: $(LIBTCC1_CROSS) $(PROGS_CROSS)
# build specific cross compiler & lib
cross-%: %-tcc$(EXESUF) %-libtcc1.a ;
install: ; @$(MAKE) --no-print-directory install$(CFGWIN)
install-strip: ; @$(MAKE) --no-print-directory install$(CFGWIN) CONFIG_strip=yes
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
@ -125,7 +130,7 @@ DEF-i386-win32 = -DTCC_TARGET_PE -DTCC_TARGET_I386
DEF-x86_64-win32= -DTCC_TARGET_PE -DTCC_TARGET_X86_64
DEF-x86_64-osx = -DTCC_TARGET_MACHO -DTCC_TARGET_X86_64
DEF-arm-wince = -DTCC_TARGET_PE -DTCC_TARGET_ARM -DTCC_ARM_EABI -DTCC_ARM_VFP -DTCC_ARM_HARDFLOAT
DEF-arm64 = -DTCC_TARGET_ARM64
DEF-arm64 = -DTCC_TARGET_ARM64 -Wno-format
DEF-c67 = -DTCC_TARGET_C67 -w # disable warnigs
DEF-arm-fpa = -DTCC_TARGET_ARM
DEF-arm-fpa-ld = -DTCC_TARGET_ARM -DLDOUBLE_SIZE=12
@ -133,6 +138,7 @@ DEF-arm-vfp = -DTCC_TARGET_ARM -DTCC_ARM_VFP
DEF-arm-eabi = -DTCC_TARGET_ARM -DTCC_ARM_VFP -DTCC_ARM_EABI
DEF-arm-eabihf = -DTCC_TARGET_ARM -DTCC_ARM_VFP -DTCC_ARM_EABI -DTCC_ARM_HARDFLOAT
DEF-arm = $(DEF-arm-eabihf)
DEF-riscv64 = -DTCC_TARGET_RISCV64
DEF-$(NATIVE_TARGET) = $(NATIVE_DEFINES)
DEFINES += $(DEF-$T) $(DEF-all)
@ -164,8 +170,15 @@ x86_64-win32_FILES = $(x86_64_FILES) tccpe.c
x86_64-osx_FILES = $(x86_64_FILES)
arm_FILES = $(CORE_FILES) arm-gen.c arm-link.c arm-asm.c
arm-wince_FILES = $(arm_FILES) tccpe.c
arm-eabihf_FILES = $(arm_FILES)
arm-fpa_FILES = $(arm_FILES)
arm-fpa-ld_FILES = $(arm_FILES)
arm-vfp_FILES = $(arm_FILES)
arm-eabi_FILES = $(arm_FILES)
arm-eabihf_FILES = $(arm_FILES)
arm64_FILES = $(CORE_FILES) arm64-gen.c arm64-link.c
c67_FILES = $(CORE_FILES) c67-gen.c c67-link.c tcccoff.c
riscv64_FILES = $(CORE_FILES) riscv64-gen.c riscv64-link.c
# libtcc sources
LIBTCC_SRC = $(filter-out tcc.c tcctools.c,$(filter %.c,$($T_FILES)))
@ -182,72 +195,87 @@ TCC_FILES = $(X)tcc.o $(LIBTCC_OBJ)
$(TCC_FILES) : DEFINES += -DONE_SOURCE=0
endif
ifeq ($(CONFIG_strip),no)
CFLAGS += -g
LDFLAGS += -g
else
CONFIG_strip = yes
LDFLAGS += -s
endif
# target specific object rule
$(X)%.o : %.c $(LIBTCC_INC)
$(CC) -o $@ -c $< $(DEFINES) $(CFLAGS)
$S$(CC) -o $@ -c $< $(DEFINES) $(CFLAGS)
# additional dependencies
$(X)tcc.o : tcctools.c
# Host Tiny C Compiler
tcc$(EXESUF): tcc.o $(LIBTCC)
$(CC) -o $@ $^ $(LIBS) $(LDFLAGS) $(LINK_LIBTCC)
$S$(CC) -o $@ $^ $(LIBS) $(LDFLAGS) $(LINK_LIBTCC)
# Cross Tiny C Compilers
%-tcc$(EXESUF): FORCE
@$(MAKE) --no-print-directory $@ CROSS_TARGET=$* ONE_SOURCE=$(or $(ONE_SOURCE),yes)
$(CROSS_TARGET)-tcc$(EXESUF): $(TCC_FILES)
$(CC) -o $@ $^ $(LIBS) $(LDFLAGS)
$S$(CC) -o $@ $^ $(LIBS) $(LDFLAGS)
# profiling version
tcc_p$(EXESUF): $($T_FILES)
$(CC) -o $@ $< $(DEFINES) $(CFLAGS_P) $(LIBS_P) $(LDFLAGS_P)
$S$(CC) -o $@ $< $(DEFINES) $(CFLAGS_P) $(LIBS_P) $(LDFLAGS_P)
# static libtcc library
libtcc.a: $(LIBTCC_OBJ)
$(AR) rcs $@ $^
$S$(AR) rcs $@ $^
# dynamic libtcc library
libtcc.so: $(LIBTCC_OBJ)
$(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LDFLAGS)
$S$(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LDFLAGS)
libtcc.so: CFLAGS+=-fPIC
libtcc.so: LDFLAGS+=-fPIC
libtcc.dylib: $(LIBTCC_OBJ)
$(CC) -shared -o libtcc.dylib libtcc.o tccpp.o tccgen.o tccelf.o tccasm.o tccrun.o x86_64-gen.o x86_64-link.o i386-asm.o -flat_namespace
# windows dynamic libtcc library
libtcc.dll : $(LIBTCC_OBJ)
$(CC) -shared -o $@ $^ $(LDFLAGS)
$S$(CC) -shared -o $@ $^ $(LDFLAGS)
libtcc.dll : DEFINES += -DLIBTCC_AS_DLL
# import file for windows libtcc.dll
libtcc.def : libtcc.dll tcc$(EXESUF)
$(XTCC) -impdef $< -o $@
$S$(XTCC) -impdef $< -o $@
XTCC ?= ./tcc$(EXESUF)
# TinyCC runtime libraries
libtcc1.a : tcc$(EXESUF) FORCE
@$(MAKE) -C lib DEFINES='$(DEF-$T)'
@$(MAKE) -C lib
# Cross libtcc1.a
%-libtcc1.a : %-tcc$(EXESUF) FORCE
@$(MAKE) -C lib DEFINES='$(DEF-$*)' CROSS_TARGET=$*
@$(MAKE) -C lib CROSS_TARGET=$*
.PRECIOUS: %-libtcc1.a
FORCE:
run-if = $(if $(shell which $1),$S $1 $2)
S = $(if $(findstring yes,$(SILENT)),@$(info * $@))
# --------------------------------------------------------------------------
# documentation and man page
tcc-doc.html: tcc-doc.texi
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 >tmp.1 \
&& mv tmp.1 $@ || rm -f tmp.1
$(call run-if,makeinfo,--no-split --html --number-sections -o $@ $<)
tcc-doc.info: tcc-doc.texi
makeinfo $< || true
$(call run-if,makeinfo,$< || true)
tcc.1 : tcc-doc.pod
$(call run-if,pod2man,--section=1 --center="Tiny C Compiler" \
--release="$(VERSION)" $< >$@ && rm -f $<)
%.pod : %.texi
$(call run-if,perl,$(TOPSRC)/texi2pod.pl $< $@)
# --------------------------------------------------------------------------
# install
@ -258,16 +286,19 @@ STRIP_yes = -s
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)
IB = $(if $1,$(IM) mkdir -p $2 && $(INSTALLBIN) $1 $2)
IBw = $(call IB,$(wildcard $1),$2)
IF = $(if $1,mkdir -p $2 && $(INSTALL) $1 $2)
IF = $(if $1,$(IM) mkdir -p $2 && $(INSTALL) $1 $2)
IFw = $(call IF,$(wildcard $1),$2)
IR = mkdir -p $2 && cp -r $1/. $2
IR = $(IM) mkdir -p $2 && cp -r $1/. $2
IM = $(info -> $2 : $1)@
B_O = bcheck.o bt-exe.o bt-log.o bt-dll.o
# install progs & libs
install-unx:
$(call IBw,$(PROGS) $(PROGS_CROSS),"$(bindir)")
$(call IFw,$(LIBTCC1) $(LIBTCC1_U),"$(tccdir)")
$(call IFw,$(LIBTCC1) $(B_O) $(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)")
@ -286,13 +317,13 @@ uninstall-unx:
@rm -fv "$(libdir)/libtcc.a" "$(libdir)/libtcc.so" "$(includedir)/libtcc.h"
@rm -fv "$(mandir)/man1/tcc.1" "$(infodir)/tcc-doc.info"
@rm -fv "$(docdir)/tcc-doc.html"
rm -r "$(tccdir)"
@rm -frv "$(tccdir)"
# install progs & libs on windows
install-win:
$(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 IFw,libtcc1.a $(B_O) $(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")
@ -305,17 +336,16 @@ ifneq "$(wildcard $(LIBTCC1_U))" ""
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"
ifeq ($(CONFIG_WIN32)-$(shell which install || echo no),yes-no)
install-win : INSTALL = cp
install-win : INSTALLBIN = cp
endif
# uninstall on windows
uninstall-win:
@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)"
@rm -fv $(foreach P,libtcc.dll $(PROGS) *-tcc.exe,"$(bindir)/$P")
@rm -fr $(foreach P,doc examples include lib libtcc,"$(tccdir)/$P"/*)
@rm -frv $(foreach P,doc examples include lib libtcc,"$(tccdir)/$P")
# --------------------------------------------------------------------------
# other stuff
@ -328,8 +358,9 @@ ETAGS : ; etags $(TAGFILES)
# create release tarball from *current* git branch (including tcc-doc.html
# and converting two files to CRLF)
TCC-VERSION = tcc-$(VERSION)
TCC-VERSION = tinycc-mob-$(shell git rev-parse --short=7 HEAD)
tar: tcc-doc.html
mkdir $(TCC-VERSION)
mkdir -p $(TCC-VERSION)
( cd $(TCC-VERSION) && git --git-dir ../.git checkout -f )
cp tcc-doc.html $(TCC-VERSION)
for f in tcc-win32.txt build-tcc.bat ; do \
@ -344,19 +375,22 @@ config.mak:
# run all tests
test:
$(MAKE) -C tests
@$(MAKE) -C tests
# run test(s) from tests2 subdir (see make help)
tests2.%:
$(MAKE) -C tests/tests2 $@
@$(MAKE) -C tests/tests2 $@
testspp.%:
@$(MAKE) -C tests/pp $@
clean:
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 lib $@
@$(MAKE) -C tests $@
@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 *.dylib
@$(MAKE) -s -C lib $@
@$(MAKE) -s -C tests $@
distclean: clean
rm -f config.h config.mak config.texi tcc.1 tcc-doc.info tcc-doc.html
@rm -fv config.h config.mak config.texi tcc.1 tcc-doc.info tcc-doc.html
.PHONY: all clean test tar tags ETAGS distclean install uninstall FORCE
@ -367,27 +401,13 @@ help:
@echo "make cross"
@echo " build cross compilers (from one source)"
@echo ""
@echo "make ONE_SOURCE=yes / no"
@echo " force building from one source / separate objects"
@echo "make ONE_SOURCE=no/yes SILENT=no/yes"
@echo " force building from separate/one object(s), less/more silently"
@echo ""
@echo "make cross-TARGET"
@echo " build one specific cross compiler for 'TARGET', as in"
@echo " $(TCC_X)"
@echo ""
@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 " 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 " build one specific cross compiler for 'TARGET'. Currently supported:"
@echo " $(wordlist 1,6,$(TCC_X))"
@echo " $(wordlist 7,99,$(TCC_X))"
@echo ""
@echo "make test"
@echo " run all tests"
@ -395,9 +415,23 @@ help:
@echo "make tests2.all / make tests2.37 / make tests2.37+"
@echo " run all/single test(s) from tests2, optionally update .expect"
@echo ""
@echo "Other supported make targets:"
@echo " install install-strip tags ETAGS tar clean distclean help"
@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 doc clean tags ETAGS tar distclean help"
@echo ""
@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 " NATIVE_DEFINES += -D..."
@echo " Or for example to configure the search paths for a cross-compiler"
@echo " that expects the linux files in <tccdir>/i386-linux:"
@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__"
# --------------------------------------------------------------------------
endif # ($(INCLUDED),no)

4
README
View File

@ -12,14 +12,14 @@ Features:
-O0'.
- UNLIMITED! Any C dynamic library can be used directly. TCC is
heading torward full ISOC99 compliance. TCC can of course compile
heading toward full ISOC99 compliance. TCC can of course compile
itself.
- SAFE! tcc includes an optional memory and bound checker. Bound
checked code can be mixed freely with standard code.
- Compile and execute C source directly. No linking or assembly
necessary. Full C preprocessor included.
necessary. Full C preprocessor included.
- C script supported : just add '#!/usr/local/bin/tcc -run' at the first
line of your C source, and execute it directly from the command

View File

@ -16,7 +16,7 @@ ST_FUNC void gen_le32(int c);
/*************************************************************/
#else
/*************************************************************/
#define USING_GLOBALS
#include "tcc.h"
static void asm_error(void)

161
arm-gen.c
View File

@ -59,7 +59,7 @@
#define RC_F7 0x4000
#endif
#define RC_IRET RC_R0 /* function return: integer register */
#define RC_LRET RC_R1 /* function return: second integer register */
#define RC_IRE2 RC_R1 /* function return: second integer register */
#define RC_FRET RC_F0 /* function return: float register */
/* pretty names for the registers */
@ -89,7 +89,7 @@ enum {
/* return registers for function */
#define REG_IRET TREG_R0 /* single word int return register */
#define REG_LRET TREG_R1 /* second word return register (for long long) */
#define REG_IRE2 TREG_R1 /* second word return register (for long long) */
#define REG_FRET TREG_F0 /* float return register */
#ifdef TCC_ARM_EABI
@ -132,6 +132,7 @@ enum {
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
/******************************************************/
#define USING_GLOBALS
#include "tcc.h"
enum float_abi float_abi;
@ -170,7 +171,7 @@ ST_FUNC void arm_init(struct TCCState *s)
float_abi = s->float_abi;
#ifndef TCC_ARM_HARDFLOAT
tcc_warning("soft float ABI currently not supported: default to softfp");
# warning "soft float ABI currently not supported: default to softfp"
#endif
}
#else
@ -382,11 +383,6 @@ void gsym_addr(int t, int a)
}
}
void gsym(int t)
{
gsym_addr(t, ind);
}
#ifdef TCC_ARM_VFP
static uint32_t vfpr(int r)
{
@ -409,9 +405,9 @@ static uint32_t intr(int r)
return 12;
if(r >= TREG_R0 && r <= TREG_R3)
return r - TREG_R0;
if (r >= TREG_SP && r <= TREG_LR)
return r + (13 - TREG_SP);
tcc_error("compiler error! register %i is no int register",r);
if (!(r >= TREG_SP && r <= TREG_LR))
tcc_error("compiler error! register %i is no int register",r);
return r + (13 - TREG_SP);
}
static void calcaddr(uint32_t *base, int *off, int *sgn, int maxoff, unsigned shift)
@ -739,25 +735,28 @@ static void gadd_sp(int val)
static void gcall_or_jmp(int is_jmp)
{
int r;
uint32_t x;
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
uint32_t x;
/* constant case */
x=encbranch(ind,ind+vtop->c.i,0);
if(x) {
if (vtop->r & VT_SYM) {
/* relocation case */
greloc(cur_text_section, vtop->sym, ind, R_ARM_PC24);
} else
put_elf_reloc(symtab_section, cur_text_section, ind, R_ARM_PC24, 0);
o(x|(is_jmp?0xE0000000:0xE1000000));
} else {
if(!is_jmp)
o(0xE28FE004); // add lr,pc,#4
o(0xE51FF004); // ldr pc,[pc,#-4]
if (vtop->r & VT_SYM)
greloc(cur_text_section, vtop->sym, ind, R_ARM_ABS32);
o(vtop->c.i);
}
if(vtop->r & VT_SYM){
x=encbranch(ind,ind+vtop->c.i,0);
if(x) {
/* relocation case */
greloc(cur_text_section, vtop->sym, ind, R_ARM_PC24);
o(x|(is_jmp?0xE0000000:0xE1000000));
} else {
if(!is_jmp)
o(0xE28FE004); // add lr,pc,#4
o(0xE51FF004); // ldr pc,[pc,#-4]
greloc(cur_text_section, vtop->sym, ind, R_ARM_ABS32);
o(vtop->c.i);
}
}else{
if(!is_jmp)
o(0xE28FE004); // add lr,pc,#4
o(0xE51FF004); // ldr pc,[pc,#-4]
o(vtop->c.i);
}
} else {
/* otherwise, indirect call */
r = gv(RC_INT);
@ -1138,7 +1137,7 @@ again:
/* XXX: implicit cast ? */
size=4;
if ((pplan->sval->type.t & VT_BTYPE) == VT_LLONG) {
lexpand_nr();
lexpand();
size = 8;
r = gv(RC_INT);
o(0xE52D0004|(intr(r)<<12)); /* push r */
@ -1162,7 +1161,7 @@ again:
case CORE_CLASS:
if ((pplan->sval->type.t & VT_BTYPE) == VT_LLONG) {
lexpand_nr();
lexpand();
gv(regmask(pplan->end));
pplan->sval->r2 = vtop->r;
vtop--;
@ -1266,8 +1265,9 @@ void gfunc_call(int nb_args)
}
/* generate function prolog of type 't' */
void gfunc_prolog(CType *func_type)
void gfunc_prolog(Sym *func_sym)
{
CType *func_type = &func_sym->type;
Sym *sym,*sym2;
int n, nf, size, align, rs, struct_ret = 0;
int addr, pn, sn; /* pn=core, sn=stack */
@ -1278,8 +1278,6 @@ void gfunc_prolog(CType *func_type)
#endif
sym = func_type->ref;
func_vt = sym->type;
func_var = (func_type->ref->f.func_type == FUNC_ELLIPSIS);
n = nf = 0;
if ((func_vt.t & VT_BTYPE) == VT_STRUCT &&
@ -1363,7 +1361,7 @@ from_stack:
addr = (n + nf + sn) * 4;
sn += size;
}
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t),
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL,
addr + 12);
}
last_itod_magic=0;
@ -1410,8 +1408,18 @@ 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)
ST_FUNC int gjmp(int t)
{
int r;
if (nocode_wanted)
@ -1422,51 +1430,37 @@ int gjmp(int t)
}
/* generate a jump to a fixed address */
void gjmp_addr(int a)
ST_FUNC void gjmp_addr(int a)
{
gjmp(a);
}
/* generate a test. set 'inv' to invert test. Stack entry is popped */
int gtst(int inv, int t)
ST_FUNC int gjmp_cond(int op, int t)
{
int v, r;
uint32_t op;
v = vtop->r & VT_VALMASK;
int r;
if (nocode_wanted)
return t;
r=ind;
op=mapcc(op);
op|=encbranch(r,t,1);
o(op);
return r;
}
if (nocode_wanted) {
;
} else if (v == VT_CMP) {
op=mapcc(inv?negcc(vtop->c.i):vtop->c.i);
op|=encbranch(r,t,1);
o(op);
t=r;
} else if (v == VT_JMP || v == VT_JMPI) {
if ((v & 1) == inv) {
if(!vtop->c.i)
vtop->c.i=t;
else {
uint32_t *x;
int p,lp;
if(t) {
p = vtop->c.i;
do {
p = decbranch(lp=p);
} while(p);
x = (uint32_t *)(cur_text_section->data + lp);
*x &= 0xff000000;
*x |= encbranch(lp,t,1);
}
t = vtop->c.i;
}
} else {
t = gjmp(t);
gsym(vtop->c.i);
}
ST_FUNC int gjmp_append(int n, int t)
{
uint32_t *x;
int p,lp;
if(n) {
p = n;
do {
p = decbranch(lp=p);
} while(p);
x = (uint32_t *)(cur_text_section->data + lp);
*x &= 0xff000000;
*x |= encbranch(lp,t,1);
t = n;
}
vtop--;
return t;
}
@ -1546,7 +1540,7 @@ void gen_opi(int op)
case '%':
#ifdef TCC_ARM_EABI
func=TOK___aeabi_idivmod;
retreg=REG_LRET;
retreg=REG_IRE2;
#else
func=TOK___modsi3;
#endif
@ -1555,7 +1549,7 @@ void gen_opi(int op)
case TOK_UMOD:
#ifdef TCC_ARM_EABI
func=TOK___aeabi_uidivmod;
retreg=REG_LRET;
retreg=REG_IRE2;
#else
func=TOK___umodsi3;
#endif
@ -1603,10 +1597,8 @@ void gen_opi(int op)
o(opc|(r<<12)|fr);
done:
vtop--;
if (op >= TOK_ULT && op <= TOK_GT) {
vtop->r = VT_CMP;
vtop->c.i = op;
}
if (op >= TOK_ULT && op <= TOK_GT)
vset_VT_CMP(op);
break;
case 2:
opc=0xE1A00000|(opc<<5);
@ -1722,9 +1714,7 @@ void gen_opf(int op)
case TOK_UGE: op=TOK_GE; break;
case TOK_UGT: op=TOK_GT; break;
}
vtop->r = VT_CMP;
vtop->c.i = op;
vset_VT_CMP(op);
return;
}
r=gv(RC_FLOAT);
@ -1926,8 +1916,9 @@ void gen_opf(int op)
} else {
r2=fpr(gv(RC_FLOAT));
}
vtop[-1].r = VT_CMP;
vtop[-1].c.i = op;
--vtop;
vset_VT_CMP(op);
++vtop;
} else {
tcc_error("unknown fp op %x!",op);
return;
@ -1949,7 +1940,7 @@ void gen_opf(int op)
/* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
and 'long long' cases. */
ST_FUNC void gen_cvt_itof1(int t)
ST_FUNC void gen_cvt_itof(int t)
{
uint32_t r, r2;
int bt;
@ -2082,7 +2073,7 @@ void gen_cvt_ftoi(int t)
gfunc_call(1);
vpushi(0);
if(t == VT_LLONG)
vtop->r2 = REG_LRET;
vtop->r2 = REG_IRE2;
vtop->r = REG_IRET;
return;
}

View File

@ -57,8 +57,6 @@ int code_reloc (int reloc_type)
case R_ARM_JUMP_SLOT:
return 1;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
@ -97,8 +95,6 @@ int gotplt_entry_type (int reloc_type)
case R_ARM_GOT32:
return ALWAYS_GOTPLT_ENTRY;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
@ -165,8 +161,6 @@ ST_FUNC void relocate_plt(TCCState *s1)
}
}
void relocate_init(Section *sr) {}
void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
{
ElfW(Sym) *sym;
@ -254,24 +248,24 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
int index;
uint8_t *p;
char *name, buf[1024];
Section *text_section;
Section *text;
name = (char *) symtab_section->link->data + sym->st_name;
text_section = s1->sections[sym->st_shndx];
text = s1->sections[sym->st_shndx];
/* Modify reloc to target a thumb stub to switch to ARM */
snprintf(buf, sizeof(buf), "%s_from_thumb", name);
index = put_elf_sym(symtab_section,
text_section->data_offset + 1,
text->data_offset + 1,
sym->st_size, sym->st_info, 0,
sym->st_shndx, buf);
to_thumb = 1;
val = text_section->data_offset + 1;
val = text->data_offset + 1;
rel->r_info = ELFW(R_INFO)(index, type);
/* Create a thumb stub function to switch to ARM mode */
put_elf_reloc(symtab_section, text_section,
text_section->data_offset + 4, R_ARM_JUMP24,
put_elf_reloc(symtab_section, text,
text->data_offset + 4, R_ARM_JUMP24,
sym_index);
p = section_ptr_add(text_section, 8);
p = section_ptr_add(text, 8);
write32le(p, 0x4778); /* bx pc */
write32le(p+2, 0x46c0); /* nop */
write32le(p+4, 0xeafffffe); /* b $sym */
@ -365,7 +359,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
return;
case R_ARM_GOT32:
/* we load the got offset */
*(int *)ptr += s1->sym_attrs[sym_index].got_offset;
*(int *)ptr += get_sym_attr(s1, sym_index, 0)->got_offset;
return;
case R_ARM_COPY:
return;

View File

@ -40,9 +40,13 @@
#define CHAR_IS_UNSIGNED
/* define if return values need to be extended explicitely
at caller side (for interfacing with non-TCC compilers) */
#define PROMOTE_RET
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
/******************************************************/
#define USING_GLOBALS
#include "tcc.h"
#include <assert.h>
@ -236,25 +240,24 @@ ST_FUNC void gsym_addr(int t_, int a_)
}
}
// Patch all branches in list pointed to by t to branch to current location:
ST_FUNC void gsym(int t)
{
gsym_addr(t, ind);
}
static int arm64_type_size(int t)
{
/*
* case values are in increasing order (from 1 to 11).
* which 'may' help compiler optimizers. See tcc.h
*/
switch (t & VT_BTYPE) {
case VT_INT: return 2;
case VT_BYTE: return 0;
case VT_SHORT: return 1;
case VT_INT: return 2;
case VT_LLONG: return 3;
case VT_PTR: return 3;
case VT_FUNC: return 3;
case VT_STRUCT: return 3;
case VT_FLOAT: return 2;
case VT_DOUBLE: return 3;
case VT_LDOUBLE: return 4;
case VT_BOOL: return 0;
case VT_LLONG: return 3;
}
assert(0);
return 0;
@ -446,10 +449,12 @@ static void arm64_sym(int r, Sym *sym, unsigned long addend)
}
}
static void arm64_load_cmp(int r, SValue *sv);
ST_FUNC void load(int r, SValue *sv)
{
int svtt = sv->type.t;
int svr = sv->r & ~VT_LVAL_TYPE;
int svr = sv->r;
int svrv = svr & VT_VALMASK;
uint64_t svcul = (uint32_t)sv->c.i;
svcul = svcul >> 31 & 1 ? svcul - ((uint64_t)1 << 32) : svcul;
@ -537,6 +542,11 @@ ST_FUNC void load(int r, SValue *sv)
return;
}
if (svr == VT_CMP) {
arm64_load_cmp(r, sv);
return;
}
printf("load(%x, (%x, %x, %llx))\n", r, svtt, sv->r, (long long)svcul);
assert(0);
}
@ -544,7 +554,7 @@ ST_FUNC void load(int r, SValue *sv)
ST_FUNC void store(int r, SValue *sv)
{
int svtt = sv->type.t;
int svr = sv->r & ~VT_LVAL_TYPE;
int svr = sv->r;
int svrv = svr & VT_VALMASK;
uint64_t svcul = (uint32_t)sv->c.i;
svcul = svcul >> 31 & 1 ? svcul - ((uint64_t)1 << 32) : svcul;
@ -580,8 +590,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 .
}
@ -957,11 +967,7 @@ ST_FUNC void gfunc_call(int nb_args)
{
int rt = return_type->t;
int bt = rt & VT_BTYPE;
if (bt == VT_BYTE || bt == VT_SHORT)
// Promote small integers:
o(0x13001c00 | (bt == VT_SHORT) << 13 |
(uint32_t)!!(rt & VT_UNSIGNED) << 30); // [su]xt[bh] w0,w0
else if (bt == VT_STRUCT && !(a[0] & 1)) {
if (bt == VT_STRUCT && !(a[0] & 1)) {
// A struct was returned in registers, so write it out:
gv(RC_R(8));
--vtop;
@ -995,16 +1001,15 @@ static int arm64_func_va_list_gr_offs;
static int arm64_func_va_list_vr_offs;
static int arm64_func_sub_sp_offset;
ST_FUNC void gfunc_prolog(CType *func_type)
ST_FUNC void gfunc_prolog(Sym *func_sym)
{
CType *func_type = &func_sym->type;
int n = 0;
int i = 0;
Sym *sym;
CType **t;
unsigned long *a;
// Why doesn't the caller (gen_function) set func_vt?
func_vt = func_type->ref->type;
func_vc = 144; // offset of where x8 is stored
for (sym = func_type->ref; sym; sym = sym->next)
@ -1036,7 +1041,7 @@ ST_FUNC void gfunc_prolog(CType *func_type)
a[i] < 32 ? 16 + (a[i] - 16) / 2 * 16 :
224 + ((a[i] - 32) >> 1 << 1));
sym_push(sym->v & ~SYM_FIELD, &sym->type,
(a[i] & 1 ? VT_LLOCAL : VT_LOCAL) | lvalue_type(sym->type.t),
(a[i] & 1 ? VT_LLOCAL : VT_LOCAL) | VT_LVAL,
off);
if (a[i] < 16) {
@ -1123,7 +1128,7 @@ ST_FUNC void gen_va_arg(CType *t)
gaddrof();
r0 = intr(gv(RC_INT));
r1 = get_reg(RC_INT);
vtop[0].r = r1 | lvalue_type(t->t);
vtop[0].r = r1 | VT_LVAL;
r1 = intr(r1);
if (!hfa) {
@ -1276,6 +1281,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)
{
@ -1293,9 +1308,50 @@ ST_FUNC void gjmp_addr(int a)
o(0x14000000 | ((a - ind) >> 2 & 0x3ffffff));
}
ST_FUNC int gtst(int inv, int t)
ST_FUNC int gjmp_append(int n, int t)
{
void *p;
/* insert vtop->c jump list in t */
if (n) {
uint32_t n1 = n, n2;
while ((n2 = read32le(p = cur_text_section->data + n1)))
n1 = n2;
write32le(p, t);
t = n;
}
return t;
}
void arm64_vset_VT_CMP(int op)
{
if (op >= TOK_ULT && op <= TOK_GT) {
vtop->cmp_r = vtop->r;
vset_VT_CMP(0x80);
}
}
static void arm64_gen_opil(int op, uint32_t l);
static void arm64_load_cmp(int r, SValue *sv)
{
sv->r = sv->cmp_r;
if (sv->c.i & 1) {
vpushi(1);
arm64_gen_opil('^', 0);
}
if (r != sv->r) {
load(r, sv);
sv->r = r;
}
}
ST_FUNC int gjmp_cond(int op, int t)
{
int bt = vtop->type.t & VT_BTYPE;
int inv = op & 1;
vtop->r = vtop->cmp_r;
if (bt == VT_LDOUBLE) {
uint32_t a, b, f = fltr(gv(RC_FLOAT));
a = get_reg(RC_INT);
@ -1320,7 +1376,6 @@ ST_FUNC int gtst(int inv, int t)
uint32_t a = intr(gv(RC_INT));
o(0x34000040 | a | !!inv << 24 | ll << 31); // cbz/cbnz wA,.+8
}
--vtop;
return gjmp(t);
}
@ -1549,11 +1604,13 @@ static void arm64_gen_opil(int op, uint32_t l)
ST_FUNC void gen_opi(int op)
{
arm64_gen_opil(op, 0);
arm64_vset_VT_CMP(op);
}
ST_FUNC void gen_opl(int op)
{
arm64_gen_opil(op, 1);
arm64_vset_VT_CMP(op);
}
ST_FUNC void gen_opf(int op)
@ -1653,6 +1710,7 @@ ST_FUNC void gen_opf(int op)
default:
assert(0);
}
arm64_vset_VT_CMP(op);
}
// Generate sign extension from 32 to 64 bits:
@ -1662,6 +1720,16 @@ ST_FUNC void gen_cvt_sxtw(void)
o(0x93407c00 | r | r << 5); // sxtw x(r),w(r)
}
/* char/short to int conversion */
ST_FUNC void gen_cvt_csti(int t)
{
int r = intr(gv(RC_INT));
o(0x13001c00
| ((t & VT_BTYPE) == VT_SHORT) << 13
| (uint32_t)!!(t & VT_UNSIGNED) << 30
| r | r << 5); // [su]xt[bh] w(r),w(r)
}
ST_FUNC void gen_cvt_itof(int t)
{
if (t == VT_LDOUBLE) {
@ -1721,7 +1789,7 @@ ST_FUNC void gen_cvt_ftoi(int t)
ST_FUNC void gen_cvt_ftof(int t)
{
int f = vtop[0].type.t;
int f = vtop[0].type.t & VT_BTYPE;
assert(t == VT_FLOAT || t == VT_DOUBLE || t == VT_LDOUBLE);
assert(f == VT_FLOAT || f == VT_DOUBLE || f == VT_LDOUBLE);
if (t == f)

View File

@ -12,7 +12,7 @@
#define R_NUM R_AARCH64_NUM
#define ELF_START_ADDR 0x00400000
#define ELF_PAGE_SIZE 0x1000
#define ELF_PAGE_SIZE 0x10000
#define PCRELATIVE_DLLPLT 1
#define RELOCATE_DLLPLT 1
@ -46,8 +46,6 @@ int code_reloc (int reloc_type)
case R_AARCH64_JUMP_SLOT:
return 1;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
@ -79,8 +77,6 @@ int gotplt_entry_type (int reloc_type)
case R_AARCH64_LD64_GOT_LO12_NC:
return ALWAYS_GOTPLT_ENTRY;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
@ -152,8 +148,6 @@ ST_FUNC void relocate_plt(TCCState *s1)
}
}
void relocate_init(Section *sr) {}
void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
{
int sym_index = ELFW(R_SYM)(rel->r_info);
@ -215,7 +209,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
case R_AARCH64_ADR_GOT_PAGE: {
uint64_t off =
(((s1->got->sh_addr +
s1->sym_attrs[sym_index].got_offset) >> 12) - (addr >> 12));
get_sym_attr(s1, sym_index, 0)->got_offset) >> 12) - (addr >> 12));
if ((off + ((uint64_t)1 << 20)) >> 21)
tcc_error("R_AARCH64_ADR_GOT_PAGE relocation failed");
write32le(ptr, ((read32le(ptr) & 0x9f00001f) |
@ -226,7 +220,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
write32le(ptr,
((read32le(ptr) & 0xfff803ff) |
((s1->got->sh_addr +
s1->sym_attrs[sym_index].got_offset) & 0xff8) << 7));
get_sym_attr(s1, sym_index, 0)->got_offset) & 0xff8) << 7));
return;
case R_AARCH64_COPY:
return;

View File

@ -56,7 +56,7 @@
#define RC_C67_B12 0x04000000
#define RC_C67_B13 0x08000000
#define RC_IRET RC_C67_A4 /* function return: integer register */
#define RC_LRET RC_C67_A5 /* function return: second integer register */
#define RC_IRE2 RC_C67_A5 /* function return: second integer register */
#define RC_FRET RC_C67_A4 /* function return: float register */
/* pretty names for the registers */
@ -89,7 +89,7 @@ enum {
/* return registers for function */
#define REG_IRET TREG_C67_A4 /* single word int return register */
#define REG_LRET TREG_C67_A5 /* second word return register (for long long) */
#define REG_IRE2 TREG_C67_A5 /* second word return register (for long long) */
#define REG_FRET TREG_C67_A4 /* float return register */
/* defined if function parameters must be evaluated in reverse order */
@ -111,6 +111,7 @@ enum {
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
/******************************************************/
#define USING_GLOBALS
#include "tcc.h"
ST_DATA const int reg_classes[NB_REGS] = {
@ -226,11 +227,6 @@ void gsym_addr(int t, int a)
}
}
void gsym(int t)
{
gsym_addr(t, ind);
}
// these are regs that tcc doesn't really know about,
// but assign them unique values so the mapping routines
// can distinguish them
@ -1944,8 +1940,9 @@ void gfunc_call(int nb_args)
// parameters are loaded and restored upon return (or if/when needed).
/* generate function prolog of type 't' */
void gfunc_prolog(CType * func_type)
void gfunc_prolog(Sym *func_sym)
{
CType *func_type = &func_sym->type;
int addr, align, size, func_call, i;
Sym *sym;
CType *type;
@ -1955,8 +1952,6 @@ void gfunc_prolog(CType * func_type)
addr = 8;
/* if the function returns a structure, then add an
implicit pointer parameter */
func_vt = sym->type;
func_var = (sym->f.func_type == FUNC_ELLIPSIS);
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
func_vc = addr;
addr += 4;
@ -1967,7 +1962,7 @@ void gfunc_prolog(CType * func_type)
/* define parameters */
while ((sym = sym->next) != NULL) {
type = &sym->type;
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t), addr);
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr);
size = type_size(type, &align);
size = (size + 3) & ~3;
@ -2035,6 +2030,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)
{
@ -2067,15 +2072,13 @@ void gjmp_addr(int a)
}
/* generate a test. set 'inv' to invert test. Stack entry is popped */
int gtst(int inv, int t)
ST_FUNC int gjmp_cond(int op, int t)
{
int ind1, n;
int v, *p;
int ind1;
int inv = op & 1;
if (nocode_wanted)
return t;
v = vtop->r & VT_VALMASK;
if (nocode_wanted) {
;
} else if (v == VT_CMP) {
/* fast case : can jump directly since flags are set */
// C67 uses B2 sort of as flags register
ind1 = ind;
@ -2093,16 +2096,18 @@ int gtst(int inv, int t)
C67_NOP(5);
t = ind1; //return where we need to patch
} else if (v == VT_JMP || v == VT_JMPI) {
/* && or || optimization */
if ((v & 1) == inv) {
return t;
}
ST_FUNC int gjmp_append(int n0, int t)
{
if (n0) {
int n = n0, *p;
/* insert vtop->c jump list in t */
// I guess the idea is to traverse to the
// null at the end of the list and store t
// there
n = vtop->c.i;
while (n != 0) {
p = (int *) (cur_text_section->data + n);
@ -2112,14 +2117,8 @@ int gtst(int inv, int t)
}
*p |= (t & 0xffff) << 7;
*(p + 1) |= ((t >> 16) & 0xffff) << 7;
t = vtop->c.i;
} else {
t = gjmp(t);
gsym(vtop->c.i);
}
t = n0;
}
vtop--;
return t;
}
@ -2195,10 +2194,8 @@ void gen_opi(int op)
ALWAYS_ASSERT(FALSE);
vtop--;
if (op >= TOK_ULT && op <= TOK_GT) {
vtop->r = VT_CMP;
vtop->c.i = op;
}
if (op >= TOK_ULT && op <= TOK_GT)
vset_VT_CMP(0x80);
break;
case '-':
case TOK_SUBC1: /* sub with carry generation */
@ -2354,7 +2351,7 @@ void gen_opf(int op)
} else {
ALWAYS_ASSERT(FALSE);
}
vtop->r = VT_CMP; // tell TCC that result is in "flags" actually B2
vset_VT_CMP(0x80);
} else {
if (op == '+') {
if ((ft & VT_BTYPE) == VT_DOUBLE) {
@ -2393,7 +2390,7 @@ void gen_opf(int op)
gfunc_call(2);
vpushi(0);
vtop->r = REG_FRET;
vtop->r2 = REG_LRET;
vtop->r2 = REG_IRE2;
} else {
// must call intrinsic SP floating point divide

View File

@ -39,8 +39,6 @@ int code_reloc (int reloc_type)
case R_C60_PLT32:
return 1;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
@ -64,8 +62,6 @@ int gotplt_entry_type (int reloc_type)
case R_C60_GOT32:
return ALWAYS_GOTPLT_ENTRY;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
@ -95,8 +91,6 @@ ST_FUNC void relocate_plt(TCCState *s1)
}
}
void relocate_init(Section *sr) {}
void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
{
switch(type) {

34
configure vendored
View File

@ -55,7 +55,7 @@ case $targetos in
confvars="$confvars OSX"
DLLSUF=".dylib"
;;
MINGW*|MSYS*|CYGWIN*)
Windows_NT|MINGW*|MSYS*|CYGWIN*)
mingw32=yes
;;
DragonFly|OpenBSD|FreeBSD|NetBSD)
@ -135,6 +135,8 @@ for opt do
;;
--strip-binaries) confvars="$confvars strip"
;;
--debug) confvars="$confvars strip=no"
;;
--with-libgcc) confvars="$confvars libgcc"
;;
--with-selinux) confvars="$confvars selinux"
@ -150,11 +152,15 @@ for opt do
esac
done
cc="${cross_prefix}${cc}"
ar="${cross_prefix}${ar}"
strip="${cross_prefix}${strip}"
if test -z "$cpu" ; then
if test -n "$ARCH" ; then
cpu="$ARCH"
cpu="$ARCH"
else
cpu=`uname -m`
cpu=`uname -m`
fi
fi
@ -197,6 +203,9 @@ case "$cpu" in
s390)
cpu="s390"
;;
riscv64)
cpu="riscv64"
;;
*)
echo "Unsupported CPU"
exit 1
@ -205,14 +214,14 @@ esac
# Checking for CFLAGS
if test -z "$CFLAGS"; then
CFLAGS="-Wall -g -O2"
CFLAGS="-Wall -O2"
fi
if test "$mingw32" = "yes" ; then
if test "$source_path_used" = "no"; then
source_path="."
fi
if test "$cc" = gcc; then
if test "${cc%% *}" = "gcc"; then
test -z "$LDFLAGS" && LDFLAGS="-static"
fi
test -z "$prefix" && prefix="C:/Program Files/tcc"
@ -286,6 +295,7 @@ Advanced options (experts only):
--extra-ldflags= specify linker options []
--cpu=CPU CPU [$cpu]
--strip-binaries strip symbol tables from resulting binaries
--debug include debug info with resulting binaries
--disable-static make libtcc.so instead of libtcc.a
--enable-static make libtcc.a instead of libtcc.dll (win32)
--disable-rpath disable use of -rpath with the above
@ -303,10 +313,6 @@ EOF
exit 1
fi
cc="${cross_prefix}${cc}"
ar="${cross_prefix}${ar}"
strip="${cross_prefix}${strip}"
if test -z "$cross_prefix" ; then
CONFTEST=./conftest$EXESUF
if ! $cc -o $CONFTEST $source_path/conftest.c 2>/dev/null ; then
@ -326,7 +332,7 @@ if test -z "$cross_prefix" ; then
fi
if test -z "$triplet"; then
if test $cpu = "x86_64" -o $cpu = "aarch64" ; then
if test $cpu = "x86_64" -o $cpu = "aarch64" -o $cpu = "riscv64" ; then
if test -f "/usr/lib64/crti.o" ; then
tcc_lddir="lib64"
fi
@ -335,7 +341,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
@ -368,7 +374,7 @@ fi
if ! echo "$cc" | grep -q "tcc"; then
OPT1="-Wdeclaration-after-statement -fno-strict-aliasing"
# we want -Wno- but gcc does not always reject unknown -Wno- options
OPT2="-Wpointer-sign -Wsign-compare -Wunused-result"
OPT2="-Wpointer-sign -Wsign-compare -Wunused-result -Wformat-truncation"
if echo "$cc" | grep -q "clang"; then
OPT1="$OPT1 -fheinous-gnu-extensions"
OPT2="$OPT2 -Wstring-plus-int"
@ -485,6 +491,10 @@ if test "$source_path_used" = "yes" ; then
else
echo 'TOPSRC=$(TOP)' >>config.mak
fi
cat >>$TMPH <<EOF
#define GCC_MAJOR $gcc_major
#define GCC_MINOR $gcc_minor
EOF
diff $TMPH config.h >/dev/null 2>&1
if test $? -ne 0 ; then

View File

@ -1,5 +1,9 @@
#include <stdio.h>
#if defined(_WIN32)
#include <fcntl.h>
#endif
/* Define architecture */
#if defined(__i386__) || defined _M_IX86
# define TRIPLET_ARCH "i386"
@ -9,6 +13,8 @@
# define TRIPLET_ARCH "arm"
#elif defined(__aarch64__)
# define TRIPLET_ARCH "aarch64"
#elif defined(__riscv) && defined(__LP64__)
# define TRIPLET_ARCH "riscv64"
#else
# define TRIPLET_ARCH "unknown"
#endif
@ -49,6 +55,9 @@ int _CRT_glob = 0;
int main(int argc, char *argv[])
{
#if defined(_WIN32)
_setmode(_fileno(stdout), _O_BINARY); /* don't translate \n to \r\n */
#endif
switch(argc == 2 ? argv[1][0] : 0) {
case 'b':
{

71
elf.h
View File

@ -262,7 +262,8 @@ typedef struct
#define EM_AARCH64 183 /* ARM AARCH64 */
#define EM_TILEPRO 188 /* Tilera TILEPro */
#define EM_TILEGX 191 /* Tilera TILE-Gx */
#define EM_NUM 192
#define EM_RISCV 243 /* RISC-V */
#define EM_NUM 253
/* If it is necessary to assign new unofficial EM_* values, please
pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
@ -381,7 +382,7 @@ typedef struct
#define SHF_MASKPROC 0xf0000000 /* Processor-specific */
#define SHF_ORDERED (1 << 30) /* Special ordering requirement
(Solaris). */
#define SHF_EXCLUDE (1 << 31) /* Section is excluded unless
#define SHF_EXCLUDE (1U << 31) /* Section is excluded unless
referenced or allocated (Solaris).*/
/* Section group handling. */
@ -3233,5 +3234,71 @@ typedef Elf32_Addr Elf32_Conflict;
#define R_TILEGX_NUM 130
/* RISC-V ELF Flags */
#define EF_RISCV_RVC 0x0001
#define EF_RISCV_FLOAT_ABI 0x0006
#define EF_RISCV_FLOAT_ABI_SOFT 0x0000
#define EF_RISCV_FLOAT_ABI_SINGLE 0x0002
#define EF_RISCV_FLOAT_ABI_DOUBLE 0x0004
#define EF_RISCV_FLOAT_ABI_QUAD 0x0006
/* RISC-V relocations. */
#define R_RISCV_NONE 0
#define R_RISCV_32 1
#define R_RISCV_64 2
#define R_RISCV_RELATIVE 3
#define R_RISCV_COPY 4
#define R_RISCV_JUMP_SLOT 5
#define R_RISCV_TLS_DTPMOD32 6
#define R_RISCV_TLS_DTPMOD64 7
#define R_RISCV_TLS_DTPREL32 8
#define R_RISCV_TLS_DTPREL64 9
#define R_RISCV_TLS_TPREL32 10
#define R_RISCV_TLS_TPREL64 11
#define R_RISCV_BRANCH 16
#define R_RISCV_JAL 17
#define R_RISCV_CALL 18
#define R_RISCV_CALL_PLT 19
#define R_RISCV_GOT_HI20 20
#define R_RISCV_TLS_GOT_HI20 21
#define R_RISCV_TLS_GD_HI20 22
#define R_RISCV_PCREL_HI20 23
#define R_RISCV_PCREL_LO12_I 24
#define R_RISCV_PCREL_LO12_S 25
#define R_RISCV_HI20 26
#define R_RISCV_LO12_I 27
#define R_RISCV_LO12_S 28
#define R_RISCV_TPREL_HI20 29
#define R_RISCV_TPREL_LO12_I 30
#define R_RISCV_TPREL_LO12_S 31
#define R_RISCV_TPREL_ADD 32
#define R_RISCV_ADD8 33
#define R_RISCV_ADD16 34
#define R_RISCV_ADD32 35
#define R_RISCV_ADD64 36
#define R_RISCV_SUB8 37
#define R_RISCV_SUB16 38
#define R_RISCV_SUB32 39
#define R_RISCV_SUB64 40
#define R_RISCV_GNU_VTINHERIT 41
#define R_RISCV_GNU_VTENTRY 42
#define R_RISCV_ALIGN 43
#define R_RISCV_RVC_BRANCH 44
#define R_RISCV_RVC_JUMP 45
#define R_RISCV_RVC_LUI 46
#define R_RISCV_GPREL_I 47
#define R_RISCV_GPREL_S 48
#define R_RISCV_TPREL_I 49
#define R_RISCV_TPREL_S 50
#define R_RISCV_RELAX 51
#define R_RISCV_SUB6 52
#define R_RISCV_SET6 53
#define R_RISCV_SET8 54
#define R_RISCV_SET16 55
#define R_RISCV_SET32 56
#define R_RISCV_32_PCREL 57
#define R_RISCV_NUM 58
#endif /* elf.h */

View File

@ -19,6 +19,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define USING_GLOBALS
#include "tcc.h"
#define MAX_OPERANDS 3

View File

@ -37,7 +37,7 @@
#define RC_EBX 0x0040
#define RC_IRET RC_EAX /* function return: integer register */
#define RC_LRET RC_EDX /* function return: second integer register */
#define RC_IRE2 RC_EDX /* function return: second integer register */
#define RC_FRET RC_ST0 /* function return: float register */
/* pretty names for the registers */
@ -52,7 +52,7 @@ enum {
/* return registers for function */
#define REG_IRET TREG_EAX /* single word int return register */
#define REG_LRET TREG_EDX /* second word return register (for long long) */
#define REG_IRE2 TREG_EDX /* second word return register (for long long) */
#define REG_FRET TREG_ST0 /* float return register */
/* defined if function parameters must be evaluated in reverse order */
@ -71,9 +71,14 @@ enum {
/* maximum alignment (for aligned attribute support) */
#define MAX_ALIGN 8
/* define if return values need to be extended explicitely
at caller side (for interfacing with non-TCC compilers) */
#define PROMOTE_RET
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
/******************************************************/
#define USING_GLOBALS
#include "tcc.h"
/* define to 1/0 to [not] have EBX as 4th register */
@ -92,6 +97,9 @@ static int func_ret_sub;
#ifdef CONFIG_TCC_BCHECK
static addr_t func_bound_offset;
static unsigned long func_bound_ind;
static int func_bound_alloca_used;
static void gen_bounds_prolog(void);
static void gen_bounds_epilog(void);
#endif
/* XXX: make it faster ? */
@ -140,11 +148,6 @@ ST_FUNC void gsym_addr(int t, int a)
}
}
ST_FUNC void gsym(int t)
{
gsym_addr(t, ind);
}
/* instruction + 4 bytes data. Return the address of the data */
static int oad(int c, int s)
{
@ -157,6 +160,12 @@ 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)
@ -260,10 +269,10 @@ ST_FUNC void load(int r, SValue *sv)
o(0xe8 + r); /* mov %ebp, r */
}
} else if (v == VT_CMP) {
oad(0xb8 + r, 0); /* mov $0, r */
o(0x0f); /* setxx %br */
o(fc);
o(0xc0 + r);
o(0xc0b60f + r * 0x90000); /* movzbl %al, %eax */
} else if (v == VT_JMP || v == VT_JMPI) {
t = v & 1;
oad(0xb8 + r, t); /* mov $1, r */
@ -335,7 +344,7 @@ static void gen_static_call(int v)
{
Sym *sym;
sym = external_global_sym(v, &func_old_type, 0);
sym = external_global_sym(v, &func_old_type);
oad(0xe8, -4);
greloc(cur_text_section, sym, ind-4, R_386_PC32);
}
@ -349,39 +358,16 @@ static void gcall_or_jmp(int is_jmp)
/* 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 */
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check && vtop->sym->v == TOK_alloca)
func_bound_alloca_used = 1;
#endif
} 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 */
rt = vtop->type.ref->type.t;
switch (rt & VT_BTYPE) {
case VT_BYTE:
if (rt & VT_UNSIGNED) {
o(0xc0b60f); /* movzx %al, %eax */
}
else {
o(0xc0be0f); /* movsx %al, %eax */
}
break;
case VT_SHORT:
if (rt & VT_UNSIGNED) {
o(0xc0b70f); /* movzx %ax, %eax */
}
else {
o(0xc0bf0f); /* movsx %ax, %eax */
}
break;
default:
break;
}
}
}
static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
@ -422,6 +408,11 @@ ST_FUNC void gfunc_call(int nb_args)
int size, align, r, args_size, i, func_call;
Sym *func_sym;
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check)
gbound_args(nb_args);
#endif
args_size = 0;
for(i = 0;i < nb_args; i++) {
if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
@ -496,6 +487,7 @@ ST_FUNC void gfunc_call(int nb_args)
else if ((vtop->type.ref->type.t & VT_BTYPE) == VT_STRUCT)
args_size -= 4;
#endif
gcall_or_jmp(0);
if (args_size && func_call != FUNC_STDCALL && func_call != FUNC_FASTCALLW)
@ -510,8 +502,9 @@ ST_FUNC void gfunc_call(int nb_args)
#endif
/* generate function prolog of type 't' */
ST_FUNC void gfunc_prolog(CType *func_type)
ST_FUNC void gfunc_prolog(Sym *func_sym)
{
CType *func_type = &func_sym->type;
int addr, align, size, func_call, fastcall_nb_regs;
int param_index, param_addr;
uint8_t *fastcall_regs_ptr;
@ -540,8 +533,6 @@ ST_FUNC void gfunc_prolog(CType *func_type)
func_sub_sp_offset = ind;
/* if the function returns a structure, then add an
implicit pointer parameter */
func_vt = sym->type;
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)
@ -576,7 +567,7 @@ ST_FUNC void gfunc_prolog(CType *func_type)
addr += size;
}
sym_push(sym->v & ~SYM_FIELD, type,
VT_LOCAL | lvalue_type(type->t), param_addr);
VT_LOCAL | VT_LVAL, param_addr);
param_index++;
}
func_ret_sub = 0;
@ -589,13 +580,8 @@ ST_FUNC void gfunc_prolog(CType *func_type)
#endif
#ifdef CONFIG_TCC_BCHECK
/* leave some room for bound checking code */
if (tcc_state->do_bounds_check) {
func_bound_offset = lbounds_section->data_offset;
func_bound_ind = ind;
oad(0xb8, 0); /* lbound section pointer */
oad(0xb8, 0); /* call to function */
}
if (tcc_state->do_bounds_check)
gen_bounds_prolog();
#endif
}
@ -605,34 +591,8 @@ ST_FUNC void gfunc_epilog(void)
addr_t v, saved_ind;
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check
&& func_bound_offset != lbounds_section->data_offset) {
addr_t saved_ind;
addr_t *bounds_ptr;
Sym *sym_data;
/* add end of table info */
bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
*bounds_ptr = 0;
/* generate bound local allocation */
saved_ind = ind;
ind = func_bound_ind;
sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
func_bound_offset, lbounds_section->data_offset);
greloc(cur_text_section, sym_data,
ind + 1, R_386_32);
oad(0xb8, 0); /* mov %eax, xxx */
gen_static_call(TOK___bound_local_new);
ind = saved_ind;
/* generate bound check local freeing */
o(0x5250); /* save returned value, if any */
greloc(cur_text_section, sym_data, ind + 1, R_386_32);
oad(0xb8, 0); /* mov %eax, xxx */
gen_static_call(TOK___bound_local_delete);
o(0x585a); /* restore returned value, if any */
}
if (tcc_state->do_bounds_check)
gen_bounds_epilog();
#endif
/* align local size to word & save local variables */
@ -690,63 +650,39 @@ ST_FUNC void gjmp_addr(int a)
}
}
ST_FUNC void gtst_addr(int inv, int a)
#if 0
/* generate a jump to a fixed address */
ST_FUNC void gjmp_cond_addr(int a, int op)
{
int v = vtop->r & VT_VALMASK;
if (v == VT_CMP) {
inv ^= (vtop--)->c.i;
a -= ind + 2;
if (a == (char)a) {
g(inv - 32);
g(a);
} else {
g(0x0f);
oad(inv - 16, a - 4);
}
} else if ((v & ~1) == VT_JMP) {
if ((v & 1) != inv) {
gjmp_addr(a);
gsym(vtop->c.i);
} else {
gsym(vtop->c.i);
o(0x05eb);
gjmp_addr(a);
}
vtop--;
}
int r = a - ind - 2;
if (r == (char)r)
g(op - 32), g(r);
else
g(0x0f), gjmp2(op - 16, r - 4);
}
#endif
/* generate a test. set 'inv' to invert test. Stack entry is popped */
ST_FUNC int gtst(int inv, int t)
ST_FUNC int gjmp_append(int n, int t)
{
int v = vtop->r & VT_VALMASK;
if (nocode_wanted) {
;
} else if (v == VT_CMP) {
/* fast case : can jump directly since flags are set */
g(0x0f);
t = gjmp2((vtop->c.i - 16) ^ inv, t);
} else if (v == VT_JMP || v == VT_JMPI) {
/* && or || optimization */
if ((v & 1) == inv) {
/* insert vtop->c jump list in t */
uint32_t n1, n = vtop->c.i;
if (n) {
while ((n1 = read32le(cur_text_section->data + n)))
n = n1;
write32le(cur_text_section->data + n, t);
t = vtop->c.i;
}
} else {
t = gjmp(t);
gsym(vtop->c.i);
}
void *p;
/* insert vtop->c jump list in t */
if (n) {
uint32_t n1 = n, n2;
while ((n2 = read32le(p = cur_text_section->data + n1)))
n1 = n2;
write32le(p, t);
t = n;
}
vtop--;
return t;
}
/* generate an integer binary operation */
ST_FUNC int gjmp_cond(int op, int t)
{
g(0x0f);
t = gjmp2(op - 16, t);
return t;
}
ST_FUNC void gen_opi(int op)
{
int r, fr, opc, c;
@ -764,10 +700,9 @@ ST_FUNC void gen_opi(int op)
c = vtop->c.i;
if (c == (char)c) {
/* generate inc and dec for smaller code */
if (c==1 && opc==0 && op != TOK_ADDC1) {
o (0x40 | r); // inc
} else if (c==1 && opc==5 && op != TOK_SUBC1) {
o (0x48 | r); // dec
if ((c == 1 || c == -1) && (op == '+' || op == '-')) {
opc = (c == 1) ^ (op == '+');
o (0x40 | (opc << 3) | r); // inc,dec
} else {
o(0x83);
o(0xc0 | (opc << 3) | r);
@ -785,10 +720,8 @@ ST_FUNC void gen_opi(int op)
o(0xc0 + r + fr * 8);
}
vtop--;
if (op >= TOK_ULT && op <= TOK_GT) {
vtop->r = VT_CMP;
vtop->c.i = op;
}
if (op >= TOK_ULT && op <= TOK_GT)
vset_VT_CMP(op);
break;
case '-':
case TOK_SUBC1: /* sub with carry generation */
@ -946,8 +879,7 @@ ST_FUNC void gen_opf(int op)
op = TOK_EQ;
}
vtop--;
vtop->r = VT_CMP;
vtop->c.i = op;
vset_VT_CMP(op);
} else {
/* no memory reference possible for long double operations */
if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
@ -1015,6 +947,7 @@ ST_FUNC void gen_cvt_itof(int t)
o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
o(0x242cdf); /* fildll (%esp) */
o(0x08c483); /* add $8, %esp */
vtop->r2 = VT_CONST;
} else if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) ==
(VT_INT | VT_UNSIGNED)) {
/* unsigned int to float/double/long double */
@ -1029,6 +962,7 @@ ST_FUNC void gen_cvt_itof(int t)
o(0x2404db); /* fildl (%esp) */
o(0x04c483); /* add $4, %esp */
}
vtop->r2 = VT_CONST;
vtop->r = TREG_ST0;
}
@ -1046,7 +980,8 @@ ST_FUNC void gen_cvt_ftoi(int t)
gfunc_call(1);
vpushi(0);
vtop->r = REG_IRET;
vtop->r2 = REG_LRET;
if ((t & VT_BTYPE) == VT_LLONG)
vtop->r2 = REG_IRE2;
}
/* convert from one floating point type to another */
@ -1056,6 +991,19 @@ ST_FUNC void gen_cvt_ftof(int t)
gv(RC_FLOAT);
}
/* char/short to int conversion */
ST_FUNC void gen_cvt_csti(int t)
{
int r, sz, xl;
r = gv(RC_INT);
sz = !(t & VT_UNSIGNED);
xl = (t & VT_BTYPE) == VT_SHORT;
o(0xc0b60f /* mov[sz] %a[xl], %eax */
| (sz << 3 | xl) << 8
| (r << 3 | r) << 16
);
}
/* computed goto support */
ST_FUNC void ggoto(void)
{
@ -1065,21 +1013,18 @@ ST_FUNC void ggoto(void)
/* bound check support functions */
#ifdef CONFIG_TCC_BCHECK
/* generate a bounded pointer addition */
ST_FUNC void gen_bounded_ptr_add(void)
{
/* prepare fast i386 function call (args in eax and edx) */
gv2(RC_EAX, RC_EDX);
/* save all temporary registers */
vtop -= 2;
save_regs(0);
/* do a fast function call */
gen_static_call(TOK___bound_ptr_add);
vpush_global_sym(&func_old_type, TOK___bound_ptr_add);
vrott(3);
gfunc_call(2);
vpushi(0);
/* returned pointer is in eax */
vtop++;
vtop->r = TREG_EAX | VT_BOUNDED;
/* address of bounding function call point */
if (nocode_wanted)
return;
/* relocation offset of the bounding function call point */
vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(Elf32_Rel));
}
@ -1092,16 +1037,10 @@ ST_FUNC void gen_bounded_ptr_deref(void)
Elf32_Rel *rel;
Sym *sym;
size = 0;
/* XXX: put that code in generic part of tcc */
if (!is_float(vtop->type.t)) {
if (vtop->r & VT_LVAL_BYTE)
size = 1;
else if (vtop->r & VT_LVAL_SHORT)
size = 2;
}
if (!size)
size = type_size(&vtop->type, &align);
if (nocode_wanted)
return;
size = type_size(&vtop->type, &align);
switch(size) {
case 1: func = TOK___bound_ptr_indir1; break;
case 2: func = TOK___bound_ptr_indir2; break;
@ -1110,19 +1049,61 @@ ST_FUNC void gen_bounded_ptr_deref(void)
case 12: func = TOK___bound_ptr_indir12; break;
case 16: func = TOK___bound_ptr_indir16; break;
default:
tcc_error("unhandled size when dereferencing bounded pointer");
func = 0;
break;
/* may happen with struct member access */
return;
//tcc_error("unhandled size when dereferencing bounded pointer");
//func = 0;
//break;
}
sym = external_global_sym(func, &func_old_type);
if (!sym->c)
put_extern_sym(sym, NULL, 0, 0);
/* patch relocation */
/* XXX: find a better solution ? */
rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.i);
sym = external_global_sym(func, &func_old_type, 0);
if (!sym->c)
put_extern_sym(sym, NULL, 0, 0);
rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info));
}
static void gen_bounds_prolog(void)
{
/* leave some room for bound checking code */
func_bound_offset = lbounds_section->data_offset;
func_bound_ind = ind;
func_bound_alloca_used = 0;
oad(0xb8, 0); /* lbound section pointer */
oad(0xb8, 0); /* call to function */
}
static void gen_bounds_epilog(void)
{
addr_t saved_ind;
addr_t *bounds_ptr;
Sym *sym_data;
if (func_bound_offset == lbounds_section->data_offset && !func_bound_alloca_used)
return;
/* add end of table info */
bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
*bounds_ptr = 0;
/* generate bound local allocation */
saved_ind = ind;
ind = func_bound_ind;
sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
func_bound_offset, lbounds_section->data_offset);
greloc(cur_text_section, sym_data, ind + 1, R_386_32);
ind = ind + 5;
gen_static_call(TOK___bound_local_new);
ind = saved_ind;
/* generate bound check local freeing */
o(0x5250); /* save returned value, if any */
greloc(cur_text_section, sym_data, ind + 1, R_386_32);
oad(0xb8, 0); /* mov %eax, xxx */
gen_static_call(TOK___bound_local_delete);
o(0x585a); /* restore returned value, if any */
}
#endif
/* Save the stack pointer onto the stack */
@ -1140,22 +1121,31 @@ ST_FUNC void gen_vla_sp_restore(int addr) {
/* Subtract from the stack pointer, and push the resulting value onto the stack */
ST_FUNC void gen_vla_alloc(CType *type, int align) {
#ifdef TCC_TARGET_PE
/* alloca does more than just adjust %rsp on Windows */
vpush_global_sym(&func_old_type, TOK_alloca);
vswap(); /* Move alloca ref past allocation size */
gfunc_call(1);
#else
int r;
r = gv(RC_INT); /* allocation size */
/* sub r,%rsp */
o(0x2b);
o(0xe0 | r);
/* We align to 16 bytes rather than align */
/* and ~15, %esp */
o(0xf0e483);
vpop();
int use_call = 0;
#if defined(CONFIG_TCC_BCHECK)
use_call = tcc_state->do_bounds_check;
#endif
#ifdef TCC_TARGET_PE /* alloca does more than just adjust %rsp on Windows */
use_call = 1;
#endif
if (use_call)
{
vpush_global_sym(&func_old_type, TOK_alloca);
vswap(); /* Move alloca ref past allocation size */
gfunc_call(1);
}
else {
int r;
r = gv(RC_INT); /* allocation size */
/* sub r,%rsp */
o(0x2b);
o(0xe0 | r);
/* We align to 16 bytes rather than align */
/* and ~15, %esp */
o(0xf0e483);
vpop();
}
}
/* end of X86 code generator */

View File

@ -22,6 +22,7 @@
#include "tcc.h"
#ifndef ELF_OBJ_ONLY
/* Returns 1 for a code relocation, 0 for a data relocation. For unknown
relocations, returns -1. */
int code_reloc (int reloc_type)
@ -44,8 +45,6 @@ int code_reloc (int reloc_type)
case R_386_JMP_SLOT:
return 1;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
@ -81,8 +80,6 @@ int gotplt_entry_type (int reloc_type)
case R_386_PLT32:
return ALWAYS_GOTPLT_ENTRY;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
@ -152,13 +149,7 @@ ST_FUNC void relocate_plt(TCCState *s1)
}
}
}
static ElfW_Rel *qrel; /* ptr to next reloc entry reused */
void relocate_init(Section *sr)
{
qrel = (ElfW_Rel *) sr->data;
}
#endif
void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
{
@ -169,7 +160,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
switch (type) {
case R_386_32:
if (s1->output_type == TCC_OUTPUT_DLL) {
esym_index = s1->sym_attrs[sym_index].dyn_index;
esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index;
qrel->r_offset = rel->r_offset;
if (esym_index) {
qrel->r_info = ELFW(R_INFO)(esym_index, R_386_32);
@ -185,7 +176,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
case R_386_PC32:
if (s1->output_type == TCC_OUTPUT_DLL) {
/* DLL relocation */
esym_index = s1->sym_attrs[sym_index].dyn_index;
esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index;
if (esym_index) {
qrel->r_offset = rel->r_offset;
qrel->r_info = ELFW(R_INFO)(esym_index, R_386_PC32);
@ -211,7 +202,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
case R_386_GOT32:
case R_386_GOT32X:
/* we load the got offset */
add32le(ptr, s1->sym_attrs[sym_index].got_offset);
add32le(ptr, get_sym_attr(s1, sym_index, 0)->got_offset);
return;
case R_386_16:
if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) {

16
include/stdalign.h 100644
View File

@ -0,0 +1,16 @@
#ifndef _STDALIGN_H
#define _STDALIGN_H
#if __STDC_VERSION__ < 201112L && (defined(__GNUC__) || defined(__TINYC__))
# define _Alignas(t) __attribute__((__aligned__(t)))
# define _Alignof(t) __alignof__(t)
#endif
#define alignas _Alignas
#define alignof _Alignof
#define __alignas_is_defined 1
#define __alignof_is_defined 1
#endif /* _STDALIGN_H */

View File

@ -1,76 +1,11 @@
#ifndef _STDARG_H
#define _STDARG_H
#ifdef __x86_64__
#ifndef _WIN64
//This should be in sync with the declaration on our lib/libtcc1.c
/* GCC compatible definition of va_list. */
typedef struct {
unsigned int gp_offset;
unsigned int fp_offset;
union {
unsigned int overflow_offset;
char *overflow_arg_area;
};
char *reg_save_area;
} __va_list_struct;
typedef __va_list_struct va_list[1];
void __va_start(__va_list_struct *ap, void *fp);
void *__va_arg(__va_list_struct *ap, int arg_type, int size, int align);
#define va_start(ap, last) __va_start(ap, __builtin_frame_address(0))
#define va_arg(ap, type) \
(*(type *)(__va_arg(ap, __builtin_va_arg_types(type), sizeof(type), __alignof__(type))))
#define va_copy(dest, src) (*(dest) = *(src))
#define va_end(ap)
/* avoid conflicting definition for va_list on Macs. */
#define _VA_LIST_T
#else /* _WIN64 */
typedef char *va_list;
#define va_start(ap,last) __builtin_va_start(ap,last)
#define va_arg(ap, t) ((sizeof(t) > 8 || (sizeof(t) & (sizeof(t) - 1))) \
? **(t **)((ap += 8) - 8) : *(t *)((ap += 8) - 8))
#define va_copy(dest, src) ((dest) = (src))
#define va_end(ap)
#endif
#elif __arm__
typedef char *va_list;
#define _tcc_alignof(type) ((int)&((struct {char c;type x;} *)0)->x)
#define _tcc_align(addr,type) (((unsigned)addr + _tcc_alignof(type) - 1) \
& ~(_tcc_alignof(type) - 1))
#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)
#define va_arg(ap,type) (ap = (void *) ((_tcc_align(ap,type)+sizeof(type)+3) \
&~3), *(type *)(ap - ((sizeof(type)+3)&~3)))
#define va_copy(dest, src) (dest) = (src)
#define va_end(ap)
#elif defined(__aarch64__)
typedef struct {
void *__stack;
void *__gr_top;
void *__vr_top;
int __gr_offs;
int __vr_offs;
} va_list;
#define va_start(ap, last) __va_start(ap, last)
#define va_arg(ap, type) __va_arg(ap, type)
#define va_end(ap)
#define va_copy(dest, src) ((dest) = (src))
#else /* __i386__ */
typedef char *va_list;
/* only correct for i386 */
#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)
#define va_arg(ap,type) (ap += (sizeof(type)+3)&~3, *(type *)(ap - ((sizeof(type)+3)&~3)))
#define va_copy(dest, src) (dest) = (src)
#define va_end(ap)
#endif
typedef __builtin_va_list va_list;
#define va_start __builtin_va_start
#define va_arg __builtin_va_arg
#define va_copy __builtin_va_copy
#define va_end __builtin_va_end
/* fix a buggy dependency on GCC in libio.h */
typedef va_list __gnuc_va_list;

View File

@ -8,6 +8,10 @@ typedef __PTRDIFF_TYPE__ ptrdiff_t;
typedef __PTRDIFF_TYPE__ intptr_t;
typedef __SIZE_TYPE__ uintptr_t;
#if __STDC_VERSION__ >= 201112L
typedef union { long long __ll; long double __ld; } max_align_t;
#endif
#ifndef __int8_t_defined
#define __int8_t_defined
typedef signed char int8_t;

View File

@ -0,0 +1,7 @@
#ifndef _STDNORETURN_H
#define _STDNORETURN_H
/* ISOC11 noreturn */
#define noreturn _Noreturn
#endif /* _STDNORETURN_H */

View File

@ -0,0 +1,64 @@
#ifdef __x86_64__
#ifndef _WIN64
//This should be in sync with the declaration in our lib/libtcc1.c
/* GCC compatible definition of va_list. */
typedef struct {
unsigned int gp_offset;
unsigned int fp_offset;
union {
unsigned int overflow_offset;
char *overflow_arg_area;
};
char *reg_save_area;
} __builtin_va_list[1];
void *__va_arg(__builtin_va_list ap, int arg_type, int size, int align);
#define __builtin_va_start(ap, last) \
(*(ap) = *(__builtin_va_list)((char*)__builtin_frame_address(0) - 24))
#define __builtin_va_arg(ap, t) \
(*(t *)(__va_arg(ap, __builtin_va_arg_types(t), sizeof(t), __alignof__(t))))
#define __builtin_va_copy(dest, src) (*(dest) = *(src))
#else /* _WIN64 */
typedef char *__builtin_va_list;
#define __builtin_va_arg(ap, t) ((sizeof(t) > 8 || (sizeof(t) & (sizeof(t) - 1))) \
? **(t **)((ap += 8) - 8) : *(t *)((ap += 8) - 8))
#endif
#elif __arm__
typedef char *__builtin_va_list;
#define _tcc_alignof(type) ((int)&((struct {char c;type x;} *)0)->x)
#define _tcc_align(addr,type) (((unsigned)addr + _tcc_alignof(type) - 1) \
& ~(_tcc_alignof(type) - 1))
#define __builtin_va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)
#define __builtin_va_arg(ap,type) (ap = (void *) ((_tcc_align(ap,type)+sizeof(type)+3) \
&~3), *(type *)(ap - ((sizeof(type)+3)&~3)))
#elif defined(__aarch64__)
typedef struct {
void *__stack;
void *__gr_top;
void *__vr_top;
int __gr_offs;
int __vr_offs;
} __builtin_va_list;
#elif defined __riscv
typedef char *__builtin_va_list;
#define __va_reg_size (__riscv_xlen >> 3)
#define _tcc_align(addr,type) (((unsigned long)addr + __alignof__(type) - 1) \
& -(__alignof__(type)))
#define __builtin_va_arg(ap,type) (*(sizeof(type) > (2*__va_reg_size) ? *(type **)((ap += __va_reg_size) - __va_reg_size) : (ap = (va_list)(_tcc_align(ap,type) + (sizeof(type)+__va_reg_size - 1)& -__va_reg_size), (type *)(ap - ((sizeof(type)+ __va_reg_size - 1)& -__va_reg_size)))))
#else /* __i386__ */
typedef char *__builtin_va_list;
#define __builtin_va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)
#define __builtin_va_arg(ap,type) (ap += (sizeof(type)+3)&~3, *(type *)(ap - ((sizeof(type)+3)&~3)))
#endif
#ifndef __builtin_va_copy
#define __builtin_va_copy(dest, src) (dest) = (src)
#endif
#define __builtin_va_end(ap) (void)(ap)

View File

@ -7,15 +7,15 @@ include $(TOP)/Makefile
VPATH = $(TOPSRC)/lib $(TOPSRC)/win32/lib
T = $(or $(CROSS_TARGET),$(NATIVE_TARGET),unknown)
X = $(if $(CROSS_TARGET),$(CROSS_TARGET)-)
BIN = $(TOP)/$(X)libtcc1.a
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))
XFLAGS = $(XFLAGS$(XCFG)) -I$(TOP)
XCFG = $(or $(findstring -win,$T),-unx)
S = $(if $(findstring yes,$(SILENT)),@$(info * $@))
# in order to use gcc, tyoe: make <target>-libtcc1-usegcc=yes
arm-libtcc1-usegcc ?= no
@ -28,46 +28,61 @@ endif
# only for native compiler
$(X)BCHECK_O = bcheck.o
$(X)BT_O = bt-exe.o bt-log.o
$(X)B_O = bcheck.o bt-exe.o bt-log.o bt-dll.o
ifeq ($(CONFIG_musl)$(CONFIG_uClibc),yes)
BCHECK_O =
else
DSO_O = dsohandle.o
endif
ifdef CONFIG_OSX
XFLAGS += -D_ANSI_SOURCE
endif
I386_O = libtcc1.o alloca86.o alloca86-bt.o
X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o
ARM_O = libtcc1.o armeabi.o alloca-arm.o armflush.o
ARM64_O = lib-arm64.o
I386_O = libtcc1.o alloca86.o alloca86-bt.o $(BT_O)
X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o $(BT_O)
ARM_O = libtcc1.o armeabi.o alloca-arm.o armflush.o $(BT_O)
ARM64_O = lib-arm64.o $(BT_O)
RISCV64_O = lib-arm64.o $(BT_O)
WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o
OBJ-i386 = $(I386_O) $(BCHECK_O)
OBJ-x86_64 = $(X86_64_O) va_list.o $(BCHECK_O)
OBJ-i386 = $(I386_O) $(BCHECK_O) $(DSO_O)
OBJ-x86_64 = $(X86_64_O) va_list.o $(BCHECK_O) $(DSO_O)
OBJ-x86_64-osx = $(X86_64_O) va_list.o
OBJ-i386-win32 = $(I386_O) chkstk.o bcheck.o $(WIN_O)
OBJ-x86_64-win32 = $(X86_64_O) chkstk.o bcheck.o $(WIN_O)
OBJ-arm64 = $(ARM64_O)
OBJ-arm = $(ARM_O)
OBJ-arm-fpa = $(ARM_O)
OBJ-arm-fpa-ld = $(ARM_O)
OBJ-arm-vfp = $(ARM_O)
OBJ-arm-eabi = $(ARM_O)
OBJ-arm-eabihf = $(ARM_O)
OBJ-i386-win32 = $(I386_O) chkstk.o $(B_O) $(WIN_O)
OBJ-x86_64-win32 = $(X86_64_O) chkstk.o $(B_O) $(WIN_O)
OBJ-arm64 = $(ARM64_O) $(DSO_O)
OBJ-arm = $(ARM_O) $(DSO_O)
OBJ-arm-fpa = $(ARM_O) $(DSO_O)
OBJ-arm-fpa-ld = $(ARM_O) $(DSO_O)
OBJ-arm-vfp = $(ARM_O) $(DSO_O)
OBJ-arm-eabi = $(ARM_O) $(DSO_O)
OBJ-arm-eabihf = $(ARM_O) $(DSO_O)
OBJ-arm-wince = $(ARM_O) $(WIN_O)
OBJ-riscv64 = $(RISCV64_O) $(DSO_O)
$(BIN) : $(patsubst %.o,$(X)%.o,$(OBJ-$T))
$(XAR) rcs $@ $^
OBJ-extra = $(filter $(B_O),$(OBJ-$T))
OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T)))
ALL = $(addprefix $(TOP)/,$(X)libtcc1.a $(OBJ-extra))
all: $(ALL)
$(TOP)/$(X)libtcc1.a : $(OBJ-libtcc1)
$S$(XAR) rcs $@ $^
$(X)%.o : %.c
$(XCC) -c $< -o $@ $(XFLAGS)
$S$(XCC) -c $< -o $@ $(XFLAGS)
$(X)%.o : %.S
$(XCC) -c $< -o $@ $(XFLAGS)
$S$(XCC) -c $< -o $@ $(XFLAGS)
$(TOP)/%.o : %.c
$S$(XCC) -c $< -o $@ $(XFLAGS)
$(TOP)/bcheck.o : XFLAGS += -g
$(TOP)/bt-exe.o : $(TOP)/tccrun.c
$(X)crt1w.o : crt1.c
$(X)wincrt1w.o : wincrt1.c
clean :
rm -f *.a *.o $(BIN)
rm -f *.a *.o $(ALL)

View File

@ -5,35 +5,25 @@
__bound_alloca:
#ifdef _WIN32
# bound checking is not implemented
pop %rdx
mov %rcx,%rax
add $15,%rax
and $-16,%rax
jz p3
p1:
cmp $4096,%rax
jbe p2
test %rax,-4096(%rsp)
sub $4096,%rsp
sub $4096,%rax
jmp p1
p2:
sub %rax,%rsp
mov %rsp,%rax
add $32,%rax
p3:
push %rdx
inc %rcx # add one extra to separate regions
jmp alloca
.globl __bound_alloca_nr
__bound_alloca_nr:
dec %rcx
push %rax
mov %rcx,%rdx
mov %rax,%rcx
sub $32,%rsp
call __bound_new_region
add $32,%rsp
pop %rax
ret
#else
pop %rdx
mov %rdi,%rax
mov %rax,%rsi # size, a second parm to the __bound_new_region
add $15,%rax
add $15 + 1,%rax # add one extra to separate regions
and $-16,%rax
jz p3

View File

@ -24,7 +24,6 @@ p1:
jmp p1
p2:
#endif
sub %rax,%rsp
mov %rsp,%rax
p3:

View File

@ -7,12 +7,12 @@
#ifdef __TINYC__
/* syscall wrapper */
unsigned syscall(unsigned syscall_nr, ...);
unsigned _tccsyscall(unsigned syscall_nr, ...);
/* arm-tcc supports only fake asm currently */
__asm__(
".global syscall\n"
"syscall:\n"
".global _tccsyscall\n"
"_tccsyscall:\n"
".int 0xe92d4080\n" // push {r7, lr}
".int 0xe1a07000\n" // mov r7, r0
".int 0xe1a00001\n" // mov r0, r1
@ -31,6 +31,8 @@ __asm__(
#define __ARM_NR_BASE (__NR_SYSCALL_BASE+0x0f0000)
#define __ARM_NR_cacheflush (__ARM_NR_BASE+2)
#define syscall _tccsyscall
#else
#define _GNU_SOURCE

File diff suppressed because it is too large Load Diff

67
lib/bt-dll.c 100644
View File

@ -0,0 +1,67 @@
/* ------------------------------------------------------------- */
/* stubs for calling bcheck functions from a dll. */
#include <windows.h>
#include <stdio.h>
#define REDIR_ALL \
REDIR(__bt_init) \
REDIR(tcc_backtrace) \
\
REDIR(__bound_ptr_add) \
REDIR(__bound_ptr_indir1) \
REDIR(__bound_ptr_indir2) \
REDIR(__bound_ptr_indir4) \
REDIR(__bound_ptr_indir8) \
REDIR(__bound_ptr_indir12) \
REDIR(__bound_ptr_indir16) \
REDIR(__bound_local_new) \
REDIR(__bound_local_delete) \
REDIR(__bound_new_region) \
\
REDIR(__bound_free) \
REDIR(__bound_malloc) \
REDIR(__bound_realloc) \
REDIR(__bound_memcpy) \
REDIR(__bound_memcmp) \
REDIR(__bound_memmove) \
REDIR(__bound_memset) \
REDIR(__bound_strlen) \
REDIR(__bound_strcpy) \
REDIR(__bound_strncpy) \
REDIR(__bound_strcmp) \
REDIR(__bound_strncmp) \
REDIR(__bound_strcat) \
REDIR(__bound_strchr) \
REDIR(__bound_strdup)
#define REDIR(s) void *s;
static struct { REDIR_ALL } all_ptrs;
#undef REDIR
#define REDIR(s) #s"\0"
static const char all_names[] = REDIR_ALL;
#undef REDIR
#define REDIR(s) __asm__(".global "#s";"#s": jmp *%0" : : "m" (all_ptrs.s) );
static void all_jmps() { REDIR_ALL }
#undef REDIR
void __bt_init_dll(int bcheck)
{
const char *s = all_names;
void **p = (void**)&all_ptrs;
do {
*p = (void*)GetProcAddress(GetModuleHandle(NULL), (char*)s);
if (NULL == *p) {
char buf[100];
sprintf(buf,
"Error: function '%s()' not found in executable. "
"(Need -bt or -b for linking the exe.)", s);
if (GetStdHandle(STD_ERROR_HANDLE))
fprintf(stderr, "TCC/BCHECK: %s\n", buf), fflush(stderr);
else
MessageBox(NULL, buf, "TCC/BCHECK", MB_ICONERROR);
ExitProcess(1);
}
s = strchr(s,'\0') + 1, ++p;
} while (*s && (bcheck || p < &all_ptrs.__bound_ptr_add));
}

43
lib/bt-exe.c 100644
View File

@ -0,0 +1,43 @@
/* ------------------------------------------------------------- */
/* for linking rt_printline and the signal/exception handler
from tccrun.c into executables. */
#define CONFIG_TCC_BACKTRACE_ONLY
#include "../tccrun.c"
int (*__rt_error)(void*, void*, const char *, va_list);
#ifndef _WIN32
# define __declspec(n)
#endif
__declspec(dllexport)
void __bt_init(rt_context *p, int num_callers)
{
__attribute__((weak)) int main();
__attribute__((weak)) void __bound_init(void*);
struct rt_context *rc = &g_rtctxt;
//fprintf(stderr, "__bt_init %d %p %p\n", num_callers, p->stab_sym, p->bounds_start), fflush(stderr);
if (num_callers) {
memcpy(rc, p, offsetof(rt_context, next));
rc->num_callers = num_callers - 1;
rc->top_func = main;
__rt_error = _rt_error;
set_exception_handler();
} else {
p->next = rc->next, rc->next = p;
}
if (__bound_init && p->bounds_start)
__bound_init(p->bounds_start);
}
/* copy a string and truncate it. */
static char *pstrcpy(char *buf, size_t buf_size, const char *s)
{
int l = strlen(s);
if (l >= buf_size)
l = buf_size - 1;
memcpy(buf, s, l);
buf[l] = 0;
return buf;
}

37
lib/bt-log.c 100644
View File

@ -0,0 +1,37 @@
/* ------------------------------------------------------------- */
/* function to get a stack backtrace on demand with a message */
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
int (*__rt_error)(void*, void*, const char *, va_list);
#ifdef _WIN32
# define DLL_EXPORT __declspec(dllexport)
#else
# define DLL_EXPORT
#endif
DLL_EXPORT int tcc_backtrace(const char *fmt, ...)
{
va_list ap;
int ret;
if (__rt_error) {
void *fp = __builtin_frame_address(1);
void *ip = __builtin_return_address(0);
va_start(ap, fmt);
ret = __rt_error(fp, ip, fmt, ap);
va_end(ap);
} else {
const char *p;
if (fmt[0] == '^' && (p = strchr(fmt + 1, fmt[0])))
fmt = p + 1;
va_start(ap, fmt);
ret = vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n"), fflush(stderr);
}
return ret;
}

1
lib/dsohandle.c 100644
View File

@ -0,0 +1 @@
void * __dso_handle __attribute((visibility("hidden"))) = &__dso_handle;

View File

@ -24,10 +24,12 @@ void *memcpy(void*,void*,__SIZE_TYPE__);
#include <string.h>
#endif
#ifndef __riscv
void __clear_cache(void *beg, void *end)
{
__arm64_clear_cache(beg, end);
}
#endif
typedef struct {
uint64_t x0, x1;

View File

@ -3,7 +3,6 @@
#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);
extern void abort(void);
/* This should be in sync with our include/stdarg.h */
@ -12,6 +11,7 @@ enum __va_arg_type {
};
/* GCC compatible definition of va_list. */
/*predefined by TCC (tcc_predefs.h):
typedef struct {
unsigned int gp_offset;
unsigned int fp_offset;
@ -20,23 +20,16 @@ typedef struct {
char *overflow_arg_area;
};
char *reg_save_area;
} __va_list_struct;
} __builtin_va_list[1];
*/
void __va_start(__va_list_struct *ap, void *fp)
{
memset(ap, 0, sizeof(__va_list_struct));
*ap = *(__va_list_struct *)((char *)fp - 16);
ap->overflow_arg_area = (char *)fp + ap->overflow_offset;
ap->reg_save_area = (char *)fp - 176 - 16;
}
void *__va_arg(__va_list_struct *ap,
enum __va_arg_type arg_type,
void *__va_arg(__builtin_va_list ap,
int arg_type,
int size, int align)
{
size = (size + 7) & ~7;
align = (align + 7) & ~7;
switch (arg_type) {
switch ((enum __va_arg_type)arg_type) {
case __va_gen_reg:
if (ap->gp_offset + size <= 48) {
ap->gp_offset += size;
@ -60,6 +53,7 @@ void *__va_arg(__va_list_struct *ap,
default: /* should never happen */
abort();
return 0;
}
}
#endif

560
libtcc.c

File diff suppressed because it is too large Load Diff

View File

@ -13,6 +13,8 @@ struct TCCState;
typedef struct TCCState TCCState;
typedef void (*TCCErrorFunc)(void *opaque, const char *msg);
/* create a new TCC compilation context */
LIBTCCAPI TCCState *tcc_new(void);
@ -23,8 +25,13 @@ LIBTCCAPI void tcc_delete(TCCState *s);
LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path);
/* set error/warning display callback */
LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque,
void (*error_func)(void *opaque, const char *msg));
LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, TCCErrorFunc error_func);
/* return error/warning callback */
LIBTCCAPI TCCErrorFunc tcc_get_error_func(TCCState *s);
/* return error/warning callback opaque pointer */
LIBTCCAPI void *tcc_get_error_opaque(TCCState *s);
/* set options as from command line (multiple supported) */
LIBTCCAPI void tcc_set_options(TCCState *s, const char *str);
@ -93,6 +100,10 @@ LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr);
/* return symbol value or NULL if not found */
LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name);
/* return symbol value or NULL if not found */
LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx,
void (*symbol_cb)(void *ctx, const char *name, const void *val));
#ifdef __cplusplus
}
#endif

1209
riscv64-gen.c 100644

File diff suppressed because it is too large Load Diff

329
riscv64-link.c 100644
View File

@ -0,0 +1,329 @@
#ifdef TARGET_DEFS_ONLY
#define EM_TCC_TARGET EM_RISCV
#define R_DATA_32 R_RISCV_32
#define R_DATA_PTR R_RISCV_64
#define R_JMP_SLOT R_RISCV_JUMP_SLOT
#define R_GLOB_DAT R_RISCV_64
#define R_COPY R_RISCV_COPY
#define R_RELATIVE R_RISCV_RELATIVE
#define R_NUM R_RISCV_NUM
#define ELF_START_ADDR 0x00010000
#define ELF_PAGE_SIZE 0x1000
#define PCRELATIVE_DLLPLT 1
#define RELOCATE_DLLPLT 1
#else /* !TARGET_DEFS_ONLY */
//#define DEBUG_RELOC
#include "tcc.h"
/* Returns 1 for a code relocation, 0 for a data relocation. For unknown
relocations, returns -1. */
int code_reloc (int reloc_type)
{
switch (reloc_type) {
case R_RISCV_BRANCH:
case R_RISCV_CALL:
case R_RISCV_JAL:
return 1;
case R_RISCV_GOT_HI20:
case R_RISCV_PCREL_HI20:
case R_RISCV_PCREL_LO12_I:
case R_RISCV_PCREL_LO12_S:
case R_RISCV_32_PCREL:
case R_RISCV_SET6:
case R_RISCV_SUB6:
case R_RISCV_ADD16:
case R_RISCV_ADD32:
case R_RISCV_ADD64:
case R_RISCV_SUB16:
case R_RISCV_SUB32:
case R_RISCV_SUB64:
case R_RISCV_32:
case R_RISCV_64:
return 0;
case R_RISCV_CALL_PLT:
return 1;
}
return -1;
}
/* Returns an enumerator to describe whether and when the relocation needs a
GOT and/or PLT entry to be created. See tcc.h for a description of the
different values. */
int gotplt_entry_type (int reloc_type)
{
switch (reloc_type) {
case R_RISCV_ALIGN:
case R_RISCV_RELAX:
case R_RISCV_RVC_BRANCH:
case R_RISCV_RVC_JUMP:
case R_RISCV_JUMP_SLOT:
case R_RISCV_SET6:
case R_RISCV_SUB6:
case R_RISCV_ADD16:
case R_RISCV_SUB16:
return NO_GOTPLT_ENTRY;
case R_RISCV_BRANCH:
case R_RISCV_CALL:
case R_RISCV_PCREL_HI20:
case R_RISCV_PCREL_LO12_I:
case R_RISCV_PCREL_LO12_S:
case R_RISCV_32_PCREL:
case R_RISCV_ADD32:
case R_RISCV_ADD64:
case R_RISCV_SUB32:
case R_RISCV_SUB64:
case R_RISCV_32:
case R_RISCV_64:
case R_RISCV_JAL:
case R_RISCV_CALL_PLT:
return AUTO_GOTPLT_ENTRY;
case R_RISCV_GOT_HI20:
return ALWAYS_GOTPLT_ENTRY;
}
return -1;
}
ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr)
{
Section *plt = s1->plt;
uint8_t *p;
unsigned plt_offset;
if (s1->output_type == TCC_OUTPUT_DLL)
tcc_error("DLLs unimplemented!");
if (plt->data_offset == 0)
section_ptr_add(plt, 32);
plt_offset = plt->data_offset;
p = section_ptr_add(plt, 16);
write64le(p, got_offset);
return plt_offset;
}
/* relocate the PLT: compute addresses and offsets in the PLT now that final
address for PLT and GOT are known (see fill_program_header) */
ST_FUNC void relocate_plt(TCCState *s1)
{
uint8_t *p, *p_end;
if (!s1->plt)
return;
p = s1->plt->data;
p_end = p + s1->plt->data_offset;
if (p < p_end) {
uint64_t plt = s1->plt->sh_addr;
uint64_t got = s1->got->sh_addr;
uint64_t off = (got - plt + 0x800) >> 12;
if ((off + ((uint32_t)1 << 20)) >> 21)
tcc_error("Failed relocating PLT (off=0x%lx, got=0x%lx, plt=0x%lx)", off, got, plt);
write32le(p, 0x397 | (off << 12)); // auipc t2, %pcrel_hi(got)
write32le(p + 4, 0x41c30333); // sub t1, t1, t3
write32le(p + 8, 0x0003be03 // ld t3, %pcrel_lo(got)(t2)
| (((got - plt) & 0xfff) << 20));
write32le(p + 12, 0xfd430313); // addi t1, t1, -(32+12)
write32le(p + 16, 0x00038293 // addi t0, t2, %pcrel_lo(got)
| (((got - plt) & 0xfff) << 20));
write32le(p + 20, 0x00135313); // srli t1, t1, log2(16/PTRSIZE)
write32le(p + 24, 0x0082b283); // ld t0, PTRSIZE(t0)
write32le(p + 28, 0x000e0067); // jr t3
p += 32;
while (p < p_end) {
uint64_t pc = plt + (p - s1->plt->data);
uint64_t addr = got + read64le(p);
uint64_t off = (addr - pc + 0x800) >> 12;
if ((off + ((uint32_t)1 << 20)) >> 21)
tcc_error("Failed relocating PLT (off=0x%lx, addr=0x%lx, pc=0x%lx)", off, addr, pc);
write32le(p, 0xe17 | (off << 12)); // auipc t3, %pcrel_hi(func@got)
write32le(p + 4, 0x000e3e03 // ld t3, %pcrel_lo(func@got)(t3)
| (((addr - pc) & 0xfff) << 20));
write32le(p + 8, 0x000e0367); // jalr t1, t3
write32le(p + 12, 0x00000013); // nop
p += 16;
}
}
}
struct pcrel_hi {
addr_t addr, val;
};
static struct pcrel_hi last_hi;
void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
addr_t addr, addr_t val)
{
uint64_t off64;
uint32_t off32;
int sym_index = ELFW(R_SYM)(rel->r_info);
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
switch(type) {
case R_RISCV_ALIGN:
case R_RISCV_RELAX:
return;
case R_RISCV_BRANCH:
off64 = val - addr;
if ((off64 + (1 << 12)) & ~(uint64_t)0x1ffe)
tcc_error("R_RISCV_BRANCH relocation failed"
" (val=%lx, addr=%lx)", val, addr);
off32 = off64 >> 1;
write32le(ptr, (read32le(ptr) & ~0xfe000f80)
| ((off32 & 0x800) << 20)
| ((off32 & 0x3f0) << 21)
| ((off32 & 0x00f) << 8)
| ((off32 & 0x400) >> 3));
return;
case R_RISCV_JAL:
off64 = val - addr;
if ((off64 + (1 << 21)) & ~(((uint64_t)1 << 22) - 2))
tcc_error("R_RISCV_JAL relocation failed"
" (val=%lx, addr=%lx)", val, addr);
off32 = off64;
write32le(ptr, (read32le(ptr) & 0xfff)
| (((off32 >> 12) & 0xff) << 12)
| (((off32 >> 11) & 1) << 20)
| (((off32 >> 1) & 0x3ff) << 21)
| (((off32 >> 20) & 1) << 31));
return;
case R_RISCV_CALL:
case R_RISCV_CALL_PLT:
write32le(ptr, (read32le(ptr) & 0xfff)
| ((val - addr + 0x800) & ~0xfff));
write32le(ptr + 4, (read32le(ptr + 4) & 0xfffff)
| (((val - addr) & 0xfff) << 20));
return;
case R_RISCV_PCREL_HI20:
#ifdef DEBUG_RELOC
printf("PCREL_HI20: val=%lx addr=%lx\n", val, addr);
#endif
off64 = (int64_t)(val - addr + 0x800) >> 12;
if ((off64 + ((uint64_t)1 << 20)) >> 21)
tcc_error("R_RISCV_PCREL_HI20 relocation failed: off=%lx cond=%lx sym=%s",
off64, ((int64_t)(off64 + ((uint64_t)1 << 20)) >> 21),
symtab_section->link->data + sym->st_name);
write32le(ptr, (read32le(ptr) & 0xfff)
| ((off64 & 0xfffff) << 12));
last_hi.addr = addr;
last_hi.val = val;
return;
case R_RISCV_GOT_HI20:
val = s1->got->sh_addr + get_sym_attr(s1, sym_index, 0)->got_offset;
off64 = (int64_t)(val - addr + 0x800) >> 12;
if ((off64 + ((uint64_t)1 << 20)) >> 21)
tcc_error("R_RISCV_GOT_HI20 relocation failed");
last_hi.addr = addr;
last_hi.val = val;
write32le(ptr, (read32le(ptr) & 0xfff)
| ((off64 & 0xfffff) << 12));
return;
case R_RISCV_PCREL_LO12_I:
#ifdef DEBUG_RELOC
printf("PCREL_LO12_I: val=%lx addr=%lx\n", val, addr);
#endif
if (val != last_hi.addr)
tcc_error("unsupported hi/lo pcrel reloc scheme");
val = last_hi.val;
addr = last_hi.addr;
write32le(ptr, (read32le(ptr) & 0xfffff)
| (((val - addr) & 0xfff) << 20));
return;
case R_RISCV_PCREL_LO12_S:
if (val != last_hi.addr)
tcc_error("unsupported hi/lo pcrel reloc scheme");
val = last_hi.val;
addr = last_hi.addr;
off32 = val - addr;
write32le(ptr, (read32le(ptr) & ~0xfe000f80)
| ((off32 & 0xfe0) << 20)
| ((off32 & 0x01f) << 7));
return;
case R_RISCV_RVC_BRANCH:
off64 = (val - addr);
if ((off64 + (1 << 8)) & ~(uint64_t)0x1fe)
tcc_error("R_RISCV_RVC_BRANCH relocation failed"
" (val=%lx, addr=%lx)", val, addr);
off32 = off64;
write16le(ptr, (read16le(ptr) & 0xe383)
| (((off32 >> 5) & 1) << 2)
| (((off32 >> 1) & 3) << 3)
| (((off32 >> 6) & 3) << 5)
| (((off32 >> 3) & 3) << 10)
| (((off32 >> 8) & 1) << 12));
return;
case R_RISCV_RVC_JUMP:
off64 = (val - addr);
if ((off64 + (1 << 11)) & ~(uint64_t)0xffe)
tcc_error("R_RISCV_RVC_BRANCH relocation failed"
" (val=%lx, addr=%lx)", val, addr);
off32 = off64;
write16le(ptr, (read16le(ptr) & 0xe003)
| (((off32 >> 5) & 1) << 2)
| (((off32 >> 1) & 7) << 3)
| (((off32 >> 7) & 1) << 6)
| (((off32 >> 6) & 1) << 7)
| (((off32 >> 10) & 1) << 8)
| (((off32 >> 8) & 3) << 9)
| (((off32 >> 4) & 1) << 11)
| (((off32 >> 11) & 1) << 12));
return;
case R_RISCV_32:
write32le(ptr, val);
return;
case R_RISCV_JUMP_SLOT:
case R_RISCV_64:
write64le(ptr, val);
return;
case R_RISCV_ADD64:
write64le(ptr, read64le(ptr) + val);
return;
case R_RISCV_ADD32:
write32le(ptr, read32le(ptr) + val);
return;
case R_RISCV_SUB64:
write64le(ptr, read64le(ptr) - val);
return;
case R_RISCV_SUB32:
write32le(ptr, read32le(ptr) - val);
return;
case R_RISCV_ADD16:
write16le(ptr, read16le(ptr) + val);
return;
case R_RISCV_SUB16:
write16le(ptr, read16le(ptr) - val);
return;
case R_RISCV_SET6:
*ptr = (*ptr & ~0x3f) | (val & 0x3f);
return;
case R_RISCV_SUB6:
*ptr = (*ptr & ~0x3f) | ((*ptr - val) & 0x3f);
return;
case R_RISCV_32_PCREL:
case R_RISCV_COPY:
/* XXX */
return;
default:
fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n",
type, (unsigned)addr, ptr, (unsigned)val);
return;
}
}
#endif

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.
@ -349,12 +354,30 @@ fault}.
Generate additional support code to check
memory allocations and array/pointer bounds. @option{-g} is implied. Note
that the generated code is slower and bigger in this case.
The bound checking code is not included in shared libaries. The main executable should always be compiled with the @option{-b}.
Note: @option{-b} is only available on i386 when using libtcc for the moment.
There are five environment variables that can be used:
@table @option
@item TCC_BOUNDS_WARN_POINTER_ADD
Print warning when pointer add creates an illegal pointer.
@item TCC_BOUNDS_PRINT_CALLS
Print bound checking calls. Can be used for debugging.
@item TCC_BOUNDS_PRINT_HEAP
Print heap objects that are not freed at exit of program.
@item TCC_BOUNDS_PRINT_STATISTIC
Print statistic information at exit of program.
@item TCC_BOUNDS_NEVER_FATAL
Try to continue in case of a bound checking error.
@end table
@item -bt N
Display N callers in stack traces. This is useful with @option{-g} or
@option{-b}.
Note: @option{-b} is only available on i386 (linux and windows) and x86_64 (linux and windows) for the moment.
@item -bt[N]
Display N callers in stack traces. This is useful with @option{-g} or @option{-b}.
With executables, additional support for stack traces is included.
A function @code{ int tcc_backtrace(const char *fmt, ...); } is provided
to trigger a stack trace with a message on demand.
@end table
@ -543,6 +566,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 +594,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:
@ -893,7 +919,7 @@ Here are some examples of caught errors:
int *tab;
tab = malloc(20 * sizeof(int));
for(i=0;i<21;i++) @{
sum += tab4[i];
sum += tab[i];
@}
free(tab);
@}
@ -906,7 +932,7 @@ Here are some examples of caught errors:
tab = malloc(20 * sizeof(int));
free(tab);
for(i=0;i<20;i++) @{
sum += tab4[i];
sum += tab[i];
@}
@}
@end example
@ -923,6 +949,40 @@ Here are some examples of caught errors:
@end table
Signal handlers are not compatible with bounds checking. The code
below can be used to protect signal handlers.
The call to __bound_checking(1) will disable bounds checking in the
whole application.
The BOUNDS_CHECKING_OFF and BOUNDS_CHECKING_ON can also be used to
disable bounds checking for some code. This is not recommended.
It is better to fix the code.
@example
#ifdef __BOUNDS_CHECKING_ON
extern void __bound_checking (int no_check);
#define BOUNDS_CHECKING_OFF __bound_checking(1)
#define BOUNDS_CHECKING_ON __bound_checking(-1)
#else
#define BOUNDS_CHECKING_OFF
#define BOUNDS_CHECKING_ON
#endif
void real_signal_handler(int sig, siginfo_t *info, void *ucontext)
@{
...
@}
void signal_handler(int sig, void *info, void *ucontext)
@{
BOUNDS_CHECKING_OFF;
real_signal_handler(sig, info, data);
BOUNDS_CHECKING_ON;
@}
@end example
@node Libtcc
@chapter The @code{libtcc} library

125
tcc.c
View File

@ -29,46 +29,51 @@ static const char help[] =
"Usage: tcc [options...] [-o outfile] [-c] infile(s)...\n"
" tcc [options...] -run infile [arguments...]\n"
"General options:\n"
" -c compile only - generate an object file\n"
" -o outfile set output filename\n"
" -run run compiled source\n"
" -fflag set or reset (with 'no-' prefix) 'flag' (see tcc -hh)\n"
" -Wwarning set or reset (with 'no-' prefix) 'warning' (see tcc -hh)\n"
" -w disable all warnings\n"
" -v -vv show version, show search paths or loaded files\n"
" -h -hh show this, show more help\n"
" -bench show compilation statistics\n"
" - use stdin pipe as infile\n"
" @listfile read arguments from listfile\n"
" -c compile only - generate an object file\n"
" -o outfile set output filename\n"
" -run run compiled source\n"
" -fflag set or reset (with 'no-' prefix) 'flag' (see tcc -hh)\n"
" -std=c99 Conform to the ISO 1999 C standard (default).\n"
" -std=c11 Conform to the ISO 2011 C standard.\n"
" -Wwarning set or reset (with 'no-' prefix) 'warning' (see tcc -hh)\n"
" -w disable all warnings\n"
" --version -v show version\n"
" -vv show search paths or loaded files\n"
" -h -hh show this, show more help\n"
" -bench show compilation statistics\n"
" - use stdin pipe as infile\n"
" @listfile read arguments from listfile\n"
"Preprocessor options:\n"
" -Idir add include path 'dir'\n"
" -Dsym[=val] define 'sym' with value 'val'\n"
" -Usym undefine 'sym'\n"
" -E preprocess only\n"
" -Idir add include path 'dir'\n"
" -Dsym[=val] define 'sym' with value 'val'\n"
" -Usym undefine 'sym'\n"
" -E preprocess only\n"
"Linker options:\n"
" -Ldir add library path 'dir'\n"
" -llib link with dynamic or static library 'lib'\n"
" -r generate (relocatable) object file\n"
" -shared generate a shared library/dll\n"
" -rdynamic export all global symbols to dynamic linker\n"
" -soname set name for shared library to be used at runtime\n"
" -Ldir add library path 'dir'\n"
" -llib link with dynamic or static library 'lib'\n"
" -r generate (relocatable) object file\n"
" -shared generate a shared library/dll\n"
" -rdynamic export all global symbols to dynamic linker\n"
" -soname set name for shared library to be used at runtime\n"
" -Wl,-opt[=val] set linker option (see tcc -hh)\n"
"Debugger options:\n"
" -g generate runtime debug info\n"
" -g generate runtime debug info\n"
#ifdef CONFIG_TCC_BCHECK
" -b compile with built-in memory and bounds checker (implies -g)\n"
" -b compile with built-in memory and bounds checker (implies -g)\n"
#endif
#ifdef CONFIG_TCC_BACKTRACE
" -bt N show N callers in stack traces\n"
" -bt[N] link with backtrace (stack dump) support [show max N callers]\n"
#endif
"Misc. options:\n"
" -x[c|a|n] specify type of the next infile\n"
" -nostdinc do not use standard system include paths\n"
" -nostdlib do not link with standard crt and libraries\n"
" -Bdir set tcc's private include/library dir\n"
" -MD generate dependency file for make\n"
" -MF file specify dependency file name\n"
" -m32/64 defer to i386/x86_64 cross compiler\n"
" -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"
" -MD generate dependency file for make\n"
" -MF file specify dependency file name\n"
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
" -m32/64 defer to i386/x86_64 cross compiler\n"
#endif
"Tools:\n"
" create library : tcc -ar [rcsv] lib.a files\n"
#ifdef TCC_TARGET_PE
@ -91,7 +96,7 @@ static const char help2[] =
" -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"
" --param -pedantic -pipe -s -traditional\n"
"-W... warnings:\n"
" all turn on some (*) warnings\n"
" error stop after first warning\n"
@ -117,6 +122,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
@ -152,6 +158,8 @@ static const char version[] =
"ARM"
#elif defined TCC_TARGET_ARM64
"AArch64"
#elif defined TCC_TARGET_RISCV64
"riscv64"
#endif
#ifdef TCC_ARM_HARDFLOAT
" Hard Float"
@ -182,8 +190,10 @@ 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);
#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);
#ifndef TCC_TARGET_PE
print_dirs("crt", s->crt_paths, s->nb_crt_paths);
printf("elfinterp:\n %s\n", DEFAULT_ELFINTERP(s));
#endif
@ -245,8 +255,8 @@ static unsigned getclock_ms(void)
int main(int argc0, char **argv0)
{
TCCState *s;
int ret, opt, n = 0, t = 0;
TCCState *s, *s1;
int ret, opt, n = 0, t = 0, done;
unsigned start_time = 0;
const char *first_file;
int argc; char **argv;
@ -254,14 +264,14 @@ int main(int argc0, char **argv0)
redo:
argc = argc0, argv = argv0;
s = tcc_new();
s = s1 = tcc_new();
opt = tcc_parse_args(s, &argc, &argv, 1);
if ((n | t) == 0) {
if (n == 0) {
if (opt == OPT_HELP)
return printf(help), 1;
return fputs(help, stdout), 0;
if (opt == OPT_HELP2)
return printf(help2), 1;
return fputs(help2, stdout), 0;
if (opt == OPT_M32 || opt == OPT_M64)
tcc_tool_cross(s, argv, opt); /* never returns */
if (s->verbose)
@ -282,12 +292,11 @@ redo:
return 0;
}
n = s->nb_files;
if (n == 0)
if (s->nb_files == 0)
tcc_error("no input files\n");
if (s->output_type == TCC_OUTPUT_PREPROCESS) {
if (s->outfile) {
if (s->outfile && 0!=strcmp("-",s->outfile)) {
ppfp = fopen(s->outfile, "w");
if (!ppfp)
tcc_error("could not write '%s'", s->outfile);
@ -295,7 +304,7 @@ redo:
} else if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) {
if (s->nb_libraries)
tcc_error("cannot specify libraries with -c");
if (n > 1 && s->outfile)
if (s->nb_files > 1 && s->outfile)
tcc_error("cannot specify output file with -c many files");
} else {
if (s->option_pthread)
@ -313,15 +322,21 @@ redo:
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;
|| s->output_type == TCC_OUTPUT_PREPROCESS)
&& (s->dflag & 16)) { /* -dt option */
if (t)
s->dflag |= 32;
s->run_test = ++t;
if (n)
--n;
}
/* compile or add each files or library */
for (first_file = NULL, ret = 0;;) {
struct filespec *f = s->files[s->nb_files - n];
first_file = NULL, ret = 0;
do {
struct filespec *f = s->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 {
@ -332,12 +347,8 @@ redo:
if (tcc_add_file(s, f->name) < 0)
ret = 1;
}
s->filetype = 0;
s->alacarte_link = 1;
if (--n == 0 || ret
|| (s->output_type == TCC_OUTPUT_OBJ && !s->option_r))
break;
}
done = ret || ++n >= s->nb_files;
} while (!done && (s->output_type != TCC_OUTPUT_OBJ || s->option_r));
if (s->run_test) {
t = 0;
@ -358,10 +369,10 @@ redo:
}
}
if (s->do_bench && (n | t | ret) == 0)
if (s->do_bench && done && !(t | ret))
tcc_print_stats(s, getclock_ms() - start_time);
tcc_delete(s);
if (ret == 0 && n)
if (!done)
goto redo; /* compile more files with -c */
if (t)
goto redo; /* run more tests with -dt -run */

423
tcc.h
View File

@ -24,9 +24,9 @@
#define _GNU_SOURCE
#include "config.h"
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <math.h>
@ -46,6 +46,7 @@ extern long double strtold (const char *__nptr, char **__endptr);
#endif
#ifdef _WIN32
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# include <io.h> /* open, close etc. */
# include <direct.h> /* getcwd */
@ -73,6 +74,12 @@ extern long double strtold (const char *__nptr, char **__endptr);
# pragma warning (disable : 4018) // signed/unsigned mismatch
# pragma warning (disable : 4146) // unary minus operator applied to unsigned type, result still unsigned
# define ssize_t intptr_t
# ifdef _X86_
# define __i386__ 1
# endif
# ifdef _AMD64_
# define __x86_64__ 1
# endif
# endif
# undef CONFIG_TCC_STATIC
#endif
@ -92,9 +99,16 @@ extern long double strtold (const char *__nptr, char **__endptr);
#ifdef _MSC_VER
# define NORETURN __declspec(noreturn)
# define ALIGNED(x) __declspec(align(x))
# define PRINTF_LIKE(x,y)
#else
# define NORETURN __attribute__((noreturn))
# define ALIGNED(x) __attribute__((aligned(x)))
# define PRINTF_LIKE(x,y) __attribute__ ((format (printf, (x), (y))))
#endif
/* gnu headers use to #define __attribute__ to empty for non-gcc compilers */
#ifdef __TINYC__
# undef __attribute__
#endif
#ifdef _WIN32
@ -117,7 +131,7 @@ extern long double strtold (const char *__nptr, char **__endptr);
/* #define PP_DEBUG */
/* include file debug */
/* #define INC_DEBUG */
/* memory leak debug */
/* memory leak debug (only for single threaded usage) */
/* #define MEM_DEBUG */
/* assembler debug */
/* #define ASM_DEBUG */
@ -128,19 +142,23 @@ extern long double strtold (const char *__nptr, char **__endptr);
/* #define TCC_TARGET_ARM *//* ARMv4 code generator */
/* #define TCC_TARGET_ARM64 *//* ARMv8 code generator */
/* #define TCC_TARGET_C67 *//* TMS320C67xx code generator */
/* #define TCC_TARGET_RISCV64 *//* risc-v code generator */
/* default target is I386 */
#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_ARM) && \
!defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_C67) && \
!defined(TCC_TARGET_X86_64)
# if defined __x86_64__ || defined _AMD64_
!defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_RISCV64)
# if defined __x86_64__
# define TCC_TARGET_X86_64
# elif defined __arm__
# define TCC_TARGET_ARM
# define TCC_ARM_EABI
# define TCC_ARM_VFP
# define TCC_ARM_HARDFLOAT
# elif defined __aarch64__
# define TCC_TARGET_ARM64
# elif defined __riscv
# define TCC_TARGET_RISCV64
# else
# define TCC_TARGET_I386
# endif
@ -151,14 +169,16 @@ extern long double strtold (const char *__nptr, char **__endptr);
/* only native compiler supports -run */
#if defined _WIN32 == defined TCC_TARGET_PE
# if (defined __i386__ || defined _X86_) && defined TCC_TARGET_I386
# if defined __i386__ && defined TCC_TARGET_I386
# define TCC_IS_NATIVE
# elif (defined __x86_64__ || defined _AMD64_) && defined TCC_TARGET_X86_64
# elif defined __x86_64__ && defined TCC_TARGET_X86_64
# define TCC_IS_NATIVE
# elif defined __arm__ && defined TCC_TARGET_ARM
# define TCC_IS_NATIVE
# elif defined __aarch64__ && defined TCC_TARGET_ARM64
# define TCC_IS_NATIVE
# elif defined __riscv && defined __LP64__ && defined TCC_TARGET_RISCV64
# define TCC_IS_NATIVE
# endif
#endif
@ -252,9 +272,15 @@ extern long double strtold (const char *__nptr, char **__endptr);
# else
# define CONFIG_TCC_ELFINTERP "/lib64/ld-linux-x86-64.so.2"
# endif
# elif defined(TCC_TARGET_RISCV64)
# define CONFIG_TCC_ELFINTERP "/lib/ld-linux-riscv64-lp64d.so.1"
# elif !defined(TCC_ARM_EABI)
# if defined(TCC_MUSL)
# define CONFIG_TCC_ELFINTERP "/lib/ld-musl-arm.so.1"
# if defined(TCC_TARGET_I386)
# define CONFIG_TCC_ELFINTERP "/lib/ld-musl-i386.so.1"
# else
# define CONFIG_TCC_ELFINTERP "/lib/ld-musl-arm.so.1"
# endif
# else
# define CONFIG_TCC_ELFINTERP "/lib/ld-linux.so.2"
# endif
@ -294,6 +320,9 @@ extern long double strtold (const char *__nptr, char **__endptr);
# define ONE_SOURCE 1
#endif
/* support using libtcc from threads */
#define CONFIG_TCC_SEMLOCK
#if ONE_SOURCE
#define ST_INLN static inline
#define ST_FUNC static
@ -315,25 +344,26 @@ extern long double strtold (const char *__nptr, char **__endptr);
#ifdef TCC_TARGET_I386
# include "i386-gen.c"
# include "i386-link.c"
#endif
#ifdef TCC_TARGET_X86_64
#elif defined TCC_TARGET_X86_64
# include "x86_64-gen.c"
# include "x86_64-link.c"
#endif
#ifdef TCC_TARGET_ARM
#elif defined TCC_TARGET_ARM
# include "arm-gen.c"
# include "arm-link.c"
# include "arm-asm.c"
#endif
#ifdef TCC_TARGET_ARM64
#elif defined TCC_TARGET_ARM64
# include "arm64-gen.c"
# include "arm64-link.c"
#endif
#ifdef TCC_TARGET_C67
#elif defined TCC_TARGET_C67
# define TCC_TARGET_COFF
# include "coff.h"
# include "c67-gen.c"
# include "c67-link.c"
#elif defined(TCC_TARGET_RISCV64)
# include "riscv64-gen.c"
# include "riscv64-link.c"
#else
#error unknown target
#endif
#undef TARGET_DEFS_ONLY
@ -426,9 +456,15 @@ typedef struct SValue {
unsigned short r; /* register + flags */
unsigned short r2; /* second register, used for 'long long'
type. If not used, set to VT_CONST */
CValue c; /* constant, if VT_CONST */
struct Sym *sym; /* symbol, if (VT_SYM | VT_CONST), or if
result of unary() for an identifier. */
union {
struct { int jtrue, jfalse; }; /* forward jmps */
CValue c; /* constant, if VT_CONST */
};
union {
struct { unsigned short cmp_op, cmp_r; }; /* VT_CMP operation */
struct Sym *sym; /* symbol, if (VT_SYM | VT_CONST), or if */
}; /* result of unary() for an identifier. */
} SValue;
/* symbol attributes */
@ -439,8 +475,10 @@ struct SymAttr {
weak : 1,
visibility : 2,
dllexport : 1,
nodecorate : 1,
dllimport : 1,
unused : 5;
addrtaken : 1,
xxxx : 3; /* not used */
};
/* function attributes or temporary attributes for parsing */
@ -448,19 +486,12 @@ struct FuncAttr {
unsigned
func_call : 3, /* calling convention (0..5), see below */
func_type : 2, /* FUNC_OLD/NEW/ELLIPSIS */
func_noreturn : 1, /* attribute((noreturn)) */
func_ctor : 1, /* attribute((constructor)) */
func_dtor : 1, /* attribute((destructor)) */
func_args : 8; /* PE __stdcall args */
};
/* GNUC attribute definition */
typedef struct AttributeDef {
struct SymAttr a;
struct FuncAttr f;
struct Section *section;
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 */
@ -478,10 +509,12 @@ typedef struct Sym {
};
long long enum_val; /* enum constant if IS_ENUM_VAL */
int *d; /* define token stream */
struct Sym *ncl; /* next cleanup */
};
CType type; /* associated type */
union {
struct Sym *next; /* next related symbol (for fields and anoms) */
struct Sym *cleanupstate; /* in defined labels */
int asm_label; /* associated asm label */
};
struct Sym *prev; /* prev symbol in stack */
@ -493,6 +526,7 @@ typedef struct Section {
unsigned long data_offset; /* current data offset */
unsigned char *data; /* section data */
unsigned long data_allocated; /* used for realloc() handling */
TCCState *s1;
int sh_name; /* elf section name (only used during output) */
int sh_num; /* elf section number */
int sh_type; /* elf section type */
@ -544,6 +578,8 @@ typedef struct DLLReference {
#define LABEL_DEFINED 0 /* label is defined */
#define LABEL_FORWARD 1 /* label is forward defined */
#define LABEL_DECLARED 2 /* label is declared but never used */
#define LABEL_GONE 3 /* label isn't in scope, but not yet popped
from local_label_stack (stmt exprs) */
/* type_decl() types */
#define TYPE_ABSTRACT 1 /* type without variable */
@ -585,6 +621,17 @@ typedef struct TokenString {
char alloc;
} TokenString;
/* GNUC attribute definition */
typedef struct AttributeDef {
struct SymAttr a;
struct FuncAttr f;
struct Section *section;
Sym *cleanup_func;
int alias_target; /* token */
int asm_label; /* associated asm label */
char attr_mode; /* __attribute__((__mode__(...))) */
} AttributeDef;
/* inline functions */
typedef struct InlineFunc {
TokenString *func_str;
@ -638,20 +685,20 @@ 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 */
int nocommon; /* if true, do not use common symbols for .bss data */
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 */
unsigned char verbose; /* if true, display some information during compilation */
unsigned char nostdinc; /* if true, no standard headers are added */
unsigned char nostdlib; /* if true, no standard libraries are added */
unsigned char nocommon; /* if true, do not use common symbols for .bss data */
unsigned char static_link; /* if true, static linking is performed */
unsigned char rdynamic; /* if true, all symbols are exported */
unsigned char symbolic; /* if true, resolve symbols in the current module first */
unsigned char filetype; /* file type for compilation (NONE,C,ASM) */
unsigned int cversion; /* supported C ISO version, 199901 (the default), 201112, ... */
char *tcc_lib_path; /* CONFIG_TCCDIR or -B option */
char *soname; /* as specified on the command line (-soname) */
char *rpath; /* as specified on the command line (-Wl,-rpath=) */
int enable_new_dtags; /* ditto, (-Wl,--enable-new-dtags) */
unsigned char enable_new_dtags; /* ditto, (-Wl,--enable-new-dtags) */
/* output type, see TCC_OUTPUT_XXX */
int output_type;
@ -659,25 +706,26 @@ struct TCCState {
int output_format;
/* C language options */
int char_is_unsigned;
int leading_underscore;
int ms_extensions; /* allow nested named struct w/o identifier behave like unnamed */
int dollars_in_identifiers; /* allows '$' char in identifiers */
int ms_bitfields; /* if true, emulate MS algorithm for aligning bitfields */
unsigned char char_is_unsigned;
unsigned char leading_underscore;
unsigned char ms_extensions; /* allow nested named struct w/o identifier behave like unnamed */
unsigned char dollars_in_identifiers; /* allows '$' char in identifiers */
unsigned char ms_bitfields; /* if true, emulate MS algorithm for aligning bitfields */
/* warning switches */
int warn_write_strings;
int warn_unsupported;
int warn_error;
int warn_none;
int warn_implicit_function_declaration;
int warn_gcc_compat;
unsigned char warn_write_strings;
unsigned char warn_unsupported;
unsigned char warn_error;
unsigned char warn_none;
unsigned char warn_implicit_function_declaration;
unsigned char warn_gcc_compat;
/* compile with debug symbol (and use them if error during execution) */
int do_debug;
unsigned char do_debug;
unsigned char do_backtrace;
#ifdef CONFIG_TCC_BCHECK
/* compile with built-in memory and bounds checker */
int do_bounds_check;
unsigned char do_bounds_check;
#endif
#ifdef TCC_TARGET_ARM
enum float_abi float_abi; /* float ABI of the generated code*/
@ -685,10 +733,15 @@ struct TCCState {
int run_test; /* nth test to run with -dt -run */
addr_t text_addr; /* address of text section */
int has_text_addr;
unsigned char has_text_addr;
unsigned section_align; /* section alignment */
/* use GNU C extensions */
unsigned char gnu_ext;
/* use TinyCC extensions */
unsigned char tcc_ext;
char *init_symbol; /* symbols to call at load-time (not used currently) */
char *fini_symbol; /* symbols to call at unload-time (not used currently) */
@ -696,7 +749,7 @@ struct TCCState {
int seg_size; /* 32. Can be 16 with i386 assembler (.code16) */
#endif
#ifdef TCC_TARGET_X86_64
int nosse; /* For -mno-sse support. */
unsigned char nosse; /* For -mno-sse support. */
#endif
/* array of all loaded dlls (including those referenced by loaded dlls) */
@ -718,9 +771,10 @@ struct TCCState {
char **crt_paths;
int nb_crt_paths;
/* -include files */
char **cmd_include_files;
int nb_cmd_include_files;
/* -D / -U options */
CString cmdline_defs;
/* -include options */
CString cmdline_incl;
/* error handling */
void *error_opaque;
@ -777,6 +831,22 @@ struct TCCState {
Section *got;
Section *plt;
/* predefined sections */
Section *text_section, *data_section, *bss_section;
Section *common_section;
Section *cur_text_section; /* current section where function code is generated */
#ifdef CONFIG_TCC_BCHECK
/* bound check related sections */
Section *bounds_section; /* contains global data bound description */
Section *lbounds_section; /* contains local data bound description */
#endif
/* symbol sections */
Section *symtab_section;
/* debug sections */
Section *stab_section;
/* Is there a new undefined sym since last new_undef_sym() */
int new_undef_sym;
/* temporary dynamic symbol sections (for dll loading) */
Section *dynsymtab_section;
/* exported dynamic symbol section */
@ -786,6 +856,9 @@ struct TCCState {
/* extra attributes (eg. GOT/PLT value) for symtab symbols */
struct sym_attr *sym_attrs;
int nb_sym_attrs;
/* ptr to next reloc entry reused */
ElfW_Rel *qrel;
# define qrel s1->qrel
#ifdef TCC_TARGET_PE
/* PE info */
@ -799,6 +872,17 @@ struct TCCState {
int uw_sym;
unsigned uw_offs;
# endif
# define ELF_OBJ_ONLY
#endif
#ifndef ELF_OBJ_ONLY
int nb_sym_versions;
struct sym_version *sym_versions;
int nb_sym_to_version;
int *sym_to_version;
int dt_verneednum;
Section *versym_section;
Section *verneed_section;
#endif
#ifdef TCC_IS_NATIVE
@ -807,24 +891,36 @@ struct TCCState {
int nb_runtime_mem;
#endif
#ifdef CONFIG_TCC_BACKTRACE
int rt_num_callers;
#endif
int fd, cc; /* used by tcc_load_ldscript */
/* benchmark info */
int total_idents;
int total_lines;
int total_bytes;
/* option -dnum (for general development purposes) */
int g_debug;
/* used by main and tcc_parse_args only */
struct filespec **files; /* files seen on command line */
int nb_files; /* number thereof */
int nb_libraries; /* number of libs thereof */
int filetype;
char *outfile; /* output filename */
int option_r; /* option -r */
int do_bench; /* option -bench */
unsigned char option_r; /* option -r */
unsigned char do_bench; /* option -bench */
int gen_deps; /* option -MD */
char *deps_outfile; /* option -MF */
int option_pthread; /* -pthread option */
unsigned char option_pthread; /* -pthread option */
int argc;
char **argv;
};
struct filespec {
char type;
char alacarte;
char name[1];
};
@ -838,17 +934,12 @@ struct filespec {
#define VT_JMPI 0x0035 /* value is the consequence of jmp false (odd) */
#define VT_LVAL 0x0100 /* var is an lvalue */
#define VT_SYM 0x0200 /* a symbol value is added */
#define VT_MUSTCAST 0x0400 /* value must be casted to be correct (used for
#define VT_MUSTCAST 0x0C00 /* value must be casted to be correct (used for
char/short stored in integer registers) */
#define VT_MUSTBOUND 0x0800 /* bound checking must be done before
#define VT_MUSTBOUND 0x4000 /* bound checking must be done before
dereferencing value */
#define VT_BOUNDED 0x8000 /* value is bounded. The address of the
bounding function call point is in vc */
#define VT_LVAL_BYTE 0x1000 /* lvalue is a byte */
#define VT_LVAL_SHORT 0x2000 /* lvalue is a short */
#define VT_LVAL_UNSIGNED 0x4000 /* lvalue is unsigned */
#define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED)
/* types */
#define VT_BTYPE 0x000f /* mask for basic type */
#define VT_VOID 0 /* void type */
@ -883,7 +974,7 @@ struct filespec {
/* currently unused: 0x000[1248]0000 */
#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 VT_STRUCT_MASK (((1U << (6+6)) - 1) << VT_STRUCT_SHIFT | VT_BITFIELD)
#define BIT_POS(t) (((t) >> VT_STRUCT_SHIFT) & 0x3f)
#define BIT_SIZE(t) (((t) >> (VT_STRUCT_SHIFT + 6)) & 0x3f)
@ -903,6 +994,11 @@ struct filespec {
#define VT_ASM (VT_VOID | VT_UNSIGNED)
#define IS_ASM_SYM(sym) (((sym)->type.t & (VT_BTYPE | VT_ASM)) == VT_ASM)
/* general: set/get the pseudo-bitfield value for bit-mask M */
#define BFVAL(M,N) ((unsigned)((M) & ~((M) << 1)) * (N))
#define BFGET(X,M) (((X) & (M)) / BFVAL(M,1))
#define BFSET(X,M,N) ((X) = ((X) & ~(M)) | BFVAL(M,N))
/* token values */
/* warning: the following compare tokens depend on i386 asm code */
@ -1079,16 +1175,11 @@ enum tcc_token {
/* ------------ libtcc.c ------------ */
/* use GNU C extensions */
ST_DATA int gnu_ext;
/* use Tiny C extensions */
ST_DATA int tcc_ext;
/* XXX: get rid of this ASAP */
ST_DATA struct TCCState *tcc_state;
/* public functions currently used by the tcc main function */
ST_FUNC char *pstrcpy(char *buf, int buf_size, const char *s);
ST_FUNC char *pstrcat(char *buf, int buf_size, const char *s);
ST_FUNC char *pstrcpy(char *buf, size_t buf_size, const char *s);
ST_FUNC char *pstrcat(char *buf, size_t buf_size, const char *s);
ST_FUNC char *pstrncpy(char *out, const char *in, size_t num);
PUB_FUNC char *tcc_basename(const char *name);
PUB_FUNC char *tcc_fileextension (const char *name);
@ -1117,10 +1208,9 @@ PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line);
#define realloc(p, s) use_tcc_realloc(p, s)
#undef strdup
#define strdup(s) use_tcc_strdup(s)
PUB_FUNC void tcc_memcheck(void);
PUB_FUNC void tcc_error_noabort(const char *fmt, ...);
PUB_FUNC NORETURN void tcc_error(const char *fmt, ...);
PUB_FUNC void tcc_warning(const char *fmt, ...);
PUB_FUNC void _tcc_error_noabort(const char *fmt, ...) PRINTF_LIKE(1,2);
PUB_FUNC NORETURN void _tcc_error(const char *fmt, ...) PRINTF_LIKE(1,2);
PUB_FUNC void _tcc_warning(const char *fmt, ...) PRINTF_LIKE(1,2);
/* other utilities */
ST_FUNC void dynarray_add(void *ptab, int *nb_ptr, void *data);
@ -1130,6 +1220,7 @@ ST_FUNC void cstr_cat(CString *cstr, const char *str, int len);
ST_FUNC void cstr_wccat(CString *cstr, int ch);
ST_FUNC void cstr_new(CString *cstr);
ST_FUNC void cstr_free(CString *cstr);
ST_FUNC int cstr_printf(CString *cs, const char *fmt, ...) PRINTF_LIKE(2,3);
ST_FUNC void cstr_reset(CString *cstr);
ST_INLN void sym_free(Sym *sym);
@ -1150,12 +1241,14 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
#define AFF_PRINT_ERROR 0x10 /* print error if file not found */
#define AFF_REFERENCED_DLL 0x20 /* load a referenced dll from another dll */
#define AFF_TYPE_BIN 0x40 /* file to add is binary */
#define AFF_WHOLE_ARCHIVE 0x80 /* load all objects from archive */
/* s->filetype: */
#define AFF_TYPE_NONE 0
#define AFF_TYPE_C 1
#define AFF_TYPE_ASM 2
#define AFF_TYPE_ASMPP 3
#define AFF_TYPE_LIB 4
#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
@ -1163,8 +1256,16 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
#define AFF_BINTYPE_C67 4
#ifndef TCC_TARGET_PE
ST_FUNC int tcc_add_crt(TCCState *s, const char *filename);
#endif
ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags);
#ifdef CONFIG_TCC_BCHECK
ST_FUNC void tcc_add_bcheck(TCCState *s1);
#endif
#ifdef CONFIG_TCC_BACKTRACE
ST_FUNC void tcc_add_btstub(TCCState *s1);
#endif
ST_FUNC void tcc_add_pragma_libs(TCCState *s1);
PUB_FUNC int tcc_add_library_err(TCCState *s, const char *f);
PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time);
@ -1194,8 +1295,6 @@ ST_DATA int tok_flags;
ST_DATA CString tokcstr; /* current parsed string, if any */
/* display benchmark infos */
ST_DATA int total_lines;
ST_DATA int total_bytes;
ST_DATA int tok_ident;
ST_DATA TokenSym **table_ident;
@ -1270,18 +1369,14 @@ static inline int toup(int c) {
/* ------------ tccgen.c ------------ */
#define SYM_POOL_NB (8192 / sizeof(Sym))
ST_DATA Sym *sym_free_first;
ST_DATA void **sym_pools;
ST_DATA int nb_sym_pools;
ST_DATA Sym *global_stack;
ST_DATA Sym *local_stack;
ST_DATA Sym *local_label_stack;
ST_DATA Sym *global_label_stack;
ST_DATA Sym *define_stack;
ST_DATA CType char_pointer_type, func_old_type, int_type, size_type;
ST_DATA SValue __vstack[1+/*to make bcheck happy*/ VSTACK_SIZE], *vtop, *pvtop;
#define vstack (__vstack + 1)
ST_DATA CType int_type, func_old_type, char_pointer_type;
ST_DATA SValue *vtop;
ST_DATA int rsym, anon_sym, ind, loc;
ST_DATA int const_wanted; /* true if constant wanted */
@ -1290,18 +1385,20 @@ ST_DATA int global_expr; /* true if compound literals must be allocated globall
ST_DATA CType func_vt; /* current function return type (used by return instruction) */
ST_DATA int func_var; /* true if current function is variadic */
ST_DATA int func_vc;
ST_DATA int 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);
ST_FUNC void tcc_debug_bincl(TCCState *s1);
ST_FUNC void tcc_debug_eincl(TCCState *s1);
ST_FUNC void tcc_debug_putfile(TCCState *s1, const char *filename);
ST_FUNC void tcc_debug_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_init(TCCState *s1);
ST_FUNC int tccgen_compile(TCCState *s1);
ST_FUNC void free_inline_functions(TCCState *s);
ST_FUNC void tccgen_finish(TCCState *s1);
ST_FUNC void check_vstack(void);
ST_INLN int is_float(int t);
@ -1310,16 +1407,19 @@ 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 Sym *external_global_sym(int v, CType *type);
ST_FUNC void vset(CType *type, int r, int v);
ST_FUNC void vset_VT_CMP(int op);
ST_FUNC void vswap(void);
ST_FUNC void vpush_global_sym(CType *type, int v);
ST_FUNC void vrote(SValue *e, int n);
ST_FUNC void vrott(int n);
ST_FUNC void vrotb(int n);
#if PTR_SIZE == 4
ST_FUNC void lexpand(void);
#endif
#ifdef TCC_TARGET_ARM
ST_FUNC int get_reg_ex(int rc, int rc2);
ST_FUNC void lexpand_nr(void);
#endif
ST_FUNC void vpushv(SValue *v);
ST_FUNC void save_reg(int r);
@ -1337,11 +1437,8 @@ ST_FUNC void vstore(void);
ST_FUNC void inc(int post, int c);
ST_FUNC void parse_mult_str (CString *astr, const char *msg);
ST_FUNC void parse_asm_str(CString *astr);
ST_FUNC int lvalue_type(int t);
ST_FUNC void indir(void);
ST_FUNC void unary(void);
ST_FUNC void expr_prod(void);
ST_FUNC void expr_sum(void);
ST_FUNC void gexpr(void);
ST_FUNC int expr_const(void);
#if defined CONFIG_TCC_BCHECK || defined TCC_TARGET_C67
@ -1350,6 +1447,9 @@ ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsign
#if defined TCC_TARGET_X86_64 && !defined TCC_TARGET_PE
ST_FUNC int classify_x86_64_va_arg(CType *ty);
#endif
#ifdef CONFIG_TCC_BCHECK
ST_FUNC void gbound_args(int nb_args);
#endif
/* ------------ tccelf.c ------------ */
@ -1367,29 +1467,14 @@ typedef struct {
unsigned int n_value; /* value of symbol */
} Stab_Sym;
ST_DATA Section *text_section, *data_section, *bss_section; /* predefined sections */
ST_DATA Section *common_section;
ST_DATA Section *cur_text_section; /* current section where function code is generated */
#ifdef CONFIG_TCC_ASM
ST_DATA Section *last_text_section; /* to handle .previous asm directive */
#endif
#ifdef CONFIG_TCC_BCHECK
/* bound check related sections */
ST_DATA Section *bounds_section; /* contains global data bound description */
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;
/* 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);
#ifdef CONFIG_TCC_BCHECK
ST_FUNC void tccelf_bounds_new(TCCState *s);
#endif
ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags);
ST_FUNC void section_realloc(Section *sec, unsigned long new_size);
ST_FUNC size_t section_add(Section *sec, addr_t size, int align);
@ -1412,10 +1497,9 @@ ST_FUNC int find_elf_sym(Section *s, const char *name);
ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, int type, int symbol);
ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset, int type, int symbol, addr_t addend);
ST_FUNC void put_stabs(const char *str, int type, int other, int desc, unsigned long value);
ST_FUNC void put_stabs_r(const char *str, int type, int other, int desc, unsigned long value, Section *sec, int sym_index);
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 put_stabs(TCCState *s1, const char *str, int type, int other, int desc, unsigned long value);
ST_FUNC void put_stabs_r(TCCState *s1, const char *str, int type, int other, int desc, unsigned long value, Section *sec, int sym_index);
ST_FUNC void put_stabn(TCCState *s1, int type, int other, int desc, int value);
ST_FUNC void resolve_common_syms(TCCState *s1);
ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve);
@ -1423,26 +1507,28 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s);
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 void tcc_add_bcheck(TCCState *s1);
ST_FUNC void tcc_add_runtime(TCCState *s1);
ST_FUNC int tcc_load_archive(TCCState *s1, int fd, int alacarte);
ST_FUNC void add_array(TCCState *s1, const char *sec, int c);
#ifndef ELF_OBJ_ONLY
ST_FUNC void build_got_entries(TCCState *s1);
#endif
ST_FUNC struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc);
ST_FUNC void squeeze_multi_relocs(Section *sec, size_t oldrelocoffset);
ST_FUNC addr_t get_elf_sym_addr(TCCState *s, const char *name, int err);
ST_FUNC void list_elf_symbols(TCCState *s, void *ctx,
void (*symbol_cb)(void *ctx, const char *name, const void *val));
#if defined TCC_IS_NATIVE || defined TCC_TARGET_PE
ST_FUNC void *tcc_get_symbol_err(TCCState *s, const char *name);
#endif
ST_FUNC int set_global_sym(TCCState *s1, const char *name, Section *sec, long offs);
#ifndef TCC_TARGET_PE
ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level);
ST_FUNC int tcc_load_ldscript(TCCState *s1);
ST_FUNC uint8_t *parse_comment(uint8_t *p);
ST_FUNC void minp(void);
ST_INLN void inp(void);
ST_FUNC int handle_eob(void);
ST_FUNC int tcc_load_ldscript(TCCState *s1, int fd);
ST_FUNC void tcc_add_runtime(TCCState *s1);
#endif
/* ------------ xxx-link.c ------------ */
@ -1456,12 +1542,13 @@ enum gotplt_entry {
ALWAYS_GOTPLT_ENTRY /* always generate (eg. PLTOFF relocs) */
};
#ifndef ELF_OBJ_ONLY
ST_FUNC int code_reloc (int reloc_type);
ST_FUNC int gotplt_entry_type (int reloc_type);
ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr);
ST_FUNC void relocate_init(Section *sr);
ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val);
ST_FUNC void relocate_plt(TCCState *s1);
#endif
ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val);
/* ------------ xxx-gen.c ------------ */
@ -1473,27 +1560,22 @@ ST_FUNC void load(int r, SValue *sv);
ST_FUNC void store(int r, SValue *v);
ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize);
ST_FUNC void gfunc_call(int nb_args);
ST_FUNC void gfunc_prolog(CType *func_type);
ST_FUNC void gfunc_prolog(Sym *func_sym);
ST_FUNC void gfunc_epilog(void);
ST_FUNC void gen_fill_nops(int);
ST_FUNC int gjmp(int t);
ST_FUNC void gjmp_addr(int a);
ST_FUNC int gtst(int inv, int t);
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
ST_FUNC void gtst_addr(int inv, int a);
#else
#define gtst_addr(inv, a) gsym_addr(gtst(inv, 0), a)
#endif
ST_FUNC int gjmp_cond(int op, int t);
ST_FUNC int gjmp_append(int n, int t);
ST_FUNC void gen_opi(int op);
ST_FUNC void gen_opf(int op);
ST_FUNC void gen_cvt_ftoi(int t);
ST_FUNC void gen_cvt_itof(int t);
ST_FUNC void gen_cvt_ftof(int t);
ST_FUNC void ggoto(void);
#ifndef TCC_TARGET_C67
ST_FUNC void o(unsigned int c);
#endif
#ifndef TCC_TARGET_ARM
ST_FUNC void gen_cvt_itof(int t);
#endif
ST_FUNC void gen_vla_sp_save(int addr);
ST_FUNC void gen_vla_sp_restore(int addr);
ST_FUNC void gen_vla_alloc(CType *type, int align);
@ -1530,6 +1612,7 @@ ST_FUNC void gen_le16(int c);
ST_FUNC void gen_le32(int c);
ST_FUNC void gen_addr32(int r, Sym *sym, int c);
ST_FUNC void gen_addrpc32(int r, Sym *sym, int c);
ST_FUNC void gen_cvt_csti(int t);
#endif
#ifdef CONFIG_TCC_BCHECK
@ -1544,6 +1627,8 @@ ST_FUNC void gen_opl(int op);
#ifdef TCC_TARGET_PE
ST_FUNC void gen_vla_result(int addr);
#endif
ST_FUNC void gen_cvt_sxtw(void);
ST_FUNC void gen_cvt_csti(int t);
#endif
/* ------------ arm-gen.c ------------ */
@ -1552,17 +1637,26 @@ ST_FUNC void gen_vla_result(int addr);
PUB_FUNC const char *default_elfinterp(struct TCCState *s);
#endif
ST_FUNC void arm_init(struct TCCState *s);
ST_FUNC void gen_cvt_itof1(int t);
#endif
/* ------------ arm64-gen.c ------------ */
#ifdef TCC_TARGET_ARM64
ST_FUNC void gen_cvt_sxtw(void);
ST_FUNC void gen_opl(int op);
ST_FUNC void gfunc_return(CType *func_type);
ST_FUNC void gen_va_start(void);
ST_FUNC void gen_va_arg(CType *t);
ST_FUNC void gen_clear_cache(void);
ST_FUNC void gen_cvt_sxtw(void);
ST_FUNC void gen_cvt_csti(int t);
#endif
/* ------------ riscv64-gen.c ------------ */
#ifdef TCC_TARGET_RISCV64
ST_FUNC void gen_opl(int op);
//ST_FUNC void gfunc_return(CType *func_type);
ST_FUNC void gen_va_start(void);
ST_FUNC void arch_transfer_ret_regs(int);
ST_FUNC void gen_cvt_sxtw(void);
#endif
/* ------------ c67-gen.c ------------ */
@ -1630,12 +1724,6 @@ ST_FUNC void dlclose(void *p);
ST_FUNC const char *dlerror(void);
ST_FUNC void *dlsym(void *handle, const char *symbol);
#endif
#ifdef CONFIG_TCC_BACKTRACE
ST_DATA int rt_num_callers;
ST_DATA const char **rt_bound_error_msg;
ST_DATA void *rt_prog_main;
ST_FUNC void tcc_set_num_callers(int n);
#endif
ST_FUNC void tcc_run_free(TCCState *s1);
#endif
@ -1656,5 +1744,42 @@ ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename)
#else
#define ST_DATA
#endif
/********************************************************/
#define text_section TCC_STATE_VAR(text_section)
#define data_section TCC_STATE_VAR(data_section)
#define bss_section TCC_STATE_VAR(bss_section)
#define common_section TCC_STATE_VAR(common_section)
#define cur_text_section TCC_STATE_VAR(cur_text_section)
#define bounds_section TCC_STATE_VAR(bounds_section)
#define lbounds_section TCC_STATE_VAR(lbounds_section)
#define symtab_section TCC_STATE_VAR(symtab_section)
#define stab_section TCC_STATE_VAR(stab_section)
#define stabstr_section stab_section->link
#define gnu_ext TCC_STATE_VAR(gnu_ext)
#define tcc_error_noabort TCC_SET_STATE(_tcc_error_noabort)
#define tcc_error TCC_SET_STATE(_tcc_error)
#define tcc_warning TCC_SET_STATE(_tcc_warning)
#define total_idents TCC_STATE_VAR(total_idents)
#define total_lines TCC_STATE_VAR(total_lines)
#define total_bytes TCC_STATE_VAR(total_bytes)
PUB_FUNC void tcc_enter_state(TCCState *s1);
/********************************************************/
#endif /* _TCC_H */
#undef TCC_STATE_VAR
#undef TCC_SET_STATE
#ifdef USING_GLOBALS
# define TCC_STATE_VAR(sym) tcc_state->sym
# define TCC_SET_STATE(fn) fn
# undef USING_GLOBALS
#else
# define TCC_STATE_VAR(sym) s1->sym
# define TCC_SET_STATE(fn) (tcc_enter_state(s1),fn)
/* actually we could avoid the tcc_enter_state(s1) hack by using
__VA_ARGS__ except that some compiler doesn't support it. */
#endif

View File

@ -18,9 +18,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define USING_GLOBALS
#include "tcc.h"
#ifdef CONFIG_TCC_ASM
static Section *last_text_section; /* to handle .previous asm directive */
ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n)
{
char buf[64];
@ -38,7 +41,7 @@ static Sym* asm_new_label1(TCCState *s1, int label, int is_local, int sh_num, in
static Sym *asm_label_find(int v)
{
Sym *sym = sym_find(v);
while (sym && sym->sym_scope)
while (sym && sym->sym_scope && !(sym->type.t & VT_STATIC))
sym = sym->prev_tok;
return sym;
}
@ -48,9 +51,7 @@ 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 global_identifier_push(v, VT_ASM | VT_EXTERN | VT_STATIC, 0);
}
/* Return a symbol we can use inside the assembler, having name NAME.
@ -107,7 +108,7 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
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);
tcc_error("local label '%d' not found backward", (int)n);
} else {
/* forward */
if (!sym || (sym->c && elfsym(sym)->st_shndx != SHN_UNDEF)) {
@ -914,9 +915,6 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
next();
if (tok == TOK_EOF)
break;
/* generate line number info */
if (global && s1->do_debug)
tcc_debug_line(s1);
parse_flags |= PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
redo:
if (tok == '#') {
@ -1148,8 +1146,8 @@ ST_FUNC void asm_instr(void)
ASMOperand operands[MAX_ASM_OPERANDS];
int nb_outputs, nb_operands, i, must_subst, out_reg;
uint8_t clobber_regs[NB_ASM_REGS];
Section *sec;
next();
/* since we always generate the asm() instruction, we can ignore
volatile */
if (tok == TOK_VOLATILE1 || tok == TOK_VOLATILE2 || tok == TOK_VOLATILE3) {
@ -1222,8 +1220,15 @@ ST_FUNC void asm_instr(void)
asm_gen_code(operands, nb_operands, nb_outputs, 0,
clobber_regs, out_reg);
/* We don't allow switching section within inline asm to
bleed out to surrounding code. */
sec = cur_text_section;
/* assemble the string with tcc internal assembler */
tcc_assemble_inline(tcc_state, astr1.data, astr1.size - 1, 0);
if (sec != cur_text_section) {
tcc_warning("inline asm tries to change current section");
use_section1(tcc_state, sec);
}
/* restore the current C token */
next();

View File

@ -40,12 +40,12 @@ int FuncEntries[MAX_FUNCS];
int OutputTheSection(Section * sect);
short int GetCoffFlags(const char *s);
void SortSymbolTable(void);
void SortSymbolTable(TCCState *s1);
Section *FindSection(TCCState * s1, const char *sname);
int C67_main_entry_point;
int FindCoffSymbolIndex(const char *func_name);
int FindCoffSymbolIndex(TCCState * s1, const char *func_name);
int nb_syms;
typedef struct {
@ -92,7 +92,7 @@ ST_FUNC int tcc_output_coff(TCCState *s1, FILE *f)
sbss = FindSection(s1, ".bss");
nb_syms = symtab_section->data_offset / sizeof(Elf32_Sym);
coff_nb_syms = FindCoffSymbolIndex("XXXXXXXXXX1");
coff_nb_syms = FindCoffSymbolIndex(s1, "XXXXXXXXXX1");
file_hdr.f_magic = COFF_C67_MAGIC; /* magic number */
file_hdr.f_timdat = 0; /* time & date stamp */
@ -366,7 +366,7 @@ ST_FUNC int tcc_output_coff(TCCState *s1, FILE *f)
// finally global symbols
if (s1->do_debug)
SortSymbolTable();
SortSymbolTable(s1);
// write line no data
@ -437,7 +437,7 @@ ST_FUNC int tcc_output_coff(TCCState *s1, FILE *f)
// output a function begin
CoffLineNo.l_addr.l_symndx =
FindCoffSymbolIndex(func_name);
FindCoffSymbolIndex(s1, func_name);
CoffLineNo.l_lnno = 0;
fwrite(&CoffLineNo, 6, 1, f);
@ -690,7 +690,7 @@ ST_FUNC int tcc_output_coff(TCCState *s1, FILE *f)
// group the symbols in order of filename, func1, func2, etc
// finally global symbols
void SortSymbolTable(void)
void SortSymbolTable(TCCState *s1)
{
int i, j, k, n = 0;
Elf32_Sym *p, *p2, *NewTable;
@ -770,7 +770,7 @@ void SortSymbolTable(void)
}
int FindCoffSymbolIndex(const char *func_name)
int FindCoffSymbolIndex(TCCState *s1, const char *func_name)
{
int i, n = 0;
Elf32_Sym *p;

1053
tccelf.c

File diff suppressed because it is too large Load Diff

5035
tccgen.c

File diff suppressed because it is too large Load Diff

378
tccpe.c
View File

@ -231,6 +231,15 @@ typedef struct _IMAGE_BASE_RELOCATION {
#define IMAGE_REL_BASED_REL32 7
#define IMAGE_REL_BASED_DIR64 10
#define IMAGE_SCN_CNT_CODE 0x00000020
#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080
#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
#define IMAGE_SCN_MEM_SHARED 0x10000000
#define IMAGE_SCN_MEM_EXECUTE 0x20000000
#define IMAGE_SCN_MEM_READ 0x40000000
#define IMAGE_SCN_MEM_WRITE 0x80000000
#pragma pack(pop)
/* ----------------------------------------------------------- */
@ -279,17 +288,6 @@ struct pe_rsrc_reloc {
/* ------------------------------------------------------------- */
/* internal temporary structures */
/*
#define IMAGE_SCN_CNT_CODE 0x00000020
#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080
#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
#define IMAGE_SCN_MEM_SHARED 0x10000000
#define IMAGE_SCN_MEM_EXECUTE 0x20000000
#define IMAGE_SCN_MEM_READ 0x40000000
#define IMAGE_SCN_MEM_WRITE 0x80000000
*/
enum {
sec_text = 0,
sec_data ,
@ -299,10 +297,12 @@ enum {
sec_other ,
sec_rsrc ,
sec_stab ,
sec_stabstr ,
sec_reloc ,
sec_last
};
#if 0
static const DWORD pe_sec_flags[] = {
0x60000020, /* ".text" , */
0xC0000040, /* ".data" , */
@ -314,14 +314,15 @@ static const DWORD pe_sec_flags[] = {
0x42000802, /* ".stab" , */
0x42000040, /* ".reloc" , */
};
#endif
struct section_info {
int cls, ord;
int cls;
char name[32];
DWORD sh_addr;
DWORD sh_size;
DWORD sh_flags;
unsigned char *data;
DWORD pe_flags;
Section *sec;
DWORD data_size;
IMAGE_SECTION_HEADER ish;
};
@ -357,7 +358,7 @@ struct pe_info {
int subsystem;
DWORD section_align;
DWORD file_align;
struct section_info *sec_info;
struct section_info **sec_info;
int sec_count;
struct pe_import_info **imp_info;
int imp_count;
@ -430,12 +431,10 @@ static int dynarray_assoc(void **pp, int n, int key)
return -1;
}
#if 0
ST_FN DWORD umin(DWORD a, DWORD b)
static DWORD umin(DWORD a, DWORD b)
{
return a < b ? a : b;
}
#endif
static DWORD umax(DWORD a, DWORD b)
{
@ -465,26 +464,37 @@ static void pe_set_datadir(struct pe_header *hdr, int dir, DWORD addr, DWORD siz
hdr->opthdr.DataDirectory[dir].Size = size;
}
static int pe_fwrite(void *data, unsigned len, FILE *fp, DWORD *psum)
struct pe_file {
FILE *op;
DWORD sum;
unsigned pos;
};
static int pe_fwrite(void *data, int len, struct pe_file *pf)
{
if (psum) {
DWORD sum = *psum;
WORD *p = data;
int i;
for (i = len; i > 0; i -= 2) {
sum += (i >= 2) ? *p++ : *(BYTE*)p;
sum = (sum + (sum >> 16)) & 0xFFFF;
}
*psum = sum;
WORD *p = data;
DWORD sum;
int ret, i;
pf->pos += (ret = fwrite(data, 1, len, pf->op));
sum = pf->sum;
for (i = len; i > 0; i -= 2) {
sum += (i >= 2) ? *p++ : *(BYTE*)p;
sum = (sum + (sum >> 16)) & 0xFFFF;
}
return len == fwrite(data, 1, len, fp) ? 0 : -1;
pf->sum = sum;
return len == ret ? 0 : -1;
}
static void pe_fpad(FILE *fp, DWORD new_pos)
static void pe_fpad(struct pe_file *pf, DWORD new_pos)
{
DWORD pos = ftell(fp);
while (++pos <= new_pos)
fputc(0, fp);
char buf[256];
int n, diff = new_pos - pf->pos;
memset(buf, 0, sizeof buf);
while (diff > 0) {
diff -= n = umin(diff, sizeof buf);
fwrite(buf, n, 1, pf->op);
}
pf->pos = new_pos;
}
/*----------------------------------------------------------------------------*/
@ -596,13 +606,14 @@ static int pe_write(struct pe_info *pe)
struct pe_header pe_header = pe_template;
int i;
FILE *op;
DWORD file_offset, sum;
struct pe_file pf = {0};
DWORD file_offset;
struct section_info *si;
IMAGE_SECTION_HEADER *psh;
TCCState *s1 = pe->s1;
op = fopen(pe->filename, "wb");
if (NULL == op) {
pf.op = fopen(pe->filename, "wb");
if (NULL == pf.op) {
tcc_error_noabort("could not write '%s': %s", pe->filename, strerror(errno));
return -1;
}
@ -621,7 +632,7 @@ static int pe_write(struct pe_info *pe)
DWORD addr, size;
const char *sh_name;
si = pe->sec_info + i;
si = pe->sec_info[i];
sh_name = si->name;
addr = si->sh_addr - pe->imagebase;
size = si->sh_size;
@ -633,12 +644,14 @@ static int pe_write(struct pe_info *pe)
switch (si->cls) {
case sec_text:
pe_header.opthdr.BaseOfCode = addr;
if (!pe_header.opthdr.BaseOfCode)
pe_header.opthdr.BaseOfCode = addr;
break;
case sec_data:
#ifndef TCC_TARGET_X86_64
pe_header.opthdr.BaseOfData = addr;
if (!pe_header.opthdr.BaseOfData)
pe_header.opthdr.BaseOfData = addr;
#endif
break;
@ -656,27 +669,22 @@ static int pe_write(struct pe_info *pe)
case sec_pdata:
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXCEPTION, addr, size);
break;
case sec_stab:
break;
}
if (pe->thunk == pe->s1->sections[si->ord]) {
if (pe->imp_size) {
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IMPORT,
pe->imp_offs + addr, pe->imp_size);
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IAT,
pe->iat_offs + addr, pe->iat_size);
}
if (pe->exp_size) {
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXPORT,
pe->exp_offs + addr, pe->exp_size);
}
if (pe->imp_size) {
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IMPORT,
pe->imp_offs, pe->imp_size);
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IAT,
pe->iat_offs, pe->iat_size);
}
if (pe->exp_size) {
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXPORT,
pe->exp_offs, pe->exp_size);
}
strncpy((char*)psh->Name, sh_name, sizeof psh->Name);
memcpy(psh->Name, sh_name, umin(strlen(sh_name), sizeof psh->Name));
psh->Characteristics = pe_sec_flags[si->cls];
psh->Characteristics = si->pe_flags;
psh->VirtualAddress = addr;
psh->Misc.VirtualSize = size;
pe_header.opthdr.SizeOfImage =
@ -705,25 +713,29 @@ static int pe_write(struct pe_info *pe)
pe_header.filehdr.Characteristics = CHARACTERISTICS_DLL;
pe_header.filehdr.Characteristics |= pe->s1->pe_characteristics;
sum = 0;
pe_fwrite(&pe_header, sizeof pe_header, op, &sum);
pe_fwrite(&pe_header, sizeof pe_header, &pf);
for (i = 0; i < pe->sec_count; ++i)
pe_fwrite(&pe->sec_info[i].ish, sizeof(IMAGE_SECTION_HEADER), op, &sum);
pe_fpad(op, pe->sizeofheaders);
pe_fwrite(&pe->sec_info[i]->ish, sizeof(IMAGE_SECTION_HEADER), &pf);
file_offset = pe->sizeofheaders;
for (i = 0; i < pe->sec_count; ++i) {
si = pe->sec_info + i;
psh = &si->ish;
if (si->data_size) {
pe_fwrite(si->data, si->data_size, op, &sum);
file_offset = psh->PointerToRawData + psh->SizeOfRawData;
pe_fpad(op, file_offset);
Section *s;
si = pe->sec_info[i];
for (s = si->sec; s; s = s->prev) {
pe_fpad(&pf, file_offset);
pe_fwrite(s->data, s->data_offset, &pf);
if (s->prev)
file_offset += s->prev->sh_addr - s->sh_addr;
}
file_offset = si->ish.PointerToRawData + si->ish.SizeOfRawData;
pe_fpad(&pf, file_offset);
}
pe_header.opthdr.CheckSum = sum + file_offset;
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);
pf.sum += file_offset;
fseek(pf.op, offsetof(struct pe_header, opthdr.CheckSum), SEEK_SET);
pe_fwrite(&pf.sum, sizeof (DWORD), &pf);
fclose (pf.op);
#ifndef _WIN32
chmod(pe->filename, 0777);
#endif
@ -785,6 +797,7 @@ static void pe_build_imports(struct pe_info *pe)
int thk_ptr, ent_ptr, dll_ptr, sym_cnt, i;
DWORD rva_base = pe->thunk->sh_addr - pe->imagebase;
int ndlls = pe->imp_count;
TCCState *s1 = pe->s1;
for (sym_cnt = i = 0; i < ndlls; ++i)
sym_cnt += pe->imp_info[i]->sym_count;
@ -793,16 +806,15 @@ static void pe_build_imports(struct pe_info *pe)
return;
pe_align_section(pe->thunk, 16);
pe->imp_offs = dll_ptr = pe->thunk->data_offset;
pe->imp_size = (ndlls + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR);
pe->iat_offs = dll_ptr + pe->imp_size;
pe->iat_size = (sym_cnt + ndlls) * sizeof(ADDR3264);
dll_ptr = pe->thunk->data_offset;
thk_ptr = dll_ptr + pe->imp_size;
ent_ptr = thk_ptr + pe->iat_size;
pe->imp_offs = dll_ptr + rva_base;
pe->iat_offs = thk_ptr + rva_base;
section_ptr_add(pe->thunk, pe->imp_size + 2*pe->iat_size);
thk_ptr = pe->iat_offs;
ent_ptr = pe->iat_offs + pe->iat_size;
for (i = 0; i < pe->imp_count; ++i) {
IMAGE_IMPORT_DESCRIPTOR *hdr;
int k, n, dllindex;
@ -892,10 +904,11 @@ static void pe_build_exports(struct pe_info *pe)
{
ElfW(Sym) *sym;
int sym_index, sym_end;
DWORD rva_base, func_o, name_o, ord_o, str_o;
DWORD rva_base, base_o, func_o, name_o, ord_o, str_o;
IMAGE_EXPORT_DIRECTORY *hdr;
int sym_count, ord;
struct pe_sort_sym **sorted, *p;
TCCState *s1 = pe->s1;
FILE *op;
char buf[260];
@ -933,13 +946,13 @@ static void pe_build_exports(struct pe_info *pe)
pe_align_section(pe->thunk, 16);
dllname = tcc_basename(pe->filename);
pe->exp_offs = pe->thunk->data_offset;
func_o = pe->exp_offs + sizeof(IMAGE_EXPORT_DIRECTORY);
base_o = pe->thunk->data_offset;
func_o = base_o + sizeof(IMAGE_EXPORT_DIRECTORY);
name_o = func_o + sym_count * sizeof (DWORD);
ord_o = name_o + sym_count * sizeof (DWORD);
str_o = ord_o + sym_count * sizeof(WORD);
hdr = section_ptr_add(pe->thunk, str_o - pe->exp_offs);
hdr = section_ptr_add(pe->thunk, str_o - base_o);
hdr->Characteristics = 0;
hdr->Base = 1;
hdr->NumberOfFunctions = sym_count;
@ -981,7 +994,9 @@ static void pe_build_exports(struct pe_info *pe)
if (op)
fprintf(op, "%s\n", name);
}
pe->exp_size = pe->thunk->data_offset - pe->exp_offs;
pe->exp_offs = base_o + rva_base;
pe->exp_size = pe->thunk->data_offset - base_o;
dynarray_reset(&sorted, &sym_count);
if (op)
fclose(op);
@ -990,18 +1005,19 @@ static void pe_build_exports(struct pe_info *pe)
/* ------------------------------------------------------------- */
static void pe_build_reloc (struct pe_info *pe)
{
DWORD offset, block_ptr, addr;
DWORD offset, block_ptr, sh_addr, addr;
int count, i;
ElfW_Rel *rel, *rel_end;
Section *s = NULL, *sr;
struct pe_reloc_header *hdr;
offset = addr = block_ptr = count = i = 0;
sh_addr = offset = block_ptr = count = i = 0;
rel = rel_end = NULL;
for(;;) {
if (rel < rel_end) {
int type = ELFW(R_TYPE)(rel->r_info);
addr = rel->r_offset + s->sh_addr;
addr = rel->r_offset + sh_addr;
++ rel;
if (type != REL_TYPE_DIRECT)
continue;
@ -1018,28 +1034,30 @@ static void pe_build_reloc (struct pe_info *pe)
}
-- rel;
} else if (i < pe->sec_count) {
sr = (s = pe->s1->sections[pe->sec_info[i++].ord])->reloc;
} else if (s) {
sr = s->reloc;
if (sr) {
rel = (ElfW_Rel *)sr->data;
rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
sh_addr = s->sh_addr;
}
s = s->prev;
continue;
}
if (count) {
/* store the last block and ready for a new one */
struct pe_reloc_header *hdr;
if (count & 1) /* align for DWORDS */
section_ptr_add(pe->reloc, sizeof(WORD)), ++count;
hdr = (struct pe_reloc_header *)(pe->reloc->data + block_ptr);
hdr -> offset = offset - pe->imagebase;
hdr -> size = count * sizeof(WORD) + sizeof(struct pe_reloc_header);
count = 0;
}
} else if (i < pe->sec_count) {
s = pe->sec_info[i]->sec, ++i;
continue;
if (rel >= rel_end)
} else if (!count)
break;
/* fill the last block and ready for a new one */
if (count & 1) /* align for DWORDS */
section_ptr_add(pe->reloc, sizeof(WORD)), ++count;
hdr = (struct pe_reloc_header *)(pe->reloc->data + block_ptr);
hdr -> offset = offset - pe->imagebase;
hdr -> size = count * sizeof(WORD) + sizeof(struct pe_reloc_header);
count = 0;
}
}
@ -1064,7 +1082,6 @@ static int pe_section_class(Section *s)
return sec_idata;
if (0 == strcmp(name, ".pdata"))
return sec_pdata;
return sec_other;
} else if (type == SHT_NOBITS) {
if (flags & SHF_WRITE)
return sec_bss;
@ -1072,9 +1089,11 @@ static int pe_section_class(Section *s)
} else {
if (0 == strcmp(name, ".reloc"))
return sec_reloc;
if (0 == strncmp(name, ".stab", 5)) /* .stab and .stabstr */
return sec_stab;
}
if (0 == memcmp(name, ".stab", 5))
return name[5] ? sec_stabstr : sec_stab;
if (flags & SHF_ALLOC)
return sec_other;
return -1;
}
@ -1088,48 +1107,39 @@ static int pe_assign_addresses (struct pe_info *pe)
if (PE_DLL == pe->type)
pe->reloc = new_section(pe->s1, ".reloc", SHT_PROGBITS, 0);
// pe->thunk = new_section(pe->s1, ".iedat", SHT_PROGBITS, SHF_ALLOC);
section_order = tcc_malloc(pe->s1->nb_sections * sizeof (int));
for (o = k = 0 ; k < sec_last; ++k) {
for (i = 1; i < pe->s1->nb_sections; ++i) {
s = pe->s1->sections[i];
if (k == pe_section_class(s)) {
// printf("%s %d\n", s->name, k);
s->sh_addr = pe->imagebase;
if (k == pe_section_class(s))
section_order[o++] = i;
}
}
}
pe->sec_info = tcc_mallocz(o * sizeof (struct section_info));
si = NULL;
addr = pe->imagebase + 1;
for (i = 0; i < o; ++i)
{
for (i = 0; i < o; ++i) {
k = section_order[i];
s = pe->s1->sections[k];
c = pe_section_class(s);
si = &pe->sec_info[pe->sec_count];
if ((c == sec_stab || c == sec_stabstr) && 0 == pe->s1->do_debug)
continue;
#ifdef PE_MERGE_DATA
if (c == sec_bss && pe->sec_count && si[-1].cls == sec_data) {
/* append .bss to .data */
s->sh_addr = addr = ((addr-1) | (s->sh_addralign-1)) + 1;
addr += s->data_offset;
si[-1].sh_size = addr - si[-1].sh_addr;
continue;
}
if (c == sec_bss)
c = sec_data;
#endif
if (c == sec_stab && 0 == pe->s1->do_debug)
continue;
strcpy(si->name, s->name);
si->cls = c;
si->ord = k;
si->sh_addr = s->sh_addr = addr = pe_virtual_align(pe, addr);
si->sh_flags = s->sh_flags;
if (si && c == si->cls) {
/* merge with previous section */
s->sh_addr = addr = ((addr - 1) | (16 - 1)) + 1;
} else {
si = NULL;
s->sh_addr = addr = pe_virtual_align(pe, addr);
}
if (c == sec_data && NULL == pe->thunk)
pe->thunk = s;
@ -1138,36 +1148,60 @@ static int pe_assign_addresses (struct pe_info *pe)
pe_build_imports(pe);
pe_build_exports(pe);
}
if (c == sec_reloc)
if (s == pe->reloc)
pe_build_reloc (pe);
if (s->data_offset)
{
if (s->sh_type != SHT_NOBITS) {
si->data = s->data;
si->data_size = s->data_offset;
}
if (0 == s->data_offset)
continue;
addr += s->data_offset;
si->sh_size = s->data_offset;
++pe->sec_count;
if (si)
goto add_section;
si = tcc_mallocz(sizeof *si);
dynarray_add(&pe->sec_info, &pe->sec_count, si);
strcpy(si->name, s->name);
si->cls = c;
si->sh_addr = addr;
si->pe_flags = IMAGE_SCN_MEM_READ;
if (s->sh_flags & SHF_EXECINSTR)
si->pe_flags |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE;
else if (s->sh_type == SHT_NOBITS)
si->pe_flags |= IMAGE_SCN_CNT_UNINITIALIZED_DATA;
else
si->pe_flags |= IMAGE_SCN_CNT_INITIALIZED_DATA;
if (s->sh_flags & SHF_WRITE)
si->pe_flags |= IMAGE_SCN_MEM_WRITE;
if (0 == (s->sh_flags & SHF_ALLOC))
si->pe_flags |= IMAGE_SCN_MEM_DISCARDABLE;
add_section:
addr += s->data_offset;
si->sh_size = addr - si->sh_addr;
if (s->sh_type != SHT_NOBITS) {
Section **ps = &si->sec;
while (*ps)
ps = &(*ps)->prev;
*ps = s, s->prev = NULL;
si->data_size = si->sh_size;
}
// printf("%08x %05x %s\n", si->sh_addr, si->sh_size, si->name);
//printf("%08x %05x %08x %s\n", si->sh_addr, si->sh_size, si->pe_flags, s->name);
}
tcc_free(section_order);
#if 0
for (i = 1; i < pe->s1->nb_sections; ++i) {
Section *s = pe->s1->sections[i];
int type = s->sh_type;
int flags = s->sh_flags;
printf("section %-16s %-10s %5x %s,%s,%s\n",
printf("section %-16s %-10s %08x %04x %s,%s,%s\n",
s->name,
type == SHT_PROGBITS ? "progbits" :
type == SHT_NOBITS ? "nobits" :
type == SHT_SYMTAB ? "symtab" :
type == SHT_STRTAB ? "strtab" :
type == SHT_RELX ? "rel" : "???",
s->sh_addr,
s->data_offset,
flags & SHF_ALLOC ? "alloc" : "",
flags & SHF_WRITE ? "write" : "",
@ -1176,14 +1210,12 @@ static int pe_assign_addresses (struct pe_info *pe)
}
pe->s1->verbose = 2;
#endif
tcc_free(section_order);
return 0;
}
/*----------------------------------------------------------------------------*/
static int pe_isafunc(int sym_index)
static int pe_isafunc(TCCState *s1, int sym_index)
{
Section *sr = text_section->reloc;
ElfW_Rel *rel, *rel_end;
@ -1203,6 +1235,7 @@ static int pe_check_symbols(struct pe_info *pe)
ElfW(Sym) *sym;
int sym_index, sym_end;
int ret = 0;
TCCState *s1 = pe->s1;
pe_align_section(text_section, 8);
@ -1222,7 +1255,7 @@ static int pe_check_symbols(struct pe_info *pe)
if (type == STT_NOTYPE) {
/* symbols from assembler have no type, find out which */
if (pe_isafunc(sym_index))
if (pe_isafunc(s1, sym_index))
type = STT_FUNC;
else
type = STT_OBJECT;
@ -1747,7 +1780,7 @@ ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd)
ret = pe_load_def(s1, fd);
else if (pe_load_res(s1, fd) == 0)
ret = 0;
else if (read_mem(fd, 0, buf, 4) && 0 == memcmp(buf, "MZ\220", 4))
else if (read_mem(fd, 0, buf, 4) && 0 == memcmp(buf, "MZ", 2))
ret = pe_load_dll(s1, filename);
return ret;
}
@ -1757,7 +1790,7 @@ ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd)
static unsigned pe_add_uwwind_info(TCCState *s1)
{
if (NULL == s1->uw_pdata) {
s1->uw_pdata = find_section(tcc_state, ".pdata");
s1->uw_pdata = find_section(s1, ".pdata");
s1->uw_pdata->sh_addralign = 4;
}
if (0 == s1->uw_sym)
@ -1820,6 +1853,12 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack)
#define PE_STDSYM(n,s) "_" n s
#endif
static void tcc_add_support(TCCState *s1, const char *filename)
{
if (tcc_add_dll(s1, filename, 0) < 0)
tcc_error_noabort("%s not found", filename);
}
static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
{
const char *start_symbol;
@ -1836,8 +1875,6 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
else
if (TCC_OUTPUT_DLL == s1->output_type) {
pe_type = PE_DLL;
/* need this for 'tccelf.c:relocate_section()' */
s1->output_type = TCC_OUTPUT_EXE;
}
else {
pe_type = PE_EXE;
@ -1857,34 +1894,46 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
if (!s1->leading_underscore || strchr(start_symbol, '@'))
++start_symbol;
/* grab the startup code from libtcc1 */
#ifdef CONFIG_TCC_BACKTRACE
if (s1->do_backtrace) {
#ifdef CONFIG_TCC_BCHECK
if (s1->do_bounds_check && s1->output_type != TCC_OUTPUT_DLL)
tcc_add_support(s1, "bcheck.o");
#endif
if (s1->output_type == TCC_OUTPUT_EXE)
tcc_add_support(s1, "bt-exe.o");
if (s1->output_type == TCC_OUTPUT_DLL)
tcc_add_support(s1, "bt-dll.o");
if (s1->output_type != TCC_OUTPUT_DLL)
tcc_add_support(s1, "bt-log.o");
if (s1->output_type != TCC_OUTPUT_MEMORY)
tcc_add_btstub(s1);
}
#endif
/* grab the startup code from libtcc1.a */
#ifdef TCC_IS_NATIVE
if (TCC_OUTPUT_MEMORY != s1->output_type || s1->runtime_main)
#endif
set_elf_sym(symtab_section,
0, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
SHN_UNDEF, start_symbol);
tcc_add_pragma_libs(s1);
set_global_sym(s1, start_symbol, NULL, 0);
if (0 == s1->nostdlib) {
static const char *libs[] = {
TCC_LIBTCC1, "msvcrt", "kernel32", "", "user32", "gdi32", NULL
"msvcrt", "kernel32", "", "user32", "gdi32", NULL
};
const char **pp, *p;
tcc_add_support(s1, TCC_LIBTCC1);
for (pp = libs; 0 != (p = *pp); ++pp) {
if (0 == *p) {
if (PE_DLL != pe_type && PE_GUI != pe_type)
break;
} else if (pp == libs && tcc_add_dll(s1, p, 0) >= 0) {
continue;
} else {
if (*p)
tcc_add_library_err(s1, p);
}
else if (PE_DLL != pe_type && PE_GUI != pe_type)
break;
}
}
/* need this for 'tccelf.c:relocate_section()' */
if (TCC_OUTPUT_DLL == s1->output_type)
s1->output_type = TCC_OUTPUT_EXE;
if (TCC_OUTPUT_MEMORY == s1->output_type)
pe_type = PE_RUN;
pe->type = pe_type;
@ -1948,7 +1997,10 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
pe.filename = filename;
pe.s1 = s1;
#ifdef CONFIG_TCC_BCHECK
tcc_add_bcheck(s1);
#endif
tcc_add_pragma_libs(s1);
pe_add_runtime(s1, &pe);
resolve_common_syms(s1);
pe_set_options(s1, &pe);
@ -1973,7 +2025,7 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
ret = -1;
else
ret = pe_write(&pe);
tcc_free(pe.sec_info);
dynarray_reset(&pe.sec_info, &pe.sec_count);
} else {
#ifdef TCC_IS_NATIVE
pe.thunk = data_section;

169
tccpp.c
View File

@ -18,6 +18,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define USING_GLOBALS
#include "tcc.h"
/********************************************************/
@ -33,8 +34,6 @@ ST_DATA const int *macro_ptr;
ST_DATA CString tokcstr; /* current parsed string, if any */
/* display benchmark infos */
ST_DATA int total_lines;
ST_DATA int total_bytes;
ST_DATA int tok_ident;
ST_DATA TokenSym **table_ident;
@ -54,7 +53,6 @@ static void tok_print(const char *msg, const int *str);
static struct TinyAlloc *toksym_alloc;
static struct TinyAlloc *tokstr_alloc;
static struct TinyAlloc *cstr_alloc;
static TokenString *macro_stack;
@ -250,7 +248,7 @@ static void *tal_realloc_impl(TinyAlloc **pal, void *p, unsigned size TAL_DEBUG_
tail_call:
is_own = (al->buffer <= (uint8_t *)p && (uint8_t *)p < al->buffer + al->size);
if ((!p || is_own) && size <= al->limit) {
if (al->p + adj_size + sizeof(tal_header_t) < al->buffer + al->size) {
if (al->p - al->buffer + adj_size + sizeof(tal_header_t) < al->size) {
header = (tal_header_t *)al->p;
header->size = adj_size;
#ifdef TAL_DEBUG
@ -331,7 +329,7 @@ static void cstr_realloc(CString *cstr, int new_size)
size = 8; /* no need to allocate a too small first string */
while (size < new_size)
size = size * 2;
cstr->data = tal_realloc(cstr_alloc, cstr->data, size);
cstr->data = tcc_realloc(cstr->data, size);
cstr->size_allocated = size;
}
@ -377,7 +375,7 @@ ST_FUNC void cstr_new(CString *cstr)
/* free string and reset it to NULL */
ST_FUNC void cstr_free(CString *cstr)
{
tal_free(cstr_alloc, cstr->data);
tcc_free(cstr->data);
cstr_new(cstr);
}
@ -387,6 +385,24 @@ ST_FUNC void cstr_reset(CString *cstr)
cstr->size = 0;
}
ST_FUNC int cstr_printf(CString *cstr, const char *fmt, ...)
{
va_list v;
int len, size;
va_start(v, fmt);
len = vsnprintf(NULL, 0, fmt, v);
va_end(v);
size = cstr->size + len + 1;
if (size > cstr->size_allocated)
cstr_realloc(cstr, size);
va_start(v, fmt);
vsnprintf((char*)cstr->data + cstr->size, size, fmt, v);
va_end(v);
cstr->size += len;
return len;
}
/* XXX: unicode ? */
static void add_char(CString *cstr, int c)
{
@ -584,7 +600,7 @@ ST_FUNC const char *get_tok_str(int v, CValue *cv)
/* return the current character, handling end of block if necessary
(but not stray) */
ST_FUNC int handle_eob(void)
static int handle_eob(void)
{
BufferedFile *bf = file;
int len;
@ -617,7 +633,7 @@ ST_FUNC int handle_eob(void)
}
/* read next char from current input file and handle end of input buffer */
ST_INLN void inp(void)
static inline void inp(void)
{
ch = *(++(file->buf_ptr));
/* end of buffer/file handling */
@ -703,7 +719,7 @@ static int handle_stray1(uint8_t *p)
/* input with '\[\r]\n' handling. Note that this function cannot
handle other characters after '\', so you cannot call it inside
strings or comments */
ST_FUNC void minp(void)
static void minp(void)
{
inp();
if (ch == '\\')
@ -748,7 +764,7 @@ static uint8_t *parse_line_comment(uint8_t *p)
}
/* C comments */
ST_FUNC uint8_t *parse_comment(uint8_t *p)
static uint8_t *parse_comment(uint8_t *p)
{
int c;
@ -1119,9 +1135,9 @@ ST_FUNC void end_macro(void)
macro_stack = str->prev;
macro_ptr = str->prev_ptr;
file->line_num = str->save_line_num;
if (str->alloc == 2) {
str->alloc = 3; /* just mark as finished */
} else {
if (str->alloc != 0) {
if (str->alloc == 2)
str->str = NULL; /* don't free */
tok_str_free(str);
}
}
@ -1213,8 +1229,7 @@ ST_FUNC void tok_str_add_tok(TokenString *s)
tok_str_add2(s, tok, &tokc);
}
/* get a token from an integer array and increment pointer
accordingly. we code it as a macro to avoid pointer aliasing. */
/* get a token from an integer array and increment pointer. */
static inline void TOK_GET(int *t, const int **pp, CValue *cv)
{
const int *p = *pp;
@ -1339,18 +1354,6 @@ ST_FUNC void free_defines(Sym *b)
define_undef(top);
sym_free(top);
}
/* restore remaining (-D or predefined) symbols if they were
#undef'd in the file */
while (b) {
int v = b->v;
if (v >= TOK_IDENT && v < tok_ident) {
Sym **d = &table_ident[v - TOK_IDENT]->sym_define;
if (!*d)
*d = b;
}
b = b->prev;
}
}
/* label lookup */
@ -1399,9 +1402,12 @@ ST_FUNC void label_pop(Sym **ptop, Sym *slast, int keep)
}
}
/* remove label */
table_ident[s->v - TOK_IDENT]->sym_label = s->prev_tok;
if (s->r != LABEL_GONE)
table_ident[s->v - TOK_IDENT]->sym_label = s->prev_tok;
if (!keep)
sym_free(s);
else
s->r = LABEL_GONE;
}
if (!keep)
*ptop = slast;
@ -1800,9 +1806,9 @@ ST_FUNC void preprocess(int is_bof)
if (s1->include_stack_ptr >= s1->include_stack + INCLUDE_STACK_SIZE)
tcc_error("#include recursion too deep");
/* store current file in stack, but increment stack later below */
*s1->include_stack_ptr = file;
i = tok == TOK_INCLUDE_NEXT ? file->include_next_index : 0;
/* push current file on stack */
*s1->include_stack_ptr++ = file;
i = tok == TOK_INCLUDE_NEXT ? file->include_next_index: 0;
n = 2 + s1->nb_include_paths + s1->nb_sysinclude_paths;
for (; i < n; ++i) {
char buf1[sizeof file->filename];
@ -1850,19 +1856,19 @@ ST_FUNC void preprocess(int is_bof)
printf("%s: including %s\n", file->prev->filename, file->filename);
#endif
/* update target deps */
dynarray_add(&s1->target_deps, &s1->nb_target_deps,
if (s1->gen_deps) {
dynarray_add(&s1->target_deps, &s1->nb_target_deps,
tcc_strdup(buf1));
/* push current file in stack */
++s1->include_stack_ptr;
}
/* add include file debug info */
if (s1->do_debug)
put_stabs(file->filename, N_BINCL, 0, 0, 0);
tcc_debug_bincl(tcc_state);
tok_flags |= TOK_FLAG_BOF | TOK_FLAG_BOL;
ch = file->buf_ptr[0];
goto the_end;
}
tcc_error("include file '%s' not found", buf);
include_done:
--s1->include_stack_ptr;
break;
case TOK_IFNDEF:
c = 1;
@ -1953,7 +1959,11 @@ include_done:
if (tok == TOK_STR) {
if (file->true_filename == file->filename)
file->true_filename = tcc_strdup(file->filename);
pstrcpy(file->filename, sizeof(file->filename), (char *)tokc.str.data);
/* prepend directory from real file */
pstrcpy(buf, sizeof buf, file->true_filename);
*tcc_basename(buf) = 0;
pstrcat(buf, sizeof buf, (char *)tokc.str.data);
tcc_debug_putfile(s1, buf);
} else if (parse_flags & PARSE_FLAG_ASM_FILE)
break;
else
@ -1963,8 +1973,6 @@ include_done:
if (file->fd > 0)
total_lines += file->line_num - n;
file->line_num = n;
if (s1->do_debug)
put_stabs(file->filename, N_BINCL, 0, 0, 0);
break;
case TOK_ERROR:
case TOK_WARNING:
@ -2278,7 +2286,7 @@ static void parse_number(const char *p)
q--;
ch = *p++;
b = 16;
} else if (tcc_ext && (ch == 'b' || ch == 'B')) {
} else if (tcc_state->tcc_ext && (ch == 'b' || ch == 'B')) {
q--;
ch = *p++;
b = 2;
@ -2621,9 +2629,7 @@ static inline void next_nomacro1(void)
}
/* add end of include file debug info */
if (tcc_state->do_debug) {
put_stabd(N_EINCL, 0, 0);
}
tcc_debug_eincl(tcc_state);
/* pop include stack */
tcc_close();
s1->include_stack_ptr--;
@ -3144,7 +3150,7 @@ static int paste_tokens(int t1, CValue *v1, int t2, CValue *v2)
if (is_space(tok))
continue;
tcc_warning("pasting \"%.*s\" and \"%s\" does not give a valid"
" preprocessing token", n, cstr.data, (char*)cstr.data + n);
" preprocessing token", n, (char *)cstr.data, (char*)cstr.data + n);
ret = 0;
break;
}
@ -3487,14 +3493,14 @@ static void macro_subst(
}
{
TokenString str;
str.str = (int*)macro_str;
begin_macro(&str, 2);
TokenString *str = tok_str_alloc();
str->str = (int*)macro_str;
begin_macro(str, 2);
tok = t;
macro_subst_tok(tok_str, nested_list, s);
if (str.alloc == 3) {
if (macro_stack != str) {
/* already finished by reading function macro arguments */
break;
}
@ -3552,7 +3558,7 @@ ST_FUNC void next(void)
tokstr_buf.len = 0;
macro_subst_tok(&tokstr_buf, &nested_list, s);
tok_str_add(&tokstr_buf, 0);
begin_macro(&tokstr_buf, 2);
begin_macro(&tokstr_buf, 0);
goto redo;
}
}
@ -3581,7 +3587,8 @@ ST_INLN void unget_tok(int last_tok)
ST_FUNC void preprocess_start(TCCState *s1, int is_asm)
{
CString cstr;
int i;
tccpp_new(s1);
s1->include_stack_ptr = s1->include_stack;
s1->ifdef_stack_ptr = s1->ifdef_stack;
@ -3590,7 +3597,6 @@ ST_FUNC void preprocess_start(TCCState *s1, int is_asm)
pp_counter = 0;
pp_debug_tok = pp_debug_symv = 0;
pp_once++;
pvtop = vtop = vstack - 1;
s1->pack_stack[0] = 0;
s1->pack_stack_ptr = s1->pack_stack;
@ -3598,26 +3604,22 @@ ST_FUNC void preprocess_start(TCCState *s1, int is_asm)
set_idnum('.', is_asm ? IS_ID : 0);
cstr_new(&cstr);
cstr_cat(&cstr, "\"", -1);
cstr_cat(&cstr, file->filename, -1);
cstr_cat(&cstr, "\"", 0);
tcc_define_symbol(s1, "__BASE_FILE__", cstr.data);
cstr_reset(&cstr);
for (i = 0; i < s1->nb_cmd_include_files; i++) {
cstr_cat(&cstr, "#include \"", -1);
cstr_cat(&cstr, s1->cmd_include_files[i], -1);
cstr_cat(&cstr, "\"\n", -1);
}
if (cstr.size) {
*s1->include_stack_ptr++ = file;
tcc_open_bf(s1, "<command line>", cstr.size);
memcpy(file->buffer, cstr.data, cstr.size);
}
cstr_free(&cstr);
if (s1->cmdline_defs.size)
cstr_cat(&cstr, s1->cmdline_defs.data, s1->cmdline_defs.size);
cstr_printf(&cstr, "#define __BASE_FILE__ \"%s\"\n", file->filename);
if (is_asm)
tcc_define_symbol(s1, "__ASSEMBLER__", NULL);
cstr_printf(&cstr, "#define __ASSEMBLER__ 1\n");
if (s1->output_type == TCC_OUTPUT_MEMORY)
cstr_printf(&cstr, "#define __TCC_RUN__ 1\n");
if (!is_asm && s1->output_type != TCC_OUTPUT_PREPROCESS)
cstr_cat(&cstr, "#include \"tcc_predefs.h\"\n", -1);
if (s1->cmdline_incl.size)
cstr_cat(&cstr, s1->cmdline_incl.data, s1->cmdline_incl.size);
//printf("%s\n", (char*)cstr.data);
*s1->include_stack_ptr++ = file;
tcc_open_bf(s1, "<command line>", cstr.size);
memcpy(file->buffer, cstr.data, cstr.size);
cstr_free(&cstr);
parse_flags = is_asm ? PARSE_FLAG_ASM_FILE : 0;
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
@ -3629,6 +3631,9 @@ ST_FUNC void preprocess_end(TCCState *s1)
while (macro_stack)
end_macro();
macro_ptr = NULL;
while (file)
tcc_close();
tccpp_delete(s1);
}
ST_FUNC void tccpp_new(TCCState *s)
@ -3636,10 +3641,6 @@ ST_FUNC void tccpp_new(TCCState *s)
int i, c;
const char *p, *r;
/* might be used in error() before preprocess_start() */
s->include_stack_ptr = s->include_stack;
s->ppfp = stdout;
/* init isid table */
for(i = CH_EOF; i<128; i++)
set_idnum(i,
@ -3654,14 +3655,15 @@ ST_FUNC void tccpp_new(TCCState *s)
/* init allocators */
tal_new(&toksym_alloc, TOKSYM_TAL_LIMIT, TOKSYM_TAL_SIZE);
tal_new(&tokstr_alloc, TOKSTR_TAL_LIMIT, TOKSTR_TAL_SIZE);
tal_new(&cstr_alloc, CSTR_TAL_LIMIT, CSTR_TAL_SIZE);
memset(hash_ident, 0, TOK_HASH_SIZE * sizeof(TokenSym *));
memset(s->cached_includes_hash, 0, sizeof s->cached_includes_hash);
cstr_new(&cstr_buf);
cstr_realloc(&cstr_buf, STRING_MAX_SIZE);
tok_str_new(&tokstr_buf);
tok_str_realloc(&tokstr_buf, TOKSTR_MAX_SIZE);
tok_ident = TOK_IDENT;
p = tcc_keywords;
while (*p) {
@ -3674,17 +3676,26 @@ ST_FUNC void tccpp_new(TCCState *s)
tok_alloc(p, r - p - 1);
p = r;
}
/* we add dummy defines for some special macros to speed up tests
and to have working defined() */
define_push(TOK___LINE__, MACRO_OBJ, NULL, NULL);
define_push(TOK___FILE__, MACRO_OBJ, NULL, NULL);
define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL);
define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL);
define_push(TOK___COUNTER__, MACRO_OBJ, NULL, NULL);
}
ST_FUNC void tccpp_delete(TCCState *s)
{
int i, n;
/* free -D and compiler defines */
free_defines(NULL);
dynarray_reset(&s->cached_includes, &s->nb_cached_includes);
/* free tokens */
n = tok_ident - TOK_IDENT;
if (n > total_idents)
total_idents = n;
for(i = 0; i < n; i++)
tal_free(toksym_alloc, table_ident[i]);
tcc_free(table_ident);
@ -3701,8 +3712,6 @@ ST_FUNC void tccpp_delete(TCCState *s)
toksym_alloc = NULL;
tal_delete(tokstr_alloc);
tokstr_alloc = NULL;
tal_delete(cstr_alloc);
cstr_alloc = NULL;
}
/* ------------------------------------------------------------------------- */

863
tccrun.c

File diff suppressed because it is too large Load Diff

View File

@ -38,6 +38,7 @@
DEF(TOK_EXTENSION, "__extension__") /* gcc keyword */
DEF(TOK_GENERIC, "_Generic")
DEF(TOK_STATIC_ASSERT, "_Static_assert")
DEF(TOK_FLOAT, "float")
DEF(TOK_DOUBLE, "double")
@ -53,6 +54,8 @@
DEF(TOK_ATTRIBUTE2, "__attribute__")
DEF(TOK_ALIGNOF1, "__alignof")
DEF(TOK_ALIGNOF2, "__alignof__")
DEF(TOK_ALIGNOF3, "_Alignof")
DEF(TOK_ALIGNAS, "_Alignas")
DEF(TOK_TYPEOF1, "typeof")
DEF(TOK_TYPEOF2, "__typeof")
DEF(TOK_TYPEOF3, "__typeof__")
@ -122,6 +125,12 @@
DEF(TOK_FASTCALL3, "__fastcall__")
DEF(TOK_REGPARM1, "regparm")
DEF(TOK_REGPARM2, "__regparm__")
DEF(TOK_CLEANUP1, "cleanup")
DEF(TOK_CLEANUP2, "__cleanup__")
DEF(TOK_CONSTRUCTOR1, "constructor")
DEF(TOK_CONSTRUCTOR2, "__constructor__")
DEF(TOK_DESTRUCTOR1, "destructor")
DEF(TOK_DESTRUCTOR2, "__destructor__")
DEF(TOK_MODE, "__mode__")
DEF(TOK_MODE_QI, "__QI__")
@ -132,8 +141,10 @@
DEF(TOK_DLLEXPORT, "dllexport")
DEF(TOK_DLLIMPORT, "dllimport")
DEF(TOK_NODECORATE, "nodecorate")
DEF(TOK_NORETURN1, "noreturn")
DEF(TOK_NORETURN2, "__noreturn__")
DEF(TOK_NORETURN3, "_Noreturn")
DEF(TOK_VISIBILITY1, "visibility")
DEF(TOK_VISIBILITY2, "__visibility__")
@ -149,8 +160,10 @@
#elif defined TCC_TARGET_X86_64
DEF(TOK_builtin_va_arg_types, "__builtin_va_arg_types")
#elif defined TCC_TARGET_ARM64
DEF(TOK___va_start, "__va_start")
DEF(TOK___va_arg, "__va_arg")
DEF(TOK_builtin_va_start, "__builtin_va_start")
DEF(TOK_builtin_va_arg, "__builtin_va_arg")
#elif defined TCC_TARGET_RISCV64
DEF(TOK_builtin_va_start, "__builtin_va_start")
#endif
/* pragma */
@ -254,7 +267,7 @@
#if defined TCC_TARGET_PE
DEF(TOK___chkstk, "__chkstk")
#endif
#ifdef TCC_TARGET_ARM64
#if defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64
DEF(TOK___arm64_clear_cache, "__arm64_clear_cache")
DEF(TOK___addtf3, "__addtf3")
DEF(TOK___subtf3, "__subtf3")
@ -293,14 +306,26 @@
DEF(TOK___bound_local_new, "__bound_local_new")
DEF(TOK___bound_local_delete, "__bound_local_delete")
# ifdef TCC_TARGET_PE
# ifdef TCC_TARGET_X86_64
DEF(TOK___bound_alloca_nr, "__bound_alloca_nr")
# endif
DEF(TOK_malloc, "malloc")
DEF(TOK_free, "free")
DEF(TOK_realloc, "realloc")
DEF(TOK_memalign, "memalign")
DEF(TOK_calloc, "calloc")
# endif
DEF(TOK_mmap, "mmap")
DEF(TOK_munmap, "munmap")
DEF(TOK_memcmp, "memcmp")
DEF(TOK_strlen, "strlen")
DEF(TOK_strcpy, "strcpy")
DEF(TOK_strncpy, "strncpy")
DEF(TOK_strcmp, "strcmp")
DEF(TOK_strncmp, "strncmp")
DEF(TOK_strcat, "strcat")
DEF(TOK_strchr, "strchr")
DEF(TOK_strdup, "strdup")
#endif
/* Tiny Assembler */

View File

@ -430,7 +430,7 @@ the_end:
#if !defined TCC_TARGET_I386 && !defined TCC_TARGET_X86_64
ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int option)
ST_FUNC void tcc_tool_cross(TCCState *s1, char **argv, int option)
{
tcc_error("-m%d not implemented.", option);
}
@ -479,7 +479,7 @@ static int execvp_win32(const char *prog, char **argv)
#define execvp execvp_win32
#endif /* _WIN32 */
ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int target)
ST_FUNC void tcc_tool_cross(TCCState *s1, char **argv, int target)
{
char program[4096];
char *a0 = argv[0];
@ -515,7 +515,7 @@ int _dowildcard = 1;
/* -------------------------------------------------------------- */
/* generate xxx.d file */
ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename)
ST_FUNC void gen_makedeps(TCCState *s1, const char *target, const char *filename)
{
FILE *depout;
char buf[1024];
@ -528,7 +528,7 @@ ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename)
filename = buf;
}
if (s->verbose)
if (s1->verbose)
printf("<- %s\n", filename);
/* XXX return err codes instead of error() ? */
@ -537,8 +537,8 @@ ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename)
tcc_error("could not open '%s'", filename);
fprintf(depout, "%s: \\\n", target);
for (i=0; i<s->nb_target_deps; ++i)
fprintf(depout, " %s \\\n", s->target_deps[i]);
for (i=0; i<s1->nb_target_deps; ++i)
fprintf(depout, " %s \\\n", s1->target_deps[i]);
fprintf(depout, "\n");
fclose(depout);
}

View File

@ -12,6 +12,7 @@ TESTS = \
hello-exe \
hello-run \
libtest \
libtest_mt \
test3 \
memtest \
dlltest \
@ -22,18 +23,18 @@ TESTS = \
tests2-dir \
pp-dir
BTESTS = test1b test3b btest
# test4 -- problem with -static
BTESTS = btest test1b
# test4_static -- Not all relocation types are implemented yet.
# asmtest / asmtest2 -- minor differences with gcc
# btest -- works on i386 (including win32)
# bounds-checking is supported only on i386
ifneq ($(ARCH),i386)
TESTS := $(filter-out $(BTESTS),$(TESTS))
# bounds-checking is supported on i386 and x86_64 on linux and windows
ifeq (-$(CONFIG_musl)-, --)
ifeq ($(ARCH),i386)
TESTS += $(BTESTS)
endif
ifeq ($(ARCH),x86_64)
TESTS += $(BTESTS)
endif
ifdef CONFIG_WIN32
TESTS := $(filter-out $(BTESTS),$(TESTS))
endif
ifdef CONFIG_OSX # -run only
TESTS := hello-run libtest tests2-dir pp-dir
@ -47,19 +48,30 @@ endif
ifeq (,$(filter i386 x86_64,$(ARCH)))
TESTS := $(filter-out dlltest asm-c-connect-test,$(TESTS))
endif
ifndef CONFIG_cross
TESTS := $(filter-out cross-%,$(TESTS))
endif
ifeq ($(OS),Windows_NT) # for libtcc_test to find libtcc.dll
PATH := $(CURDIR)/$(TOP)$(if $(findstring :\,$(PATH)),;,:)$(PATH)
PATH := $(CURDIR)/$(TOP)$(if $(findstring ;,$(PATH)),;,:)$(PATH)
endif
ifeq ($(ARCH),arm)
# tcctest refers to the alignment of functions, and with thumb mode
# the low bit of code addresses selects the mode, so the "alignment"
# of functions via bit masking comes out as 1. Just disable thumb.
test.ref: CFLAGS+=-marm
endif
ifeq ($(ARCH),i386)
# tcctest.c:get_asm_string uses a construct that is checked too strictly
# by GCC in 32bit mode when PIC is enabled.
test.ref: CFLAGS+=-fno-PIC -fno-PIE
endif
RUN_TCC = $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS)
DISAS = objdump -d
DUMPTCC = (set -x; $(TOP)/tcc -vv; ldd $(TOP)/tcc; exit 1)
all test : clean-s $(TESTS)
all test :
@$(MAKE) --no-print-directory -s clean
@$(MAKE) --no-print-directory -s -r $(TESTS)
hello-exe: ../examples/ex1.c
@echo ------------ $@ ------------
@ -69,13 +81,16 @@ hello-run: ../examples/ex1.c
@echo ------------ $@ ------------
$(TCC) -run $< || $(DUMPTCC)
libtest: libtcc_test$(EXESUF)
libtes%: libtcc_tes%$(EXESUF)
@echo ------------ $@ ------------
./libtcc_test$(EXESUF) $(TCCFLAGS)
./libtcc_tes$*$(EXESUF) $(TOPSRC)/tcc.c $(TCCFLAGS) $(NATIVE_DEFINES)
libtcc_test$(EXESUF): libtcc_test.c $(LIBTCC)
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
libtcc_test_mt$(EXESUF): libtcc_test_mt.c $(LIBTCC)
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
%-dir:
@echo ------------ $@ ------------
$(MAKE) -k -C $*
@ -88,22 +103,24 @@ test.ref: tcctest.c
# auto test
test1 test1b: tcctest.c test.ref
@echo ------------ $@ ------------
$(TCC) -run $< > test.out1
@diff -u test.ref test.out1 && echo "Auto Test OK"
$(TCC) $(RUN_TCC) -w -run $< > test.out1
@diff -u test.ref test.out1 && echo "$(AUTO_TEST) OK"
# iterated test2 (compile tcc then compile tcctest.c !)
test2 test2b: tcctest.c test.ref
@echo ------------ $@ ------------
$(TCC) $(RUN_TCC) $(RUN_TCC) -run $< > test.out2
@diff -u test.ref test.out2 && echo "Auto Test2 OK"
$(TCC) $(RUN_TCC) $(RUN_TCC) -w -run $< > test.out2
@diff -u test.ref test.out2 && echo "$(AUTO_TEST)2 OK"
# iterated test3 (compile tcc then compile tcc then compile tcctest.c !)
test3 test3b: tcctest.c test.ref
@echo ------------ $@ ------------
$(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -run $< > test.out3
@diff -u test.ref test.out3 && echo "Auto Test3 OK"
$(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -w -run $< > test.out3
@diff -u test.ref test.out3 && echo "$(AUTO_TEST)3 OK"
test%b : TCCFLAGS += -b
AUTO_TEST = Auto Test
test%b : TCCFLAGS += -b -bt1
test%b : AUTO_TEST = Auto Bound-Test
# binary output test
test4: tcctest.c test.ref
@ -112,19 +129,22 @@ test4: tcctest.c test.ref
$(TCC) -c -o tcctest3.o $<
$(TCC) -o tcctest3 tcctest3.o
./tcctest3 > test3.out
@if diff -u test.ref test3.out ; then echo "Object Auto Test OK"; fi
@if diff -u test.ref test3.out ; then echo "Object $(AUTO_TEST) OK"; fi
# dynamic output
$(TCC) -o tcctest1 $<
./tcctest1 > test1.out
@if diff -u test.ref test1.out ; then echo "Dynamic Auto Test OK"; fi
@if diff -u test.ref test1.out ; then echo "Dynamic $(AUTO_TEST) OK"; fi
# dynamic output + bound check
$(TCC) -b -o tcctest4 $<
./tcctest4 > test4.out
@if diff -u test.ref test4.out ; then echo "BCheck Auto Test OK"; fi
# static output
@if diff -u test.ref test4.out ; then echo "BCheck $(AUTO_TEST) OK"; fi
test4_static: tcctest.c test.ref
@echo ------------ $@ ------------
# static output.
$(TCC) -static -o tcctest2 $<
./tcctest2 > test2.out
@if diff -u test.ref test2.out ; then echo "Static Auto Test OK"; fi
@if diff -u test.ref test2.out ; then echo "Static $(AUTO_TEST) OK"; fi
# use tcc to create libtcc.so/.dll and the tcc(.exe) frontend and run them
dlltest:
@ -145,32 +165,30 @@ memtest:
@echo ------------ $@ ------------
$(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
./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS) -w $(TOPSRC)/tests/tcctest.c
@echo OK
# memory and bound check auto test
BOUNDS_OK = 1 4 8 10 14
BOUNDS_FAIL= 2 5 7 9 11 12 13 15
BOUNDS_OK = 1 4 8 10 14 16
BOUNDS_FAIL= 2 5 6 7 9 11 12 13 15 17
btest: boundtest.c
@echo ------------ $@ ------------
@for i in $(BOUNDS_OK); do \
echo ; echo --- boundtest $$i ---; \
if $(TCC) -b -run $< $$i ; then \
echo succeeded as expected; \
if $(TCC) -b -run $< $$i >/dev/null 2>&1 ; then \
echo "Test $$i succeeded as expected" ; \
else\
echo Failed positive test $$i ; exit 1 ; \
echo "Failed positive test $$i" ; exit 1 ; \
fi ;\
done ;\
for i in $(BOUNDS_FAIL); do \
echo ; echo --- boundtest $$i ---; \
if $(TCC) -b -run $< $$i ; then \
echo Failed negative test $$i ; exit 1 ;\
if $(TCC) -b -bt1 -run $< $$i >/dev/null 2>&1 ; then \
echo "Failed negative test $$i" ; exit 1 ;\
else\
echo failed as expected; \
echo "Test $$i failed as expected" ; \
fi ;\
done ;\
echo; echo Bound test OK
echo Bound test OK
# speed test
speedtest: ex2 ex3
@ -181,6 +199,7 @@ speedtest: ex2 ex3
time $(TCC) -run $(TOPSRC)/examples/ex3.c 35
weaktest: tcctest.c test.ref
@echo ------------ $@ ------------
$(TCC) -c $< -o weaktest.tcc.o
$(CC) -c $< -o weaktest.gcc.o $(NATIVE_DEFINES) $(CFLAGS) -w -O0 -std=gnu99 -fno-omit-frame-pointer
objdump -t weaktest.tcc.o | grep ' w ' | sed -e 's/.* \([a-zA-Z0-9_]*\)$$/\1/' | LC_ALL=C sort > weaktest.tcc.o.txt
@ -206,22 +225,19 @@ asmtest2: MAYBE_RUN_TCC = $(RUN_TCC)
# Check that code generated by libtcc is binary compatible with
# that generated by CC
abitest-cc$(EXESUF): abitest.c $(LIBTCC)
abitest-cc.exe: abitest.c $(LIBTCC)
$(CC) -o $@ $^ $(CFLAGS) $(LIBS) -w
abitest-tcc$(EXESUF): abitest.c libtcc.c
abitest-tcc.exe: abitest.c libtcc.c
$(TCC) -o $@ $^ $(NATIVE_DEFINES) $(LIBS)
ABITESTS := abitest-cc$(EXESUF)
ifneq ($(CONFIG_arm_eabi),yes) # not ARM soft-float
ABITESTS += abitest-tcc$(EXESUF)
endif
abitest: $(ABITESTS)
abitest-% : abitest-%.exe
@echo ------------ $@ ------------
./abitest-cc$(EXESUF) $(TCCFLAGS)
./$< $(TCCFLAGS)
abitest: abitest-cc
ifneq ($(CONFIG_arm_eabi),yes) # not ARM soft-float
./abitest-tcc$(EXESUF) $(TCCFLAGS)
abitest: abitest-tcc
endif
vla_test$(EXESUF): vla_test.c
@ -244,21 +260,18 @@ 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"
@diff -u asm-c-connect.out1 asm-c-connect.out2 || (echo "error"; exit 1)
TCC_YY = $(foreach T,$(TCC_X),$(if $(wildcard $(TOP)/$T-tcc$(EXESUF)),$T))
cross-test :
$(if $(strip $(TCC_YY)),\
$(MAKE) $(foreach T,$(TCC_YY),cross-$T.test) --no-print-directory,:)
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"
$(TOP)/arm-wince-tcc$(EXESUF) $(TCCFLAGS-win) -c $(TOPSRC)/win32/examples/hello_win.c && echo "ok"
$(TOP)/$*-tcc$(EXESUF) -v $(TCCFLAGS-$(if $(findstring win,$*),win,unx))\
-c $(TOPSRC)/examples/ex3.c
# targets for development
%.bin: %.c tcc
@ -279,11 +292,8 @@ 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)
rm -f ex? tcc_g weaktest.*.txt *.def
rm -f asm-c-connect$(EXESUF) asm-c-connect-sep$(EXESUF)
rm -f ex? tcc_g weaktest.*.txt *.def libtcc_test_mt
@$(MAKE) -C tests2 $@
@$(MAKE) -C pp $@
# silent clean, used before running tests
clean-s:
@$(MAKE) -s --no-print-directory clean

View File

@ -50,15 +50,12 @@ int test4(void)
int i, sum = 0;
int *tab4;
fprintf(stderr, "%s start\n", __FUNCTION__);
tab4 = malloc(20 * sizeof(int));
for(i=0;i<20;i++) {
sum += tab4[i];
}
free(tab4);
fprintf(stderr, "%s end\n", __FUNCTION__);
return sum;
}
@ -68,20 +65,16 @@ int test5(void)
int i, sum = 0;
int *tab4;
fprintf(stderr, "%s start\n", __FUNCTION__);
tab4 = malloc(20 * sizeof(int));
for(i=0;i<21;i++) {
sum += tab4[i];
}
free(tab4);
fprintf(stderr, "%s end\n", __FUNCTION__);
return sum;
}
/* error */
/* XXX: currently: bug */
int test6(void)
{
int i, sum = 0;
@ -199,16 +192,13 @@ int test16()
char *demo = "This is only a test.";
char *p;
fprintf(stderr, "%s start\n", __FUNCTION__);
p = alloca(16);
strcpy(p,"12345678901234");
printf("alloca: p is %s\n", p);
/* Test alloca embedded in a larger expression */
printf("alloca: %s\n", strcpy(alloca(strlen(demo)+1),demo) );
printf("alloca : %s : %s\n", p, strcpy(alloca(strlen(demo)+1),demo) );
fprintf(stderr, "%s end\n", __FUNCTION__);
return 0;
}
/* error */
@ -217,16 +207,13 @@ int test17()
char *demo = "This is only a test.";
char *p;
fprintf(stderr, "%s start\n", __FUNCTION__);
p = alloca(16);
strcpy(p,"12345678901234");
printf("alloca: p is %s\n", p);
/* Test alloca embedded in a larger expression */
printf("alloca: %s\n", strcpy(alloca(strlen(demo)),demo) );
printf("alloca : %s : %s\n", p, strcpy(alloca(strlen(demo)),demo) );
fprintf(stderr, "%s end\n", __FUNCTION__);
return 0;
}
int (*table_test[])(void) = {
@ -246,15 +233,25 @@ int (*table_test[])(void) = {
test14,
test15,
test16,
test17,
test17
};
int main(int argc, char **argv)
{
int i;
char *cp;
int index;
int (*ftest)(void);
int index_max = sizeof(table_test)/sizeof(table_test[0]);
/* check bounds checking main arg */
for (i = 0; i < argc; i++) {
cp = argv[i];
while (*cp) {
cp++;
}
}
if (argc < 2) {
printf(
"test TCC bound checking system\n"

View File

@ -6,9 +6,15 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "libtcc.h"
void handle_error(void *opaque, const char *msg)
{
fprintf(opaque, "%s\n", msg);
}
/* this function is called by the generated code */
int add(int a, int b)
{
@ -53,6 +59,14 @@ int main(int argc, char **argv)
exit(1);
}
assert(tcc_get_error_func(s) == NULL);
assert(tcc_get_error_opaque(s) == NULL);
tcc_set_error_func(s, stderr, handle_error);
assert(tcc_get_error_func(s) == handle_error);
assert(tcc_get_error_opaque(s) == stderr);
/* if tcclib.h and libtcc1.a are not installed, where can we find them */
for (i = 1; i < argc; ++i) {
char *a = argv[i];

View File

@ -0,0 +1,309 @@
/*
* Multi-thread Test for libtcc
*/
#ifndef FIB
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "libtcc.h"
#define M 20 /* number of states */
#define F(n) (n % 20 + 2) /* fib argument */
#ifdef _WIN32
#include <windows.h>
#define TF_TYPE(func, param) DWORD WINAPI func(void *param)
typedef TF_TYPE(ThreadFunc, x);
HANDLE hh[M];
void create_thread(ThreadFunc f, int n)
{
DWORD tid;
hh[n] = CreateThread(NULL, 0, f, (void*)(size_t)n, 0, &tid);
}
void wait_threads(int n)
{
WaitForMultipleObjects(n, hh, TRUE, INFINITE);
while (n)
CloseHandle(hh[--n]);
}
void sleep_ms(unsigned n)
{
Sleep(n);
}
#else
#include <sys/time.h>
#include <unistd.h>
#include <pthread.h>
#define TF_TYPE(func, param) void* func(void *param)
typedef TF_TYPE(ThreadFunc, x);
pthread_t hh[M];
void create_thread(ThreadFunc f, int n)
{
pthread_create(&hh[n], NULL, f, (void*)(size_t)n);
}
void wait_threads(int n)
{
while (n)
pthread_join(hh[--n], NULL);
}
void sleep_ms(unsigned n)
{
usleep(n * 1000);
}
#endif
void handle_error(void *opaque, const char *msg)
{
fprintf(opaque, "%s\n", msg);
}
/* this function is called by the generated code */
int add(int a, int b)
{
return a + b;
}
#define _str(s) #s
#define str(s) _str(s)
/* as a trick, prepend #line directive for better error/warning messages */
#define PROG(lbl) \
char lbl[] = "#line " str(__LINE__) " " str(__FILE__) "\n\n"
PROG(my_program)
"#include <tcclib.h>\n" /* include the "Simple libc header for TCC" */
"int add(int a, int b);\n"
"int fib(int n)\n"
"{\n"
" if (n <= 2)\n"
" return 1;\n"
" else\n"
" return add(fib(n-1),fib(n-2));\n"
"}\n"
"\n"
"int foo(int n)\n"
"{\n"
" printf(\" %d\", fib(n));\n"
" return 0;\n"
"# warning is this the correct file:line...\n"
"}\n";
int g_argc; char **g_argv;
void parse_args(TCCState *s)
{
int i;
/* if tcclib.h and libtcc1.a are not installed, where can we find them */
for (i = 1; i < g_argc; ++i) {
char *a = g_argv[i];
if (a[0] == '-') {
if (a[1] == 'B')
tcc_set_lib_path(s, a+2);
else if (a[1] == 'I')
tcc_add_include_path(s, a+2);
else if (a[1] == 'L')
tcc_add_library_path(s, a+2);
else if (a[1] == 'D') {
char *dup = strdup(a);
char *eq = strchr(dup+2, '=');
if (eq) {
*eq = 0;
tcc_define_symbol(s, dup+2, eq+1);
*eq = '=';
} else
tcc_define_symbol(s, dup+2, NULL);
free(dup);
}
}
}
}
TCCState *new_state(int w)
{
TCCState *s = tcc_new();
if (!s) {
fprintf(stderr, __FILE__ ": could not create tcc state\n");
exit(1);
}
tcc_set_error_func(s, stdout, handle_error);
parse_args(s);
if (!w) tcc_set_options(s, "-w");
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
return s;
}
void *reloc_state(TCCState *s, const char *entry)
{
void *func;
tcc_add_symbol(s, "add", add);
if (tcc_relocate(s, TCC_RELOCATE_AUTO) < 0) {
fprintf(stderr, __FILE__ ": could not relocate tcc state.\n");
return NULL;
}
func = tcc_get_symbol(s, entry);
if (!func)
fprintf(stderr, __FILE__ ": could not get entry symbol.\n");
return func;
}
/* work with several states at the same time */
int state_test(void)
{
TCCState *s[M];
int (*func[M])(int);
int n;
for (n = 0; n < M + 4; ++n) {
unsigned a = n, b = n - 1, c = n - 2, d = n - 3, e = n - 4;
if (a < M)
s[a] = new_state(0);
if (b < M)
if (tcc_compile_string(s[b], my_program) == -1)
break;
if (c < M)
func[c] = reloc_state(s[c], "foo");
if (d < M && func[d])
func[d](F(d));
if (e < M)
tcc_delete(s[e]);
}
return 0;
}
/* simple compilation in threads */
TF_TYPE(thread_test_simple, vn)
{
TCCState *s;
int (*func)(int);
int ret;
int n = (size_t)vn;
s = new_state(0);
sleep_ms(1);
ret = tcc_compile_string(s, my_program);
sleep_ms(1);
if (ret >= 0) {
func = reloc_state(s, "foo");
if (func)
func(F(n));
}
tcc_delete(s);
return 0;
}
/* more complex compilation in threads */
TF_TYPE(thread_test_complex, vn)
{
TCCState *s;
int ret;
int n = (size_t)vn;
char *argv[30], b[10];
int argc = 0, i;
sprintf(b, "%d", F(n));
for (i = 1; i < g_argc; ++i) argv[argc++] = g_argv[i];
#if 0
argv[argc++] = "-run";
for (i = 1; i < g_argc; ++i) argv[argc++] = g_argv[i];
#endif
argv[argc++] = "-DFIB";
argv[argc++] = "-run";
argv[argc++] = __FILE__;
argv[argc++] = b;
argv[argc] = NULL;
s = new_state(1);
sleep_ms(2);
ret = tcc_add_file(s, argv[0]);
sleep_ms(3);
if (ret < 0)
exit(1);
tcc_run(s, argc, argv);
tcc_delete(s);
fflush(stdout);
return 0;
}
void time_tcc(int n, const char *src)
{
TCCState *s;
int ret;
while (--n >= 0) {
s = new_state(1);
ret = tcc_add_file(s, src);
tcc_delete(s);
if (ret < 0)
exit(1);
}
}
static unsigned getclock_ms(void)
{
#ifdef _WIN32
return GetTickCount();
#else
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec*1000 + (tv.tv_usec+500)/1000;
#endif
}
int main(int argc, char **argv)
{
int n;
unsigned t;
g_argc = argc;
g_argv = argv;
if (argc < 2) {
fprintf(stderr, "usage: libtcc_test_mt tcc.c <options>\n");
return 1;
}
#if 1
printf("mixed calls\n "), fflush(stdout);
t = getclock_ms();
state_test();
printf("\n(%u ms)\n", getclock_ms() - t);
#endif
#if 1
printf("threads\n "), fflush(stdout);
t = getclock_ms();
for (n = 0; n < M; ++n)
create_thread(thread_test_simple, n);
wait_threads(n);
printf("\n(%u ms)\n", getclock_ms() - t);
#endif
#if 1
printf("tcc in threads\n "), fflush(stdout);
t = getclock_ms();
for (n = 0; n < M; ++n)
create_thread(thread_test_complex, n);
wait_threads(n);
printf("\n(%u ms)\n", getclock_ms() - t);
#endif
#if 1
printf("compiling tcc 10 times\n"), fflush(stdout);
t = getclock_ms();
time_tcc(10, argv[1]);
printf("(%u ms)\n", (getclock_ms() - t) / 10), fflush(stdout);
#endif
return 0;
}
#else
#include <tcclib.h>
int fib(n)
{
return (n <= 2) ? 1 : fib(n-1) + fib(n-2);
}
int main(int argc, char **argv)
{
printf(" %d", fib(atoi(argv[1]), 2));
return 0;
}
#endif

View File

@ -10,7 +10,7 @@ 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
@ -29,6 +29,8 @@ 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 $*.[cS] >$*.expect 2>&1

View File

@ -3,8 +3,6 @@
*/
#include "config.h"
#if GCC_MAJOR >= 3
/* Unfortunately, gcc version < 3 does not handle that! */
#define ALL_ISOC99
@ -14,6 +12,14 @@
/* gcc 2.95.3 does not handle correctly CR in strings or after strays */
#define CORRECT_CR_HANDLING
/* __VA_ARGS__ and __func__ support */
#define C99_MACROS
/* deprecated and no longer supported in gcc 3.3 */
//#define ACCEPT_CR_IN_STRINGS
#ifndef __TINYC__
typedef __SIZE_TYPE__ uintptr_t;
#endif
#if defined(_WIN32)
@ -33,12 +39,6 @@
#define LONG_DOUBLE_LITERAL(x) x ## L
#endif
/* deprecated and no longer supported in gcc 3.3 */
//#define ACCEPT_CR_IN_STRINGS
/* __VA_ARGS__ and __func__ support */
#define C99_MACROS
/* test various include syntaxes */
#define TCCLIB_INC <tcclib.h>
@ -77,8 +77,10 @@ void expr_test();
void macro_test();
void recursive_macro_test();
void scope_test();
void scope_test2();
void forward_test();
void funcptr_test();
void if_test();
void loop_test();
void switch_test();
void goto_test();
@ -122,6 +124,7 @@ void math_cmp_test(void);
void callsave_test(void);
void builtin_frame_address_test(void);
void attrib_test(void);
void bounds_check1_test(void);
int fib(int n);
void num(int n);
@ -178,7 +181,7 @@ static int onetwothree = 123;
#ifdef __TINYC__
/* We try to handle this syntax. Make at least sure it doesn't segfault. */
char invalid_function_def()[] {}
char invalid_function_def()[] {return 0;}
#endif
#define __INT64_C(c) c ## LL
@ -507,6 +510,40 @@ void string_test()
}
}
void if1t(int n, int a, int b, int c)
{
if (a && b) printf("if1t: %d 1 %d %d\n", n, a, b);
if (a && !b) printf("if1t: %d 2 %d %d\n", n, a, b);
if (!a && b) printf("if1t: %d 3 %d %d\n", n, a, b);
if (!a && !b) printf("if1t: %d 4 %d %d\n", n, a, b);
if (a || b) printf("if1t: %d 5 %d %d\n", n, a, b);
if (a || !b) printf("if1t: %d 6 %d %d\n", n, a, b);
if (!a || b) printf("if1t: %d 7 %d %d\n", n, a, b);
if (!a || !b) printf("if1t: %d 8 %d %d\n", n, a, b);
if (a && b || c) printf("if1t: %d 9 %d %d %d\n", n, a, b, c);
if (a || b && c) printf("if1t: %d 10 %d %d %d\n", n, a, b, c);
if (a > b - 1 && c) printf("if1t: %d 11 %d %d %d\n", n, a, b, c);
if (a > b - 1 || c) printf("if1t: %d 12 %d %d %d\n", n, a, b, c);
if (a > 0 && 1) printf("if1t: %d 13 %d %d %d\n", n, a, b, c);
if (a > 0 || 0) printf("if1t: %d 14 %d %d %d\n", n, a, b, c);
}
void if2t(void)
{
if (0 && 1 || printf("if2t:ok\n") || 1)
printf("if2t:ok2\n");
printf("if2t:ok3\n");
}
void if_test(void)
{
if1t(1, 0, 0, 0);
if1t(2, 0, 3, 0);
if1t(3, 2, 0, 0);
if1t(4, 2, 3, 0);
if2t();
}
void loop_test()
{
int i;
@ -571,6 +608,7 @@ void goto_test()
printf("goto:\n");
i = 0;
/* This needs to parse as label, not as start of decl. */
typedef_and_label x;
typedef_and_label:
s_loop:
if (i >= 10)
@ -718,8 +756,10 @@ int main(int argc, char **argv)
macro_test();
recursive_macro_test();
scope_test();
scope_test2();
forward_test();
funcptr_test();
if_test();
loop_test();
switch_test();
goto_test();
@ -768,6 +808,7 @@ int main(int argc, char **argv)
if (via_volatile (42) != 42)
printf ("via_volatile broken\n");
attrib_test();
bounds_check1_test();
return 0;
}
@ -800,6 +841,30 @@ void scope_test()
printf("g5=%d\n", g);
}
int st2_i;
int *st2_p = &st2_i;
void scope_test2()
{
char a[50];
st2_i = 42;
for (int st2_i = 1; st2_i < 10; st2_i++) {
extern int st2_i;
st2_i++;
printf("exloc: %d\n", st2_i);
}
printf("exloc: %d\n", *st2_p);
}
/* C has tentative definition, and they may be repeated. */
extern int st_global1;
int st_global1=42;
extern int st_global1;
int st_global1;
extern int st_global2;
int st_global2;
extern int st_global2;
int st_global2;
void array_test()
{
int i, j, a[4];
@ -917,6 +982,8 @@ void expr2_test()
printf("res= %d %d\n", a, b);
}
int const_len_ar[sizeof(1/0)]; /* div-by-zero, but in unevaluated context */
void constant_expr_test()
{
int a;
@ -925,6 +992,7 @@ void constant_expr_test()
printf("%d\n", a * 16);
printf("%d\n", a * 1);
printf("%d\n", a + 0);
printf("%d\n", sizeof(const_len_ar));
}
int tab4[10];
@ -1134,7 +1202,7 @@ void struct_test()
s->f3 = 1;
printf("st2: %d %d %d\n",
s->f1, s->f2, s->f3);
printf("str_addr=%x\n", (int)st1.str - (int)&st1.f1);
printf("str_addr=%x\n", (int)(uintptr_t)st1.str - (int)(uintptr_t)&st1.f1);
/* align / size tests */
printf("aligntest1 sizeof=%d alignof=%d\n",
@ -1174,17 +1242,24 @@ void struct_test()
printf("Large: offsetof(compound_head)=%d\n", (int)((char*)&ls.compound_head - (char*)&ls));
}
/* simulate char/short return value with undefined upper bits */
static int __csf(int x) { return x; }
static void *_csf = __csf;
#define csf(t,n) ((t(*)(int))_csf)(n)
/* XXX: depend on endianness */
void char_short_test()
{
int var1, var2;
signed char var3;
long long var4;
printf("char_short:\n");
var1 = 0x01020304;
var2 = 0xfffefdfc;
printf("s8=%d %d\n",
*(char *)&var1, *(char *)&var2);
*(signed char *)&var1, *(signed char *)&var2);
printf("u8=%d %d\n",
*(unsigned char *)&var1, *(unsigned char *)&var2);
printf("s16=%d %d\n",
@ -1195,12 +1270,44 @@ void char_short_test()
*(int *)&var1, *(int *)&var2);
printf("u32=%d %d\n",
*(unsigned int *)&var1, *(unsigned int *)&var2);
*(char *)&var1 = 0x08;
*(signed char *)&var1 = 0x08;
printf("var1=%x\n", var1);
*(short *)&var1 = 0x0809;
printf("var1=%x\n", var1);
*(int *)&var1 = 0x08090a0b;
printf("var1=%x\n", var1);
var1 = 0x778899aa;
var4 = 0x11223344aa998877ULL;
var1 = var3 = var1 + 1;
var4 = var3 = var4 + 1;
printf("promote char/short assign %d "LONG_LONG_FORMAT"\n", var1, var4);
var1 = 0x778899aa;
var4 = 0x11223344aa998877ULL;
printf("promote char/short assign VA %d %d\n", var3 = var1 + 1, var3 = var4 + 1);
printf("promote char/short cast VA %d %d\n", (signed char)(var1 + 1), (signed char)(var4 + 1));
#if !defined(__arm__)
/* We can't really express GCC behaviour of return type promotion in
the presence of undefined behaviour (like __csf is). */
var1 = csf(unsigned char,0x89898989);
var4 = csf(signed char,0xabababab);
printf("promote char/short funcret %d "LONG_LONG_FORMAT"\n", var1, var4);
printf("promote char/short fumcret VA %d %d %d %d\n",
csf(unsigned short,0xcdcdcdcd),
csf(short,0xefefefef),
csf(_Bool,0x33221100),
csf(_Bool,0x33221101));
#endif
var3 = -10;
var1 = (signed char)(unsigned char)(var3 + 1);
var4 = (signed char)(unsigned char)(var3 + 1);
printf("promote multicast (char)(unsigned char) %d "LONG_LONG_FORMAT"\n", var1, var4);
var4 = 0x11223344aa998877ULL;
var4 = (unsigned)(int)(var4 + 1);
printf("promote multicast (unsigned)(int) "LONG_LONG_FORMAT"\n", var4);
var4 = 0x11223344bbaa9988ULL;
var4 = (unsigned)(signed char)(var4 + 1);
printf("promote multicast (unsigned)(char) "LONG_LONG_FORMAT"\n", var4);
}
/******************/
@ -1374,6 +1481,12 @@ void optimize_out(void)
printf("ool6:%d\n", defined_function());
goto breakhere;
}
j = 1;
while (j) {
j--;
continue;
printf("ool7:%d\n", undefined_function());
}
/* Test that constants in logical && are optimized: */
i = 0 && undefined_function();
@ -1433,6 +1546,9 @@ int defined_function(void)
static int tab_reinit[];
static int tab_reinit[10];
static int tentative_ar[];
static int tentative_ar[] = {1,2,3};
//int cinit1; /* a global variable can be defined several times without error ! */
int cinit1;
int cinit1;
@ -1597,6 +1713,7 @@ void cast_test()
unsigned b,d;
short s;
char *p = NULL;
unsigned long ul = 0x80000000UL;
p -= 0x700000000042;
printf("cast_test:\n");
@ -1649,6 +1766,9 @@ void cast_test()
/* from integers to pointers */
printf("%p %p %p %p\n",
(void *)a, (void *)b, (void *)c, (void *)d);
/* int to int with sign set */
printf("0x%lx\n", (unsigned long)(int)ul);
}
/* initializers tests */
@ -1752,6 +1872,8 @@ arrtype2 sinit22 = {5,6,7};
int sinit23[2] = { "astring" ? sizeof("astring") : -1,
&sinit23 ? 42 : -1 };
int sinit24 = 2 || 1 / 0; /* exception in constant but unevaluated context */
extern int external_inited = 42;
void init_test(void)
@ -1866,6 +1988,7 @@ void init_test(void)
printf("arrtype6: %d\n", sizeof(arrtype2));
printf("sinit23= %d %d\n", sinit23[0], sinit23[1]);
printf("sinit24=%d\n", sinit24);
printf("linit18= %d %d\n", linit18[0], linit18[1]);
}
@ -1991,7 +2114,7 @@ void c99_bool_test(void)
{
#ifdef BOOL_ISOC99
int a;
_Bool b;
_Bool b, b2;
printf("bool_test:\n");
printf("sizeof(_Bool) = %d\n", sizeof(_Bool));
@ -2001,6 +2124,9 @@ void c99_bool_test(void)
printf("b = %d\n", b);
b++;
printf("b = %d\n", b);
b2 = 0;
printf("sizeof(x ? _Bool : _Bool) = %d (should be sizeof int)\n",
sizeof((volatile)a ? b : b2));
#endif
}
@ -2234,6 +2360,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 +2384,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 +2396,12 @@ int fib(int n)
return fib(n-1) + fib(n-2);
}
#if __GNUC__ == 3
# define aligned_function 0
#else
void __attribute__((aligned(16))) aligned_function(int i) {}
#endif
void funcptr_test()
{
void (*func)(int);
@ -2296,6 +2432,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)(uintptr_t)func) & 15);
}
void lloptest(long long a, long long b)
@ -2420,6 +2560,11 @@ long long llfunc2(long long x, long long y, int z)
return x * y * z;
}
void check_opl_save_regs(char *a, long long b, int c)
{
*a = b < 0 && !c;
}
void longlong_test(void)
{
long long a, b, c;
@ -2487,6 +2632,19 @@ 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);
u = 0x11223344aa998877ULL;
u = (unsigned)(int)(u + 1);
printf("long long u=" ULONG_LONG_FORMAT "\n", u);
/* was a problem with missing save_regs in gen_opl on 32-bit platforms */
char cc = 78;
check_opl_save_regs(&cc, -1, 0);
printf("check_opl_save_regs: %d\n", cc);
}
void manyarg_test(void)
@ -2524,6 +2682,18 @@ void manyarg_test(void)
42.0, 43.0, ld);
}
void*
va_arg_with_struct_ptr(va_list ap) {
/*
* This was a BUG identified with FFTW-3.3.8 on arm64.
* The test case only checks it compiles on all supported
* architectures. This function is not currently called.
*/
struct X { int _x; };
struct X *x = va_arg(ap, struct X *);
return x;
}
void vprintf1(const char *fmt, ...)
{
va_list ap, aq;
@ -2601,6 +2771,19 @@ void stdarg_for_libc(const char *fmt, ...)
va_end(args);
}
void stdarg_syntax(int n, ...)
{
int i;
va_list ap;
if (1)
va_start(ap, n);
else
;
i = va_arg(ap, int);
printf("stdarg_void_expr: %d\n", i);
(va_end(ap));
}
void stdarg_test(void)
{
LONG_DOUBLE ld = 1234567891234LL;
@ -2648,6 +2831,7 @@ void stdarg_test(void)
bob.profile = 42;
stdarg_for_struct(bob, bob, bob, bob.profile);
stdarg_for_libc("stdarg_for_libc: %s %.2f %d\n", "string", 1.23, 456);
stdarg_syntax(1, 17);
}
void whitespace_test(void)
@ -2816,10 +3000,6 @@ void c99_vla_test(int size1, int size2)
#endif
}
#ifndef __TINYC__
typedef __SIZE_TYPE__ uintptr_t;
#endif
void sizeof_test(void)
{
int a;
@ -2962,6 +3142,22 @@ void statement_expr_test(void)
/* Test that we can give out addresses of local labels. */
consume_ulong(({ __label__ __here; __here: (unsigned long)&&__here; }));
/* Test interaction between local and global label stacks and the
need to defer popping symbol from them when within statement
expressions. Note how the labels are both named LBL. */
i = 0;
({
{
__label__ LBL;
LBL: if (i++ == 0) goto LBL;
}
/* jump to a classical label out of an expr-stmt that had previously
overshadowed that classical label */
goto LBL;
});
LBL:
printf("stmtexpr: %d should be 2\n", i);
}
void local_label_test(void)
@ -3189,6 +3385,20 @@ void override_func2 (void)
extern int bug_table[] __attribute__((section("__bug_table")));
char * get_asm_string (void)
{
/* On i386 when -fPIC is enabled this would cause a compile error with GCC,
the problem being the "i" constraint used with a symbolic operand
resolving to a local label. That check is overly zealous as the code
within the asm makes sure to use it only in PIC-possible contexts,
but all GCC versions behave like so. We arrange for PIC to be disabled
for compiling tcctest.c in the Makefile.
Additionally the usage of 'c' in "%c0" in the template is actually wrong,
as that would expect an operand that is a condition code. The operand
as is (a local label) is accepted by GCC in non-PIC mode, and on x86-64.
What the linux kernel really wanted is 'p' to disable the addition of '$'
to the printed operand (as in "$.LC0" where the template only wants the
bare operand ".LC0"). But the code below is what the linux kernel
happens to use and as such is the one we want to test. */
extern int some_symbol;
asm volatile (".globl some_symbol\n"
"jmp .+6\n"
@ -3255,7 +3465,7 @@ void clobber_r12(void)
}
#endif
void test_high_clobbers(void)
void test_high_clobbers_really(void)
{
#if defined __x86_64__ && !defined _WIN64
register long val asm("r12");
@ -3271,6 +3481,20 @@ void test_high_clobbers(void)
#endif
}
void test_high_clobbers(void)
{
#if defined __x86_64__ && !defined _WIN64
long x1, x2;
asm volatile("mov %%r12,%0" :: "m" (x1)); /* save r12 */
test_high_clobbers_really();
asm volatile("mov %%r12,%0" :: "m" (x2)); /* new r12 */
asm volatile("mov %0,%%r12" :: "m" (x1)); /* restore r12 */
/* should be 0 but tcc doesn't save r12 automatically, which has
bad effects when gcc helds TCCState *s in r12 in tcc.c:main */
//printf("r12-clobber-diff: %lx\n", x2 - x1);
#endif
}
static long cpu_number;
void trace_console(long len, long len2)
{
@ -3387,10 +3611,18 @@ void asm_dot_test(void)
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");
#ifndef _WIN32
asm(".pushsection \".data\"; Y=.; .int 999; X=Y; .int 456; X=.-4; .popsection");
#else
asm(".data; Y=.; .int 999; X=Y; .int 456; X=.-4; .text");
#endif
asm(".text; mov X"RX",%eax; jmp p0");
case 4:
asm(".data; X=.; .int 789; Y=.; .int 999");
#ifndef _WIN32
asm(".data; X=.; .int 789; Y=.; .int 999; .previous");
#else
asm(".data; X=.; .int 789; Y=.; .int 999; .text");
#endif
asm(".text; mov X"RX",%eax; X=Y; jmp p0");
case 0:
asm(".text; p0=.; mov %%eax,%0;" : "=m"(r)); break;
@ -3535,6 +3767,9 @@ void builtin_test(void)
printf("res = %d\n", __builtin_constant_p(&constant_p_var));
printf("res = %d\n", __builtin_constant_p(constant_p_var));
printf("res = %d\n", __builtin_constant_p(100000 / constant_p_var));
printf("res = %d\n", __builtin_constant_p(i && 0));
printf("res = %d\n", __builtin_constant_p(i && 1));
printf("res = %d\n", __builtin_constant_p(i && 0 ? i : 34));
s = 1;
ll = 2;
i = __builtin_choose_expr (1 != 0, ll, s);
@ -3695,6 +3930,7 @@ int fcompare (double a, double b, int code)
case 4: return a > b;
case 5: return a <= b;
}
return 0;
}
void math_cmp_test(void)
@ -3703,6 +3939,7 @@ void math_cmp_test(void)
double one = 1.0;
double two = 2.0;
int comp = 0;
int v;
#define bug(a,b,op,iop,part) printf("Test broken: %s %s %s %s %d\n", #a, #b, #op, #iop, part)
/* This asserts that "a op b" is _not_ true, but "a iop b" is true.
@ -3724,7 +3961,8 @@ void math_cmp_test(void)
if ((a iop b) || comp) \
; \
else \
bug (a,b,op,iop,5);
bug (a,b,op,iop,5); \
if (v = !(a op b), !v) bug(a,b,op,iop,7);
/* Equality tests. */
FCMP(nan, nan, ==, !=, 0);
@ -3793,8 +4031,10 @@ void builtin_frame_address_test(void)
char *fp0 = __builtin_frame_address(0);
printf("str: %s\n", str);
#ifndef __riscv
bfa1(str-fp0);
#endif
#endif
}
char via_volatile (char i)
@ -3869,3 +4109,18 @@ int force_get_order(unsigned long s)
{
return __get_order(s);
}
#define pv(m) printf(sizeof (s->m + 0) == 8 ? "%016llx\n" : "%02x\n", s->m)
/* Test failed when using bounds checking */
void bounds_check1_test (void)
{
struct s {
int x;
long long y;
} _s, *s = &_s;
s->x = 10;
s->y = 20;
pv(x);
pv(y);
}

View File

@ -1,6 +1,13 @@
#include <stdio.h>
extern int printf(const char*, ...);
struct fred
struct fred;
void fred$(struct fred* this)
{
printf("~fred()\n");
}
struct __attribute__((__cleanup__(fred$))) fred
{
int boris;
int natasha;
@ -8,7 +15,7 @@ struct fred
int main()
{
struct fred bloggs;
struct fred __attribute__((__cleanup__(fred$))) bloggs;
bloggs.boris = 12;
bloggs.natasha = 34;

View File

@ -1,6 +1,8 @@
03_struct.c:14: warning: attribute '__cleanup__' ignored on type
12
34
12
34
56
78
~fred()

View File

@ -15,6 +15,11 @@ void qfunc()
printf("qfunc()\n");
}
void zfunc()
{
((void (*)(void))0) ();
}
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

@ -0,0 +1,227 @@
extern int printf(const char*, ...);
static int glob_i = 0;
void incr_glob_i(int *i)
{
glob_i += *i;
}
#define INCR_GI { \
int i __attribute__ ((__cleanup__(incr_glob_i))) = 1; \
}
#define INCR_GI0 INCR_GI INCR_GI INCR_GI INCR_GI
#define INCR_GI1 INCR_GI0 INCR_GI0 INCR_GI0 INCR_GI0
#define INCR_GI2 INCR_GI1 INCR_GI1 INCR_GI1 INCR_GI1
#define INCR_GI3 INCR_GI2 INCR_GI2 INCR_GI2 INCR_GI2
#define INCR_GI4 INCR_GI3 INCR_GI3 INCR_GI3 INCR_GI3
#define INCR_GI5 INCR_GI4 INCR_GI4 INCR_GI4 INCR_GI4
#define INCR_GI6 INCR_GI5 INCR_GI5 INCR_GI5 INCR_GI5
#define INCR_GI7 INCR_GI6 INCR_GI6 INCR_GI6 INCR_GI6
void check2(char **hum);
void check(int *j)
{
char * __attribute__ ((cleanup(check2))) stop_that = "wololo";
int chk = 0;
{
char * __attribute__ ((cleanup(check2))) stop_that = "plop";
{
non_plopage:
printf("---- %d\n", chk);
}
if (!chk) {
chk = 1;
goto non_plopage;
}
}
{
char * __attribute__ ((cleanup(check2))) stop_that = "tata !";
goto out;
stop_that = "titi";
}
again:
chk = 2;
{
char * __attribute__ ((cleanup(check2))) cascade1 = "1";
{
char * __attribute__ ((cleanup(check2))) cascade2 = "2";
{
char * __attribute__ ((cleanup(check2))) cascade3 = "3";
goto out;
cascade3 = "nope";
}
}
}
out:
if (chk != 2)
goto again;
{
{
char * __attribute__ ((cleanup(check2))) out = "last goto out";
++chk;
if (chk != 3)
goto out;
}
}
return;
}
void check_oh_i(char *oh_i)
{
printf("c: %c\n", *oh_i);
}
void goto_hell(double *f)
{
printf("oo: %f\n", *f);
}
char *test()
{
char *__attribute__ ((cleanup(check2))) str = "I don't think this should be print(but gcc got it wrong too)";
return str;
}
void test_ret_subcall(char *that)
{
printf("should be print before\n");
}
void test_ret()
{
char *__attribute__ ((cleanup(check2))) that = "that";
return test_ret_subcall(that);
}
void test_ret2()
{
char *__attribute__ ((cleanup(check2))) that = "-that";
{
char *__attribute__ ((cleanup(check2))) that = "this should appear only once";
}
{
char *__attribute__ ((cleanup(check2))) that = "-that2";
return;
}
}
void test2(void) {
int chk = 0;
again:
if (!chk) {
char * __attribute__ ((cleanup(check2))) stop_that = "test2";
chk++;
goto again;
}
}
int test3(void) {
char * __attribute__ ((cleanup(check2))) stop_that = "three";
int chk = 0;
if (chk) {
{
outside:
{
char * __attribute__ ((cleanup(check2))) stop_that = "two";
printf("---- %d\n", chk);
}
}
}
if (!chk)
{
char * __attribute__ ((cleanup(check2))) stop_that = "one";
if (!chk) {
chk = 1;
goto outside;
}
}
return 0;
}
void cl(int *ip)
{
printf("%d\n", *ip);
}
void loop_cleanups(void)
{
__attribute__((cleanup(cl))) int l = 1000;
printf("-- loop 0 --\n");
for ( __attribute__((cleanup(cl))) int i = 0; i < 10; ++i) {
__attribute__((cleanup(cl))) int j = 100;
}
printf("-- loop 1 --\n");
for (__attribute__((cleanup(cl))) int i = 0; i < 10; ++i) {
__attribute__((cleanup(cl))) int j = 200;
continue;
}
printf("-- loop 2 --\n");
for (__attribute__((cleanup(cl))) int i = 0; i < 10; ++i) {
__attribute__((cleanup(cl))) int j = 300;
break;
}
printf("-- loop 3 --\n");
for (int i = 0; i < 2; ++i) {
__attribute__((cleanup(cl))) int j = 400;
switch (i) {
case 0:
continue;
default:
{
__attribute__((cleanup(cl))) int jj = 500;
break;
}
}
}
printf("after break\n");
}
int main()
{
int i __attribute__ ((__cleanup__(check))) = 0, not_i;
int chk = 0;
(void)not_i;
{
__attribute__ ((__cleanup__(check_oh_i))) char oh_i = 'o', o = 'a';
}
INCR_GI7;
printf("glob_i: %d\n", glob_i);
naaaaaaaa:
if (!chk) {
__attribute__ ((__cleanup__(check_oh_i))) char oh_i = 'f';
double __attribute__ ((__cleanup__(goto_hell))) f = 2.6;
chk = 1;
goto naaaaaaaa;
}
i = 105;
printf("because what if free was call inside cleanup function %s\n", test());
test_ret();
test_ret2();
test2();
test3();
loop_cleanups();
return i;
}
void check2(char **hum)
{
printf("str: %s\n", *hum);
}

View File

@ -0,0 +1,59 @@
c: a
c: o
glob_i: 65536
oo: 2.600000
c: f
str: I don't think this should be print(but gcc got it wrong too)
because what if free was call inside cleanup function I don't think this should be print(but gcc got it wrong too)
should be print before
str: that
str: this should appear only once
str: -that2
str: -that
str: test2
str: one
---- 1
str: two
str: three
-- loop 0 --
100
100
100
100
100
100
100
100
100
100
10
-- loop 1 --
200
200
200
200
200
200
200
200
200
200
10
-- loop 2 --
300
0
-- loop 3 --
400
500
400
after break
1000
---- 0
---- 1
str: plop
str: tata !
str: 3
str: 2
str: 1
str: last goto out
str: wololo

View File

@ -0,0 +1,29 @@
_Alignas(16) int i1;
int _Alignas(16) i2;
void _Alignas(16) *p2;
_Alignas(16) i3;
int _Alignas(double) i4;
int _Alignas(int) i5;
#if 0
/* The following are currently wrongly accepted by TCC but really shouldn't. */
int _Alignas(int _Alignas(16)) i6; //wrong, 'int _Alignas(16)' is no type-name
typedef int _Alignas(16) int16aligned_t; //wrong, _Alignas invalid on typedef
int16aligned_t i7;
#endif
/* i8 should get an alignment of 16, because unlike _Alignas the
corresponding attribute _does_ apply to type-name, though not in
some clang versions. */
int _Alignas(int __attribute__((aligned(16)))) i8;
extern int printf(const char*, ...);
#ifdef _MSC_VER
#define alignof(x) (int)__alignof(x)
#else
#define alignof(x) (int)__alignof__(x)
#endif
int main()
{
printf("%d %d %d %d\n",
alignof(i1) == 16, alignof(i4) == alignof(double),
alignof(i5) == alignof(int) , alignof(i8) == 16);
return 0;
}

View File

@ -0,0 +1 @@
1 1 1 1

View File

@ -0,0 +1,20 @@
/* Test that the memmove TCC is emitting for the struct copy
and hence implicitely declares can be declared properly also
later. */
struct S { int a,b,c,d, e[1024];};
int foo (struct S *a, struct S *b)
{
*a = *b;
return 0;
}
void *memmove(void*,void*,long);
void foo2 (struct S *a, struct S *b)
{
memmove(a, b, sizeof *a);
}
int main()
{
return 0;
}

View File

@ -0,0 +1,54 @@
#define GOT(f) \
__attribute__((weak)) void f(void); \
printf("%d %s\n", !!f, #f);
int printf(const char*, ...);
void check_exports()
{
// 0
GOT(inline_inline_2decl_only)
GOT(inline_inline_undeclared)
GOT(inline_inline_predeclared)
GOT(inline_inline_postdeclared)
GOT(inline_inline_prepostdeclared)
GOT(inline_inline_undeclared2)
GOT(inline_inline_predeclared2)
GOT(inline_inline_postdeclared2)
GOT(inline_inline_prepostdeclared2)
// 1
GOT(extern_extern_postdeclared)
GOT(extern_extern_postdeclared2)
GOT(extern_extern_predeclared)
GOT(extern_extern_predeclared2)
GOT(extern_extern_prepostdeclared)
GOT(extern_extern_prepostdeclared2)
GOT(extern_extern_undeclared)
GOT(extern_extern_undeclared2)
GOT(extern_postdeclared)
GOT(extern_postdeclared2)
GOT(extern_predeclared)
GOT(extern_predeclared2)
GOT(extern_prepostdeclared)
GOT(extern_undeclared)
GOT(extern_undeclared2)
GOT(inst2_extern_inline_postdeclared)
GOT(inst2_extern_inline_predeclared)
GOT(inst3_extern_inline_predeclared)
GOT(inst_extern_inline_postdeclared)
GOT(inst_extern_inline_predeclared)
GOT(main)
GOT(noinst_extern_inline_func)
GOT(noinst_extern_inline_postdeclared)
GOT(noinst_extern_inline_postdeclared2)
GOT(noinst_extern_inline_undeclared)
// 0
GOT(noinst_static_inline_postdeclared)
GOT(noinst2_static_inline_postdeclared)
GOT(noinst_static_inline_predeclared)
GOT(noinst2_static_inline_predeclared)
GOT(static_func)
}

View File

@ -0,0 +1,132 @@
inline void inline_inline_2decl_only(void);
inline void inline_inline_2decl_only(void);
inline void inline_inline_undeclared(void){}
inline void inline_inline_predeclared(void);
inline void inline_inline_predeclared(void){}
inline void inline_inline_postdeclared(void){}
inline void inline_inline_postdeclared(void);
inline void inline_inline_prepostdeclared(void);
inline void inline_inline_prepostdeclared(void){}
inline void inline_inline_prepostdeclared(void);
inline void inline_inline_undeclared2(void){}
inline void inline_inline_predeclared2(void);
inline void inline_inline_predeclared2(void);
inline void inline_inline_predeclared2(void){}
inline void inline_inline_postdeclared2(void){}
inline void inline_inline_postdeclared2(void);
inline void inline_inline_postdeclared2(void);
inline void inline_inline_prepostdeclared2(void);
inline void inline_inline_prepostdeclared2(void);
inline void inline_inline_prepostdeclared2(void){}
inline void inline_inline_prepostdeclared2(void);
inline void inline_inline_prepostdeclared2(void);
extern void extern_extern_undeclared(void){}
extern void extern_extern_predeclared(void);
extern void extern_extern_predeclared(void){}
extern void extern_extern_postdeclared(void){}
extern void extern_extern_postdeclared(void);
extern void extern_extern_prepostdeclared(void);
extern void extern_extern_prepostdeclared(void){}
extern void extern_extern_prepostdeclared(void);
extern void extern_extern_undeclared2(void){}
extern void extern_extern_predeclared2(void);
extern void extern_extern_predeclared2(void);
extern void extern_extern_predeclared2(void){}
extern void extern_extern_postdeclared2(void){}
extern void extern_extern_postdeclared2(void);
extern void extern_extern_postdeclared2(void);
extern void extern_extern_prepostdeclared2(void);
extern void extern_extern_prepostdeclared2(void);
extern void extern_extern_prepostdeclared2(void){}
extern void extern_extern_prepostdeclared2(void);
extern void extern_extern_prepostdeclared2(void);
void extern_undeclared(void){}
void extern_predeclared(void);
void extern_predeclared(void){}
void extern_postdeclared(void){}
void extern_postdeclared(void);
void extern_prepostdeclared(void);
void extern_prepostdeclared(void){}
void extern_prepostdeclared(void);
void extern_undeclared2(void){}
void extern_predeclared2(void);
void extern_predeclared2(void);
void extern_predeclared2(void){}
void extern_postdeclared2(void){}
void extern_postdeclared2(void);
void extern_postdeclared2(void);
extern inline void noinst_extern_inline_undeclared(void){}
extern inline void noinst_extern_inline_postdeclared(void){}
inline void noinst_extern_inline_postdeclared(void);
extern inline void noinst_extern_inline_postdeclared2(void){}
inline void noinst_extern_inline_postdeclared2(void);
inline void noinst_extern_inline_postdeclared2(void);
extern inline void inst_extern_inline_postdeclared(void){}
extern inline void inst_extern_inline_postdeclared(void);
inline void inst2_extern_inline_postdeclared(void){}
void inst2_extern_inline_postdeclared(void);
void inst_extern_inline_predeclared(void);
extern inline void inst_extern_inline_predeclared(void){}
void inst2_extern_inline_predeclared(void);
inline void inst2_extern_inline_predeclared(void){}
extern inline void inst3_extern_inline_predeclared(void);
inline void inst3_extern_inline_predeclared(void){}
static inline void noinst_static_inline_postdeclared(void){}
static inline void noinst_static_inline_postdeclared(void);
static inline void noinst2_static_inline_postdeclared(void){}
static void noinst2_static_inline_postdeclared(void);
static void noinst_static_inline_predeclared(void);
static inline void noinst_static_inline_predeclared(void){}
static void noinst2_static_inline_predeclared(void);
static inline void noinst2_static_inline_predeclared(void){}
static void static_func(void);
void static_func(void) { }
inline void noinst_extern_inline_func(void);
void noinst_extern_inline_func(void) { }
int main()
{
inline_inline_undeclared(); inline_inline_predeclared(); inline_inline_postdeclared();
inline_inline_undeclared2(); inline_inline_predeclared2(); inline_inline_postdeclared2();
noinst_static_inline_predeclared();
noinst2_static_inline_predeclared();
noinst_static_inline_predeclared();
noinst2_static_inline_predeclared();
void check_exports();
check_exports();
return 0;
}

View File

@ -0,0 +1,39 @@
0 inline_inline_2decl_only
0 inline_inline_undeclared
0 inline_inline_predeclared
0 inline_inline_postdeclared
0 inline_inline_prepostdeclared
0 inline_inline_undeclared2
0 inline_inline_predeclared2
0 inline_inline_postdeclared2
0 inline_inline_prepostdeclared2
1 extern_extern_postdeclared
1 extern_extern_postdeclared2
1 extern_extern_predeclared
1 extern_extern_predeclared2
1 extern_extern_prepostdeclared
1 extern_extern_prepostdeclared2
1 extern_extern_undeclared
1 extern_extern_undeclared2
1 extern_postdeclared
1 extern_postdeclared2
1 extern_predeclared
1 extern_predeclared2
1 extern_prepostdeclared
1 extern_undeclared
1 extern_undeclared2
1 inst2_extern_inline_postdeclared
1 inst2_extern_inline_predeclared
1 inst3_extern_inline_predeclared
1 inst_extern_inline_postdeclared
1 inst_extern_inline_predeclared
1 main
1 noinst_extern_inline_func
1 noinst_extern_inline_postdeclared
1 noinst_extern_inline_postdeclared2
1 noinst_extern_inline_undeclared
0 noinst_static_inline_postdeclared
0 noinst2_static_inline_postdeclared
0 noinst_static_inline_predeclared
0 noinst2_static_inline_predeclared
0 static_func

View File

@ -0,0 +1,12 @@
extern int printf(const char *, ...);
void f(void);
void bar(void) { void f(void); f(); }
void foo(void) { extern void f(void); f(); }
void f(void) { printf("f\n"); }
int main()
{
bar();
foo();
return 0;
}

View File

@ -0,0 +1,2 @@
f
f

View File

@ -0,0 +1,17 @@
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
int
main(void)
{
int ret;
pthread_condattr_t attr;
pthread_cond_t condition;
pthread_condattr_init (&attr);
pthread_condattr_setpshared (&attr, PTHREAD_PROCESS_SHARED);
printf ("%s\n", pthread_cond_init (&condition, &attr) ? "fail":"ok");
pthread_condattr_destroy (&attr);
return 0;
}

View File

@ -0,0 +1 @@
ok

View File

@ -0,0 +1,13 @@
extern int printf(const char *, ...);
static void func_ull_ull(unsigned long long l1,unsigned long long l2){
}
int main()
{
int a,b,c,d;
a=1;b=2;c=3;d=4;
func_ull_ull((unsigned long long)a/1.0,(unsigned long long)b/1.0);
printf("%d %d %d %d",a,b,c,d);
return 0;
}

View File

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

View File

@ -0,0 +1,20 @@
extern int write (int fd, void *buf, int len);
static void __attribute__ ((constructor))
testc (void)
{
write (1, "constructor\n", 12);
}
static void __attribute__ ((destructor))
testd (void)
{
write (1, "destructor\n", 11);
}
int
main (void)
{
write (1, "main\n", 5);
return 0;
}

View File

@ -0,0 +1,3 @@
constructor
main
destructor

View File

@ -0,0 +1,24 @@
#include <stdio.h>
/* This test used to fail on x86_64 on linux with sse registers */
struct Point {
float x;
float y;
};
struct Rect {
struct Point top_left;
struct Point size;
};
float foo(struct Point p, struct Rect r) {
return r.size.x;
}
int main(int argc, char **argv) {
struct Point p = {1, 2};
struct Rect r = {{3, 4}, {5, 6}};
printf("%f\n", foo(p, r));
return 0;
}

View File

@ -0,0 +1 @@
5.000000

View File

@ -0,0 +1,27 @@
#include <stdio.h>
typedef struct
{
double average;
int count;
}
stats_type;
static void
testc (stats_type *s, long long data)
{
s->average = (s->average * s->count + data) / (s->count + 1);
s->count++;
}
int main (void)
{
stats_type s;
s.average = 0;
s.count = 0;
testc (&s, 10);
testc (&s, 20);
printf ("%g %d\n", s.average, s.count);
return 0;
}

View File

@ -0,0 +1 @@
15 2

View File

@ -0,0 +1,22 @@
#include <stdio.h>
union u {
unsigned long ul;
long double ld;
};
void
conv (union u *p)
{
p->ul = (unsigned int) p->ld;
}
int main (void)
{
union u v;
v.ld = 42;
conv (&v);
printf ("%lu\n", v.ul);
return 0;
}

View File

@ -0,0 +1 @@
42

View File

@ -0,0 +1,165 @@
#include <stdio.h>
/* ------------------------------------------------------- */
#if defined test_backtrace_1
void f3()
{
printf("* f3()\n"), fflush(stdout);
*(void**)0 = 0;
}
void f2()
{
printf("* f2()\n"), fflush(stdout);
f3();
}
void f1()
{
printf("* f1()\n"), fflush(stdout);
f2();
}
int main(int argc, char **argv)
{
printf("* main\n"), fflush(stdout);
f1();
printf("* exit main\n"), fflush(stdout);
return 0;
}
/* ------------------------------------------------------- */
#elif defined test_bcheck_1
struct s { int a,b,c,d,e; };
struct s s[3];
struct s *ps = s;
void f1()
{
printf("* f1()\n"), fflush(stdout);
ps[3] = ps[2];
}
int main(int argc, char **argv)
{
printf("* main\n"), fflush(stdout);
f1();
printf("* exit main\n"), fflush(stdout);
return 0;
}
/* ------------------------------------------------------- */
#elif defined test_tcc_backtrace_2
/* test custom backtrace and 'exit()' redirection */
int tcc_backtrace(const char *fmt, ...);
void exit(int);
void f2()
{
printf("* f2()\n");
printf("* exit f2\n"), fflush(stdout);
exit(34);
}
void f1()
{
printf("* f1()\n"), fflush(stdout);
tcc_backtrace("Hello from %s!", "f1");
f2();
}
int main(int argc, char **argv)
{
printf("* main\n"), fflush(stdout);
f1();
printf("* exit main\n"), fflush(stdout);
return 0;
}
/* ------------------------------------------------------- */
#elif defined test_tcc_backtrace_3
/* this test should be run despite of the exit(34) above */
int main(int argc, char **argv)
{
printf("* main\n"), fflush(stdout);
return 1;
}
/* ------------------------------------------------------- */
#else
#include <malloc.h>
#include <string.h>
char *strdup();
int main()
{
char pad1[10];
char a[10];
char pad2[10];
char b[10];
char pad3[10];
memset (pad1, 0, sizeof(pad1));
memset (pad2, 0, sizeof(pad2));
memset (pad3, 0, sizeof(pad3));
memset (a, 'a', 10);
a[3] = 0;
a[9] = 0;
memset (b, 'b', 10);
#if defined test_bcheck_100
memcpy(&a[1],&b[0],10);
#elif defined test_bcheck_101
memcpy(&a[0],&b[1],10);
#elif defined test_bcheck_102
memcpy(&a[0],&a[3],4);
#elif defined test_bcheck_103
memcpy(&a[3],&a[0],4);
#elif defined test_bcheck_104
memcmp(&b[1],&b[0],10);
#elif defined test_bcheck_105
memcmp(&b[0],&b[1],10);
#elif defined test_bcheck_106
memmove(&b[1],&b[0],10);
#elif defined test_bcheck_107
memmove(&b[0],&b[1],10);
#elif defined test_bcheck_108
memset(&b[1],'b',10);
#elif defined test_bcheck_109
strlen(&b[0]);
#elif defined test_bcheck_110
strcpy(&a[7], &a[0]);
#elif defined test_bcheck_111
strcpy(&a[0], &b[7]);
#elif defined test_bcheck_112
strcpy(&a[0], &a[1]);
#elif defined test_bcheck_113
strcpy(&a[2], &a[0]);
#elif defined test_bcheck_114
strncpy(&a[7], &a[0], 10);
#elif defined test_bcheck_115
strncpy(&a[0], &b[7], 10);
#elif defined test_bcheck_116
strncpy(&a[0], &a[1], 10);
#elif defined test_bcheck_117
strncpy(&a[2], &a[0], 10);
#elif defined test_bcheck_118
strcmp(&b[2], &b[0]);
#elif defined test_bcheck_119
strcmp(&b[0], &b[2]);
#elif defined test_bcheck_120
strncmp(&b[5], &b[0], 10);
#elif defined test_bcheck_121
strncmp(&b[0], &b[5], 10);
#elif defined test_bcheck_122
strcat(&a[7], &a[0]);
#elif defined test_bcheck_123
strcat(&a[0], &b[3]);
#elif defined test_bcheck_124
strcat(&a[0], &a[4]);
#elif defined test_bcheck_125
strcat(&a[3], &a[0]);
#elif defined test_bcheck_126
strchr(&b[0], 'a');
#elif defined test_bcheck_127
free(strdup(&b[0]));
#endif
}
/* ------------------------------------------------------- */
#endif

View File

@ -0,0 +1,142 @@
[test_backtrace_1]
* main
* f1()
* f2()
* f3()
112_backtrace.c:9: at f3: RUNTIME ERROR: invalid memory access
112_backtrace.c:14: by f2
112_backtrace.c:19: by f1
112_backtrace.c:24: by main
[returns 255]
[test_bcheck_1]
* main
* f1()
112_backtrace.c:38: at f1: BCHECK: invalid pointer ........, size 0x? in memmove dest
112_backtrace.c:43: by main
[returns 255]
[test_tcc_backtrace_2]
* main
* f1()
112_backtrace.c:64: at f1: Hello from f1!
112_backtrace.c:70: by main
* f2()
* exit f2
[returns 34]
[test_tcc_backtrace_3]
* main
[returns 1]
[test_bcheck_100]
112_backtrace.c:107: at main: BCHECK: invalid pointer ........, size 0x? in memcpy dest
[returns 255]
[test_bcheck_101]
112_backtrace.c:109: at main: BCHECK: invalid pointer ........, size 0x? in memcpy src
[returns 255]
[test_bcheck_102]
112_backtrace.c:111: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in memcpy
[returns 255]
[test_bcheck_103]
112_backtrace.c:113: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in memcpy
[returns 255]
[test_bcheck_104]
112_backtrace.c:115: at main: BCHECK: invalid pointer ........, size 0x? in memcmp s1
[returns 255]
[test_bcheck_105]
112_backtrace.c:117: at main: BCHECK: invalid pointer ........, size 0x? in memcmp s2
[returns 255]
[test_bcheck_106]
112_backtrace.c:119: at main: BCHECK: invalid pointer ........, size 0x? in memmove dest
[returns 255]
[test_bcheck_107]
112_backtrace.c:121: at main: BCHECK: invalid pointer ........, size 0x? in memmove src
[returns 255]
[test_bcheck_108]
112_backtrace.c:123: at main: BCHECK: invalid pointer ........, size 0x? in memset
[returns 255]
[test_bcheck_109]
112_backtrace.c:125: at main: BCHECK: invalid pointer ........, size 0x? in strlen
[returns 255]
[test_bcheck_110]
112_backtrace.c:127: at main: BCHECK: invalid pointer ........, size 0x? in strcpy dest
[returns 255]
[test_bcheck_111]
112_backtrace.c:129: at main: BCHECK: invalid pointer ........, size 0x? in strcpy src
[returns 255]
[test_bcheck_112]
112_backtrace.c:131: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in strcpy
[returns 255]
[test_bcheck_113]
112_backtrace.c:133: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in strcpy
[returns 255]
[test_bcheck_114]
112_backtrace.c:135: at main: BCHECK: invalid pointer ........, size 0x? in strncpy dest
[returns 255]
[test_bcheck_115]
112_backtrace.c:137: at main: BCHECK: invalid pointer ........, size 0x? in strncpy src
[returns 255]
[test_bcheck_116]
112_backtrace.c:139: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in strncpy
[returns 255]
[test_bcheck_117]
112_backtrace.c:141: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in strncpy
[returns 255]
[test_bcheck_118]
112_backtrace.c:143: at main: BCHECK: invalid pointer ........, size 0x? in strcmp s1
[returns 255]
[test_bcheck_119]
112_backtrace.c:145: at main: BCHECK: invalid pointer ........, size 0x? in strcmp s2
[returns 255]
[test_bcheck_120]
112_backtrace.c:147: at main: BCHECK: invalid pointer ........, size 0x? in strncmp s1
[returns 255]
[test_bcheck_121]
112_backtrace.c:149: at main: BCHECK: invalid pointer ........, size 0x? in strncmp s2
[returns 255]
[test_bcheck_122]
112_backtrace.c:151: at main: BCHECK: invalid pointer ........, size 0x? in strcat dest
[returns 255]
[test_bcheck_123]
112_backtrace.c:153: at main: BCHECK: invalid pointer ........, size 0x? in strcat dest
[returns 255]
[test_bcheck_124]
112_backtrace.c:155: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in strcat
[returns 255]
[test_bcheck_125]
112_backtrace.c:157: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in strcat
[returns 255]
[test_bcheck_126]
112_backtrace.c:159: at main: BCHECK: invalid pointer ........, size 0x? in strchr
[returns 255]
[test_bcheck_127]
112_backtrace.c:161: at main: BCHECK: invalid pointer ........, size 0x? in strdup
[returns 255]

View File

@ -0,0 +1,43 @@
int tcc_backtrace(const char*, ...);
#define hello() \
tcc_backtrace("hello from %s() / %s:%d",__FUNCTION__,__FILE__,__LINE__)
#ifndef _WIN32
# define __declspec(n)
#endif
#if DLL==1
__declspec(dllexport) int f_1()
{
hello();
return 0;
}
#elif DLL==2
__declspec(dllexport) int f_2()
{
hello();
return 0;
}
#else
int f_1();
int f_2();
int f_main()
{
hello();
return 0;
}
int main ()
{
f_1();
f_2();
f_main();
return 0;
}
#endif

View File

@ -0,0 +1,6 @@
113_btdll.c:12: at f_1: hello from f_1() / 113_btdll.c:12
113_btdll.c:37: by main
113_btdll.c:20: at f_2: hello from f_2() / 113_btdll.c:20
113_btdll.c:38: by main
113_btdll.c:31: at f_main: hello from f_main() / 113_btdll.c:31
113_btdll.c:39: by main

View File

@ -0,0 +1,94 @@
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
static volatile int run = 1;
static int dummy[10];
static sem_t sem;
static void
add (void)
{
int i;
for (i = 0; i < (sizeof(dummy)/sizeof(dummy[0])); i++) {
dummy[i]++;
}
}
static void *
high_load (void *unused)
{
while (run) {
add();
}
return NULL;
}
static void *
do_signal (void *unused)
{
while (run) {
kill (getpid(), SIGUSR1);
while (sem_wait(&sem) < 0 && errno == EINTR);
}
return NULL;
}
/* See tcc-doc.info */
#ifdef __BOUNDS_CHECKING_ON
extern void __bound_checking (int no_check);
#define BOUNDS_CHECKING_OFF __bound_checking(1)
#define BOUNDS_CHECKING_ON __bound_checking(-1)
#else
#define BOUNDS_CHECKING_OFF
#define BOUNDS_CHECKING_ON
#endif
static void real_signal_handler(int sig)
{
add();
sem_post (&sem);
}
static void signal_handler(int sig)
{
BOUNDS_CHECKING_OFF;
real_signal_handler(sig);
BOUNDS_CHECKING_ON;
}
int
main (void)
{
int i;
pthread_t id1, id2;
struct sigaction act;
struct timespec request;
memset (&act, 0, sizeof (act));
act.sa_handler = signal_handler;
act.sa_flags = 0;
sigemptyset (&act.sa_mask);
sigaction (SIGUSR1, &act, NULL);
sem_init (&sem, 1, 0);
pthread_create(&id1, NULL, high_load, NULL);
pthread_create(&id2, NULL, do_signal, NULL);
clock_gettime (CLOCK_MONOTONIC, &request);
request.tv_sec += 1;
request.tv_nsec += 0;
printf ("start\n");
while (clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &request, NULL)) {
}
printf ("end\n");
run = 0;
pthread_join(id1, NULL);
pthread_join(id2, NULL);
sem_destroy (&sem);
return 0;
}

View File

@ -0,0 +1,2 @@
start
end

View File

@ -1,4 +1,5 @@
#include <stdio.h>
//#include <stdio.h>
extern int printf(const char *, ...);
int main()
{

View File

@ -1,6 +1,19 @@
#include <stdio.h>
#include <math.h>
float fd;
int
test()
{
// was an internal tcc compiler error with arm64 backend until 2019-11-08
if (fd < 5.5) {
return 1;
} else {
return 0;
}
}
int main()
{
// variables

View File

@ -1,4 +1,43 @@
#include <stdio.h>
#include <assert.h>
extern int printf(const char*, ...);
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);
/* The following line causes a warning */
void *xx = fp?f:1;
}
struct condstruct {
int i;
};
static int getme(struct condstruct* s, int i)
{
int i1 = (i != 0 ? 0 : s)->i;
int i2 = (i == 0 ? s : 0)->i;
int i3 = (i != 0 ? (void*)0 : s)->i;
int i4 = (i == 0 ? s : (void*)0)->i;
return i1 + i2 + i3 + i4;
}
int main()
{
@ -9,6 +48,32 @@ 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'};
static const struct stru2 { int x; } d = { 'D' };
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);
ASSERT(sizeof(int) == sizeof(0 ? 'a' : c));
ASSERT(sizeof(double) == sizeof(0 ? 'a' : 1.0));
ASSERT(sizeof(double) == sizeof(0 ? 0.0 : 'a'));
ASSERT(sizeof(float) == sizeof(0 ? 'a' : 1.0f));
ASSERT(sizeof(double) == sizeof(0 ? 0.0 : 1.0f));
struct condstruct cs = { 38 };
printf("%d\n", getme(&cs, 0));
// the following lines contain type mismatch errors in every ternary expression
//printf("comparing double with pointer : size = %d\n", sizeof(0 ? &c : 0.0));
//printf("'%c' <> '%c'\n", (0 ? a : d).x, (1 ? a : d).x);
//0 ? a : 0.0;
}
return 0;
}

View File

@ -1,3 +1,4 @@
33_ternary_op.c:26: warning: pointer/integer mismatch in conditional expression
0
1
4
@ -8,3 +9,4 @@
21
24
27
152

View File

@ -456,11 +456,13 @@ char *pmatch(char *line, char *pattern)
while (*l && (e = pmatch(l, p)))
l = e; /* Get longest match */
while (*p++ != ENDPAT); /* Skip over pattern */
while (l >= are) { /* Try to match rest */
while (l > are) { /* Try to match rest */
if (e = pmatch(l, p))
return(e);
--l; /* Nope, try earlier */
}
if (e = pmatch(l, p))
return(e);
return(0); /* Nothing else worked */
default:

View File

@ -48,4 +48,275 @@ 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); }
#elif defined test_duplicate_def_1
static enum myenum { L = -1 } L;
#elif defined test_duplicate_def_2
void foo(void) {
static enum myenum { L = -1 } L;
}
#elif defined test_abstract_decls
int bar(const char *()); // abstract declarator here is okay
int bar (const char *(*g)()) // should match this 'g' argument
{
g();
return 42;
}
int foo(int ()) // abstract decl is wrong in definitions
{
return 0;
#elif defined test_invalid_1
void f(char*);
void g(void) {
f((char[]){1, ,});
}
#elif defined test_invalid_2
int ga = 0.42 { 2 };
#elif defined test_invalid_3
struct S { int a, b; };
struct T { struct S x; };
struct T gt = { 42 a: 1, 43 };
#elif defined test_invalid_4
enum E {
x = 1 / 0
};
#elif defined test_conflicting_types
int i;
void foo(void) {
int i;
{
extern double i;
i = 42.2;
}
}
#elif defined test_nested_types
union u {
union u {
int i;
} m;
};
#elif defined test_vla_1
int X=1;
int main(void) {
int t[][][X];
}
#elif defined test_invalid_alignas
/* _Alignas is no type qualifier */
void * _Alignas(16) p1;
#elif defined test_static_assert
#define ONE 0
_Static_assert(ONE == 0, "don't show me this");
_Static_assert(ONE == 1, "ONE is not 1");
#elif defined test_static_assert_2
_Static_assert(1, "1"" is 1");
_Static_assert(0, "0"" is 0");
#elif defined test_static_assert_c2x
_Static_assert(1);
_Static_assert(0);
#elif defined test_void_array
void t[3];
#elif defined test_incomplete_enum_array
enum e t[3];
#elif defined test_incomplete_struct_array
struct s t[3];
#elif defined test_const_fun_array
typedef void f(void);
const f t[3];
#elif defined test_incomplete_array_array
int t[][3]; // gr: not an error, see below
/******************************************************************/
#elif defined test_extern_array
int iii[] = { 1,2,3 };
extern int iii[];
int x[];
int x[2];
int x[];
int x[2];
int x[];
extern int x[2];
extern int x[];
int x[3];
/******************************************************************/
#elif defined test_func_1 \
|| defined test_func_2 \
|| defined test_func_3 \
|| defined test_func_4 \
|| defined test_func_5 \
|| defined test_func_6
#if defined test_func_1
int hello(int);
#elif defined test_func_4
static int hello(int);
#endif
int main () {
#if defined test_func_6
static
#endif
int hello(int);
hello(123);
return 0;
}
int printf(const char*, ...);
#if defined test_func_3
static int hello(int a)
#elif defined test_func_5
int hello(int a, int b)
#else
int hello(int a)
#endif
{ printf("%s: a = %d\n", __FUNCTION__, a); return 0; }
/******************************************************************/
#elif defined test_var_1 \
|| defined test_var_2 \
|| defined test_var_3
#define P(n,v) printf("%-5s: %d ; %d\n", __FUNCTION__, n, v)
#if defined test_var_1
int xxx[];
#endif
int bar();
int printf(const char*, ...);
int main ()
{
#if !defined test_var_3
int xxx = 2;
#endif
{
extern int xxx[
#if defined test_var_3
2
#endif
];
P(1, xxx[0]);
xxx[0] += 2;
}
#if !defined test_var_3
P(2, xxx);
#endif
bar(123);
return 0;
}
int xxx[1] = {1};
int bar() { P(3, xxx[0]); return 0; }
#elif defined test_var_4
struct yyy { int y; };
struct zzz;
void f1() {
extern char *x;
extern char **xx;
extern struct yyy y;
extern struct yyy *yy;
extern struct zzz z;
extern struct zzz *zz;
}
void f2() {
extern char *x;
extern char **xx;
extern struct yyy y;
extern struct yyy *yy;
extern struct zzz z;
extern struct zzz *zz;
}
struct yyy y, *yy;
struct zzz { int z; } z, *zz;
/******************************************************************/
#elif defined test_long_double_type_for_win32
int main()
{
double *a = 0;
long double *b = a;
int n = _Generic(*a, double:0, long double:1);
}
/******************************************************************/
#endif

View File

@ -20,9 +20,133 @@
60_errors_and_warnings.c:26: error: redefinition of enumerator 'RED'
[test_63_local_enumerator_redefinition]
[returns 1]
[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
[test_duplicate_def_1]
60_errors_and_warnings.c:128: error: redefinition of 'L'
[test_duplicate_def_2]
60_errors_and_warnings.c:131: error: redeclaration of 'L'
[test_abstract_decls]
60_errors_and_warnings.c:141: error: identifier expected
[test_invalid_1]
60_errors_and_warnings.c:146: error: identifier expected
[test_invalid_2]
60_errors_and_warnings.c:149: error: ';' expected (got "{")
[test_invalid_3]
60_errors_and_warnings.c:153: error: ',' expected (got "a")
[test_invalid_4]
60_errors_and_warnings.c:157: error: division by zero in constant
[test_conflicting_types]
60_errors_and_warnings.c:163: error: incompatible types for redefinition of 'i'
[test_nested_types]
60_errors_and_warnings.c:170: error: struct/union/enum already defined
[test_vla_1]
60_errors_and_warnings.c:177: error: need explicit inner array size in VLAs
[test_invalid_alignas]
60_errors_and_warnings.c:181: error: identifier expected
[test_static_assert]
60_errors_and_warnings.c:187: error: ONE is not 1
[test_static_assert_2]
60_errors_and_warnings.c:191: error: 0 is 0
[test_static_assert_c2x]
60_errors_and_warnings.c:195: error: _Static_assert fail
[test_void_array]
60_errors_and_warnings.c:198: error: declaration of an array of incomplete type elements
[test_incomplete_enum_array]
60_errors_and_warnings.c:201: error: declaration of an array of incomplete type elements
[test_incomplete_struct_array]
60_errors_and_warnings.c:204: error: declaration of an array of incomplete type elements
[test_const_fun_array]
60_errors_and_warnings.c:208: error: declaration of an array of functions
[test_incomplete_array_array]
[test_extern_array]
60_errors_and_warnings.c:224: error: incompatible types for redefinition of 'x'
[test_func_1]
hello: a = 123
[test_func_2]
hello: a = 123
[test_func_3]
60_errors_and_warnings.c:254: warning: static storage ignored for redefinition of 'hello'
hello: a = 123
[test_func_4]
hello: a = 123
[test_func_5]
60_errors_and_warnings.c:254: error: incompatible types for redefinition of 'hello'
[test_func_6]
60_errors_and_warnings.c:242: error: function without file scope cannot be static
[test_var_1]
main : 1 ; 1
main : 2 ; 2
bar : 3 ; 3
[test_var_2]
main : 1 ; 1
main : 2 ; 2
bar : 3 ; 3
[test_var_3]
60_errors_and_warnings.c:286: error: incompatible types for redefinition of 'xxx'
[test_var_4]
[test_long_double_type_for_win32]
60_errors_and_warnings.c:317: warning: assignment from incompatible pointer type

View File

@ -230,6 +230,17 @@ void ret(void)
printf("%.1Lf %.1Lf\n", fr_hfa34().a, fr_hfa34().d);
}
void*
va_arg_with_struct_ptr(va_list ap) {
/*
* This was a BUG identified with FFTW-3.3.8 on arm64.
* The test case only checks it compiles.
*/
struct X { int _x; };
struct X *x = va_arg(ap, struct X *);
return x;
}
int match(const char **s, const char *f)
{
const char *p = *s;

View File

@ -39,5 +39,17 @@ int f5 (fptr5 fp, fptr1 i)
{
return fp(i);
}
typedef int intx4[4];
int f8 (intx4, int);
int f8 (int ([4]), int);
int f8 (int y[4], int i)
{
return y[i];
}
int f9 (int (*)(int), int);
int f9 (int ((int)), int);
int f9 (int f(int), int i)
{
return f(i);
}
int main () { return 0; }

View File

@ -16,4 +16,50 @@ void __attribute__((stdcall)) foo (void)
{
}
int main () { return 0; }
#define __stdcall __attribute__((stdcall))
extern int some_stdcall_func (int, int, int) __stdcall;
__stdcall int __stdcall some_stdcall_func(int foo, int bar, int baz) {
//printf("Hello from stdcall: %i %i %i\n", foo, bar, baz);
return 43;
}
/* 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 *, ...);
static int globalvar;
int main()
{
void *function_pointer = &actual_function;
int localvar = 42, i;
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);
/* All these should work and leave the stack pointer in its original
position. */
some_stdcall_func(1, 10, 100);
((int __stdcall (*)(int, int, int))some_stdcall_func) (2, 20, 200);
((int(*__stdcall)(int, int, int))some_stdcall_func) (3, 30, 300);
for (i = 0; i < 1024; i++) {
globalvar = i;
/* This was once misparsed at <= gitrev 325241c0, forgetting
the stdcall attribute on the function pointer leading to
stack increment being done twice (in callee and caller).
This will clobber 'i' and 'localvar' which is how we detect
this. */
((int(__stdcall*)(int, int, int))some_stdcall_func) (4, 40, 400);
if (localvar != 42 || globalvar != i)
printf("error, localvar=%d i=%d globalvar=%d\n", localvar, i, globalvar);
}
return 0;
}

View File

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

View File

@ -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;
}

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