From bb80cbe0d9e1b5de6c8355b01c210363d6e43362 Mon Sep 17 00:00:00 2001 From: grischka Date: Fri, 14 Oct 2022 20:10:38 +0200 Subject: [PATCH] tcctest.c: sizeof (long) != 8 Bad assumption make bad things happen: long d3; asm(..."1:\tdec %3\n\t" : ... "=&c" (d3) Which wants 'dec RDI' but did 'dec EDI' on _WIN64. Also: - tcctest.c: enable more asm tests for win64 - configure: show errors if any with 'gcc conftest.c' - tccgen.c: remove decl0(x, y, z) --- configure | 2 +- tccgen.c | 43 ++++++++++++++++++++----------------------- tests/tcctest.c | 48 +++++++++++++++++++++++++----------------------- 3 files changed, 46 insertions(+), 47 deletions(-) diff --git a/configure b/configure index 9924701c..dcaa8bf7 100755 --- a/configure +++ b/configure @@ -357,7 +357,7 @@ fi if test -z "$cross_prefix" ; then CONFTEST=./conftest$EXESUF - if ! $cc -o $CONFTEST $source_path/conftest.c 2>/dev/null ; then + if ! $cc -o $CONFTEST $source_path/conftest.c ; then echo "configure: error: '$cc' failed to compile conftest.c." else cc_name="$($CONFTEST compiler)" diff --git a/tccgen.c b/tccgen.c index aae4c45c..f8ecc4ee 100644 --- a/tccgen.c +++ b/tccgen.c @@ -130,8 +130,7 @@ 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); static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope); -static void decl(int l); -static int decl0(int l, int is_for_loop_init, Sym *); +static int decl(int l); static void expr_eq(void); static void vpush_type_size(CType *type, int *a); static int is_compatible_unqualified_types(CType *type1, CType *type2); @@ -6881,7 +6880,7 @@ again: skip('('); if (tok != ';') { /* c99 for-loop init decl? */ - if (!decl0(VT_LOCAL, 1, NULL)) { + if (!decl(VT_JMP)) { /* no, regular for-loop init expr */ gexpr(); vpop(); @@ -7795,7 +7794,7 @@ static void decl_initializer(init_params *p, CType *type, unsigned long c, int f is put in the value stack. If 'has_init' is 2, a special parsing is done to handle string constants. */ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, - int has_init, int v, int scope) + int has_init, int v, int global) { int size, align, addr; TokenString *init_str = NULL; @@ -7932,7 +7931,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, } } else { sym = NULL; - if (v && scope == VT_CONST) { + if (v && global) { /* see if the symbol was already defined */ sym = sym_find(v); if (sym) { @@ -8198,9 +8197,10 @@ static void free_inline_functions(TCCState *s) dynarray_reset(&s->inline_fns, &s->nb_inline_fns); } -/* 'l' is VT_LOCAL or VT_CONST to define default storage type, or VT_CMP - if parsing old style parameter decl list (and FUNC_SYM is set then) */ -static int decl0(int l, int is_for_loop_init, Sym *func_sym) +/* '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, ...) */ +static int decl(int l) { int v, has_init, r, oldint; CType type, btype; @@ -8236,7 +8236,7 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym) oldint = 0; if (!parse_btype(&btype, &adbase, l == VT_LOCAL)) { - if (is_for_loop_init) + if (l == VT_JMP) return 0; /* skip redundant ';' if not in old parameter decl scope */ if (tok == ';' && l != VT_CMP) { @@ -8288,13 +8288,15 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym) } #endif if ((type.t & VT_BTYPE) == VT_FUNC) { - if ((type.t & VT_STATIC) && (l == VT_LOCAL)) + if ((type.t & VT_STATIC) && (l != VT_CONST)) tcc_error("function without file scope cannot be static"); /* if old style function prototype, we accept a declaration list */ sym = type.ref; - if (sym->f.func_type == FUNC_OLD && l == VT_CONST) - decl0(VT_CMP, 0, sym); + if (sym->f.func_type == FUNC_OLD && l == VT_CONST) { + func_vt = type; + decl(VT_CMP); + } #if defined TCC_TARGET_MACHO || defined TARGETOS_ANDROID if (sym->f.func_alwinl && ((type.t & (VT_EXTERN | VT_INLINE)) @@ -8388,12 +8390,12 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym) } else { if (l == VT_CMP) { /* find parameter in function parameter list */ - for (sym = func_sym->next; sym; sym = sym->next) + for (sym = func_vt.ref->next; sym; sym = sym->next) if ((sym->v & ~SYM_FIELD) == v) goto found; tcc_error("declaration for parameter '%s' but no such parameter", get_tok_str(v, NULL)); -found: + found: if (type.t & VT_STORAGE) /* 'register' is okay */ tcc_error("storage class specified for '%s'", get_tok_str(v, NULL)); @@ -8460,20 +8462,20 @@ found: esym->st_value, esym->st_size, 1); } } else { - if (type.t & VT_STATIC) + if (l == VT_CONST || (type.t & VT_STATIC)) r |= VT_CONST; else - r |= l; + r |= VT_LOCAL; if (has_init) next(); else if (l == VT_CONST) /* uninitialized global variables may be overridden */ type.t |= VT_EXTERN; - decl_initializer_alloc(&type, &ad, r, has_init, v, l); + decl_initializer_alloc(&type, &ad, r, has_init, v, l == VT_CONST); } } if (tok != ',') { - if (is_for_loop_init) + if (l == VT_JMP) return 1; skip(';'); break; @@ -8485,11 +8487,6 @@ found: return 0; } -static void decl(int l) -{ - decl0(l, 0, NULL); -} - /* ------------------------------------------------------------------------- */ #undef gjmp_addr #undef gjmp diff --git a/tests/tcctest.c b/tests/tcctest.c index f5bd9aab..f6e6574f 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -3251,10 +3251,12 @@ void local_label_test(void) /* inline assembler test */ #if defined(__i386__) || defined(__x86_64__) +typedef __SIZE_TYPE__ word; + /* from linux kernel */ static char * strncat1(char * dest,const char * src,size_t count) { -long d0, d1, d2, d3; +word d0, d1, d2, d3; __asm__ __volatile__( "repne\n\t" "scasb\n\t" @@ -3276,7 +3278,7 @@ return dest; static char * strncat2(char * dest,const char * src,size_t count) { -long d0, d1, d2, d3; +word d0, d1, d2, d3; __asm__ __volatile__( "repne scasb\n\t" /* one-line repne prefix + string op */ "dec %1\n\t" @@ -3297,7 +3299,7 @@ return dest; static inline void * memcpy1(void * to, const void * from, size_t n) { -size_t d0, d1, d2; +word d0, d1, d2; __asm__ __volatile__( "rep ; movsl\n\t" "testb $2,%b4\n\t" @@ -3308,14 +3310,14 @@ __asm__ __volatile__( "movsb\n" "2:" : "=&c" (d0), "=&D" (d1), "=&S" (d2) - :"0" (n/4), "q" (n),"1" ((size_t) to),"2" ((size_t) from) + :"0" (n/4), "q" (n),"1" ((word) to),"2" ((word) from) : "memory"); return (to); } static inline void * memcpy2(void * to, const void * from, size_t n) { -size_t d0, d1, d2; +word d0, d1, d2; __asm__ __volatile__( "rep movsl\n\t" /* one-line rep prefix + string op */ "testb $2,%b4\n\t" @@ -3326,7 +3328,7 @@ __asm__ __volatile__( "movsb\n" "2:" : "=&c" (d0), "=&D" (d1), "=&S" (d2) - :"0" (n/4), "q" (n),"1" ((size_t) to),"2" ((size_t) from) + :"0" (n/4), "q" (n),"1" ((word) to),"2" ((word) from) : "memory"); return (to); } @@ -3395,12 +3397,12 @@ struct struct123 { int b; }; struct struct1231 { - unsigned long addr; + word addr; }; -unsigned long mconstraint_test(struct struct1231 *r) +word mconstraint_test(struct struct1231 *r) { - unsigned long ret; + word ret; unsigned int a[2]; a[0] = 0; __asm__ volatile ("lea %2,%0; movl 4(%0),%k0; addl %2,%k0; movl $51,%2; movl $52,4%2; movl $63,%1" @@ -3422,11 +3424,11 @@ int fls64(unsigned long long x) void other_constraints_test(void) { - unsigned long ret; + word ret; int var; -#if !defined(_WIN64) && CC_NAME != CC_clang +#if CC_NAME != CC_clang __asm__ volatile ("mov %P1,%0" : "=r" (ret) : "p" (&var)); - printf ("oc1: %d\n", ret == (unsigned long)&var); + printf ("oc1: %d\n", ret == (word)&var); #endif } @@ -3510,6 +3512,7 @@ void asm_local_label_diff (void) printf ("asm_local_label_diff: %d %d\n", alld_stuff[0], alld_stuff[1]); } #endif +#endif /* This checks that static local variables are available from assembler. */ void asm_local_statics (void) @@ -3518,7 +3521,6 @@ void asm_local_statics (void) asm("incl %0" : "+m" (localint)); printf ("asm_local_statics: %d\n", localint); } -#endif static unsigned int set; @@ -3533,7 +3535,7 @@ void fancy_copy2 (unsigned *in, unsigned *out) asm volatile ("mov %0,(%1)" : : "r" (*in), "r" (out) : "memory"); } -#if defined __x86_64__ && !defined _WIN64 +#if defined __x86_64__ void clobber_r12(void) { asm volatile("mov $1, %%r12" ::: "r12"); @@ -3542,9 +3544,9 @@ void clobber_r12(void) void test_high_clobbers_really(void) { -#if defined __x86_64__ && !defined _WIN64 - register long val asm("r12"); - long val2; +#if defined __x86_64__ + register word val asm("r12"); + word val2; /* This tests if asm clobbers correctly save/restore callee saved registers if they are clobbered and if it's the high 8 x86-64 registers. This is fragile for GCC as the constraints do not @@ -3558,8 +3560,8 @@ void test_high_clobbers_really(void) void test_high_clobbers(void) { -#if defined __x86_64__ && !defined _WIN64 - long x1, x2; +#if defined __x86_64__ + word x1, x2; asm volatile("mov %%r12,%0" :: "m" (x1)); /* save r12 */ test_high_clobbers_really(); asm volatile("mov %%r12,%0" :: "m" (x2)); /* new r12 */ @@ -3625,7 +3627,7 @@ void trace_console(long len, long len2) void test_asm_dead_code(void) { - long rdi; + word rdi; /* Try to make sure that xdi contains a zero, and hence will lead to a segfault if the next asm is evaluated without arguments being set up. */ @@ -3727,12 +3729,12 @@ void asm_test(void) char buf[128]; unsigned int val, val2; struct struct123 s1; - struct struct1231 s2 = { (unsigned long)&s1 }; + struct struct1231 s2 = { (word)&s1 }; /* Hide the outer base_func, but check later that the inline asm block gets the outer one. */ int base_func = 42; void override_func3 (void); - unsigned long asmret; + word asmret; #ifdef BOOL_ISOC99 _Bool somebool; #endif @@ -3783,8 +3785,8 @@ void asm_test(void) printf("asmstr: %s\n", get_asm_string()); asm_local_label_diff(); #endif - asm_local_statics(); #endif + asm_local_statics(); #ifndef __clang__ /* clang can't deal with the type change */ /* Check that we can also load structs of appropriate layout