diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e3c1b241..885b310a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,4 @@ -name: build and run tests +name: build and test on: push: @@ -17,7 +17,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: make & test tcc - run: ./configure && make && make test -k + run: ./configure --config-codesign=no && make && make test -k test-x86_64-win32: runs-on: windows-2019 diff --git a/Makefile b/Makefile index 98d65f67..e6404d5f 100644 --- a/Makefile +++ b/Makefile @@ -55,6 +55,8 @@ else # `make test' when libtcc.dylib is used (configure --disable-static), so # we bake a relative path into the binary. $libdir is used after install. LINK_LIBTCC += -Wl,-rpath,"@executable_path/$(TOP)" -Wl,-rpath,"$(libdir)" + # -current/compatibility_version must not contain letters. + MACOS_DYLIB_VERSION := $(firstword $(subst rc, ,$(VERSION))) DYLIBVER += -current_version $(MACOS_DYLIB_VERSION) DYLIBVER += -compatibility_version $(MACOS_DYLIB_VERSION) endif @@ -193,7 +195,6 @@ endif # include custom configuration (see make help) -include config-extra.mak -ifneq ($(X),) ifneq ($(T),$(NATIVE_TARGET)) # assume support files for cross-targets in "/usr/" by default TRIPLET-i386 ?= i686-linux-gnu @@ -201,11 +202,12 @@ TRIPLET-x86_64 ?= x86_64-linux-gnu TRIPLET-arm ?= arm-linux-gnueabi TRIPLET-arm64 ?= aarch64-linux-gnu TRIPLET-riscv64 ?= riscv64-linux-gnu +MARCH-i386 ?= i386-linux-gnu +MARCH-$T ?= $(TRIPLET-$T) TR = $(if $(TRIPLET-$T),$T,ignored) CRT-$(TR) ?= /usr/$(TRIPLET-$T)/lib -LIB-$(TR) ?= {B}:/usr/$(TRIPLET-$T)/lib -INC-$(TR) ?= {B}/include:/usr/$(TRIPLET-$T)/include -endif +LIB-$(TR) ?= {B}:/usr/$(TRIPLET-$T)/lib:/usr/lib/$(MARCH-$T) +INC-$(TR) ?= {B}/include:/usr/$(TRIPLET-$T)/include:/usr/include endif CORE_FILES = tcc.c tcctools.c libtcc.c tccpp.c tccgen.c tccdbg.c tccelf.c tccasm.c tccrun.c diff --git a/configure b/configure index 799973b1..062d0e3f 100755 --- a/configure +++ b/configure @@ -603,12 +603,6 @@ echo "VERSION = $version" >> config.mak echo "#define TCC_VERSION \"$version\"" >> $TMPH echo "@set VERSION $version" > config.texi -if test "$targetos" = "Darwin"; then - # On macOS, -current_version and -compatibility_version must not contain letters. - macos_dylib_version=`echo $version | sed 's/[^0-9.]//g'` - echo "MACOS_DYLIB_VERSION = $macos_dylib_version" >> config.mak -fi - if test "$source_path_used" = "yes" ; then case $source_path in /*) echo "TOPSRC=$source_path";; diff --git a/i386-asm.c b/i386-asm.c index 3cc8d18b..e134d804 100644 --- a/i386-asm.c +++ b/i386-asm.c @@ -515,7 +515,13 @@ static void gen_disp32(ExprValue *pe) sym->type.t = VT_FUNC; sym->type.ref = NULL; } +#ifdef TCC_TARGET_X86_64 + greloca(cur_text_section, sym, ind, R_X86_64_PLT32, pe->v - 4); + gen_le32(0); +#else gen_addrpc32(VT_SYM, sym, pe->v); +#endif + } } diff --git a/include/tccdefs.h b/include/tccdefs.h index 8c173f00..8ec64646 100644 --- a/include/tccdefs.h +++ b/include/tccdefs.h @@ -124,20 +124,16 @@ /* avoids usage of GCC/clang specific builtins in libc-headerfiles: */ #define __FINITE_MATH_ONLY__ 1 #define _FORTIFY_SOURCE 0 - #define __has_builtin(x) 0 + //#define __has_builtin(x) 0 #elif defined __ANDROID__ #define BIONIC_IOCTL_NO_SIGNEDNESS_OVERLOAD - #define __PRETTY_FUNCTION__ __FUNCTION__ - #define __has_builtin(x) 0 - #define __has_feature(x) 0 - #define _Nonnull - #define _Nullable #else /* Linux */ #endif + /* Some derived integer types needed to get stdint.h to compile correctly on some platforms */ #ifndef __NetBSD__ #define __UINTPTR_TYPE__ unsigned __PTRDIFF_TYPE__ @@ -152,6 +148,16 @@ #define __REDIRECT_NTHNL(name, proto, alias) name proto __asm__ (#alias) __THROWNL #endif + /* not implemented */ + #define __PRETTY_FUNCTION__ __FUNCTION__ + #define __has_builtin(x) 0 + #define __has_feature(x) 0 + /* C23 Keywords */ + #define _Nonnull + #define _Nullable + #define _Nullable_result + #define _Null_unspecified + /* skip __builtin... with -E */ #ifndef __TCC_PP__ diff --git a/libtcc.c b/libtcc.c index 71b8d36a..35002b6b 100644 --- a/libtcc.c +++ b/libtcc.c @@ -620,9 +620,9 @@ static void error1(int mode, const char *fmt, va_list ap) f->filename, f->line_num - !!(tok_flags & TOK_FLAG_BOL)); } else if (s1->current_filename) { cstr_printf(&cs, "%s: ", s1->current_filename); - } - if (0 == cs.size) + } else { cstr_printf(&cs, "tcc: "); + } cstr_printf(&cs, mode == ERROR_WARN ? "warning: " : "error: "); cstr_vprintf(&cs, fmt, ap); if (!s1 || !s1->error_func) { @@ -930,17 +930,8 @@ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type) return 0; } + /* add sections */ tccelf_new(s); - if (s->do_debug) { - /* add debug sections */ - tcc_debug_new(s); - } -#ifdef CONFIG_TCC_BCHECK - if (s->do_bounds_check) { - /* if bound checking, then add corresponding sections */ - tccelf_bounds_new(s); - } -#endif if (output_type == TCC_OUTPUT_OBJ) { /* always elf for objects */ @@ -951,66 +942,21 @@ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type) tcc_add_library_path(s, CONFIG_TCC_LIBPATHS); #ifdef TCC_TARGET_PE -# ifdef _WIN32 +# ifdef TCC_IS_NATIVE /* allow linking with system dll's directly */ tcc_add_systemdir(s); # endif - /* target PE has its own startup code in libtcc1.a */ - return 0; - #elif defined TCC_TARGET_MACHO # ifdef TCC_IS_NATIVE tcc_add_macos_sdkpath(s); # endif - /* Mach-O with LC_MAIN doesn't need any crt startup code. */ - return 0; - #else /* paths for crt objects */ tcc_split_path(s, &s->crt_paths, &s->nb_crt_paths, CONFIG_TCC_CRTPREFIX); - - /* add libc crt1/crti objects */ - if (output_type != TCC_OUTPUT_MEMORY && !s->nostdlib) { -#if TARGETOS_OpenBSD - if (output_type != TCC_OUTPUT_DLL) - tcc_add_crt(s, "crt0.o"); - if (output_type == TCC_OUTPUT_DLL) - tcc_add_crt(s, "crtbeginS.o"); - else - tcc_add_crt(s, "crtbegin.o"); -#elif TARGETOS_FreeBSD - if (output_type != TCC_OUTPUT_DLL) - tcc_add_crt(s, "crt1.o"); - tcc_add_crt(s, "crti.o"); - if (s->static_link) - tcc_add_crt(s, "crtbeginT.o"); - else if (output_type & TCC_OUTPUT_DYN) - tcc_add_crt(s, "crtbeginS.o"); - else - tcc_add_crt(s, "crtbegin.o"); -#elif TARGETOS_NetBSD - if (output_type != TCC_OUTPUT_DLL) - tcc_add_crt(s, "crt0.o"); - tcc_add_crt(s, "crti.o"); - if (s->static_link) - tcc_add_crt(s, "crtbeginT.o"); - else if (output_type & TCC_OUTPUT_DYN) - tcc_add_crt(s, "crtbeginS.o"); - else - tcc_add_crt(s, "crtbegin.o"); -#elif defined TARGETOS_ANDROID - if (output_type != TCC_OUTPUT_DLL) - tcc_add_crt(s, "crtbegin_dynamic.o"); - else - tcc_add_crt(s, "crtbegin_so.o"); -#else - if (output_type != TCC_OUTPUT_DLL) - tcc_add_crt(s, "crt1.o"); - tcc_add_crt(s, "crti.o"); + if (output_type != TCC_OUTPUT_MEMORY && !s->nostdlib) + tccelf_add_crtbegin(s); #endif - } return 0; -#endif } LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname) @@ -1096,7 +1042,7 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) if (fd < 0) { if (flags & AFF_PRINT_ERROR) tcc_error_noabort("file '%s' not found", filename); - return ret; + return FILE_NOT_FOUND; } s1->current_filename = filename; @@ -1226,18 +1172,21 @@ LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname) return 0; } -static int tcc_add_library_internal(TCCState *s, const char *fmt, +static int tcc_add_library_internal(TCCState *s1, const char *fmt, const char *filename, int flags, char **paths, int nb_paths) { char buf[1024]; - int i; + int i, ret; for(i = 0; i < nb_paths; i++) { snprintf(buf, sizeof(buf), fmt, paths[i], filename); - if (tcc_add_file_internal(s, buf, flags | AFF_TYPE_BIN) == 0) - return 0; + ret = tcc_add_file_internal(s1, buf, (flags & ~AFF_PRINT_ERROR) | AFF_TYPE_BIN); + if (ret != FILE_NOT_FOUND) + return ret; } - return -1; + if (flags & AFF_PRINT_ERROR) + tcc_error_noabort("file '%s' not found", filename); + return FILE_NOT_FOUND; } /* find and load a dll. Return non zero if not found */ @@ -1253,17 +1202,14 @@ ST_FUNC void tcc_add_support(TCCState *s1, const char *filename) char buf[100]; if (CONFIG_TCC_CROSSPREFIX[0]) filename = strcat(strcpy(buf, CONFIG_TCC_CROSSPREFIX), filename); - if (tcc_add_dll(s1, filename, 0) < 0) - tcc_error_noabort("%s not found", filename); + tcc_add_dll(s1, filename, AFF_PRINT_ERROR); } #if !defined TCC_TARGET_PE && !defined TCC_TARGET_MACHO ST_FUNC int tcc_add_crt(TCCState *s1, const char *filename) { - if (-1 == tcc_add_library_internal(s1, "%s/%s", - filename, 0, s1->crt_paths, s1->nb_crt_paths)) - return tcc_error_noabort("file '%s' not found", filename); - return 0; + return tcc_add_library_internal(s1, "%s/%s", + filename, AFF_PRINT_ERROR, s1->crt_paths, s1->nb_crt_paths); } #endif @@ -1285,18 +1231,19 @@ LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname) #endif int flags = s->filetype & AFF_WHOLE_ARCHIVE; while (*pp) { - if (0 == tcc_add_library_internal(s, *pp, - libraryname, flags, s->library_paths, s->nb_library_paths)) - return 0; + int ret = tcc_add_library_internal(s, *pp, + libraryname, flags, s->library_paths, s->nb_library_paths); + if (ret != FILE_NOT_FOUND) + return ret; ++pp; } - return -1; + return FILE_NOT_FOUND; } PUB_FUNC int tcc_add_library_err(TCCState *s1, const char *libname) { int ret = tcc_add_library(s1, libname); - if (ret < 0) + if (ret == FILE_NOT_FOUND) tcc_error_noabort("library '%s' not found", libname); return ret; } @@ -1790,6 +1737,37 @@ static int set_flag(TCCState *s, const FlagDef *flags, const char *name) return ret; } +static const char dumpmachine_str[] = +/* this is a best guess, please refine as necessary */ +#ifdef TCC_TARGET_I386 + "i386-pc" +#elif defined TCC_TARGET_X86_64 + "x86_64-pc" +#elif defined TCC_TARGET_C67 + "c67" +#elif defined TCC_TARGET_ARM + "arm" +#elif defined TCC_TARGET_ARM64 + "aarch64" +#elif defined TCC_TARGET_RISCV64 + "riscv64" +#endif + "-" +#ifdef TCC_TARGET_PE + "mingw32" +#elif defined(TCC_TARGET_MACHO) + "apple-darwin" +#elif TARGETOS_FreeBSD || TARGETOS_FreeBSD_kernel + "freebsd" +#elif TARGETOS_OpenBSD + "openbsd" +#elif TARGETOS_NetBSD + "netbsd" +#else + "linux-gnu" +#endif +; + static int args_parser_make_argv(const char *r, int *argc, char ***argv) { int ret = 0, q, c; @@ -2140,43 +2118,11 @@ dorun: s->gen_phony_deps = 1; break; case TCC_OPTION_dumpmachine: - /* this is a best guess, please refine as necessary */ - printf("%s", -#ifdef TCC_TARGET_I386 - "i386-pc" -#elif defined TCC_TARGET_X86_64 - "x86_64-pc" -#elif defined TCC_TARGET_C67 - "c67" -#elif defined TCC_TARGET_ARM - "arm" -#elif defined TCC_TARGET_ARM64 - "aarch64" -#elif defined TCC_TARGET_RISCV64 - "riscv64" -#endif - "-" -#ifdef TCC_TARGET_PE - "mingw32" -#elif defined(TCC_TARGET_MACHO) - "apple-darwin" -#elif TARGETOS_FreeBSD || TARGETOS_FreeBSD_kernel - "freebsd" -#elif TARGETOS_OpenBSD - "openbsd" -#elif TARGETOS_NetBSD - "netbsd" -#else - "linux-gnu" -#endif - "\n" - ); + printf("%s\n", dumpmachine_str); exit(0); - break; case TCC_OPTION_dumpversion: printf ("%s\n", TCC_VERSION); exit(0); - break; case TCC_OPTION_x: x = 0; if (*optarg == 'c') diff --git a/tcc.h b/tcc.h index e4173863..c36f2a69 100644 --- a/tcc.h +++ b/tcc.h @@ -1155,6 +1155,7 @@ struct filespec { #define TOK_PLCHLDR 0xa4 /* placeholder token as defined in C99 */ #define TOK_NOSUBST 0xa5 /* means following token has already been pp'd */ #define TOK_PPJOIN 0xa6 /* A '##' in the right position to mean pasting */ +#define TOK_SOTYPE 0xa7 /* alias of '(' for parsing sizeof (type) */ /* assignment operators */ #define TOK_A_ADD 0xb0 @@ -1291,6 +1292,9 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) #define AFF_BINTYPE_AR 3 #define AFF_BINTYPE_C67 4 +/* return value of tcc_add_file_internal(): 0, -1, or FILE_NOT_FOUND */ +#define FILE_NOT_FOUND -2 + #ifndef ELF_OBJ_ONLY ST_FUNC int tcc_add_crt(TCCState *s, const char *filename); #endif @@ -1532,9 +1536,6 @@ ST_FUNC void tccelf_new(TCCState *s); ST_FUNC void tccelf_delete(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); @@ -1575,6 +1576,8 @@ ST_FUNC int set_global_sym(TCCState *s1, const char *name, Section *sec, addr_t #ifndef ELF_OBJ_ONLY ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level); ST_FUNC int tcc_load_ldscript(TCCState *s1, int fd); +ST_FUNC void tccelf_add_crtbegin(TCCState *s1); +ST_FUNC void tccelf_add_crtend(TCCState *s1); #endif #ifndef TCC_TARGET_PE ST_FUNC void tcc_add_runtime(TCCState *s1); diff --git a/tccasm.c b/tccasm.c index fcae05eb..19f778dd 100644 --- a/tccasm.c +++ b/tccasm.c @@ -834,6 +834,10 @@ static void asm_parse_directive(TCCState *s1, int global) if (!strcmp(newtype, "function") || !strcmp(newtype, "STT_FUNC")) { sym->type.t = (sym->type.t & ~VT_BTYPE) | VT_FUNC; + if (sym->c) { + ElfSym *esym = elfsym(sym); + esym->st_info = ELFW(ST_INFO)(ELFW(ST_BIND)(esym->st_info), STT_FUNC); + } } else tcc_warning_c(warn_unsupported)("change type of '%s' from 0x%x to '%s' ignored", get_tok_str(sym->v, NULL), sym->type.t, newtype); diff --git a/tccelf.c b/tccelf.c index 8f1d9642..93a46ba9 100644 --- a/tccelf.c +++ b/tccelf.c @@ -83,17 +83,21 @@ ST_FUNC void tccelf_new(TCCState *s) ".dynstrtab", ".dynhashtab", SHF_PRIVATE); get_sym_attr(s, 0, 1); -} + + if (s->do_debug) { + /* add debug sections */ + tcc_debug_new(s); + } #ifdef CONFIG_TCC_BCHECK -ST_FUNC void tccelf_bounds_new(TCCState *s) -{ - TCCState *s1 = s; - /* create bounds sections (make ro after relocation done with GNU_RELRO) */ - bounds_section = new_section(s, ".bounds", SHT_PROGBITS, shf_RELRO); - lbounds_section = new_section(s, ".lbounds", SHT_PROGBITS, shf_RELRO); -} + if (s->do_bounds_check) { + /* if bound checking, then add corresponding sections */ + /* (make ro after relocation done with GNU_RELRO) */ + bounds_section = new_section(s, ".bounds", SHT_PROGBITS, shf_RELRO); + lbounds_section = new_section(s, ".lbounds", SHT_PROGBITS, shf_RELRO); + } #endif +} static void free_section(Section *s) { @@ -173,16 +177,22 @@ ST_FUNC void tccelf_end_file(TCCState *s1) for (i = 0; i < nb_syms; ++i) { ElfSym *sym = (ElfSym*)s->data + first_sym + i; - if (sym->st_shndx == SHN_UNDEF - && ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) - sym->st_info = ELFW(ST_INFO)(STB_GLOBAL, ELFW(ST_TYPE)(sym->st_info)); + + if (sym->st_shndx == SHN_UNDEF) { + int sym_bind = ELFW(ST_BIND)(sym->st_info); + int sym_type = ELFW(ST_TYPE)(sym->st_info); + if (sym_bind == STB_LOCAL) + sym_bind = STB_GLOBAL; #ifndef TCC_TARGET_PE - /* An ELF relocatable file should have the types of its undefined global symbol set - to STT_NOTYPE or it will confuse binutils bfd */ - if (s1->output_format == TCC_OUTPUT_FORMAT_ELF && s1->output_type == TCC_OUTPUT_OBJ) - if (sym->st_shndx == SHN_UNDEF && ELFW(ST_BIND)(sym->st_info) == STB_GLOBAL) - sym->st_info = ELFW(ST_INFO)(STB_GLOBAL, ELFW(ST_TYPE)(STT_NOTYPE)); + if (sym_bind == STB_GLOBAL && s1->output_type == TCC_OUTPUT_OBJ) { + /* undefined symbols with STT_FUNC are confusing gnu ld when + linking statically to STT_GNU_IFUNC */ + sym_type = STT_NOTYPE; + } #endif + sym->st_info = ELFW(ST_INFO)(sym_bind, sym_type); + } + tr[i] = set_elf_sym(s, sym->st_value, sym->st_size, sym->st_info, sym->st_other, sym->st_shndx, (char*)s->link->data + sym->st_name); } @@ -1666,6 +1676,67 @@ static void tcc_tcov_add_file(TCCState *s1, const char *filename) set_local_sym(s1, &"___tcov_data"[!s1->leading_underscore], tcov_section, 0); } +#if !defined TCC_TARGET_PE && !defined TCC_TARGET_MACHO +/* add libc crt1/crti objects */ +ST_FUNC void tccelf_add_crtbegin(TCCState *s1) +{ +#if TARGETOS_OpenBSD + if (s1->output_type != TCC_OUTPUT_DLL) + tcc_add_crt(s1, "crt0.o"); + if (s1->output_type == TCC_OUTPUT_DLL) + tcc_add_crt(s1, "crtbeginS.o"); + else + tcc_add_crt(s1, "crtbegin.o"); +#elif TARGETOS_FreeBSD || TARGETOS_NetBSD + if (s1->output_type != TCC_OUTPUT_DLL) +#if TARGETOS_FreeBSD + tcc_add_crt(s1, "crt1.o"); +#else + tcc_add_crt(s1, "crt0.o"); +#endif + tcc_add_crt(s1, "crti.o"); + if (s1->static_link) + tcc_add_crt(s1, "crtbeginT.o"); + else if (s1->output_type == TCC_OUTPUT_DLL) + tcc_add_crt(s1, "crtbeginS.o"); + else + tcc_add_crt(s1, "crtbegin.o"); +#elif TARGETOS_ANDROID + if (s1->output_type == TCC_OUTPUT_DLL) + tcc_add_crt(s1, "crtbegin_so.o"); + else + tcc_add_crt(s1, "crtbegin_dynamic.o"); +#else + if (s1->output_type != TCC_OUTPUT_DLL) + tcc_add_crt(s1, "crt1.o"); + tcc_add_crt(s1, "crti.o"); +#endif +} + +ST_FUNC void tccelf_add_crtend(TCCState *s1) +{ +#if TARGETOS_OpenBSD + if (s1->output_type == TCC_OUTPUT_DLL) + tcc_add_crt(s1, "crtendS.o"); + else + tcc_add_crt(s1, "crtend.o"); +#elif TARGETOS_FreeBSD || TARGETOS_NetBSD + if (s1->output_type == TCC_OUTPUT_DLL) + tcc_add_crt(s1, "crtendS.o"); + else + tcc_add_crt(s1, "crtend.o"); + tcc_add_crt(s1, "crtn.o"); +#elif TARGETOS_ANDROID + if (s1->output_type == TCC_OUTPUT_DLL) + tcc_add_crt(s1, "crtend_so.o"); + else + tcc_add_crt(s1, "crtend_android.o"); +#else + tcc_add_crt(s1, "crtn.o"); +#endif +} +#endif /* !defined TCC_TARGET_PE && !defined TCC_TARGET_MACHO */ + #ifndef TCC_TARGET_PE /* add tcc runtime libraries */ ST_FUNC void tcc_add_runtime(TCCState *s1) @@ -1708,7 +1779,7 @@ ST_FUNC void tcc_add_runtime(TCCState *s1) if (TCC_LIBGCC[0] == '/') tcc_add_file(s1, TCC_LIBGCC); else - tcc_add_dll(s1, TCC_LIBGCC, 0); + tcc_add_dll(s1, TCC_LIBGCC, AFF_PRINT_ERROR); } #endif #if defined TCC_TARGET_ARM && TARGETOS_FreeBSD @@ -1716,31 +1787,10 @@ ST_FUNC void tcc_add_runtime(TCCState *s1) #endif if (TCC_LIBTCC1[0]) tcc_add_support(s1, TCC_LIBTCC1); - - /* add crt end if not memory output */ - if (s1->output_type != TCC_OUTPUT_MEMORY) { -#if defined TCC_TARGET_MACHO - /* nothing to do */ -#elif TARGETOS_FreeBSD || TARGETOS_NetBSD - if (s1->output_type & TCC_OUTPUT_DYN) - tcc_add_crt(s1, "crtendS.o"); - else - tcc_add_crt(s1, "crtend.o"); - tcc_add_crt(s1, "crtn.o"); -#elif TARGETOS_OpenBSD - if (s1->output_type == TCC_OUTPUT_DLL) - tcc_add_crt(s1, "crtendS.o"); - else - tcc_add_crt(s1, "crtend.o"); -#elif TARGETOS_ANDROID - if (s1->output_type == TCC_OUTPUT_DLL) - tcc_add_crt(s1, "crtend_so.o"); - else - tcc_add_crt(s1, "crtend_android.o"); -#else - tcc_add_crt(s1, "crtn.o"); +#ifndef TCC_TARGET_MACHO + if (s1->output_type != TCC_OUTPUT_MEMORY) + tccelf_add_crtend(s1); #endif - } } } #endif /* ndef TCC_TARGET_PE */ @@ -3834,7 +3884,7 @@ static int ld_add_file(TCCState *s1, const char filename[]) return 0; filename = tcc_basename(filename); } - return tcc_add_dll(s1, filename, 0); + return tcc_add_dll(s1, filename, AFF_PRINT_ERROR); } static int ld_add_file_list(TCCState *s1, const char *cmd, int as_needed) diff --git a/tccgen.c b/tccgen.c index 688557e2..fb192500 100644 --- a/tccgen.c +++ b/tccgen.c @@ -43,8 +43,6 @@ static int nb_sym_pools; static Sym *all_cleanups, *pending_gotos; static int local_scope; -static int in_sizeof; -static int constant_p; ST_DATA char debug_modes; ST_DATA SValue *vtop; @@ -130,6 +128,10 @@ typedef struct { static void init_prec(void); #endif +static void block(int flags); +#define STMT_EXPR 1 +#define STMT_COMPOUND 2 + static void gen_cast(CType *type); static void gen_cast_s(int t); static inline CType *pointed_type(CType *type); @@ -139,7 +141,6 @@ static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td); static void parse_expr_type(CType *type); static void init_putv(init_params *p, CType *type, unsigned long c); static void decl_initializer(init_params *p, CType *type, unsigned long c, int flags); -static void block(int is_expr, int allow_decl); static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope); static int decl(int l); static void expr_eq(void); @@ -3466,11 +3467,7 @@ static void vpush_type_size(CType *type, int *a) int size = type_size(type, a); if (size < 0) tcc_error("unknown type size"); -#if PTR_SIZE == 8 - vpushll(size); -#else - vpushi(size); -#endif + vpushs(size); } } @@ -4433,11 +4430,11 @@ do_decl: c = 0; flexible = 0; while (tok != '}') { - if (tok == TOK_STATIC_ASSERT) { - do_Static_assert(); - continue; - } if (!parse_btype(&btype, &ad1, 0)) { + if (tok == TOK_STATIC_ASSERT) { + do_Static_assert(); + continue; + } skip(';'); continue; } @@ -4844,7 +4841,7 @@ static inline void convert_parameter_type(CType *pt) to indicate a const function parameter */ pt->t &= ~(VT_CONSTANT | VT_VOLATILE); /* array must be transformed to pointer according to ANSI C */ - pt->t &= ~VT_ARRAY; + pt->t &= ~(VT_ARRAY | VT_VLA); if ((pt->t & VT_BTYPE) == VT_FUNC) { mk_pointer(pt); } @@ -5069,7 +5066,8 @@ check: type->ref = s; if (vla_array_str) { - if (t1 & VT_VLA) + /* for function args, the top dimension is converted to pointer */ + if ((t1 & VT_VLA) && (td & TYPE_NEST)) s->vla_array_str = vla_array_str; else tok_str_free_str(vla_array_str); @@ -5435,7 +5433,7 @@ static void parse_atomic(int atok) ST_FUNC void unary(void) { - int n, t, align, size, r, sizeof_caller; + int n, t, align, size, r; CType type; Sym *s; AttributeDef ad; @@ -5444,8 +5442,6 @@ ST_FUNC void unary(void) if (debug_modes) tcc_debug_line(tcc_state), tcc_tcov_check_line (tcc_state, 1); - sizeof_caller = in_sizeof; - in_sizeof = 0; type.ref = NULL; /* XXX: GCC 2.95.3 does not generate a table although it should be better here */ @@ -5527,7 +5523,9 @@ ST_FUNC void unary(void) ad.section = rodata_section; decl_initializer_alloc(&type, &ad, VT_CONST, 2, 0, 0); break; + case TOK_SOTYPE: case '(': + t = tok; next(); /* cast ? */ if (parse_btype(&type, &ad, 0)) { @@ -5545,11 +5543,10 @@ ST_FUNC void unary(void) r |= VT_LVAL; memset(&ad, 0, sizeof(AttributeDef)); decl_initializer_alloc(&type, &ad, r, 1, 0, 0); + } else if (t == TOK_SOTYPE) { /* from sizeof/alignof (...) */ + vpush(&type); + return; } else { - if (sizeof_caller) { - vpush(&type); - return; - } unary(); gen_cast(&type); } @@ -5566,7 +5563,7 @@ 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. */ - block(1, 0); + 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). If it can't be entered then the state is that from before the @@ -5630,8 +5627,9 @@ ST_FUNC void unary(void) case TOK_ALIGNOF3: t = tok; next(); - in_sizeof++; - expr_type(&type, unary); /* Perform a in_sizeof = 0; */ + if (tok == '(') + tok = TOK_SOTYPE; + expr_type(&type, unary); if (t == TOK_SIZEOF) { vpush_type_size(&type, &align); gen_cast_s(VT_SIZE_T); @@ -5687,11 +5685,12 @@ ST_FUNC void unary(void) } break; case TOK_builtin_constant_p: - constant_p = 1; parse_builtin_params(1, "e"); - n = constant_p && - (vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST && - !((vtop->r & VT_SYM) && vtop->sym->a.addrtaken); + n = 1; + if ((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST + || ((vtop->r & VT_SYM) && vtop->sym->a.addrtaken) + ) + n = 0; vtop--; vpushi(n); break; @@ -5947,10 +5946,10 @@ special_math_val: default: tok_identifier: + if (tok < TOK_UIDENT) + tcc_error("expression expected before '%s'", get_tok_str(tok, &tokc)); t = tok; next(); - if (t < TOK_UIDENT) - expect("identifier"); s = sym_find(t); if (!s || IS_ASM_SYM(s)) { const char *name = get_tok_str(t, NULL); @@ -6546,13 +6545,19 @@ static void expr_eq(void) ST_FUNC void gexpr(void) { expr_eq(); - while (tok == ',') { - constant_p &= (vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST && - !((vtop->r & VT_SYM) && vtop->sym->a.addrtaken); - vpop(); - next(); - expr_eq(); - convert_parameter_type (&vtop->type); + if (tok == ',') { + do { + vpop(); + next(); + expr_eq(); + } while (tok == ','); + + /* convert array & function to pointer */ + convert_parameter_type(&vtop->type); + + /* make builtin_constant_p((1,2)) return 0 (like on gcc) */ + if ((vtop->r & VT_VALMASK) == VT_CONST && nocode_wanted && !CONST_WANTED) + gv(RC_TYPE(vtop->type.t)); } } @@ -6908,7 +6913,7 @@ static void lblock(int *bsym, int *csym) loop_scope = co; } co->bsym = bsym; - block(0, 0); + block(0); co->bsym = b; if (csym) { co->csym = c; @@ -6916,13 +6921,13 @@ static void lblock(int *bsym, int *csym) } } -static void block(int is_expr, int allow_decl) +static void block(int flags) { int a, b, c, d, e, t; struct scope o; Sym *s; - if (is_expr) { + if (flags & STMT_EXPR) { /* default return value is (void) */ vpushi(0); vtop->type.t = VT_VOID; @@ -6945,12 +6950,12 @@ again: gexpr(); skip(')'); a = gvtst(1, 0); - block(0, 0); + block(0); if (tok == TOK_ELSE) { d = gjmp(0); gsym(a); next(); - block(0, 0); + block(0); gsym(d); /* patch else jmp */ } else { gsym(a); @@ -6991,13 +6996,13 @@ again: while (tok != '}') { decl(VT_LOCAL); if (tok != '}') { - if (is_expr) + if (flags & STMT_EXPR) vpop(); - block(is_expr, 1); + block(flags | STMT_COMPOUND); } } - prev_scope(&o, is_expr); + prev_scope(&o, flags & STMT_EXPR); if (debug_modes) tcc_debug_stabn(tcc_state, N_RBRAC, ind - func_ind); if (local_scope) @@ -7168,7 +7173,6 @@ again: cr->sym = gind(); dynarray_add(&cur_switch->p, &cur_switch->n, cr); skip(':'); - is_expr = 0; goto block_after_label; } else if (t == TOK_DEFAULT) { @@ -7178,7 +7182,6 @@ again: tcc_error("too many 'default'"); cur_switch->def_sym = cur_switch->nocode_wanted ? 1 : gind(); skip(':'); - is_expr = 0; goto block_after_label; } else if (t == TOK_GOTO) { @@ -7253,20 +7256,21 @@ again: if (debug_modes) tcc_tcov_reset_ind(tcc_state); vla_restore(cur_scope->vla.loc); - /* c23 declaration after label */ - if (allow_decl && tok != ';') - decl(VT_LOCAL); - if (tok != '}') - goto again; - /* we accept this, but it is a mistake */ - tcc_warning_c(warn_all)("deprecated use of label at end of compound statement"); + if (tok != '}') { + if (0 == (flags & STMT_COMPOUND)) + goto again; + /* C23: insert implicit null-statement whithin compound statement */ + } else { + /* we accept this, but it is a mistake */ + tcc_warning_c(warn_all)("deprecated use of label at end of compound statement"); + } } else { /* expression case */ if (t != ';') { unget_tok(t); expr: - if (is_expr) { + if (flags & STMT_EXPR) { vpop(); gexpr(); } else { @@ -8271,8 +8275,8 @@ static void func_vla_arg(Sym *sym) Sym *arg; for (arg = sym->type.ref->next; arg; arg = arg->next) - if (arg->type.t & VT_VLA) - func_vla_arg_code(arg); + if ((arg->type.t & VT_BTYPE) == VT_PTR && (arg->type.ref->type.t & VT_VLA)) + func_vla_arg_code(arg->type.ref); } /* parse a function defined by symbol 'sym' and generate its code in @@ -8316,7 +8320,7 @@ static void gen_function(Sym *sym) rsym = 0; clear_temp_local_var_list(); func_vla_arg(sym); - block(0, 0); + block(0); gsym(rsym); nocode_wanted = 0; @@ -8424,11 +8428,6 @@ static int decl(int l) while (1) { - if (tok == TOK_STATIC_ASSERT) { - do_Static_assert(); - continue; - } - oldint = 0; if (!parse_btype(&btype, &adbase, l == VT_LOCAL)) { if (l == VT_JMP) @@ -8438,6 +8437,10 @@ static int decl(int l) next(); continue; } + if (tok == TOK_STATIC_ASSERT) { + do_Static_assert(); + continue; + } if (l != VT_CONST) break; if (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3) { @@ -8633,6 +8636,7 @@ static int decl(int l) has_init = (tok == '='); if (has_init && (type.t & VT_VLA)) tcc_error("variable length array cannot be initialized"); + if (((type.t & VT_EXTERN) && (!has_init || l != VT_CONST)) || (type.t & VT_BTYPE) == VT_FUNC /* as with GCC, uninitialized global arrays with no size @@ -8643,20 +8647,6 @@ static int decl(int l) /* external variable or function */ type.t |= VT_EXTERN; sym = external_sym(v, &type, r, &ad); - if (ad.alias_target) { - /* Aliases need to be emitted when their target - symbol is emitted, even if perhaps unreferenced. - We only support the case where the base is - already defined, otherwise we would need - deferring to emit the aliases until the end of - the compile unit. */ - Sym *alias_target = sym_find(ad.alias_target); - ElfSym *esym = elfsym(alias_target); - if (!esym) - tcc_error("unsupported forward __alias__ attribute"); - put_extern_sym2(sym, esym->st_shndx, - esym->st_value, esym->st_size, 1); - } } else { if (l == VT_CONST || (type.t & VT_STATIC)) r |= VT_CONST; @@ -8667,18 +8657,22 @@ static int decl(int l) else if (l == VT_CONST) /* uninitialized global variables may be overridden */ type.t |= VT_EXTERN; - - if (ad.alias_target && 1) { - Sym *alias_target = sym_find(ad.alias_target); - ElfSym *esym = elfsym(alias_target); - if (!esym) tcc_error("unsupported forward __alias__ attribute"); - sym = external_sym(v, &type, r, &ad); - put_extern_sym2(sym, esym->st_shndx, - esym->st_value, esym->st_size, 1); - } - decl_initializer_alloc(&type, &ad, r, has_init, v, l == VT_CONST); } + + if (ad.alias_target && l == VT_CONST) { + /* Aliases need to be emitted when their target symbol + is emitted, even if perhaps unreferenced. + We only support the case where the base is already + defined, otherwise we would need deferring to emit + the aliases until the end of the compile unit. */ + Sym *alias_target = sym_find(ad.alias_target); + ElfSym *esym = elfsym(alias_target); + if (!esym) + tcc_error("unsupported forward __alias__ attribute"); + put_extern_sym2(sym_find(v), esym->st_shndx, + esym->st_value, esym->st_size, 1); + } } if (tok != ',') { if (l == VT_JMP) diff --git a/tccpe.c b/tccpe.c index 11ec6df6..06d817df 100644 --- a/tccpe.c +++ b/tccpe.c @@ -35,7 +35,7 @@ # define REL_TYPE_DIRECT R_X86_64_64 # define R_XXX_THUNKFIX R_X86_64_PC32 # define R_XXX_RELATIVE R_X86_64_RELATIVE -# define R_XXX_FUNCCALL R_X86_64_PC32 +# define R_XXX_FUNCCALL R_X86_64_PLT32 # define IMAGE_FILE_MACHINE 0x8664 # define RSRC_RELTYPE 3 diff --git a/tccpp.c b/tccpp.c index dc68dc17..4c4f6e06 100644 --- a/tccpp.c +++ b/tccpp.c @@ -2960,8 +2960,7 @@ static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args) spc = 0; while (*st >= 0) { TOK_GET(&t, &st, &cval); - if (t != TOK_PLCHLDR - && t != TOK_NOSUBST + if (t != TOK_NOSUBST && 0 == check_space(t, &spc)) { const char *s = get_tok_str(t, &cval); while (*s) { @@ -3004,6 +3003,9 @@ static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args) str.len--; goto add_var; } + } else { + if (*st <= 0) /* expanded to empty string */ + tok_str_add(&str, TOK_PLCHLDR); } } else { add_var: @@ -3021,11 +3023,7 @@ static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args) } st = s->next->d; } - if (*st <= 0) { - /* expanded to empty string */ - if (str.len) - tok_str_add(&str, TOK_PLCHLDR); - } else for (;;) { + for (;;) { int t2; TOK_GET(&t2, &st, &cval); if (t2 <= 0) @@ -3135,7 +3133,8 @@ static inline int *macro_twosharps(const int *ptr0) } else { start_of_nosubsts = -1; } - tok_str_add2(¯o_str1, t, &cval); + if (t != TOK_PLCHLDR) + tok_str_add2(¯o_str1, t, &cval); } tok_str_add(¯o_str1, 0); //tok_print(" ###", macro_str1.str); @@ -3154,7 +3153,7 @@ static int next_argstream(Sym **nested_list, TokenString *ws_str) if (macro_ptr) { p = macro_ptr, t = *p; if (ws_str) { - while (is_space(t) || TOK_LINEFEED == t || TOK_PLCHLDR == t) + while (is_space(t) || TOK_LINEFEED == t) tok_str_add(ws_str, t), t = *++p; } if (t == 0) { @@ -3289,7 +3288,7 @@ static int macro_subst_tok( } do { next_nomacro(); /* eat '(' */ - } while (tok == TOK_PLCHLDR || is_space(tok)); + } while (is_space(tok)); /* argument macro */ args = NULL; @@ -3298,8 +3297,7 @@ static int macro_subst_tok( for(;;) { do { next_argstream(nested_list, NULL); - } while (tok == TOK_PLCHLDR || is_space(tok) || - TOK_LINEFEED == tok); + } while (is_space(tok) || TOK_LINEFEED == tok); empty_arg: /* handle '()' case */ if (!args && !sa && tok == ')') @@ -3488,7 +3486,7 @@ ST_FUNC void next(void) t = tok; if (macro_ptr) { if (!TOK_HAS_VALUE(t)) { - if (t == TOK_NOSUBST || t == TOK_PLCHLDR) { + if (t == TOK_NOSUBST) { /* discard preprocessor markers */ goto redo; } else if (t == 0) { diff --git a/tccrun.c b/tccrun.c index b102d829..3ad9a41c 100644 --- a/tccrun.c +++ b/tccrun.c @@ -263,8 +263,11 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv) /* These aren't C symbols, so don't need leading underscore handling. */ run_cdtors(s1, "__init_array_start", "__init_array_end", argc, argv, envp); - if (!(ret = setjmp(rc->jb))) + ret = setjmp(rc->jb); + if (0 == ret) ret = prog_main(argc, argv, envp); + else if (256 == ret) + ret = 0; run_cdtors(s1, "__fini_array_start", "__fini_array_end", 0, NULL, NULL); run_on_exit(ret); if (s1->dflag & 16 && ret) /* tcc -dt -run ... */ diff --git a/tests/pp/18.c b/tests/pp/18.c index 0961426a..de47790e 100644 --- a/tests/pp/18.c +++ b/tests/pp/18.c @@ -13,3 +13,18 @@ X181 M_EMPTYI_P_C1() X182 M_EMPTYI_P_C1(x) X183 usefnlike() + +#define ABC(x) ABC : x +#define A(a,b,c) a ## b ## c +#define B(a,b,c) A(a,b,c) +#define C(a,b,c) a b c +B( + C(A,C(,,),), + C(B(,,),B,B(,,)), + C(B(,,),B(,,),C) + )/* */(a b c) + +#define TEST(x) TEST : x +#define K(a,b) a ## b +#define L(a,b) K( TE a , b ST ) +L(,)(t e s t) diff --git a/tests/pp/18.expect b/tests/pp/18.expect index 447a9b2e..a8d1a4c2 100644 --- a/tests/pp/18.expect +++ b/tests/pp/18.expect @@ -1,3 +1,5 @@ X181 1 X182 0 X183 yeah +ABC : a b c +TEST : t e s t diff --git a/tests/pp/23.c b/tests/pp/23.c deleted file mode 100644 index 1df233f7..00000000 --- a/tests/pp/23.c +++ /dev/null @@ -1,117 +0,0 @@ -#define M_DEFERRED_COMMA , - -#define M_EAT(...) -#define M_APPLY(a, ...) a (__VA_ARGS__) -#define M_ID(...) __VA_ARGS__ - -#define M_C2I(a, ...) a ## __VA_ARGS__ -#define M_C(a, ...) M_C2I(a, __VA_ARGS__) -#define M_C3I(a, b, ...) a ## b ## __VA_ARGS__ -#define M_C3(a, b, ...) M_C3I(a ,b, __VA_ARGS__) -#define M_C4I(a, b, c, ...) a ## b ## c ## __VA_ARGS__ -#define M_C4(a, b, c, ...) M_C4I(a ,b, c, __VA_ARGS__) - -#define M_INVI_0 1 -#define M_INVI_1 0 -#define M_INV(x) M_C(M_INVI_, x) - -#define M_ANDI_00 0 -#define M_ANDI_01 0 -#define M_ANDI_10 0 -#define M_ANDI_11 1 -#define M_AND(x,y) M_C3(M_ANDI_, x, y) - -#define M_ANDI_000 0 -#define M_ANDI_001 0 -#define M_ANDI_010 0 -#define M_ANDI_011 0 -#define M_ANDI_100 0 -#define M_ANDI_101 0 -#define M_ANDI_110 0 -#define M_ANDI_111 1 -#define M_AND3(x,y,z) M_C4(M_ANDI_, x, y, z) - -#define M_ORI_00 0 -#define M_ORI_01 1 -#define M_ORI_10 1 -#define M_ORI_11 1 -#define M_OR(x,y) M_C3(M_ORI_, x, y) - -#define M_ORI_000 0 -#define M_ORI_001 1 -#define M_ORI_010 1 -#define M_ORI_011 1 -#define M_ORI_100 1 -#define M_ORI_101 1 -#define M_ORI_110 1 -#define M_ORI_111 1 -#define M_OR3(x,y,z) M_C4(M_ORI_, x, y, z) - -#define M_RETI_ARG2(_1, _2, ...) _2 -#define M_RET_ARG2(...) M_RETI_ARG2(__VA_ARGS__,) - -#define M_RETI_ARG4(_1, _2, _3, _4, ...) _4 -#define M_RET_ARG4(...) M_RETI_ARG4(__VA_ARGS__,) - -#define M_TOBOOLI_0 1, 0, -#define M_BOOL(x) M_RET_ARG2(M_C(M_TOBOOLI_, x), 1, useless) - -#define M_IFI_0(true_c, ...) __VA_ARGS__ -#define M_IFI_1(true_c, ...) true_c -#define M_IF(c) M_C(M_IFI_, M_BOOL(c)) - -#define M_NARGS(...) M_RET_ARG4(__VA_ARGS__, 3, 2, 1, useless) - -#define M_MAP(...) M_MAP_0(__VA_ARGS__) -#define M_MAP_0(f, ...) M_C(M_MAP_, M_NARGS(__VA_ARGS__))(f, __VA_ARGS__) -#define M_MAP_1(f, _1) f(_1) -#define M_MAP_2(f, _1, _2) f(_1) f(_2) -#define M_MAP_3(f, _1, _2, _3) f(_1) f(_2) f(_3) - -#define M_MAP2(...) M_MAP2I_0(__VA_ARGS__) -#define M_MAP2I_0(f, d, ...) M_C(M_MAP2I_, M_NARGS(__VA_ARGS__))(f, d, __VA_ARGS__) -#define M_MAP2I_1(f, d, _1) f(d, _1) -#define M_MAP2I_2(f, d, _1, _2) f(d, _1) f(d, _2) -#define M_MAP2I_3(f, d, _1, _2, _3) f(d, _1) f(d, _2) f(d, _3) - -#define M_CROSS_MAP(f, alist, blist) M_CROSSI_MAP1(f, alist, blist) -#define M_CROSSI_MAP1(f, alist, blist) M_C(M_CROSSI_MAP1_, M_NARGS alist)(f, blist, M_ID alist) -#define M_CROSSI_MAP1_1(...) M_CROSSI_MAP1_1b(__VA_ARGS__) -#define M_CROSSI_MAP1_1b(f, blist, a1) M_MAP2(f, a1, M_ID blist) -#define M_CROSSI_MAP1_2(...) M_CROSSI_MAP1_2b(__VA_ARGS__) -#define M_CROSSI_MAP1_2b(f, blist, a1, a2) M_MAP2(f, a1, M_ID blist) M_MAP2(f, a2, M_ID blist) -#define M_CROSSI_MAP1_3(...) M_CROSSI_MAP1_3b(__VA_ARGS__) -#define M_CROSSI_MAP1_3b(f, blist, a1, a2, a3) M_MAP2(f, a1, M_ID blist) M_MAP2(f, a2, M_ID blist) M_MAP2(f, a3, M_ID blist) - -#define M_COMMA_P(...) M_RETI_ARG4(__VA_ARGS__, 1, 1, 0, useless) - -#define M_PARENTHESISI_DETECT1(...) , -#define M_PARENTHESIS_P(...) \ - M_AND3(M_COMMA_P(M_PARENTHESISI_DETECT1 __VA_ARGS__), \ - M_INV(M_COMMA_P(__VA_ARGS__)), \ - M_EMPTY_P(M_EAT __VA_ARGS__)) - -#define M_EMPTYI_DETECT(...) , -#define M_EMPTYI_P_C1(...) M_COMMA_P(M_EMPTYI_DETECT __VA_ARGS__ () ) -#define M_EMPTYI_P_C2(...) M_COMMA_P(M_EMPTYI_DETECT __VA_ARGS__) -#define M_EMPTYI_P_C3(...) M_COMMA_P(__VA_ARGS__ () ) -#define M_EMPTY_P(...) M_AND(M_EMPTYI_P_C1(__VA_ARGS__), M_INV(M_OR3(M_EMPTYI_P_C2(__VA_ARGS__), M_COMMA_P(__VA_ARGS__),M_EMPTYI_P_C3(__VA_ARGS__)))) - -#define M_G3N_IS_PRESENT(num) \ - M_IF(M_PARENTHESIS_P(M_C(M_GENERIC_ORG_, num)() ))(M_DEFERRED_COMMA M_ID M_C(M_GENERIC_ORG_, num)(), ) - -#define M_G3N_IS_PRESENT2(el1, num) \ - M_IF(M_PARENTHESIS_P(M_C4(M_GENERIC_ORG_, el1, _COMP_, num)()))(M_DEFERRED_COMMA M_APPLY(M_C3, el1, _COMP_, M_ID M_C4(M_GENERIC_ORG_, el1, _COMP_, num)()), ) - -#define FLT1 (GENTYPE(float), TYPE(float) ) - -#define M_GENERIC_ORG_2() (USER) -#define M_GENERIC_ORG_USER_COMP_1() (CORE) -#define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_6() FLT1 - -// Shall expand to ", USER" -M_MAP(M_G3N_IS_PRESENT, 1, 2, 3) -// Shall expand to ", USER_COMP_CORE" -M_CROSS_MAP(M_G3N_IS_PRESENT2, (MLIB , USER), ( 1, 2, 3 ) ) -// Shall expand to ", USER_COMP_CORE" (composition of both) [fail] -M_CROSS_MAP(M_G3N_IS_PRESENT2, (MLIB M_MAP(M_G3N_IS_PRESENT, 1, 2, 3)), ( 1, 2, 3 ) ) diff --git a/tests/pp/23.expect b/tests/pp/23.expect deleted file mode 100644 index 303e410a..00000000 --- a/tests/pp/23.expect +++ /dev/null @@ -1,3 +0,0 @@ - , USER - , USER_COMP_CORE - , USER_COMP_CORE diff --git a/tests/tcctest.c b/tests/tcctest.c index b81cf5a7..f03a940a 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -140,11 +140,6 @@ static int onetwothree = 123; #define B3 4 #endif -#ifdef __TINYC__ -/* We try to handle this syntax. Make at least sure it doesn't segfault. */ -char invalid_function_def()[] {return 0;} -#endif - #define __INT64_C(c) c ## LL #define INT64_MIN (-__INT64_C(9223372036854775807)-1) @@ -341,18 +336,13 @@ static struct recursive_macro { int rm_field; } G; WRAP((printf("rm_field = %d %d\n", rm_field, WRAP(rm_field)))); } -#if !defined(__TINYC__) && (__GNUC__ >= 14 || __clang_major__ >= 15) -#define IMPLICIT_INT int -#else -#define IMPLICIT_INT -#endif - -int op(IMPLICIT_INT a, IMPLICIT_INT b) +#if __TINYC__ +int op(a, b) { return a / b; } -int ret(IMPLICIT_INT a) +int ret(a) { if (a == 2) return 1; @@ -360,6 +350,7 @@ int ret(IMPLICIT_INT a) return 2; return 0; } +#endif #if !defined(__TINYC__) && (__GNUC__ >= 8) /* Old GCCs don't regard "foo"[1] as constant, even in GNU dialect. */ @@ -716,7 +707,7 @@ int tab2[3][2]; int g; -void f1(IMPLICIT_INT g) +void f1(int g) { printf("g1=%d\n", g); } @@ -1511,25 +1502,35 @@ void compound_literal_test(void) #endif } + +#if __TINYC__ + /* K & R protos */ -IMPLICIT_INT kr_func1(IMPLICIT_INT a, IMPLICIT_INT b) +kr_func1(a, b) { return a + b; } -int kr_func2(IMPLICIT_INT a, IMPLICIT_INT b) +int kr_func2(a, b) { return a + b; } -IMPLICIT_INT kr_test() +kr_test() { printf("func1=%d\n", kr_func1(3, 4)); printf("func2=%d\n", kr_func2(3, 4)); return 0; } +/* We try to handle this syntax. Make at least sure it doesn't segfault. */ +char invalid_function_def()[] {return 0;} + +#else +# define kr_test() printf("func1=7\nfunc2=7\n") +#endif + void num(int n) { char *tab, *p; @@ -2058,7 +2059,7 @@ void c99_bool_test(void) printf("b = %d\n", b); b2 = 0; printf("sizeof(x ? _Bool : _Bool) = %d (should be sizeof int)\n", - sizeof((volatile IMPLICIT_INT)a ? b : b2)); + sizeof ((volatile int)a ? b : b2)); #endif } @@ -3062,7 +3063,7 @@ void c99_vla_test_3d(int s, int arr[2][3][s]) void c99_vla_test_3e(int s, int arr[][3][--s]) { - printf ("%d %d\n", s, arr[1][2][3]); + printf ("%d %d %d\n", sizeof arr, s, arr[1][2][3]); } void c99_vla_test_3(void) @@ -3145,6 +3146,10 @@ void sizeof_test(void) printf("sizeof(1 && 1) = %d\n", sizeof(1 && 1)); printf("sizeof(t || 1) = %d\n", sizeof(t || 1)); printf("sizeof(0 || 0) = %d\n", sizeof(0 || 0)); + + int arr[4], fn(); + printf("sizeof(0, arr) = %d\n", sizeof(0, arr)); + printf("sizeof(0, fn) = %d\n", sizeof(0, fn)); } void typeof_test(void) @@ -3915,30 +3920,29 @@ void builtin_test(void) COMPAT_TYPE(char *, unsigned char *); COMPAT_TYPE(char *, signed char *); COMPAT_TYPE(char *, char *); -/* space is needed because tcc preprocessor introduces a space between each token */ - COMPAT_TYPE(char * *, void *); + COMPAT_TYPE(char **, void *); #endif printf("res1 = %d\n", __builtin_constant_p(1)); printf("res2 = %d\n", __builtin_constant_p(1 + 2)); printf("res3 = %d\n", __builtin_constant_p(&constant_p_var)); printf("res4 = %d\n", __builtin_constant_p(constant_p_var)); printf("res5 = %d\n", __builtin_constant_p(100000 / constant_p_var)); -#ifdef __clang__ - /* clang doesn't regard this as constant expression */ - printf("res6 = 1\n"); + printf("res6 = %d\n", __builtin_constant_p(i && 1)); + printf("res7 = %d\n", __builtin_constant_p("hi")); + printf("res8 = %d\n", __builtin_constant_p(func())); +#ifndef __clang__ + printf("res10 = %d\n", __builtin_constant_p(i && 0)); + printf("res11 = %d\n", __builtin_constant_p(i * 0)); + printf("res12 = %d\n", __builtin_constant_p(i && 0 ? i : 34)); + printf("res13 = %d\n", __builtin_constant_p((1,7))); #else - printf("res6 = %d\n", __builtin_constant_p(i && 0)); + /* clang doesn't regard these as constant expression */ + printf("res10 = 1\n"); + printf("res11 = 1\n"); + printf("res12 = 1\n"); + printf("res13 = 0\n"); #endif - printf("res7 = %d\n", __builtin_constant_p(i && 1)); -#ifdef __clang__ - /* clang doesn't regard this as constant expression */ - printf("res8 = 1\n"); -#else - printf("res8 = %d\n", __builtin_constant_p(i && 0 ? i : 34)); -#endif - printf("res9 = %d\n", __builtin_constant_p("hi")); - printf("res10 = %d\n", __builtin_constant_p(func())); - printf("res11 = %d\n", __builtin_constant_p((i++, 7))); + s = 1; ll = 2; i = __builtin_choose_expr (1 != 0, ll, s); diff --git a/tests/tests2/06_case.c b/tests/tests2/06_case.c index 75b8d45d..c0191e2b 100644 --- a/tests/tests2/06_case.c +++ b/tests/tests2/06_case.c @@ -14,8 +14,7 @@ int main() break; case 2: - int a = 2; - printf("%d\n", a); + printf("%d\n", 2); break; default: diff --git a/tests/tests2/120+_alias.c b/tests/tests2/120+_alias.c index 8f29d8d9..56db69db 100644 --- a/tests/tests2/120+_alias.c +++ b/tests/tests2/120+_alias.c @@ -2,14 +2,17 @@ extern int printf (const char *, ...); extern void target(void); extern void alias_for_target(void); extern void asm_for_target(void); +extern int g_int, alias_int; void inunit2(void); void inunit2(void) { + printf("in unit2:\n"); target(); alias_for_target(); /* This symbol is not supposed to be available in this unit: asm_for_target(); */ + printf("g_int = %d\nalias_int = %d\n", g_int, alias_int); } diff --git a/tests/tests2/120_alias.c b/tests/tests2/120_alias.c index 5bead0f5..35bd44f8 100644 --- a/tests/tests2/120_alias.c +++ b/tests/tests2/120_alias.c @@ -1,17 +1,24 @@ /* Check semantics of various constructs to generate renamed symbols. */ + extern int printf (const char *, ...); void target(void); void target(void) { printf("in target function\n"); } - void alias_for_target(void) __attribute__((alias("target"))); + +int g_int = 34; +int alias_int __attribute__((alias("g_int"))); + #ifdef __leading_underscore -void asm_for_target(void) __asm__("_target"); +# define _ "_" #else -void asm_for_target(void) __asm__("target"); +# define _ #endif +void asm_for_target(void) __asm__(_"target"); +int asm_int __asm__(_"g_int"); + /* This is not supposed to compile, alias targets must be defined in the same unit. In TCC they even must be defined before the reference void alias_for_undef(void) __attribute__((alias("undefined"))); @@ -24,6 +31,7 @@ int main(void) target(); alias_for_target(); asm_for_target(); + printf("g_int = %d\nalias_int = %d\nasm_int = %d\n", g_int, alias_int, asm_int); inunit2(); return 0; } diff --git a/tests/tests2/120_alias.expect b/tests/tests2/120_alias.expect index 021e3f06..52099d0e 100644 --- a/tests/tests2/120_alias.expect +++ b/tests/tests2/120_alias.expect @@ -1,5 +1,11 @@ in target function in target function in target function +g_int = 34 +alias_int = 34 +asm_int = 34 +in unit2: in target function in target function +g_int = 34 +alias_int = 34 diff --git a/tests/tests2/60_errors_and_warnings.expect b/tests/tests2/60_errors_and_warnings.expect index 25a76245..18e8fc61 100644 --- a/tests/tests2/60_errors_and_warnings.expect +++ b/tests/tests2/60_errors_and_warnings.expect @@ -68,7 +68,7 @@ 60_errors_and_warnings.c:148: error: identifier expected [test_invalid_1] -60_errors_and_warnings.c:153: error: identifier expected +60_errors_and_warnings.c:153: error: expression expected before ',' [test_invalid_2] 60_errors_and_warnings.c:156: error: ';' expected (got "{") diff --git a/x86_64-gen.c b/x86_64-gen.c index e04df10a..4f46efc9 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -646,11 +646,7 @@ static void gcall_or_jmp(int is_jmp) if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST && ((vtop->r & VT_SYM) && (vtop->c.i-4) == (int)(vtop->c.i-4))) { /* constant symbolic case -> simple relocation */ -#ifdef TCC_TARGET_PE - greloca(cur_text_section, vtop->sym, ind + 1, R_X86_64_PC32, (int)(vtop->c.i-4)); -#else greloca(cur_text_section, vtop->sym, ind + 1, R_X86_64_PLT32, (int)(vtop->c.i-4)); -#endif oad(0xe8 + is_jmp, 0); /* call/jmp im */ } else { /* otherwise, indirect call */ @@ -668,11 +664,7 @@ static void gen_bounds_call(int v) { Sym *sym = external_helper_sym(v); oad(0xe8, 0); -#ifdef TCC_TARGET_PE - greloca(cur_text_section, sym, ind-4, R_X86_64_PC32, -4); -#else greloca(cur_text_section, sym, ind-4, R_X86_64_PLT32, -4); -#endif } #ifdef TCC_TARGET_PE @@ -1046,7 +1038,7 @@ void gfunc_epilog(void) Sym *sym = external_helper_sym(TOK___chkstk); oad(0xb8, v); /* mov stacksize, %eax */ oad(0xe8, 0); /* call __chkstk, (does the stackframe too) */ - greloca(cur_text_section, sym, ind-4, R_X86_64_PC32, -4); + greloca(cur_text_section, sym, ind-4, R_X86_64_PLT32, -4); o(0x90); /* fill for FUNC_PROLOG_SIZE = 11 bytes */ } else { o(0xe5894855); /* push %rbp, mov %rsp, %rbp */