Commit Graph

208 Commits

Author SHA1 Message Date
Edmund Grimley Evans
0e79df499a tccgen.c: (!nocode_wanted) -> (nocode_wanted) in arm64 part. 2015-03-10 22:37:36 +00:00
Thomas Preud'homme
5bcc3eed7b Add some missing nocode_wanted guard
int i = i++ causes a segfault because of missing guard. Looking
recursively at all backend functions called from middle end several more
guard appeared to be missing.
2015-03-10 23:27:14 +08:00
Michael Matz
2eb4f4a3ba Remove incorrect comment
Not the code was confused, I was :)
2015-03-09 01:33:42 +01:00
Michael Matz
50899e30ab Fix stack overwrite on structure return
The common code to move a returned structure packed into
registers into memory on the caller side didn't take the
register size into account when allocating local storage,
so sometimes that lead to stack overwrites (e.g. in 73_arm64.c),
on x86_64.  This fixes it by generally making gfunc_sret also return
the register size.
2015-03-09 00:19:59 +01:00
Edmund Grimley Evans
d73b488401 arm64: Implement __clear_cache.
__clear_cache is defined in lib-arm64.c with a single call to
__arm64_clear_cache, which is the real built-in function and is
turned into inline assembler by gen_clear_cache in arm64-gen.c
2015-03-08 00:10:44 +00:00
Edmund Grimley Evans
ac70e6b840 tccgen.c: Optimise 0<<x, 0>>x, -1>>x, x&0, x*0, x|-1, x%1.
More precisely, treat (0 << x) and so on as constant expressions, but
not if const_wanted as we do not want to allow "case (x*0):", ...

Do not optimise (0 / x) and (0 % x) here as x might be zero, though
for an architecture that does not generate an exception for division
by zero the back end might choose to optimise those.
2015-03-07 17:32:39 +00:00
seyko
8d4c861144 fix for the array in struct initialization w/o '{', case 2
a test program:

    struct {
    int a[2], b[2];
    } cases[] = {
	{ ((int)0), (((int)0)) },
	((int)0), (((int)0)) /* error: ',' expected (got ")") */
    };
    int main() { return 0; }

This commit allow to skip ')' in the decl_initializer() and to see ','
2015-03-07 09:40:12 +03:00
Edmund Grimley Evans
238e760a29 Add __builtin_return_address.
Implementation is mostly shared with __builtin_frame_address.
It seems to work on arm64, i386 and x86_64. It may need to be
adapted for other targets.
2015-03-06 21:01:14 +00:00
seyko
d9b87c087c fixing decl_initializer() for size_only: don't eat ')'
a test program:

    struct { int c[1]; } s1[] = { (int)0       }; /* OK */
    struct { int c[1]; } s2[] = { { ((int)0) } }; /* OK */
    struct { int c[1]; } s3[] = { 0            }; /* OK */
    struct { int c[1]; } sx[] = { ((int)0)     }; /* error: ')' expected (got "}") */
    int main() { return 0; }
2015-03-05 20:18:25 +03:00
seyko
c45a8695eb A reverse of the commit 14745bdeb because of the problems while compiling linux 2.4.26
A test program:
    ///////////
    typedef unsigned int __u32;
    static inline const __u32 __fswab32(__u32 x)
    {
	return ({ __u32 __tmp = (x) ; ___swab32(__tmp); });
    }
    void func()
    {
	int aaa = 1;
	int snd_wnd = 2;
	int TCP_FLAG_ACK = 3;
	int pred_flags = (__builtin_constant_p((__u32)
	    (((aaa << 26) |
	    (__builtin_constant_p((__u32)((TCP_FLAG_ACK))) ?
		({ __u32 __x = (((TCP_FLAG_ACK))); ((__u32)( (((__u32)(__x) & (__u32)0x000000ffUL) << 24) | (((__u32)(__x) & (__u32)0x0000ff00UL) << 8) | (((__u32)(__x) & (__u32)0x00ff0000UL) >> 8) | (((__u32)(__x) & (__u32)0xff000000UL) >> 24) )); }) : __fswab32(((TCP_FLAG_ACK)))) | snd_wnd))) ? ({ __u32 __x = ((((aaa << 26) | (__builtin_constant_p((__u32)((TCP_FLAG_ACK))) ? ({ __u32 __x = (((TCP_FLAG_ACK))); ((__u32)( (((__u32)(__x) & (__u32)0x000000ffUL) << 24) | (((__u32)(__x) & (__u32)0x0000ff00UL) << 8) | (((__u32)(__x) & (__u32)0x00ff0000UL) >> 8) | (((__u32)(__x) & (__u32)0xff000000UL) >> 24) )); }) : __fswab32(((TCP_FLAG_ACK)))) | snd_wnd))); ((__u32)( (((__u32)(__x) & (__u32)0x000000ffUL) << 24) | (((__u32)(__x) & (__u32)0x0000ff00UL) << 8) | (((__u32)(__x) & (__u32)0x00ff0000UL) >> 8) | (((__u32)(__x) & (__u32)0xff000000UL) >> 24) )); }) : __fswab32((((aaa << 26) | (__builtin_constant_p((__u32)((TCP_FLAG_ACK))) ? ({ __u32 __x = (((TCP_FLAG_ACK))); ((__u32)( (((__u32)(__x) & (__u32)0x000000ffUL) << 24) | (((__u32)(__x) & (__u32)0x0000ff00UL) << 8) | (((__u32)(__x) & (__u32)0x00ff0000UL) >> 8) | (((__u32)(__x) & (__u32)0xff000000UL) >> 24) )); })
		: __fswab32(((TCP_FLAG_ACK)))) | snd_wnd))));
    }
    ////////////
