tcctok.h:
- Add __bound_setjmp/setjmp/_setjmp/longjmp
tccgen.c:
- redirect setjmp/longjmp to bcheck.c code
i386-gen.c/x86_64-gen.c
- Change func_bound_alloca_used into func_bound_add_epilog
- Set func_bound_add_epilog also when setjmp is called
bcheck.c:
- Add __bound_setjmp/__bound_longjmp
- __bound_local_delete: remove setjmp if used in function
- __bound_exit: clear setjmp list and print statistic
- make malloc_redir more readable (unrelated)
New testcases:
- 115_bound_setjmp
- 116_bound_setjmp2
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).
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 :)
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.
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
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.
- 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 == '-')
...
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.
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
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.
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.
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)
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.
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.
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)
... 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).
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.
- 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.)
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.
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.
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.
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.
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.
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.
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.
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 :)
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.
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);`)
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.
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.
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
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]
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]
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
tccgen.c:
doubles need to be aligned, on ARM. The section_reserve()
in init_putv does not do that.
-D ONE_SOURCE: is now the default and not longer needed. Also,
tcc.h now sets the default native target. These both make
compiling tcc simple as "gcc tcc.c -o tcc -ldl" again.
arm-asm.c:
enable pseudo asm also for inline asm
tests/tests2/Makefile:
disable bitfield tests except on windows and x86_64
and don't generate-always
tcc.c:
fix a loop with -dt on errors
configure:
print compiler version (as recognized)
tccpp.c:
actually define symbols for tcc -dt
clear static variables (needed for -dt or libtcc usage)
96_nodata_wanted.c:
use __label__ instead of asm
lib/files:
use native symbols (__i386__ etc.) instead of TCC_TARGET_...
* check that _Generic don't match unsigned char * with char *
this case is usefull as with -funsigned-char, 'char *' are unsigned
* change VT_LONG so it's now a qualifier
VT_LONG are never use for code generation, but only durring parsing state,
in _Generic we need to be able to make diference between
'long' and 'long long'
So VT_LONG is now use as a type qualifier, it's old behaviour is still
here, but we can keep trace of what was a long and what wasn't
* add TOK_CLONG and TOK_CULONG
tcc was directly converting value like '7171L' into TOK_CLLONG or
TOK_CINT depending of the machine architecture.
because of that, we was unable to make diference between a long and a
long long, which doesn't work with _Generic.
So now 7171L is a TOK_CLONG, and we can handle _Generic properly
* check that _Generic can make diference between long and long long
* uncomment "type match twice" as it should now pass tests on any platforms
* add inside_generic global
the point of this variable is to use VT_LONG in comparaison only
when we are evaluating a _Generic.
problem is with my lastest patchs tcc can now make the diference between
a 'long long' and a 'long', but in 64 bit stddef.h typedef uint64_t as
typedef signed long long int int64_t and stdint.h as unsigned long int, so tcc
break when stdint.h and stddef.h are include together.
Another solution woud be to modifie include/stddef.h so it define uint64_t as
unsigned long int when processor is 64 bit, but this could break some
legacy code, so for now, VT_LONG are use only inside generc.
* check that _Generic parse first argument correctly
* check that _Generic evaluate correctly exresion like "f() / 2"
* -dt now with lowercase t
* test snippets now separated by real preprocessor statements
which is valid C also for other compilers
#if defined test_xxx
< test snippet x >
#elif defined test_yyy
< test snippet y >
#elif ...
#endif
* simpler implementation, behaves like -run if no 'test_...' macros
are seen, works with -E too
* for demonstration I combined some of the small tests for errors
and warnings (56..63,74) in "60_errors_and_warnings.c"
Also:
* libtcc.c:
put tcc_preprocess() and tcc_assemble() under the setjmp clause
to let them return to caller after errors. This is for -dt -E.
* tccgen.c:
- get rid of save/restore_parse_state(), macro_ptr is saved
by begin_macro anyway, now line_num too.
- use expr_eq for parsing _Generic's controlling_type
- set nocode_wanted with const_wanted. too, This is to keep
VT_JMP on vtop when parsing preprocessor expressions.
* tccpp.c: tcc -E: suppress trailing whitespace from lines with
comments (that -E removes) such as
NO_GOTPLT_ENTRY,\t /* never generate ... */
The existing variable 'nocode_wanted' is now used to control
output of static data too. So...
(nocode_wanted == 0)
code and data (normal within functions)
(nocode_wanted < 0)
means: no code, but data (global or static data)
(nocode_wanted > 0)
means: no code and no data (code and data suppressed)
(nocode_wanted & 0xC0000000)
means: we're in declaration of static data
Also: new option '-dT' to be used with -run
tcc -dT -run file.c
This will look in file.c for certain comment-boundaries:
/*-* test-xxx: ...some description */
and then for each test below run it from memory. This way
various features and error messages can be tested with one
single file. See 96_nodata_wanted.c for an example.
Also: tccgen.c: one more bitfield fix
tccpp.c:
* #pragma comment(option,"-some-option")
to set commandline option from C code. May work only
for some options.
libtcc.c:
* option "-d1..9": sets a 'g_debug' global variable.
(for development)
tests2/Makefile:
* new make targets: tests2.37 / tests2.37+
run single test from tests2, optionally update .expect
* new variable GEN-ALWAYS to always generate certain .expects
* bitfields test
tccgen.c:
* bitfields: fix a bug and improve slightly more
* _Generic: ignore "type match twice"
For integer promotion with for example arithmetics or
expr_cond (x ? y : z), integral types need to be promoted
to signed if they fit.
According to latest standards, this also applies to bit-field
types taking into account their specific width.
In tcc, VT_BITFIELD set means width < original type width
Field-widths between 33 and 63 are promoted to signed long long
accordingly.
struct { unsigned long long ullb:35; } s = { 1 };
#define X (s.ullb - 2)
int main (void)
{
long long Y = X;
printf("%d %016llx %016llx\n", X < 0, -X, -Y);
return 0;
}
Results:
GCC 4.7 : 0 0000000000000001 FFFFFFF800000001
MSVC : 1 0000000000000001 0000000000000001
TCC : 1 0000000000000001 0000000000000001
Also, gcc would promote long long bitfields of size < 32
to int as well. Example:
struct { unsigned long long x:20; } t = { 123 };
/* with gcc: */ printf("%d %d\n", t.x, 456);
/* with tcc: */ printf("%lld %d\n", t.x, 456);