diff --git a/Changelog b/Changelog index 56604af..daca68c 100644 --- a/Changelog +++ b/Changelog @@ -1,5 +1,21 @@ version 0.9.24: +- Import more changesets from Rob Landley's fork (part 2): + 487: Handle long long constants in gen_opic() (Rob Landley) + 484: Handle parentheses within __attribute__((...)) (Rob Landley) + 480: Remove a goto in decl_initializer_alloc (Rob Landley) + 475: Fix dereferences in inline assembly output (Joshua Phillips) + 474: Cast ptrs to ints of different sizes correctly (Joshua Phillips) + 473: Fix size of structs with empty array member (Joshua Phillips) + 470: No warning for && and || with mixed pointers/integers (Rob Landley) + 469: Fix symbol visibility problems in the linker (Vincent Pit) + 468: Allow && and || involving pointer arguments (Rob Landley) + 455: Optimize case labels with no code in between (Zdenek Pavlas) + 450: Implement alloca for x86 (grischka) + 415: Parse unicode escape sequences (Axel Liljencrantz) + 407: Add a simple va_copy() in stdarg.h (Hasso Tepper) + 400: Allow typedef names as symbols (Dave Dodge) + - Import some changesets from Rob Landley's fork (part 1): 462: Use LGPL with bcheck.c and il-gen.c 458: Fix global compound literals (in unary: case '&':) (Andrew Johnson) diff --git a/Makefile b/Makefile index b526fe5..dc01d46 100644 --- a/Makefile +++ b/Makefile @@ -176,6 +176,9 @@ else LIBTCC1_OBJS=libtcc1.o LIBTCC1_CC=$(CC) endif +ifeq ($(ARCH),i386) +LIBTCC1_OBJS+=alloca86.o alloca86-bt.o +endif %.o: %.c $(LIBTCC1_CC) -O2 -Wall -c -o $@ $< @@ -237,7 +240,11 @@ libinstall: libtcc.a $(INSTALL) -m644 libtcc.h "$(includedir)" libtcc.o: tcc.c i386-gen.c Makefile +ifdef CONFIG_WIN32 + $(CC) $(CFLAGS) -DTCC_TARGET_PE -DLIBTCC -c -o $@ $< +else $(CC) $(CFLAGS) -DLIBTCC -c -o $@ $< +endif libtcc.a: libtcc.o $(AR) rcs $@ $^ @@ -282,11 +289,11 @@ cache: tcc_g # documentation and man page tcc-doc.html: tcc-doc.texi - texi2html -monolithic -number $< + -texi2html -monolithic -number $< tcc.1: tcc-doc.texi - ./texi2pod.pl $< tcc.pod - pod2man --section=1 --center=" " --release=" " tcc.pod > $@ + -./texi2pod.pl $< tcc.pod + -pod2man --section=1 --center=" " --release=" " tcc.pod > $@ FILE=tcc-$(shell cat VERSION) diff --git a/stddef.h b/stddef.h index 89bd7b0..9965f89 100644 --- a/stddef.h +++ b/stddef.h @@ -12,10 +12,15 @@ typedef __PTRDIFF_TYPE__ ptrdiff_t; __GNUC__ ? */ #if !defined(__int8_t_defined) && !defined(__dietlibc__) #define __int8_t_defined -typedef char int8_t; -typedef short int int16_t; -typedef int int32_t; +typedef char int8_t; +typedef short int int16_t; +typedef int int32_t; typedef long long int int64_t; #endif +#ifdef __i386__ +void *_alloca(size_t); +#define alloca _alloca +#endif + #endif diff --git a/tcc.c b/tcc.c index d8a0230..3d80a31 100644 --- a/tcc.c +++ b/tcc.c @@ -1290,6 +1290,7 @@ static void put_extern_sym2(Sym *sym, Section *section, case TOK_memset: case TOK_strlen: case TOK_strcpy: + case TOK__alloca: strcpy(buf, "__bound_"); strcat(buf, name); name = buf; @@ -3123,6 +3124,8 @@ static void parse_escape_string(CString *outstr, const uint8_t *buf, int is_long c = n; goto add_char_nonext; case 'x': + case 'u': + case 'U': p++; n = 0; for(;;) { @@ -4360,7 +4363,7 @@ static void macro_subst(TokenString *tok_str, Sym **nested_list, ptr = (int *)macro_ptr; macro_ptr = ml.p; if (can_read_stream && *can_read_stream == &ml) - *can_read_stream = ml.prev; + *can_read_stream = ml.prev; if (ret != 0) goto no_subst; } else { @@ -5298,8 +5301,8 @@ void gen_opl(int op) #if defined(TCC_TARGET_I386) b = psym(0x850f, 0); #elif defined(TCC_TARGET_ARM) - b = ind; - o(0x1A000000 | encbranch(ind, 0, 1)); + b = ind; + o(0x1A000000 | encbranch(ind, 0, 1)); #elif defined(TCC_TARGET_C67) error("not implemented"); #else @@ -5329,23 +5332,29 @@ void gen_opl(int op) independent opt */ void gen_opic(int op) { - int fc, c1, c2, n; + int c1, c2, t1, t2, n, c; SValue *v1, *v2; + long long l1, l2, l; + typedef unsigned long long U; v1 = vtop - 1; v2 = vtop; + t1 = v1->type.t & VT_BTYPE; + t2 = v2->type.t & VT_BTYPE; + l1 = (t1 == VT_LLONG) ? v1->c.ll : v1->c.i; + l2 = (t2 == VT_LLONG) ? v2->c.ll : v2->c.i; + /* currently, we cannot do computations with forward symbols */ c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; if (c1 && c2) { - fc = v2->c.i; switch(op) { - case '+': v1->c.i += fc; break; - case '-': v1->c.i -= fc; break; - case '&': v1->c.i &= fc; break; - case '^': v1->c.i ^= fc; break; - case '|': v1->c.i |= fc; break; - case '*': v1->c.i *= fc; break; + case '+': l1 += l2; break; + case '-': l1 -= l2; break; + case '&': l1 &= l2; break; + case '^': l1 ^= l2; break; + case '|': l1 |= l2; break; + case '*': l1 *= l2; break; case TOK_PDIV: case '/': @@ -5353,66 +5362,68 @@ void gen_opic(int op) case TOK_UDIV: case TOK_UMOD: /* if division by zero, generate explicit division */ - if (fc == 0) { + if (l2 == 0) { if (const_wanted) error("division by zero in constant"); goto general_case; } switch(op) { - default: v1->c.i /= fc; break; - case '%': v1->c.i %= fc; break; - case TOK_UDIV: v1->c.i = (unsigned)v1->c.i / fc; break; - case TOK_UMOD: v1->c.i = (unsigned)v1->c.i % fc; break; + default: l1 /= l2; break; + case '%': l1 %= l2; break; + case TOK_UDIV: l1 = (U)l1 / l2; break; + case TOK_UMOD: l1 = (U)l1 % l2; break; } break; - case TOK_SHL: v1->c.i <<= fc; break; - case TOK_SHR: v1->c.i = (unsigned)v1->c.i >> fc; break; - case TOK_SAR: v1->c.i >>= fc; break; + case TOK_SHL: l1 <<= l2; break; + case TOK_SHR: l1 = (U)l1 >> l2; break; + case TOK_SAR: l1 >>= l2; break; /* tests */ - case TOK_ULT: v1->c.i = (unsigned)v1->c.i < (unsigned)fc; break; - case TOK_UGE: v1->c.i = (unsigned)v1->c.i >= (unsigned)fc; break; - case TOK_EQ: v1->c.i = v1->c.i == fc; break; - case TOK_NE: v1->c.i = v1->c.i != fc; break; - case TOK_ULE: v1->c.i = (unsigned)v1->c.i <= (unsigned)fc; break; - case TOK_UGT: v1->c.i = (unsigned)v1->c.i > (unsigned)fc; break; - case TOK_LT: v1->c.i = v1->c.i < fc; break; - case TOK_GE: v1->c.i = v1->c.i >= fc; break; - case TOK_LE: v1->c.i = v1->c.i <= fc; break; - case TOK_GT: v1->c.i = v1->c.i > fc; break; + case TOK_ULT: l1 = (U)l1 < (U)l2; break; + case TOK_UGE: l1 = (U)l1 >= (U)l2; break; + case TOK_EQ: l1 = l1 == l2; break; + case TOK_NE: l1 = l1 != l2; break; + case TOK_ULE: l1 = (U)l1 <= (U)l2; break; + case TOK_UGT: l1 = (U)l1 > (U)l2; break; + case TOK_LT: l1 = l1 < l2; break; + case TOK_GE: l1 = l1 >= l2; break; + case TOK_LE: l1 = l1 <= l2; break; + case TOK_GT: l1 = l1 > l2; break; /* logical */ - case TOK_LAND: v1->c.i = v1->c.i && fc; break; - case TOK_LOR: v1->c.i = v1->c.i || fc; break; + case TOK_LAND: l1 = l1 && l2; break; + case TOK_LOR: l1 = l1 || l2; break; default: goto general_case; } + v1->c.ll = l1; vtop--; } else { /* if commutative ops, put c2 as constant */ if (c1 && (op == '+' || op == '&' || op == '^' || op == '|' || op == '*')) { vswap(); - swap(&c1, &c2); + c = c1, c1 = c2, c2 = c; + l = l1, l1 = l2, l2 = l; } - fc = vtop->c.i; + /* Filter out NOP operations like x*1, x-0, x&-1... */ if (c2 && (((op == '*' || op == '/' || op == TOK_UDIV || op == TOK_PDIV) && - fc == 1) || + l2 == 1) || ((op == '+' || op == '-' || op == '|' || op == '^' || op == TOK_SHL || op == TOK_SHR || op == TOK_SAR) && - fc == 0) || + l2 == 0) || (op == '&' && - fc == -1))) { + l2 == -1))) { /* nothing to do */ vtop--; } else if (c2 && (op == '*' || op == TOK_PDIV || op == TOK_UDIV)) { /* try to use shifts instead of muls or divs */ - if (fc > 0 && (fc & (fc - 1)) == 0) { + if (l2 > 0 && (l2 & (l2 - 1)) == 0) { n = -1; - while (fc) { - fc >>= 1; + while (l2) { + l2 >>= 1; n++; } - vtop->c.i = n; + vtop->c.ll = n; if (op == '*') op = TOK_SHL; else if (op == TOK_PDIV) @@ -5426,14 +5437,17 @@ void gen_opic(int op) (VT_CONST | VT_SYM)) { /* symbol + constant case */ if (op == '-') - fc = -fc; + l2 = -l2; vtop--; - vtop->c.i += fc; + vtop->c.ll += l2; } else { general_case: if (!nocode_wanted) { /* call low level op generator */ - gen_opi(op); + if (t1 == VT_LLONG || t2 == VT_LLONG) + gen_opl(op); + else + gen_opi(op); } else { vtop--; } @@ -5540,7 +5554,8 @@ static void check_comparison_pointer_types(SValue *p1, SValue *p2, int op) bt2 = type2->t & VT_BTYPE; /* accept comparison between pointer and integer with a warning */ if ((is_integer_btype(bt1) || is_integer_btype(bt2)) && op != '-') { - warning("comparison between pointer and integer"); + if (op != TOK_LOR && op != TOK_LAND ) + warning("comparison between pointer and integer"); return; } @@ -5586,7 +5601,7 @@ void gen_op(int op) if (bt1 == VT_PTR || bt2 == VT_PTR) { /* at least one operand is a pointer */ /* relationnal op: must be both pointers */ - if (op >= TOK_ULT && op <= TOK_GT) { + if (op >= TOK_ULT && op <= TOK_LOR) { check_comparison_pointer_types(vtop - 1, vtop, op); /* pointers are handled are unsigned */ t = VT_INT | VT_UNSIGNED; @@ -5696,8 +5711,6 @@ void gen_op(int op) gen_cast(&type1); if (is_float(t)) gen_opif(op); - else if ((t & VT_BTYPE) == VT_LLONG) - gen_opl(op); else gen_opic(op); if (op >= TOK_ULT && op <= TOK_GT) { @@ -5947,6 +5960,11 @@ static void gen_cast(CType *type) the lvalue already contains the real type size (see VT_LVAL_xxx constants) */ } + } else if ((dbt & VT_BTYPE) == VT_PTR && !(vtop->r & VT_LVAL)) { + /* if we are casting between pointer types, + we must update the VT_LVAL_xxx size */ + vtop->r = (vtop->r & ~VT_LVAL_TYPE) + | (lvalue_type(type->ref->type.t) & VT_LVAL_TYPE); } vtop->type = *type; } @@ -6502,12 +6520,15 @@ static void parse_attribute(AttributeDef *ad) if (tcc_state->warn_unsupported) warning("'%s' attribute ignored", get_tok_str(t, NULL)); /* skip parameters */ - /* XXX: skip parenthesis too */ if (tok == '(') { - next(); - while (tok != ')' && tok != -1) + int parenthesis = 0; + do { + if (tok == '(') + parenthesis++; + else if (tok == ')') + parenthesis--; next(); - next(); + } while (parenthesis && tok != -1); } break; } @@ -6668,7 +6689,8 @@ static void struct_decl(CType *type, int u) if (a == TOK_STRUCT) { c = (c + align - 1) & -align; offset = c; - c += size; + if (size > 0) + c += size; } else { offset = 0; if (size > c) @@ -6719,13 +6741,14 @@ static void struct_decl(CType *type, int u) */ static int parse_btype(CType *type, AttributeDef *ad) { - int t, u, type_found, typespec_found; + int t, u, type_found, typespec_found, typedef_found; Sym *s; CType type1; memset(ad, 0, sizeof(AttributeDef)); type_found = 0; typespec_found = 0; + typedef_found = 0; t = 0; while(1) { switch(tok) { @@ -6809,9 +6832,9 @@ static int parse_btype(CType *type, AttributeDef *ad) case TOK_SIGNED2: case TOK_SIGNED3: typespec_found = 1; - t |= VT_SIGNED; - next(); - break; + t |= VT_SIGNED; + next(); + break; case TOK_REGISTER: case TOK_AUTO: case TOK_RESTRICT1: @@ -6858,11 +6881,12 @@ static int parse_btype(CType *type, AttributeDef *ad) parse_expr_type(&type1); goto basic_type2; default: - if (typespec_found) + if (typespec_found || typedef_found) goto the_end; s = sym_find(tok); if (!s || !(s->type.t & VT_TYPEDEF)) goto the_end; + typedef_found = 1; t |= (s->type.t & ~VT_TYPEDEF); type->ref = s->type.ref; next(); @@ -8164,6 +8188,9 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, int v1, v2; if (!case_sym) expect("switch"); + /* since a case is like a label, we must skip it with a jmp */ + b = gjmp(0); + next_case: next(); v1 = expr_const(); v2 = v1; @@ -8173,24 +8200,26 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, if (v2 < v1) warning("empty case range"); } - /* since a case is like a label, we must skip it with a jmp */ - b = gjmp(0); gsym(*case_sym); vseti(case_reg, 0); vpushi(v1); if (v1 == v2) { gen_op(TOK_EQ); - *case_sym = gtst(1, 0); + *case_sym = 0; } else { gen_op(TOK_GE); *case_sym = gtst(1, 0); vseti(case_reg, 0); vpushi(v2); gen_op(TOK_LE); - *case_sym = gtst(1, *case_sym); } - gsym(b); skip(':'); + if (tok == TOK_CASE) { + b = gtst(0, b); + goto next_case; + } + *case_sym = gtst(1, *case_sym); + gsym(b); is_expr = 0; goto block_after_label; } else @@ -8873,11 +8902,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, } if (v) { - if (scope == VT_CONST) { - if (!sym) - goto do_def; - } else { - do_def: + if (scope != VT_CONST || !sym) { sym = sym_push(v, type, r | VT_SYM, 0); } /* update symbol definition */ diff --git a/tccasm.c b/tccasm.c index 4732405..8834b53 100644 --- a/tccasm.c +++ b/tccasm.c @@ -806,7 +806,7 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands, sv = *op->vt; if (op->reg >= 0) { sv.r = op->reg; - if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) + if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory) sv.r |= VT_LVAL; } subst_asm_operand(out_str, &sv, modifier); diff --git a/tccelf.c b/tccelf.c index 4dfbcfe..73f84cc 100644 --- a/tccelf.c +++ b/tccelf.c @@ -182,9 +182,11 @@ static int add_elf_sym(Section *s, unsigned long value, unsigned long size, { Elf32_Sym *esym; int sym_bind, sym_index, sym_type, esym_bind; + unsigned char sym_vis, esym_vis, new_vis; sym_bind = ELF32_ST_BIND(info); sym_type = ELF32_ST_TYPE(info); + sym_vis = ELF32_ST_VISIBILITY(other); if (sym_bind != STB_LOCAL) { /* we search global or weak symbols */ @@ -194,6 +196,19 @@ static int add_elf_sym(Section *s, unsigned long value, unsigned long size, esym = &((Elf32_Sym *)s->data)[sym_index]; if (esym->st_shndx != SHN_UNDEF) { esym_bind = ELF32_ST_BIND(esym->st_info); + /* propagate the most constraining visibility */ + /* STV_DEFAULT(0)st_other); + if (esym_vis == STV_DEFAULT) { + new_vis = sym_vis; + } else if (sym_vis == STV_DEFAULT) { + new_vis = esym_vis; + } else { + new_vis = (esym_vis < sym_vis) ? esym_vis : sym_vis; + } + esym->st_other = (esym->st_other & ~ELF32_ST_VISIBILITY(-1)) + | new_vis; + other = esym->st_other; /* in case we have to patch esym */ if (sh_num == SHN_UNDEF) { /* ignore adding of undefined symbol if the corresponding symbol is already defined */ @@ -202,6 +217,8 @@ static int add_elf_sym(Section *s, unsigned long value, unsigned long size, goto do_patch; } else if (sym_bind == STB_WEAK && esym_bind == STB_GLOBAL) { /* weak is ignored if already global */ + } else if (sym_vis == STV_HIDDEN || sym_vis == STV_INTERNAL) { + /* ignore hidden symbols after */ } else { #if 0 printf("new_bind=%d new_shndx=%d last_bind=%d old_shndx=%d\n", @@ -1949,7 +1966,7 @@ static int tcc_load_object_file(TCCState *s1, if (sym_index >= nb_syms) goto invalid_reloc; sym_index = old_to_new_syms[sym_index]; - /* ignore link_once in rel section. */ + /* ignore link_once in rel section. */ if (!sym_index && !sm->link_once) { invalid_reloc: error_noabort("Invalid relocation entry [%2d] '%s' @ %.8x", diff --git a/tcctok.h b/tcctok.h index c88dcc9..dab5942 100644 --- a/tcctok.h +++ b/tcctok.h @@ -123,7 +123,6 @@ /* builtin functions or variables */ DEF(TOK_memcpy, "memcpy") DEF(TOK_memset, "memset") - DEF(TOK_alloca, "alloca") DEF(TOK___divdi3, "__divdi3") DEF(TOK___moddi3, "__moddi3") DEF(TOK___udivdi3, "__udivdi3") @@ -188,6 +187,7 @@ DEF(TOK_memmove, "memmove") DEF(TOK_strlen, "strlen") DEF(TOK_strcpy, "strcpy") + DEF(TOK__alloca, "_alloca") #endif /* Tiny Assembler */ diff --git a/win32/include/_mingw.h b/win32/include/_mingw.h index 9623a72..90a8b11 100644 --- a/win32/include/_mingw.h +++ b/win32/include/_mingw.h @@ -18,6 +18,8 @@ #ifndef __MINGW_H #define __MINGW_H +#include + #define __int64 long long #define __int32 long #define __int16 short diff --git a/win32/include/stdarg.h b/win32/include/stdarg.h index d562d6d..a9b22b7 100644 --- a/win32/include/stdarg.h +++ b/win32/include/stdarg.h @@ -6,6 +6,7 @@ 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) /* fix a buggy dependency on GCC in libio.h */ diff --git a/win32/include/stddef.h b/win32/include/stddef.h index 89bd7b0..9965f89 100644 --- a/win32/include/stddef.h +++ b/win32/include/stddef.h @@ -12,10 +12,15 @@ typedef __PTRDIFF_TYPE__ ptrdiff_t; __GNUC__ ? */ #if !defined(__int8_t_defined) && !defined(__dietlibc__) #define __int8_t_defined -typedef char int8_t; -typedef short int int16_t; -typedef int int32_t; +typedef char int8_t; +typedef short int int16_t; +typedef int int32_t; typedef long long int int64_t; #endif +#ifdef __i386__ +void *_alloca(size_t); +#define alloca _alloca +#endif + #endif