error: ';' expected (got "(")
2015-03-03 15:44:29 +03:00
seyko
6fd4e5bace a void to void cast.
Allow tcc to compile the following program
    ///////
	void func1() {}
	void func2() {
	  return func1();
	}
    //////
gcc accepts this program
2015-03-03 15:39:57 +03:00
seyko
09feeca5df a statement expressions with a pointer return type
A test program:
    //////////////
    int main()
    {
	void *p = ({ 0 ; ((void *)1); });
    }
    /////////////
Porblem is introduced in a commit a80acab: Display error on statement expressions with complex return type
This error is exposed when compiling a linux 2.4.26. tcc 0.9.23 can sucessfully compile
this version of the linux.
2015-03-03 15:29:14 +03:00
seyko
1a1e9548fb iitialisation of the empty struct
Current tcc don't understand an initialization of the empty struct
This problem was found trying to compile a linux kernel 2.4.26
which can be compiled by tcc 0.9.23

  A test program:
  ////////////////////
  // ./tcc -c test_3.c
  // test_3.c:31: error: too many field init
  #undef __GNUC__
  #undef __GNUC_MINOR__
  #define __GNUC__  2
  #define __GNUC_MINOR__ 95
  typedef struct { } rwlock_t;
  struct fs_struct {
   int count;
   rwlock_t lock;
   int umask;
  };
  #define INIT_FS { \
	1, \
	RW_LOCK_UNLOCKED, \
	0022, \
  }
  #if (__GNUC__ > 2 || __GNUC_MINOR__ > 91)
    typedef struct { } rwlock_t;
    #define RW_LOCK_UNLOCKED (rwlock_t) { }
  #else
    typedef struct { int gcc_is_buggy; } rwlock_t;
    #define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
  #endif
  static struct fs_struct init_fs = INIT_FS;
  // static struct fs_struct init_fs = { { (1) }, (rwlock_t) { 0 }, 0022, };
  //                                                           ^ with this all Ok
  // static struct fs_struct init_fs = { { (1) }, (rwlock_t) { }, 0022, };
  //                                                          ^ current tcc don't understand, but tcc 0.9.23 can
  int main()
  {
    return 0;
  }
  ////////////////////
  A regression is detected after a patch 69fdb57edd
  ////////////////////
  // A test for patch 69fdb57edd
  // Author: grischka <grischka>
  // Date:   Wed Jun 17 02:09:07 2009 +0200
  //     unions: initzialize only one field
  //         struct {
  //           union {
  //             int a,b;
  //           };
  //           int c;
  //         } sss = { 1,2 };
  //     This had previously assigned 1,2 to a,b and 0 to c which is wrong.
  //
  // Expected: sss.a=1 sss.b=1 sss.c=2
  int main()
  {
    struct {
      union {
        int a,b;
      };
      int c;
    } sss = { 1, 2 };

    printf ("sss.a=%d sss.b=%d sss.c=%d\n", sss.a, sss.b, sss.c);
    return 0;
  }
  ////////////////////
