From deb7a3fc73acb9bed5aa8a8b60b6ed17a5a19a5b Mon Sep 17 00:00:00 2001 From: grischka Date: Wed, 6 Aug 2025 10:44:50 +0200 Subject: [PATCH] tcc.c:main() free all & etc... tcc.c: - be nice to leak checkers tcctools.c: - remove unused TCCState params tccrun.c: - call bound_exit() after signals to let it free mem tccelf.c: - use section_add() instead of section_ptr_add() when more appropriate tccpp.c: - use size_t to align tal_header naturally - 'POINTER_SIZE' and 'PTR_SIZE' in the same source is confusing - "char file_name[TAL_DEBUG_FILE_LEN + 1];" looks silly. - next_nomacro(): skip UTF8 BOM at BOF tccgen.c: - get rid of STMT_EXPR clause on top of block - warn with useless type like 'int;' - move skip()'s in block() for better error line-info - BIT_SIZE bits are meaningful only with VT_BITFIELD (not with enums for example) workflow/test-win32: - build with MSVC using build-tcc.bat also alloca.S: - fix 'off by one' problem on win32 (must touch current page too because the 'push %edx' at the end could touch the next page) - must not align greater than 4 when used for struct args (i386-gen.c:gfunc_call()) libtcc.c: - accept -g1dwarf (dwarf output, only line info) --- .github/workflows/build.yml | 30 +++++++++-- i386-gen.c | 1 + lib/alloca-bt.S | 12 ++--- lib/alloca.S | 9 ++-- libtcc.c | 45 ++++++---------- tcc.c | 43 ++++++++------- tcc.h | 9 ++-- tccelf.c | 25 +++++---- tccgen.c | 96 ++++++++++++++++++---------------- tccpp.c | 32 +++++------- tccrun.c | 13 +++-- tcctools.c | 12 ++--- tests/Makefile | 2 +- tests/tests2/Makefile | 3 +- win32/build-tcc.bat | 7 ++- win32/include/stdlib.h | 8 ++- win32/include/winapi/winbase.h | 2 +- 17 files changed, 187 insertions(+), 162 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1c83e5c9..1110dc5e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,7 +31,7 @@ jobs: test-x86_64-win32: runs-on: windows-2025 - timeout-minutes: 4 + timeout-minutes: 6 steps: - uses: actions/checkout@v4 - name: make & test tcc (x86_64-win32) @@ -44,10 +44,22 @@ jobs: C:\msys64\usr\bin\bash -l -c "pacman -S --noconfirm mingw-w64-x86_64-gcc" echo ::endgroup:: C:\msys64\usr\bin\bash -l -c "./configure && make && make test -k" + - uses: ilammy/msvc-dev-cmd@v1 + with: + arch: amd64 + - name: build with MSVC (x86_64-win32) + shell: cmd + run: | + echo ::group:: run build-tcc.bat + cd win32 + call build-tcc.bat -t 64 -c cl + echo ::endgroup:: + .\tcc -I.. libtcc.dll -v ../tests/libtcc_test.c -o libtest.exe && .\libtest.exe + .\tcc -I.. libtcc.dll -run ../tests/libtcc_test.c test-i386-win32: runs-on: windows-2025 - timeout-minutes: 4 + timeout-minutes: 6 steps: - uses: actions/checkout@v4 - name: make & test tcc (i386-win32) @@ -59,7 +71,19 @@ jobs: set CHERE_INVOKING=yes C:\msys64\usr\bin\bash -l -c "pacman -S --noconfirm mingw-w64-i686-gcc" echo ::endgroup:: - C:\msys64\usr\bin\bash -l -c "./configure && make all && make test -k" + C:\msys64\usr\bin\bash -l -c "./configure && make && make test -k" + - uses: ilammy/msvc-dev-cmd@v1 + with: + arch: x86 + - name: build with MSVC (i386-win32) + shell: cmd + run: | + echo ::group:: run build-tcc.bat + cd win32 + call build-tcc.bat -t 32 -c cl + echo ::endgroup:: + .\tcc -I.. libtcc.dll -v ../tests/libtcc_test.c -o libtest.exe && .\libtest.exe + .\tcc -I.. libtcc.dll -run ../tests/libtcc_test.c test-armv7-linux: runs-on: ubuntu-22.04 diff --git a/i386-gen.c b/i386-gen.c index 342d045b..653bbf29 100644 --- a/i386-gen.c +++ b/i386-gen.c @@ -417,6 +417,7 @@ ST_FUNC void gfunc_call(int nb_args) /* allocate the necessary size on stack */ #ifdef TCC_TARGET_PE if (size >= 4096) { + save_reg(TREG_EDX); r = get_reg(RC_EAX); oad(0x68, size); // push size /* cannot call normal 'alloca' with bound checking */ diff --git a/lib/alloca-bt.S b/lib/alloca-bt.S index c704af4b..30c36e62 100644 --- a/lib/alloca-bt.S +++ b/lib/alloca-bt.S @@ -17,13 +17,13 @@ _(__bound_alloca): mov %eax, %ecx test %eax,%eax jz p6 - add $15+1,%eax - and $-16,%eax + add $3 + 1,%eax + and $-4,%eax #ifdef _WIN32 p4: cmp $4096,%eax - jbe p5 + jb p5 test %eax,-4096(%esp) sub $4096,%esp sub $4096,%eax @@ -33,7 +33,6 @@ p5: #endif sub %eax,%esp - and $-16,%esp mov %esp,%eax push %edx @@ -72,12 +71,11 @@ _(__bound_alloca_nr): #else pop %rdx mov %rdi,%rax + and %eax,%eax + jz p3 mov %rax,%rsi # size, a second parm to the __bound_new_region - add $15 + 1,%rax # add one extra to separate regions and $-16,%rax - jz p3 - sub %rax,%rsp mov %rsp,%rdi # pointer, a first parm to the __bound_new_region diff --git a/lib/alloca.S b/lib/alloca.S index 16f09f57..f77a0cca 100644 --- a/lib/alloca.S +++ b/lib/alloca.S @@ -15,14 +15,14 @@ _(alloca): _(__alloca): pop %edx pop %eax - add $15,%eax - and $-16,%eax + add $3,%eax + and $-4,%eax jz p3 #ifdef _WIN32 p1: cmp $4096,%eax - jbe p2 + jb p2 test %eax,-4096(%esp) sub $4096,%esp sub $4096,%eax @@ -30,7 +30,6 @@ p1: p2: #endif sub %eax,%esp - and $-16,%esp mov %esp,%eax p3: push %edx @@ -55,7 +54,7 @@ _(alloca): #ifdef _WIN32 p1: cmp $4096,%rax - jbe p2 + jb p2 test %rax,-4096(%rsp) sub $4096,%rsp sub $4096,%rax diff --git a/libtcc.c b/libtcc.c index ce3ac72a..b9bd9f57 100644 --- a/libtcc.c +++ b/libtcc.c @@ -804,7 +804,6 @@ static int tcc_compile(TCCState *s1, int filetype, const char *str, int fd) s1->error_set_jmp_enabled = 1; if (setjmp(s1->error_jmp_buf) == 0) { - s1->nb_errors = 0; if (fd == -1) { int len = strlen(str); @@ -1816,8 +1815,7 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv) const TCCOption *popt; const char *optarg, *r; const char *run = NULL; - int x; - int tool = 0, arg_start = 0, not_empty = 0, optind = 1; + int optind = 1, empty = 1, x; char **argv = *pargv; int argc = *pargc; @@ -1836,21 +1834,16 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv) continue; } optind++; - if (tool) { /* ignore all except -v and @listfile */ - s->verbose += !strcmp(r, "-v"); - continue; - } - if (r[0] != '-' || r[1] == '\0') { /* file or '-' (stdin) */ args_parser_add_file(s, r, s->filetype); - not_empty = 1; + empty = 0; dorun: if (run) { /* tcc -run */ - if (tcc_set_options(s, run)) + if (tcc_set_options(s, run) < 0) return -1; - arg_start = optind - 1; /* argv[0] will be */ - break; + x = 0; + goto extra_action; } continue; } @@ -1923,14 +1916,16 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv) case TCC_OPTION_g: s->do_debug = 2; s->dwarf = CONFIG_DWARF_VERSION; + g_redo: if (strstart("dwarf", &optarg)) { s->dwarf = (*optarg) ? (0 - atoi(optarg)) : DEFAULT_DWARF_VERSION; } else if (0 == strcmp("stabs", optarg)) { s->dwarf = 0; } else if (isnum(*optarg)) { - x = *optarg - '0'; + x = *optarg++ - '0'; /* -g0 = no info, -g1 = lines/functions only, -g2 = full info */ s->do_debug = x > 2 ? 2 : x == 0 && s->do_backtrace ? 1 : x; + goto g_redo; #ifdef TCC_TARGET_PE } else if (0 == strcmp(".pdb", optarg)) { s->dwarf = 5, s->do_debug |= 16; @@ -2030,7 +2025,6 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv) } break; case TCC_OPTION_W: - s->warn_none = 0; if (optarg[0] && set_flag(s, options_W, optarg) < 0) goto unsupported_option; break; @@ -2141,29 +2135,24 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv) case TCC_OPTION_ar: x = OPT_AR; extra_action: - arg_start = optind - 1; - if (not_empty) + if (NULL == argv[0]) /* from tcc_set_options() */ + return -1; + if (!empty && x) return tcc_error_noabort("cannot parse %s here", r); - tool = x; - break; + --optind; + *pargc = argc - optind; + *pargv = argv + optind; + return x; default: unsupported_option: tcc_warning_c(warn_unsupported)("unsupported option '%s'", r); break; } - not_empty = 1; + empty = 0; } - if (s->link_optind < s->link_argc) return tcc_error_noabort("argument to '-Wl,%s' is missing", s->link_argv[s->link_optind]); - if (NULL == argv[0]) /* from tcc_set_options() */ - return 0; - if (arg_start) { - *pargc = argc - arg_start; - *pargv = argv + arg_start; - return tool; - } - if (not_empty) + if (!empty) return 0; if (s->verbose == 2) return OPT_PRINT_DIRS; diff --git a/tcc.c b/tcc.c index 3221ed42..623aabd1 100644 --- a/tcc.c +++ b/tcc.c @@ -283,51 +283,51 @@ static unsigned getclock_ms(void) #endif } -int main(int argc0, char **argv0) +int main(int argc, char **argv) { TCCState *s, *s1; int ret, opt, n = 0, t = 0, done; unsigned start_time = 0, end_time = 0; const char *first_file; - int argc; char **argv; + int argc0 = argc; + char **argv0 = argv; FILE *ppfp = stdout; redo: argc = argc0, argv = argv0; s = s1 = tcc_new(); opt = tcc_parse_args(s, &argc, &argv); - if (opt < 0) - return 1; if (n == 0) { + ret = 0; if (opt == OPT_HELP) { fputs(help, stdout); - if (!s->verbose) - return 0; - ++opt; - } - if (opt == OPT_HELP2) { - fputs(help2, stdout); - return 0; - } - if (opt == OPT_M32 || opt == OPT_M64) - return tcc_tool_cross(s, argv, opt); - if (s->verbose) + if (s->verbose) + goto help2; + } else if (opt == OPT_HELP2) { + help2: fputs(help2, stdout); + } else if (opt == OPT_M32 || opt == OPT_M64) { + ret = tcc_tool_cross(argv, opt); + } else if (s->verbose) printf("%s", version); + if (opt == OPT_AR) - return tcc_tool_ar(s, argc, argv); + ret = tcc_tool_ar(argc, argv); #ifdef TCC_TARGET_PE if (opt == OPT_IMPDEF) - return tcc_tool_impdef(s, argc, argv); + ret = tcc_tool_impdef(argc, argv); #endif - if (opt == OPT_V) - return 0; if (opt == OPT_PRINT_DIRS) { /* initialize search dirs */ set_environment(s); tcc_set_output_type(s, TCC_OUTPUT_MEMORY); print_search_dirs(s); - return 0; + } + if (opt < 0) err: + ret = 1; + if (opt) { + tcc_delete(s); + return ret; } if (s->nb_files == 0) { @@ -345,7 +345,7 @@ redo: tcc_error_noabort("cannot specify output file with -c many files"); } if (s->nb_errors) - return 1; + goto err; if (s->do_bench) start_time = getclock_ms(); } @@ -419,7 +419,6 @@ redo: tcc_print_stats(s, end_time - start_time); tcc_delete(s); - if (!done) goto redo; if (ppfp && ppfp != stdout) diff --git a/tcc.h b/tcc.h index 19e16625..154e6775 100644 --- a/tcc.h +++ b/tcc.h @@ -95,13 +95,12 @@ extern long double strtold (const char *__nptr, char **__endptr); # define O_BINARY 0 #endif -#ifndef offsetof -#define offsetof(type, field) ((size_t) &((type *)0)->field) +#ifdef __clang__ // clang -fsanitize compains about: NULL+value +#define offsetof(type, field) __builtin_offsetof(type, field) #endif -#ifdef __clang__ // clang -fsanitize compains about: NULL+value -#undef offsetof -#define offsetof(type, field) __builtin_offsetof(type, field) +#ifndef offsetof +#define offsetof(type, field) ((size_t) &((type *)0)->field) #endif #ifndef countof diff --git a/tccelf.c b/tccelf.c index b9944944..0f7859c0 100644 --- a/tccelf.c +++ b/tccelf.c @@ -318,8 +318,7 @@ ST_FUNC size_t section_add(Section *sec, addr_t size, int align) ST_FUNC void *section_ptr_add(Section *sec, addr_t size) { size_t offset = section_add(sec, size, 1); - // clang -fsanitize compains about: NULL+value - return sec->data ? sec->data + offset : (void *)offset; + return sec->data + offset; } #ifndef ELF_OBJ_ONLY @@ -1598,7 +1597,7 @@ ST_FUNC void tcc_add_btstub(TCCState *s1) s = data_section; /* Align to PTR_SIZE */ - section_ptr_add(s, -s->data_offset & (PTR_SIZE - 1)); + section_add(s, 0, PTR_SIZE); o = s->data_offset; /* create a struct rt_context (see tccrun.c) */ if (s1->dwarf) { @@ -2837,7 +2836,6 @@ static int elf_output_file(TCCState *s1, const char *filename) int textrel, got_sym, dt_flags_1; file_type = s1->output_type; - s1->nb_errors = 0; ret = -1; interp = dynstr = dynamic = NULL; sec_order = NULL; @@ -3030,7 +3028,6 @@ static int elf_output_obj(TCCState *s1, const char *filename) { Section *s; int i, ret, file_offset; - s1->nb_errors = 0; /* Allocate strings for section names */ alloc_sec_names(s1, 1); file_offset = (sizeof (ElfW(Ehdr)) + 3) & -4; @@ -3049,6 +3046,7 @@ static int elf_output_obj(TCCState *s1, const char *filename) LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename) { + s->nb_errors = 0; if (s->test_coverage) tcc_tcov_add_file(s, filename); if (s->output_type == TCC_OUTPUT_OBJ) @@ -3254,21 +3252,19 @@ invalid: s->sh_entsize = sh->sh_entsize; sm_table[i].new_section = 1; found: + size = sh->sh_size; /* align start of section */ - s->data_offset += -s->data_offset & (sh->sh_addralign - 1); + offset = section_add(s, size, sh->sh_addralign); if (sh->sh_addralign > s->sh_addralign) s->sh_addralign = sh->sh_addralign; - sm_table[i].offset = s->data_offset; + sm_table[i].offset = offset; sm_table[i].s = s; /* concatenate sections */ - size = sh->sh_size; - if (sh->sh_type != SHT_NOBITS) { + if (sh->sh_type != SHT_NOBITS && size) { unsigned char *ptr; lseek(fd, file_offset + sh->sh_offset, SEEK_SET); - ptr = section_ptr_add(s, size); + ptr = s->data + offset; full_read(fd, ptr, size); - } else { - s->data_offset += size; } #if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64 /* align code sections to instruction lenght */ @@ -3310,6 +3306,9 @@ invalid: } } + if (!symtab) + goto done; + /* resolve symbols */ old_to_new_syms = tcc_mallocz(nb_syms * sizeof(int)); @@ -3405,7 +3404,7 @@ invalid: break; } } - + done: ret = 0; the_end: tcc_free(symtab); diff --git a/tccgen.c b/tccgen.c index 1f853b50..a1d03298 100644 --- a/tccgen.c +++ b/tccgen.c @@ -2963,13 +2963,13 @@ static int combine_types(CType *dest, SValue *op1, SValue *op2, int op) (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED)) type.t |= VT_UNSIGNED; } else { - int t1_bit = BIT_SIZE(t1) <= 31 ? VT_BITFIELD : 0; - int t2_bit = BIT_SIZE(t2) <= 31 ? VT_BITFIELD : 0; /* integer operations */ type.t = VT_INT | (VT_LONG & (t1 | t2)); /* convert to unsigned if it does not fit in an integer */ - if ((t1 & (VT_BTYPE | VT_UNSIGNED | t1_bit)) == (VT_INT | VT_UNSIGNED) || - (t2 & (VT_BTYPE | VT_UNSIGNED | t2_bit)) == (VT_INT | VT_UNSIGNED)) + if (((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED) + && (!(t1 & VT_BITFIELD) || BIT_SIZE(t1) == 32)) + || ((t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED) + && (!(t2 & VT_BITFIELD) || BIT_SIZE(t2) == 32))) type.t |= VT_UNSIGNED; } if (dest) @@ -5615,6 +5615,8 @@ ST_FUNC void unary(void) as statement expressions can't ever be entered from the outside, so any reactivation of code emission (from labels or loop heads) can be disabled again after the end of it. */ + /* default return value is (void) */ + vpushi(0), vtop->type.t = VT_VOID; block(STMT_EXPR); /* If the statement expr can be entered, then we retain the current nocode_wanted state (from e.g. a 'return 0;' in the stmt-expr). @@ -7036,12 +7038,6 @@ static void block(int flags) struct scope o; Sym *s; - if (flags & STMT_EXPR) { - /* default return value is (void) */ - vpushi(0); - vtop->type.t = VT_VOID; - } - again: t = tok; /* If the token carries a value, next() might destroy it. Only with @@ -7057,8 +7053,8 @@ again: new_scope_s(&o); skip('('); gexpr(); - skip(')'); a = gvtst(1, 0); + skip(')'); block(0); if (tok == TOK_ELSE) { d = gjmp(0); @@ -7076,8 +7072,8 @@ again: d = gind(); skip('('); gexpr(); - skip(')'); a = gvtst(1, 0); + skip(')'); b = 0; lblock(&a, &b); gjmp_addr(d); @@ -7105,8 +7101,6 @@ again: while (tok != '}') { decl(VT_LOCAL); if (tok != '}') { - if (flags & STMT_EXPR) - vpop(); block(flags | STMT_COMPOUND); } } @@ -7208,9 +7202,9 @@ again: skip(TOK_WHILE); skip('('); gexpr(); + c = gvtst(0, 0); skip(')'); skip(';'); - c = gvtst(0, 0); gsym_addr(c, d); gsym(a); prev_scope_s(&o); @@ -7228,9 +7222,9 @@ again: new_scope_s(&o); skip('('); gexpr(); - skip(')'); if (!is_integer_btype(vtop->type.t & VT_BTYPE)) tcc_error("switch value not an integer"); + skip(')'); sw->sv = *vtop--; /* save switch value */ a = 0; b = gjmp(0); /* jump to first case */ @@ -8294,6 +8288,9 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, if (type->t & VT_VLA) { int a; + if (has_init) + tcc_error("variable length array cannot be initialized"); + if (NODATA_WANTED) goto no_alloc; @@ -8513,6 +8510,27 @@ static void do_Static_assert(void) skip(';'); } +#ifdef TCC_TARGET_PE +static void pe_check_linkage(CType *type, AttributeDef *ad) +{ + if (!ad->a.dllimport && !ad->a.dllexport) + return; + if (type->t & VT_STATIC) + tcc_error("cannot have dll linkage with static"); + if (type->t & VT_TYPEDEF) { + const char *m = ad->a.dllimport ? "im" : "ex"; + tcc_warning("'dll%sport' attribute ignored for typedef", m); + ad->a.dllimport = 0; + ad->a.dllexport = 0; + } else if (ad->a.dllimport) { + if ((type->t & VT_BTYPE) == VT_FUNC) + ad->a.dllimport = 0; + else + type->t |= VT_EXTERN; + } +} +#endif + /* 'l' is VT_LOCAL or VT_CONST to define default storage type or VT_CMP if parsing old style parameter list or VT_JMP if parsing c99 for decl: for (int i = 0, ...) */ @@ -8559,17 +8577,17 @@ static int decl(int l) } if (tok == ';') { - if ((btype.t & VT_BTYPE) == VT_STRUCT) { - v = btype.ref->v; - if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) >= SYM_FIRST_ANOM) - tcc_warning("unnamed struct/union that defines no instances"); - next(); - continue; - } - if (IS_ENUM(btype.t)) { - next(); - continue; - } + if ((btype.t & VT_BTYPE) == VT_STRUCT + && (btype.ref->v & ~SYM_STRUCT) < SYM_FIRST_ANOM) + ; /* struct decl with named tag */ + else if (IS_ENUM(btype.t)) + ; /* enum decl */ + else + tcc_warning("useless type defines no instances"); + if (l == VT_JMP) + return 1; + next(); + continue; } while (1) { /* iterate thru each declaration */ @@ -8637,20 +8655,7 @@ static int decl(int l) } #ifdef TCC_TARGET_PE - if (ad.a.dllimport || ad.a.dllexport) { - if (type.t & VT_STATIC) - tcc_error("cannot have dll linkage with static"); - if (type.t & VT_TYPEDEF) { - tcc_warning("'%s' attribute ignored for typedef", - ad.a.dllimport ? (ad.a.dllimport = 0, "dllimport") : - (ad.a.dllexport = 0, "dllexport")); - } else if (ad.a.dllimport) { - if ((type.t & VT_BTYPE) == VT_FUNC) - ad.a.dllimport = 0; - else - type.t |= VT_EXTERN; - } - } + pe_check_linkage(&type, &ad); #endif if (tok == '{') { if (l != VT_CONST) @@ -8700,6 +8705,7 @@ static int decl(int l) } break; } else { + has_init = 0; if (l == VT_CMP) { /* find parameter in function parameter list */ for (sym = func_vt.ref->next; sym; sym = sym->next) @@ -8747,9 +8753,9 @@ static int decl(int l) /* not lvalue if array */ r |= VT_LVAL; } - has_init = (tok == '='); - if (has_init && (type.t & VT_VLA)) - tcc_error("variable length array cannot be initialized"); + + if (tok == '=') + has_init = 1; if (((type.t & VT_EXTERN) && (!has_init || l != VT_CONST)) || (type.t & VT_BTYPE) == VT_FUNC @@ -8789,7 +8795,7 @@ static int decl(int l) } if (tok != ',') { if (l == VT_JMP) - return 1; + return has_init ? v : 1; skip(';'); break; } diff --git a/tccpp.c b/tccpp.c index 5556757e..80c4ea3f 100644 --- a/tccpp.c +++ b/tccpp.c @@ -117,16 +117,6 @@ ST_FUNC void expect(const char *msg) #define USE_TAL -#ifdef _MSC_VER -# if defined _M_AMD64 || defined _M_ARM64 || defined _M_ARM64EC || defined _M_IA64 || defined _M_X64 -# define POINTER_SIZE 8 -# else -# define POINTER_SIZE 4 -# endif -#else -# define POINTER_SIZE sizeof(void *) -#endif - #ifndef USE_TAL #define tal_free(al, p) tcc_free(p) #define tal_realloc(al, p, size) tcc_realloc(p, size) @@ -143,7 +133,6 @@ ST_FUNC void expect(const char *msg) #define tal_free(al, p) tal_free_impl(al, p, __FILE__, __LINE__) #define tal_realloc(al, p, size) tal_realloc_impl(&al, p, size, __FILE__, __LINE__) #define TAL_DEBUG_PARAMS , const char *file, int line -#define TAL_DEBUG_FILE_LEN 40 #endif #define TOKSYM_TAL_SIZE (768 * 1024) /* allocator for tiny TokenSym in table_ident */ @@ -167,13 +156,16 @@ typedef struct TinyAlloc { } TinyAlloc; typedef struct tal_header_t { - ALIGNED(POINTER_SIZE) unsigned size; + size_t size; /* word align */ #ifdef TAL_DEBUG int line_num; /* negative line_num used for double free check */ - char file_name[TAL_DEBUG_FILE_LEN + 1]; + char file_name[40]; #endif } tal_header_t; +#define TAL_ALIGN(size) \ + (((size) + (sizeof (size_t) - 1)) & ~(sizeof (size_t) - 1)) + /* ------------------------------------------------------------------------- */ static TinyAlloc *tal_new(TinyAlloc **pal, unsigned limit, unsigned size) @@ -208,7 +200,7 @@ tail_call: tal_header_t *header = (tal_header_t *)p; if (header->line_num > 0) { fprintf(stderr, "%s:%d: chunk of %d bytes leaked\n", - header->file_name, header->line_num, header->size); + header->file_name, header->line_num, (int)header->size); } p += header->size + sizeof(tal_header_t); } @@ -256,7 +248,7 @@ static void *tal_realloc_impl(TinyAlloc **pal, void *p, unsigned size TAL_DEBUG_ tal_header_t *header; void *ret; int is_own; - unsigned adj_size = (size + POINTER_SIZE - 1) & -POINTER_SIZE; + unsigned adj_size = TAL_ALIGN(size); TinyAlloc *al = *pal; tail_call: @@ -266,9 +258,8 @@ tail_call: header = (tal_header_t *)al->p; header->size = adj_size; #ifdef TAL_DEBUG - { int ofs = strlen(file) - TAL_DEBUG_FILE_LEN; - strncpy(header->file_name, file + (ofs > 0 ? ofs : 0), TAL_DEBUG_FILE_LEN); - header->file_name[TAL_DEBUG_FILE_LEN] = 0; + { int ofs = strlen(file) + 1 - sizeof header->file_name; + strcpy(header->file_name, file + (ofs > 0 ? ofs : 0)); header->line_num = line; } #endif ret = al->p + sizeof(tal_header_t); @@ -2986,6 +2977,11 @@ maybe_newline: tok = c; p++; break; + case 0xEF: /* UTF8 BOM ? */ + if (p[1] == 0xBB && p[2] == 0xBF && p == file->buffer) { + p += 3; + goto redo_no_start; + } default: if (c >= 0x80 && c <= 0xFF) /* utf8 identifiers */ goto parse_ident_fast; diff --git a/tccrun.c b/tccrun.c index 37e6c9bf..b9072da2 100644 --- a/tccrun.c +++ b/tccrun.c @@ -312,6 +312,7 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff) addr_t mem, addr; if (NULL == ptr) { + s1->nb_errors = 0; #ifdef TCC_TARGET_PE pe_output_file(s1, NULL); #else @@ -495,10 +496,6 @@ static void bt_link(TCCState *s1) { #ifdef CONFIG_TCC_BACKTRACE rt_context *rc; -#ifdef CONFIG_TCC_BCHECK - void *p; -#endif - if (!s1->do_backtrace) return; rc = tcc_get_symbol(s1, "__rt_info"); @@ -511,6 +508,7 @@ static void bt_link(TCCState *s1) rc->prog_base &= 0xffffffff00000000ULL; #ifdef CONFIG_TCC_BCHECK if (s1->do_bounds_check) { + void *p; if ((p = tcc_get_symbol(s1, "__bound_init"))) ((void(*)(void*,int))p)(rc->bounds_start, 1); } @@ -599,6 +597,13 @@ static void rt_exit(rt_frame *f, int code) s = rt_find_state(f); rt_post_sem(); if (s && s->run_lj) { +#ifdef CONFIG_TCC_BCHECK + if (f->fp) { /* called from signal */ + void *p = tcc_get_symbol(s, "__bound_exit"); + if (p) + ((void (*)(void))p)(); + } +#endif if (code == 0) code = RT_EXIT_ZERO; ((void(*)(void*,int))s->run_lj)(s->run_jb, code); diff --git a/tcctools.c b/tcctools.c index 0f7acef7..46f15d1a 100644 --- a/tcctools.c +++ b/tcctools.c @@ -54,7 +54,7 @@ static int ar_usage(int ret) { return ret; } -ST_FUNC int tcc_tool_ar(TCCState *s1, int argc, char **argv) +ST_FUNC int tcc_tool_ar(int argc, char **argv) { static const ArHdr arhdr_init = { "/ ", @@ -360,7 +360,7 @@ the_end: #ifdef TCC_TARGET_PE -ST_FUNC int tcc_tool_impdef(TCCState *s1, int argc, char **argv) +ST_FUNC int tcc_tool_impdef(int argc, char **argv) { int ret, v, i; char infile[260]; @@ -487,9 +487,9 @@ the_end: #if !defined TCC_TARGET_I386 && !defined TCC_TARGET_X86_64 -ST_FUNC int tcc_tool_cross(TCCState *s1, char **argv, int option) +ST_FUNC int tcc_tool_cross(char **argv, int option) { - tcc_error_noabort("-m%d not implemented.", option); + fprintf(stderr, "tcc -m%d not implemented\n", option); return 1; } @@ -546,7 +546,7 @@ static int execvp_win32(const char *prog, char **argv) #define execvp execvp_win32 #endif /* _WIN32 */ -ST_FUNC int tcc_tool_cross(TCCState *s1, char **argv, int target) +ST_FUNC int tcc_tool_cross(char **argv, int target) { char program[4096]; char *a0 = argv[0]; @@ -565,7 +565,7 @@ ST_FUNC int tcc_tool_cross(TCCState *s1, char **argv, int target) if (strcmp(a0, program)) execvp(argv[0] = program, argv); - tcc_error_noabort("could not run '%s'", program); + fprintf(stderr, "tcc: could not run '%s'\n", program); return 1; } diff --git a/tests/Makefile b/tests/Makefile index 2cacf039..6e0f3bd6 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -79,7 +79,7 @@ endif all test : @echo ------------ version ------------ - @ASAN_OPTIONS=detect_leaks=0 $(TCC_LOCAL) -v + @$(TCC_LOCAL) -v @$(MAKE) --no-print-directory -s clean @$(MAKE) --no-print-directory -s -r _all diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile index fb3327ee..0726e99d 100644 --- a/tests/tests2/Makefile +++ b/tests/tests2/Makefile @@ -102,7 +102,6 @@ GEN-ALWAYS = 112_backtrace.test 113_btdll.test 126_bound_global.test: FILTER += \ -e 's;[0-9A-Fa-fx]\{5,\};........;g' \ -e 's;0x[0-9A-Fa-f]\{1,\};0x?;g' -112_backtrace.test: LEAK=ASAN_OPTIONS=detect_leaks=0 # this test creates two DLLs and an EXE 113_btdll.test: T1 = \ @@ -137,7 +136,7 @@ all test tests2.all: $(filter-out $(SKIP),$(TESTS)) @echo Test: $*... @$(call T1,$<) $(T3) -T1 = $(LEAK) $(TCC) $(FLAGS) $(T2) $(ARGS) +T1 = $(TCC) $(FLAGS) $(T2) $(ARGS) T2 = $(if $(NORUN),$1 -o $(basename $@).exe && ./$(basename $@).exe,-run $1) T3 = $(FILTER) >$*.output 2>&1 || true \ && diff -Nbu $(filter %.expect,$^) $*.output \ diff --git a/win32/build-tcc.bat b/win32/build-tcc.bat index 9c66327a..e5b576bc 100644 --- a/win32/build-tcc.bat +++ b/win32/build-tcc.bat @@ -132,6 +132,10 @@ if %TX%==32 echo>> ..\config.h #ifdef TCC_TARGET_I386 echo>> ..\config.h #define CONFIG_TCC_CROSSPREFIX "%PX%-" echo>> ..\config.h #endif +@rem echo>> ..\config.h #define CONFIG_TCC_PREDEFS 1 +@rem %CC% -DC2STR ..\conftest.c -o c2str.exe +@rem .\c2str.exe ../include/tccdefs.h ../tccdefs_.h + for %%f in (*tcc.exe *tcc.dll) do @del %%f @if _%TCC_C%_==__ goto compiler_2parts @@ -200,8 +204,9 @@ exit /B %ERRORLEVEL% .\tcc -B. -m%1 -c ../lib/alloca.S .\tcc -B. -m%1 -c ../lib/alloca-bt.S .\tcc -B. -m%1 -c ../lib/stdatomic.c +.\tcc -B. -m%1 -c ../lib/atomic.S .\tcc -B. -m%1 -c ../lib/builtin.c -.\tcc -B. -m%1 -ar lib/%2libtcc1.a libtcc1.o crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o chkstk.o alloca.o alloca-bt.o stdatomic.o builtin.o +.\tcc -B. -m%1 -ar lib/%2libtcc1.a libtcc1.o crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o chkstk.o alloca.o alloca-bt.o stdatomic.o atomic.o builtin.o .\tcc -B. -m%1 -c ../lib/bcheck.c -o lib/%2bcheck.o -bt -I.. .\tcc -B. -m%1 -c ../lib/bt-exe.c -o lib/%2bt-exe.o .\tcc -B. -m%1 -c ../lib/bt-log.c -o lib/%2bt-log.o diff --git a/win32/include/stdlib.h b/win32/include/stdlib.h index 3a656e70..21a0fbd9 100644 --- a/win32/include/stdlib.h +++ b/win32/include/stdlib.h @@ -376,10 +376,16 @@ extern "C" { _CRTIMP int __cdecl _set_error_mode(int _Mode); void __cdecl srand(unsigned int _Seed); double __cdecl strtod(const char *_Str,char **_EndPtr); - float __cdecl strtof(const char *nptr, char **endptr); #if !defined __NO_ISOCEXT /* in libmingwex.a */ +#if __TINYC__ + __CRT_INLINE float __cdecl strtof (const char *p, char ** e) { return strtod(p, e); } + __CRT_INLINE long double __cdecl strtold(const char *p, char ** e) { return strtod(p, e); } +#else float __cdecl strtof (const char * __restrict__, char ** __restrict__); long double __cdecl strtold(const char * __restrict__, char ** __restrict__); +#endif +#else + float __cdecl strtof(const char *nptr, char **endptr); #endif /* __NO_ISOCEXT */ _CRTIMP double __cdecl _strtod_l(const char *_Str,char **_EndPtr,_locale_t _Locale); long __cdecl strtol(const char *_Str,char **_EndPtr,int _Radix); diff --git a/win32/include/winapi/winbase.h b/win32/include/winapi/winbase.h index 5faa572a..da38579c 100644 --- a/win32/include/winapi/winbase.h +++ b/win32/include/winapi/winbase.h @@ -859,7 +859,7 @@ extern "C" { } #endif -#ifndef !defined (InterlockedAnd64) +#ifndef InterlockedAnd64 #define InterlockedAnd64 InterlockedAnd64_Inline __CRT_INLINE LONGLONG InterlockedAnd64_Inline (LONGLONG volatile *Destination,LONGLONG Value) {