2015-03-03 15:15:48 +03:00
seyko
bbf8221ec3 tcc don't understand am extern array of structs.
A regression was found trying to compile a linux kernel 2.4.26
  which can be compiled by tcc 0.9.23

    ///////////////////
    #include <stdio.h>

    // test for a bug:
    // compiler don't understand am extern array of structs
    // $ tcc test_1.c
    // test_1.c:8: error: unknown struct/union/enum

    extern struct FILE std_files[4];

    int main()
    {
	return 0;
    }
    //////////////////

  tcc-current
  /* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */
  static void struct_decl(CType *type, int u, int tdef)
  ...
    if (tok != '{') {
        v = tok;
        next();
        /* struct already defined ? return it */
        if (v < TOK_IDENT)
            expect("struct/union/enum name");
        s = struct_find(v);
        if (s) {
            if (s->type.t != a)
                tcc_error("invalid type");
            goto do_decl;
        } else if (tok >= TOK_IDENT && !tdef)
            tcc_error("unknown struct/union/enum");
    } else {
        v = anon_sym++;
    }

  tcc-0.9.23 which don't have such error
  /* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */
  static void struct_decl(CType *type, int u)
  ....
    if (tok != '{') {
        v = tok;
        next();
        /* struct already defined ? return it */
        if (v < TOK_IDENT)
            expect("struct/union/enum name");
        s = struct_find(v);
        if (s) {
            if (s->type.t != a)
                error("invalid type");
            goto do_decl;
        }
    } else {
        v = anon_sym++;
    }
2015-03-03 15:00:13 +03:00
Edmund Grimley Evans
40f7e11c53 tccgen.c: Make sure that gen_op always returns an rvalue.
Either this fix, or an alternative one, is required for arm64.
2015-02-23 22:51:10 +00:00
Edmund Grimley Evans
b14ef0e24b Add arm64 (AArch64) as a target architecture. 2015-02-23 22:51:03 +00:00
Edmund Grimley Evans
738606dbd5 Use RELA relocations properly for R_DATA_PTR on x86_64.
libtcc.c: Add greloca, a generalisation of greloc that takes an addend.
tcc.h: Add greloca and put_elf_reloca.
tccelf.c: Add put_elf_reloca, a generalisation of put_elf_reloc.
tccgen.c: On x86_64, use greloca instead of greloc in init_putv.
2015-02-21 21:29:03 +00:00
Edmund Grimley Evans
ff3f9aa6ba Fix handling of case_reg in switch statement.
The back end functions gen_op(comparison) and gtst() might allocate
registers so case_reg should be left on the value stack while they
are called and set again afterwards.
2015-02-20 23:16:00 +00:00
grischka
9d7fb33360 tccgen: use lvalue as result from bitfield assignment
test case:

    #include <stdio.h>
    int main(int argc, char **argv)
    {
        struct _s { unsigned a:9, b:5, c:7; } _s, *s = &_s;
        int n = 250;
        s->a = s->b = s->c = n + 4;
        printf("--> %d / %d / %d\n", s->a, s->b, s->c);
        return 0;
    }

before:
--> 254 / 30 / 126
now:
--> 30 / 30 / 126
2014-09-23 12:30:08 +02:00
grischka
14745bdeb7 tccgen: nocode_wanted: do not output constants
This for example suppresses string constants such as with

    int main()
    {
        return sizeof "foo";
    }

Actually, setting

    nocode_wanted = 1;

in libtcc.c for the initial global level seemed wrong, since
obviously "nocode_wanted" means code as any side effects, also
such as string constants.

This reverts a part of 2de1b2d14c
(documented as "Some in-between fixes" in Changelog)
2014-08-01 10:59:38 +02:00
Michael Matz
356c6f6293 Remove unused variable 2014-04-14 05:41:57 +02:00
Michael Matz
fbda78aefe Parse and emit hidden visibility
This adds parsing of (GCC compatible) visibility attribute
in order to mark selected global symbols as hidden.  The generated
.o files contain hidden symbols already, the TCC linker doesn't
yet do the right thing.
2014-04-14 02:53:11 +02:00
Urs Janssen
822f4630e3 add missing prototypes 2014-04-10 11:53:54 +02:00
Thomas Preud'homme
c2422ba87f Fix test for macro nesting 2014-04-07 21:16:04 +08:00
Vincent Lefevre
3e9a7e9d69 Corrected spelling mistakes in comments and strings 2014-04-07 13:31:00 +02:00
grischka
0e43f3aef4 win32: warn people about using undeclared WINAPI functions
*** UNCONDITIONALLY ***

Esp. sihce tinycc winapi headers are not as complete as people might
expect this can otherwise lead to obscure problems that are difficult
to debug.

(Originally 'warn_implicit_function_declaration' was set to 1
always for windows but someone must have deleted that line)
2014-04-06 10:59:40 +02:00
grischka
5879c854fb tccgen: x86_64: fix garbage in the SValue upper bits
This was going wrong (case TOK_LAND in unary: computed labels)
-        vset(&s->type, VT_CONST | VT_SYM, 0);
-        vtop->sym = s;

This does the right thing and is shorter:

+        vpushsym(&s->type, s);


Test case was:

    int main(int argc, char **argv)
    {
        int x;
        static void *label_return = &&lbl_return;
        printf("label_return = %p\n", label_return);
        goto *label_return; //<<<<< here segfault on linux X86_64 without the memset on vset
        printf("unreachable\n");
    lbl_return:
        return 0;
    }


Also::
- Rename "void* CValue.ptr" to more usable "addr_t ptr_offset"
  and start to use it in obvious cases.

- use __attribute__ ((noreturn)) only with gnu compiler

- Revert CValue memsets ("After several days searching ...")
  commit 4bc83ac393

Doesn't mean that the vsetX/vpush thingy isn't brittle and
there still might be bugs as to differences in how the CValue
union  was set and is then interpreted later on.

However the big memset hammer was just too slow (-3% overall).
2014-04-04 20:20:44 +02:00
Thomas Preud'homme
3e56584223 Allow local redefinition of enumerator 2014-03-31 22:59:10 +08:00
Thomas Preud'homme
f272407353 Fix typo in code added by b018bac9c8 2014-03-29 14:57:59 +08:00
Thomas Preud'homme
b125743323 Create bcheck region for argv and arge argument
For program manipulating argv or arge as pointer with construct such as:

(while *argv++) {
  do_something_with_argv;
}

it is necessary to have argv and arge inside a region. This patch create
regions argv and arge) if main is declared with those parameters.
2014-03-29 14:46:26 +08:00
mingodad
4bc83ac393 After several days searching why my code refactoring to remove globals was crashing,
I found the problem it was because CValue stack variables have rubish as it inital values
and assigning to a member that is smaller than the big union item and trying to
recover it later as a different member gives bak garbage.

ST_FUNC void vset(TCCState* tcc_state, CType *type, int r, int v)
{
    CValue cval;
    memset(&cval, 0, sizeof(CValue));

    cval.i = v; //,<<<<<<<<<<< here is the main bug that mix with garbage
    vsetc(tcc_state, type, r, &cval);
}

/* store a value or an expression directly in global data or in local array */
static void init_putv(TCCState* tcc_state, CType *type, Section *sec, unsigned long c,
                      int v, int expr_type)
{
...
        case VT_PTR:
            if (tcc_state->tccgen_vtop->r & VT_SYM) {
                greloc(tcc_state, sec, tcc_state->tccgen_vtop->sym, c, R_DATA_PTR);
            }

//<<< on the next line is where we try to get the assigned value to cvalue.i as cvalue.ull

            *(addr_t *)ptr |= (tcc_state->tccgen_vtop->c.ull & bit_mask) << bit_pos;
            break;

Also this patch makes vla tests pass on linux 32 bits
2014-03-26 20:18:48 +00:00
Thomas Preud'homme
b68499e971 Make parse_btype only accept one basic type
This makes int char c; and struct {} int c; generate an error. Thanks
Mobi Phil for reporting.
2014-03-24 23:40:39 +08:00
Thomas Preud'homme
33cea54dc7 Fix type_to_str test for unsigned int 2014-03-09 13:32:40 +08:00
Thomas Preud'homme
fdb3b10d06 Fix various errors uncovered by static analysis
Reported-by: Carlos Montiers <cmontiers@gmail.com>
2014-03-08 18:38:49 +08:00
Thomas Preud'homme
b0b5165d16 Def signedness != signed != unsigned for char
When checking for exact compatibility between types (such as in
__builtin_types_compatible_p) consider the case of default signedness to
be incompatible with both of the explicit signedness for char. That is,
char is incompatible with signed char *and* unsigned char, no matter
what the default signedness for char is.
2014-02-06 21:40:22 +08:00
Thomas Preud'homme
17314a1fb3 Fix parameter passing of long long bitfield 2014-02-04 20:55:24 +08:00
Thomas Preud'homme
4e5f15c685 switch last 2 params of TOK_memset on ARM
On ARM, TOK_memset is executed via __aeabi_memset which reverse the
order of the last two parameters.
2014-02-03 22:28:08 +08:00
Michael Matz
05c9b76131 Fix floating point unary minus and plus
negate(x) is subtract(-0,x), not subtract(+0,x), which makes
a difference with signed zeros.  Also +x was expressed as x+0,
in order for the integer promotions to happen, but also mangles signed
zeros, so just don't do that with floating types.
2014-01-12 04:44:27 +01:00
Michael Matz
9e11476e15 Fix Fixes for PE x86_64 for fail in code
Applying 64bit relocs assumes that the CVal is initialized to zero
for the whole 64bit.  Consolidate this a bit, at the same time
zeroing the .ull member more consistently when needed.  Fixes segfault
on x86_64-linux using global vars in tcctest.c.
2014-01-11 23:42:58 +01:00
Archidemon
fdf9fba578 Fixes previous fixes 2014-01-10 11:58:16 +06:00
Archidemon
ea7b17f641 Fixes for PE x86_64 for fail in code
int (*fn1)=0x13fde16b5;

and

int fn1(int a) {...}

struct {
  int (*fn2)(int a);
} b = { fn1 };
2014-01-10 09:45:18 +06:00
grischka
3fe2a95d7f be stricter with aliasing
Refactoring (no logical changes):
- use memcpy in tccgen.c:ieee_finite(double d)
- use union to store attribute flags in Sym
Makefile: "CFLAGS+=-fno-strict-aliasing" basically not necessary
anymore but I left it for now because gcc sometimes behaves
unexpectedly without.

Also:
- configure: back to mode 100755
- tcc.h: remove unused variables tdata/tbss_section
- x86_64-gen.c: adjust gfunc_sret for prototype
2014-01-07 14:57:07 +01:00
grischka
2bd0daabbe misc. fixes
- tccgen: error out for cast to void, as in
      void foo(void) { return 1; }
  This avoids an assertion failure in x86_64-gen.c, also.
  also fix tests2/03_struct.c accordingly

- Error: "memory full" - be more specific

- Makefiles: remove circular dependencies, lookup tcctest.c from VPATH

- tcc.h: cleanup lib, include, crt and libgcc search paths"
  avoid duplication or trailing slashes with no CONFIG_MULTIARCHDIR
  (as from 9382d6f1a0)

- tcc.h: remove ";{B}" from PE search path
  in ce5e12c2f9 James Lyon wrote:
  "... I'm not sure this is the right way to fix this problem."
  And the answer is: No, please. (copying libtcc1.a for tests instead)

- win32/build_tcc.bat: do not move away a versioned file
2014-01-06 19:56:26 +01:00
Thomas Preud'homme
8efaa71190 Fix struct ret in variadic fct with ARM hardfloat
The procedure calling standard for ARM architecture mandate the use of
the base standard for variadic function. Therefore, hgen float aggregate
must be returned via stack when greater than 4 bytes and via core
registers else in case of variadic function.

This patch improve gfunc_sret() to take into account whether the
function is variadic or not and make use of gfunc_sret() return value to
determine whether to pass a structure via stack in gfunc_prolog(). It
also take advantage of knowing if a function is variadic or not move
float result value from VFP register to core register in gfunc_epilog().
2014-01-06 22:57:05 +08:00
Thomas Preud'homme
eda2c756ed Move logic for if (int value) to tccgen.c
Move the logic to do a test of an integer value (ex if (0)) out of
arch-specific code to tccgen.c to avoid code duplication. This also
fixes test of long long value which was only testing the bottom half of
such values on 32 bits architectures.
2014-01-04 21:10:05 +08:00
Thomas Preud'homme
3eed3506b4 Fix negation of 0.0 and -0.0 2014-01-04 17:07:58 +08:00
grischka
fbc8810334 Fix "Add support for struct > 4B returned via registers"
- avoid assumption "ret_align == register_size" which is
  false for non-arm targets
- rename symbol "sret" to more descriptive "ret_nregs"

This fixes commit dcec8673f2

Also:
- remove multiple definitions in win32/include/math.h
2013-12-16 15:38:10 +01:00
Thomas Preud'homme
dcec8673f2 Add support for struct > 4B returned via registers
On ARM with hardfloat calling convention, structure containing 4 fields
or less of the same float type are returned via float registers. This
means that a structure can be returned in up to 4 double registers in a
structure is composed of 4 doubles. This commit adds support for return
of structures in several registers.
2013-11-22 09:27:15 +08:00
Thomas Preud'homme
cf02f920c1 Revert "Add support for thread-local storage variables"
TLS support in tinyCC is absolutely not ready:
- segment register not select in load and store
- no relocation added for computing offset of per-thread symbol
- no support for TLS-specific relocations
- no program header added as per Drepper document about TLS

This reverts commit 1c4afd1350.
2013-11-03 18:55:54 +08:00
Thomas Preud'homme
1c4afd1350 Add support for thread-local storage variables 2013-10-29 22:10:02 +08:00