From 9712aff9c00ecf24adc89f42aa674ede4e35137d Mon Sep 17 00:00:00 2001 From: herman ten brugge Date: Sun, 5 Jul 2020 14:01:50 +0200 Subject: [PATCH] Fix gcc testsuite problems arm-gen.c: - is_hgen_float_aggr/gfunc_sret: Fix for zero sized structs arm64-gen.c: - arm64_ldrs: Fix for zero sized structs - arm64_sym: Use R_AARCH64_ABS64 instead of R_AARCH64_MOVW_UABS_G* This has same speed. See 117_gcc_test.c(tst_adr) - load: Fix for zero sized structs and add VT_CONST | VT_LVAL support - store: add VT_CONST | VT_LVAL support - arm64_gen_bl_or_b: Allow branch. See 117_gcc_test.c(tst_branch) - gen_bounds_prolog: Use R_AARCH64_ABS64 for bound checking - gen_bounds_epilog: Use R_AARCH64_ABS64 for bound checking - gfunc_call: Allow large stack - arm64_gen_opic: Do not crash on large shift riscv64-gen.c: - load: Move type_size call. (move_reg set sv.type.ref NULL for VT_STRUCT) - gfunc_call: Allow large stack - gen_opil: Fix word mode calls x86_64-gen.c: - load: Fix for zero sized structs libtcc.c: - Add some defines for gcc testsuite (only most common) tccgen.c: - parse_builtin_params: Add types for builtins - unary: Add builtins: __builtin_abort __builtin_memcpy __builtin_memcmp __builtin_memmove __builtin_memset __builtin_strlen __builtin_strcpy __builtin_strncpy __builtin_strcmp __builtin_strncmp __builtin_strcat __builtin_strchr __builtin_strdup __builtin_malloc __builtin_realloc __builtin_calloc __builtin_free __builtin_alloca - decl_initializer: Fix crash. See 60_errors_and_warnings(test_var_array) tccmacho.c: - Remove 'ret = 0' tcctok.h: - Add builtin/bound checking tokens tests/gcctestsuite.sh: - Add more counters and run execute tests tests/bug.c - Some remaining bugs in tcc (not complete) tests/tests2/60_errors_and_warnings: - Add test_var_array test tests/tests2/117_gcc_test: - New test Results of gcctestsuite.sh for all targets: linux: x86_64: 3036 test(s) ok. 328 test(s) failed. 24 test(s) exe failed. i386: 3037 test(s) ok. 327 test(s) failed. 24 test(s) exe failed. arm: 2986 test(s) ok. 362 test(s) failed. 40 test(s) exe failed. arm64: 2996 test(s) ok. 367 test(s) failed. 25 test(s) exe failed. macos: 3031 test(s) ok. 332 test(s) failed. 25 test(s) exe failed. riscv: 2948 test(s) ok. 401 test(s) failed. 39 test(s) exe failed. windows: x86_64: 3027 test(s) ok. 333 test(s) failed. 28 test(s) exe failed. i386: 3029 test(s) ok. 331 test(s) failed. 28 test(s) exe failed. linux with bounds checking: x86_64: 3030 test(s) ok. 328 test(s) failed. 30 test(s) exe failed. i386: 3028 test(s) ok. 327 test(s) failed. 33 test(s) exe failed. arm: 2997 test(s) ok. 362 test(s) failed. 29 test(s) exe failed. arm64: 2986 test(s) ok. 367 test(s) failed. 35 test(s) exe failed. macos: 3026 test(s) ok. 332 test(s) failed. 30 test(s) exe failed. riscv: 2936 test(s) ok. 409 test(s) failed. 43 test(s) exe failed. windows with bounds checking: x86_64: 3029 test(s) ok. 332 test(s) failed. 27 test(s) exe failed. i386: 3027 test(s) ok. 331 test(s) failed. 30 test(s) exe failed. all: fail for complex and vector types, nested functions and a lot of gcc defines/buitins. arm/arm64/riscv: fail for asm and alloca. riscv: fail with 'error: unimp: store(struct)' --- arm-gen.c | 12 +- arm64-gen.c | 119 ++++++----- libtcc.c | 18 ++ riscv64-gen.c | 68 +++--- tccgen.c | 236 ++++++++++++++++++++- tccmacho.c | 1 - tcctok.h | 52 ++++- tests/bug.c | 75 +++++++ tests/gcctestsuite.sh | 39 ++-- tests/tests2/117_gcc_test.c | 134 ++++++++++++ tests/tests2/117_gcc_test.expect | 0 tests/tests2/60_errors_and_warnings.c | 7 + tests/tests2/60_errors_and_warnings.expect | 3 + x86_64-gen.c | 3 + 14 files changed, 659 insertions(+), 108 deletions(-) create mode 100644 tests/bug.c create mode 100644 tests/tests2/117_gcc_test.c create mode 100644 tests/tests2/117_gcc_test.expect diff --git a/arm-gen.c b/arm-gen.c index b925fe3..44c7d8b 100644 --- a/arm-gen.c +++ b/arm-gen.c @@ -925,10 +925,12 @@ static int is_hgen_float_aggr(CType *type) int btype, nb_fields = 0; ref = type->ref->next; - btype = unalias_ldbl(ref->type.t & VT_BTYPE); - if (btype == VT_FLOAT || btype == VT_DOUBLE) { - for(; ref && btype == unalias_ldbl(ref->type.t & VT_BTYPE); ref = ref->next, nb_fields++); - return !ref && nb_fields <= 4; + if (ref) { + btype = unalias_ldbl(ref->type.t & VT_BTYPE); + if (btype == VT_FLOAT || btype == VT_DOUBLE) { + for(; ref && btype == unalias_ldbl(ref->type.t & VT_BTYPE); ref = ref->next, nb_fields++); + return !ref && nb_fields <= 4; + } } } return 0; @@ -1017,7 +1019,7 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int ret->ref = NULL; ret->t = VT_DOUBLE; return (size + 7) >> 3; - } else if (size <= 4) { + } else if (size > 0 && size <= 4) { *ret_align = 4; *regsize = 4; ret->ref = NULL; diff --git a/arm64-gen.c b/arm64-gen.c index 211e771..fdb71bb 100644 --- a/arm64-gen.c +++ b/arm64-gen.c @@ -323,6 +323,9 @@ static void arm64_ldrs(int reg_, int size) // Use x30 for intermediate value in some cases. switch (size) { default: assert(0); break; + case 0: + /* Can happen with zero size structs */ + break; case 1: arm64_ldrx(0, 0, reg, reg, 0); break; @@ -429,30 +432,12 @@ static void arm64_strv(int sz_, int dst, int bas, uint64_t off) static void arm64_sym(int r, Sym *sym, unsigned long addend) { - // Currently TCC's linker does not generate COPY relocations for - // STT_OBJECTs when tcc is invoked with "-run". This typically - // results in "R_AARCH64_ADR_PREL_PG_HI21 relocation failed" when - // a program refers to stdin. A workaround is to avoid that - // relocation and use only relocations with unlimited range. - int avoid_adrp = 1; - - if (avoid_adrp || sym->a.weak) { - // (GCC uses a R_AARCH64_ABS64 in this case.) - greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G0_NC, addend); - o(0xd2800000 | r); // mov x(rt),#0,lsl #0 - greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G1_NC, addend); - o(0xf2a00000 | r); // movk x(rt),#0,lsl #16 - greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G2_NC, addend); - o(0xf2c00000 | r); // movk x(rt),#0,lsl #32 - greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G3, addend); - o(0xf2e00000 | r); // movk x(rt),#0,lsl #48 - } - else { - greloca(cur_text_section, sym, ind, R_AARCH64_ADR_PREL_PG_HI21, addend); - o(0x90000000 | r); - greloca(cur_text_section, sym, ind, R_AARCH64_ADD_ABS_LO12_NC, addend); - o(0x91000000 | r | r << 5); - } + o(0x10000060 | r); // adr xr,pc+12 + o(0xf9400000 | r | (r << 5)); // ldr xr,[xr] + o(0x14000003); // b + 8 + greloca(cur_text_section, sym, ind, R_AARCH64_ABS64, addend); + o(0); + o(0); } static void arm64_load_cmp(int r, SValue *sv); @@ -474,12 +459,24 @@ ST_FUNC void load(int r, SValue *sv) return; } - if ((svr & ~VT_VALMASK) == VT_LVAL && svrv < VT_CONST) { + if (svr == (VT_CONST | VT_LVAL)) { + arm64_sym(30, sv->sym, sv->c.i); // use x30 for address if (IS_FREG(r)) - arm64_ldrv(arm64_type_size(svtt), fltr(r), intr(svrv), 0); + arm64_ldrv(arm64_type_size(svtt), fltr(r), 30, 0); else arm64_ldrx(!(svtt & VT_UNSIGNED), arm64_type_size(svtt), - intr(r), intr(svrv), 0); + intr(r), 30, 0); + return; + } + + if ((svr & ~VT_VALMASK) == VT_LVAL && svrv < VT_CONST) { + if ((svtt & VT_BTYPE) != VT_VOID) { + if (IS_FREG(r)) + arm64_ldrv(arm64_type_size(svtt), fltr(r), intr(svrv), 0); + else + arm64_ldrx(!(svtt & VT_UNSIGNED), arm64_type_size(svtt), + intr(r), intr(svrv), 0); + } return; } @@ -573,6 +570,15 @@ ST_FUNC void store(int r, SValue *sv) return; } + if (svr == (VT_CONST | VT_LVAL)) { + arm64_sym(30, sv->sym, sv->c.i); // use x30 for address + if (IS_FREG(r)) + arm64_strv(arm64_type_size(svtt), fltr(r), 30, 0); + else + arm64_strx(arm64_type_size(svtt), intr(r), 30, 0); + return; + } + if ((svr & ~VT_VALMASK) == VT_LVAL && svrv < VT_CONST) { if (IS_FREG(r)) arm64_strv(arm64_type_size(svtt), fltr(r), intr(svrv), 0); @@ -597,9 +603,9 @@ ST_FUNC void store(int r, SValue *sv) static void arm64_gen_bl_or_b(int b) { if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST && (vtop->r & VT_SYM)) { - assert(!b); - greloca(cur_text_section, vtop->sym, ind, R_AARCH64_CALL26, 0); - o(0x94000000); // bl . + greloca(cur_text_section, vtop->sym, ind, + b ? R_AARCH64_JUMP26 : R_AARCH64_CALL26, 0); + o(0x14000000 | (uint32_t)!b << 31); // b/bl . #ifdef CONFIG_TCC_BCHECK if (tcc_state->do_bounds_check && (vtop->sym->v == TOK_setjmp || @@ -684,7 +690,8 @@ static void gen_bounds_prolog(void) func_bound_offset = lbounds_section->data_offset; func_bound_ind = ind; func_bound_add_epilog = 0; - o(0xd503201f); /* nop -> mov x0,#0,lsl #0, lbound section pointer */ + o(0xd503201f); /* nop -> mov x0, lbound section pointer */ + o(0xd503201f); o(0xd503201f); o(0xd503201f); o(0xd503201f); @@ -712,14 +719,12 @@ static void gen_bounds_epilog(void) if (offset_modified) { saved_ind = ind; ind = func_bound_ind; - greloca(cur_text_section, sym_data, ind, R_AARCH64_MOVW_UABS_G0_NC, 0); - o(0xd2800000); /* mov x0,#0,lsl #0, lbound section pointer */ - greloca(cur_text_section, sym_data, ind, R_AARCH64_MOVW_UABS_G1_NC, 0); - o(0xf2a00000); /* movk x0,#0,lsl #16 */ - greloca(cur_text_section, sym_data, ind, R_AARCH64_MOVW_UABS_G2_NC, 0); - o(0xf2c00000); /* movk x0,#0,lsl #32 */ - greloca(cur_text_section, sym_data, ind, R_AARCH64_MOVW_UABS_G3, 0); - o(0xf2e00000); /* movk x0,#0,lsl #48 */ + o(0x10000060 | 0); // adr x0,pc+12 + o(0xf9400000 | 0 | (0 << 5)); // ldr x0,[x0] + o(0x14000003); // b + 8 + greloca(cur_text_section, sym_data, ind, R_AARCH64_ABS64, 0); + o(0); + o(0); gen_bounds_call(TOK___bound_local_new); ind = saved_ind; } @@ -727,14 +732,12 @@ static void gen_bounds_epilog(void) /* generate bound check local freeing */ o(0xf81f0fe0); /* str x0, [sp, #-16]! */ o(0x3c9f0fe0); /* str q0, [sp, #-16]! */ - greloca(cur_text_section, sym_data, ind, R_AARCH64_MOVW_UABS_G0_NC, 0); - o(0xd2800000); // mov x0,#0,lsl #0 - greloca(cur_text_section, sym_data, ind, R_AARCH64_MOVW_UABS_G1_NC, 0); - o(0xf2a00000); // movk x0,#0,lsl #16 - greloca(cur_text_section, sym_data, ind, R_AARCH64_MOVW_UABS_G2_NC, 0); - o(0xf2c00000); // movk x0,#0,lsl #32 - greloca(cur_text_section, sym_data, ind, R_AARCH64_MOVW_UABS_G3, 0); - o(0xf2e00000); // movk x0,#0,lsl #48 + o(0x10000060 | 0); // adr x0,pc+12 + o(0xf9400000 | 0 | (0 << 5)); // ldr x0,[x0] + o(0x14000003); // b + 8 + greloca(cur_text_section, sym_data, ind, R_AARCH64_ABS64, 0); + o(0); + o(0); gen_bounds_call(TOK___bound_local_delete); o(0x3cc107e0); /* ldr q0, [sp], #16 */ o(0xf84107e0); /* ldr x0, [sp], #16 */ @@ -1014,9 +1017,12 @@ ST_FUNC void gfunc_call(int nb_args) stack = (stack + 15) >> 4 << 4; - assert(stack < 0x1000); - if (stack) - o(0xd10003ff | stack << 10); // sub sp,sp,#(n) + if (stack >= 0x1000000) // 16Mb + tcc_error("stack size too big %lu", stack); + if (stack & 0xfff) + o(0xd10003ff | (stack & 0xfff) << 10); // sub sp,sp,#(n) + if (stack >> 12) + o(0xd14003ff | (stack >> 12) << 10); // First pass: set all values on stack for (i = nb_args; i; i--) { @@ -1109,8 +1115,10 @@ ST_FUNC void gfunc_call(int nb_args) save_regs(0); arm64_gen_bl_or_b(0); --vtop; - if (stack) - o(0x910003ff | stack << 10); // add sp,sp,#(n) + if (stack & 0xfff) + o(0x910003ff | (stack & 0xfff) << 10); // add sp,sp,#(n) + if (stack >> 12) + o(0x914003ff | (stack >> 12) << 10); { int rt = return_type->t; @@ -1611,8 +1619,11 @@ static int arm64_gen_opic(int op, uint32_t l, int rev, uint64_t val, val = val & (n - 1); if (rev) return 0; - if (!val) - assert(0); + if (!val) { + // tcc_warning("shift count >= width of type"); + o(0x2a0003e0 | l << 31 | a << 16); + return 1; + } else if (op == TOK_SHL) o(0x53000000 | l << 31 | l << 22 | x | a << 5 | (n - val) << 16 | (n - 1 - val) << 10); // lsl diff --git a/libtcc.c b/libtcc.c index 17dd33f..8b942fd 100644 --- a/libtcc.c +++ b/libtcc.c @@ -963,6 +963,24 @@ LIBTCCAPI TCCState *tcc_new(void) tcc_define_symbol(s, "__FINITE_MATH_ONLY__", "1"); tcc_define_symbol(s, "_FORTIFY_SOURCE", "0"); #endif /* ndef TCC_TARGET_MACHO */ + + if (PTR_SIZE == 4) { + tcc_define_symbol(s, "__SIZEOF_LONG__", "4"); + tcc_define_symbol(s, "__LONG_MAX__", "0x7fffffffL"); + } + else { + tcc_define_symbol(s, "__SIZEOF_LONG__", "8"); + tcc_define_symbol(s, "__LONG_MAX__", "0x7fffffffffffffffL"); + } + tcc_define_symbol(s, "__SIZEOF_INT__", "4"); + tcc_define_symbol(s, "__SIZEOF_LONG_LONG__", "8"); + tcc_define_symbol(s, "__CHAR_BIT__", "8"); + tcc_define_symbol(s, "__ORDER_LITTLE_ENDIAN__", "1234"); + tcc_define_symbol(s, "__ORDER_BIG_ENDIAN__", "4321"); + tcc_define_symbol(s, "__BYTE_ORDER__", "__ORDER_LITTLE_ENDIAN__"); + tcc_define_symbol(s, "__INT_MAX__", "0x7fffffff"); + tcc_define_symbol(s, "__LONG_LONG_MAX__", "0x7fffffffffffffffLL"); + tcc_define_symbol(s, "__builtin_offsetof(type,field)", "((unsigned long) &((type *)0)->field)"); return s; } diff --git a/riscv64-gen.c b/riscv64-gen.c index 3767702..391386f 100644 --- a/riscv64-gen.c +++ b/riscv64-gen.c @@ -207,9 +207,10 @@ ST_FUNC void load(int r, SValue *sv) int rr = is_ireg(r) ? ireg(r) : freg(r); int fc = sv->c.i; int bt = sv->type.t & VT_BTYPE; - int align, size = type_size(&sv->type, &align); + int align, size; if (fr & VT_LVAL) { int func3, opcode = is_freg(r) ? 0x07 : 0x03, br; + size = type_size(&sv->type, &align); assert (!is_freg(r) || bt == VT_FLOAT || bt == VT_DOUBLE); if (bt == VT_FUNC) /* XXX should be done in generic code */ size = PTR_SIZE; @@ -290,6 +291,7 @@ ST_FUNC void load(int r, SValue *sv) EI(0x13, 0, rr, ireg(v), 0); // addi RR, V, 0 == mv RR, V else { int func7 = is_ireg(r) ? 0x70 : 0x78; + size = type_size(&sv->type, &align); if (size == 8) func7 |= 1; assert(size == 4 || size == 8); @@ -577,7 +579,7 @@ ST_FUNC void gfunc_call(int nb_args) { int i, align, size, areg[2]; int info[nb_args ? nb_args : 1]; - int stack_adj = 0, tempspace = 0, ofs, splitofs = 0; + int stack_adj = 0, tempspace = 0, stack_add, ofs, splitofs = 0; SValue *sv; Sym *sa; @@ -644,8 +646,15 @@ ST_FUNC void gfunc_call(int nb_args) } stack_adj = (stack_adj + 15) & -16; tempspace = (tempspace + 15) & -16; - if (stack_adj + tempspace) { - EI(0x13, 0, 2, 2, -(stack_adj + tempspace)); // addi sp, sp, -adj + stack_add = stack_adj + tempspace; + if (stack_add) { + if (stack_add >= 0x1000) { + o(0x37 | (5 << 7) | (-stack_add & 0xfffff000)); //lui t0, upper(v) + EI(0x13, 0, 5, 5, -stack_add << 20 >> 20); // addi t0, t0, lo(v) + ER(0x33, 0, 2, 2, 5, 0); // add sp, sp, t0 + } + else + EI(0x13, 0, 2, 2, -stack_add); // addi sp, sp, -adj for (i = ofs = 0; i < nb_args; i++) { if (info[i] & (64 | 32)) { vrotb(nb_args - i); @@ -757,8 +766,15 @@ ST_FUNC void gfunc_call(int nb_args) save_regs(nb_args + 1); gcall_or_jmp(1); vtop -= nb_args + 1; - if (stack_adj + tempspace) - EI(0x13, 0, 2, 2, stack_adj + tempspace); // addi sp, sp, adj + if (stack_add) { + if (stack_add >= 0x1000) { + o(0x37 | (5 << 7) | (stack_add & 0xfffff000)); //lui t0, upper(v) + EI(0x13, 0, 5, 5, stack_add << 20 >> 20); // addi t0, t0, lo(v) + ER(0x33, 0, 2, 2, 5, 0); // add sp, sp, t0 + } + else + EI(0x13, 0, 2, 2, stack_add); // addi sp, sp, adj + } } static int func_sub_sp_offset, num_va_regs, func_va_list_ofs; @@ -1009,6 +1025,7 @@ static void gen_opil(int op, int ll) int fc = vtop->c.i; if (fc == vtop->c.i && !(((unsigned)fc + (1 << 11)) >> 12)) { int cll = 0; + int m = ll ? 31 : 63; vswap(); gv(RC_INT); a = ireg(vtop[0].r); @@ -1023,6 +1040,7 @@ static void gen_opil(int op, int ll) fc = -fc; case '+': func3 = 0; // addi d, a, fc + cll = ll; do_cop: EI(0x13 | cll, func3, ireg(d), a, fc); --vtop; @@ -1045,22 +1063,22 @@ static void gen_opil(int op, int ll) case '^': func3 = 4; goto do_cop; // xori d, a, fc case '|': func3 = 6; goto do_cop; // ori d, a, fc case '&': func3 = 7; goto do_cop; // andi d, a, fc - case TOK_SHL: func3 = 1; fc &= 63; goto do_cop; // slli d, a, fc - case TOK_SHR: func3 = 5; cll = ll; fc &= 63; goto do_cop; // srli d, a, fc - case TOK_SAR: func3 = 5; cll = ll; fc = 1024 | (fc & 63); goto do_cop; + case TOK_SHL: func3 = 1; cll = ll; fc &= m; goto do_cop; // slli d, a, fc + case TOK_SHR: func3 = 5; cll = ll; fc &= m; goto do_cop; // srli d, a, fc + case TOK_SAR: func3 = 5; cll = ll; fc = 1024 | (fc & m); goto do_cop; - case TOK_UGE: - case TOK_UGT: - case TOK_GE: - case TOK_GT: - gen_opil(op - 1, ll); + case TOK_UGE: /* -> TOK_ULT */ + case TOK_UGT: /* -> TOK_ULE */ + case TOK_GE: /* -> TOK_LT */ + case TOK_GT: /* -> TOK_LE */ + gen_opil(op - 1, !ll); vtop->cmp_op ^= 1; return; case TOK_NE: case TOK_EQ: if (fc) - gen_opil('-', ll), a = ireg(vtop++->r); + gen_opil('-', !ll), a = ireg(vtop++->r); --vtop; vset_VT_CMP(op); vtop->cmp_r = a | 0 << 8; @@ -1087,25 +1105,25 @@ static void gen_opil(int op, int ll) break; case '+': - ER(0x33, 0, d, a, b, 0); // add d, a, b + ER(0x33 | ll, 0, d, a, b, 0); // add d, a, b break; case '-': - ER(0x33, 0, d, a, b, 0x20); // sub d, a, b + ER(0x33 | ll, 0, d, a, b, 0x20); // sub d, a, b break; case TOK_SAR: - ER(0x33 | ll, 5, d, a, b, 0x20); // sra d, a, b + ER(0x33 | ll | ll, 5, d, a, b, 0x20); // sra d, a, b break; case TOK_SHR: - ER(0x33 | ll, 5, d, a, b, 0); // srl d, a, b + ER(0x33 | ll | ll, 5, d, a, b, 0); // srl d, a, b break; case TOK_SHL: - ER(0x33, 1, d, a, b, 0); // sll d, a, b + ER(0x33 | ll, 1, d, a, b, 0); // sll d, a, b break; case '*': - ER(0x33, 0, d, a, b, 1); // mul d, a, b + ER(0x33 | ll, 0, d, a, b, 1); // mul d, a, b break; case '/': - ER(0x33, 4, d, a, b, 1); // div d, a, b + ER(0x33 | ll, 4, d, a, b, 1); // div d, a, b break; case '&': ER(0x33, 7, d, a, b, 0); // and d, a, b @@ -1117,14 +1135,14 @@ static void gen_opil(int op, int ll) ER(0x33, 6, d, a, b, 0); // or d, a, b break; case '%': - ER(0x33, 6, d, a, b, 1); // rem d, a, b + ER(ll ? 0x3b: 0x33, 6, d, a, b, 1); // rem d, a, b break; case TOK_UMOD: - ER(0x33, 7, d, a, b, 1); // remu d, a, b + ER(0x33 | ll, 7, d, a, b, 1); // remu d, a, b break; case TOK_PDIV: case TOK_UDIV: - ER(0x33, 5, d, a, b, 1); // divu d, a, b + ER(0x33 | ll, 5, d, a, b, 1); // divu d, a, b break; } } diff --git a/tccgen.c b/tccgen.c index 8fa5958..4f82e7e 100644 --- a/tccgen.c +++ b/tccgen.c @@ -5356,17 +5356,51 @@ static void parse_type(CType *type) static void parse_builtin_params(int nc, const char *args) { char c, sep = '('; - CType t; + CType type; if (nc) nocode_wanted++; next(); + if (*args == 0) + skip(sep); while ((c = *args++)) { skip(sep); sep = ','; switch (c) { - case 'e': expr_eq(); continue; - case 't': parse_type(&t); vpush(&t); continue; - default: tcc_error("internal error"); break; + case 'e': expr_eq(); + continue; + case 't': parse_type(&type); + vpush(&type); + continue; + case 'v': + case 'V': expr_eq(); + type.t = VT_VOID; + if (c == 'V') type.t |= VT_CONSTANT; + type.ref = NULL; + mk_pointer (&type); + gen_assign_cast(&type); + continue; + case 's': + case 'S': expr_eq(); + type.t = VT_BYTE; + if (tcc_state->char_is_unsigned) + type.t |= VT_UNSIGNED; + if (c == 'S') type.t |= VT_CONSTANT; + type.ref = NULL; + mk_pointer (&type); + gen_assign_cast(&type); + continue; + case 'i': expr_eq(); + type.t = VT_INT; + type.ref = NULL; + gen_assign_cast(&type); + continue; + case 'l': expr_eq(); + type.t = VT_SIZE_T; + type.ref = NULL; + gen_assign_cast(&type); + continue; + default: tcc_error("internal error"); + break; } } skip(')'); @@ -5746,6 +5780,197 @@ ST_FUNC void unary(void) break; } #endif + case TOK___builtin_abort: + vpush_global_sym(&func_old_type, TOK_abort); + parse_builtin_params(0, ""); + gfunc_call(0); +builtin_void_return: + vpushi(0); + type.t = VT_VOID; + type.ref = NULL; + vtop->type = type; + vtop->r = R_RET(type.t); + break; + case TOK___builtin_memcpy: + t = TOK_memcpy; +#ifdef CONFIG_TCC_BCHECK + if (tcc_state->do_bounds_check) t = TOK___bound_memcpy; +#endif + vpush_global_sym(&func_old_type, t); + parse_builtin_params(0, "vVl"); + gfunc_call(3); +builtin_void_ptr_return: + vpushi(0); + type.t = VT_VOID; + type.ref = NULL; + mk_pointer (&type); + vtop->type = type; + vtop->r = R_RET(type.t); + break; + case TOK___builtin_memcmp: + t = TOK_memcmp; +#ifdef CONFIG_TCC_BCHECK + if (tcc_state->do_bounds_check) t = TOK___bound_memcmp; +#endif + vpush_global_sym(&func_old_type, t); + parse_builtin_params(0, "VVl"); + gfunc_call(3); +builtin_int_return: + vpushi(0); + type.t = VT_INT; + type.ref = NULL; + vtop->type = type; + vtop->r = R_RET(type.t); + break; + case TOK___builtin_memmove: + t = TOK_memmove; +#ifdef CONFIG_TCC_BCHECK + if (tcc_state->do_bounds_check) t = TOK___bound_memmove; +#endif + vpush_global_sym(&func_old_type, t); + parse_builtin_params(0, "vVl"); + gfunc_call(3); + goto builtin_void_ptr_return; + case TOK___builtin_memset: + t = TOK_memset; +#ifdef CONFIG_TCC_BCHECK + if (tcc_state->do_bounds_check) t = TOK___bound_memset; +#endif + vpush_global_sym(&func_old_type, t); + parse_builtin_params(0, "vil"); + gfunc_call(3); + goto builtin_void_ptr_return; + case TOK___builtin_strlen: + t = TOK_strlen; +#ifdef CONFIG_TCC_BCHECK + if (tcc_state->do_bounds_check) t = TOK___bound_strlen; +#endif + vpush_global_sym(&func_old_type, t); + parse_builtin_params(0, "S"); + gfunc_call(1); + vpushi(0); + type.t = VT_SIZE_T; + type.ref = NULL; + vtop->type = type; + vtop->r = R_RET(type.t); + break; + case TOK___builtin_strcpy: + t = TOK_strcpy; +#ifdef CONFIG_TCC_BCHECK + if (tcc_state->do_bounds_check) t = TOK___bound_strcpy; +#endif + vpush_global_sym(&func_old_type, t); + parse_builtin_params(0, "sS"); + gfunc_call(2); +builtin_string_ptr_return: + vpushi(0); + type.t = VT_BYTE; + if (tcc_state->char_is_unsigned) + type.t |= VT_UNSIGNED; + type.ref = NULL; + mk_pointer (&type); + vtop->type = type; + vtop->r = R_RET(type.t); + break; + case TOK___builtin_strncpy: + t = TOK_strncpy; +#ifdef CONFIG_TCC_BCHECK + if (tcc_state->do_bounds_check) t = TOK___bound_strncpy; +#endif + vpush_global_sym(&func_old_type, t); + parse_builtin_params(0, "sSl"); + gfunc_call(3); + goto builtin_string_ptr_return; + case TOK___builtin_strcmp: + t = TOK_strcmp; +#ifdef CONFIG_TCC_BCHECK + if (tcc_state->do_bounds_check) t = TOK___bound_strcmp; +#endif + vpush_global_sym(&func_old_type, t); + parse_builtin_params(0, "SS"); + gfunc_call(2); + goto builtin_int_return; + case TOK___builtin_strncmp: + t = TOK_strncmp; +#ifdef CONFIG_TCC_BCHECK + if (tcc_state->do_bounds_check) t = TOK___bound_strncmp; +#endif + vpush_global_sym(&func_old_type, t); + parse_builtin_params(0, "SSl"); + gfunc_call(3); + goto builtin_int_return; + case TOK___builtin_strcat: + t = TOK_strcat; +#ifdef CONFIG_TCC_BCHECK + if (tcc_state->do_bounds_check) t = TOK___bound_strcat; +#endif + vpush_global_sym(&func_old_type, t); + parse_builtin_params(0, "sS"); + gfunc_call(2); + goto builtin_string_ptr_return; + case TOK___builtin_strchr: + t = TOK_strchr; +#ifdef CONFIG_TCC_BCHECK + if (tcc_state->do_bounds_check) t = TOK___bound_strchr; +#endif + vpush_global_sym(&func_old_type, t); + parse_builtin_params(0, "Si"); + gfunc_call(2); + goto builtin_string_ptr_return; + case TOK___builtin_strdup: + t = TOK_strdup; +#ifdef CONFIG_TCC_BCHECK + if (tcc_state->do_bounds_check) t = TOK___bound_strdup; +#endif + vpush_global_sym(&func_old_type, t); + parse_builtin_params(0, "S"); + gfunc_call(1); + goto builtin_string_ptr_return; + case TOK___builtin_malloc: + t = TOK_malloc; +#if defined(CONFIG_TCC_BCHECK) && defined(TCC_TARGET_PE) + if (tcc_state->do_bounds_check) t = TOK___bound_malloc; +#endif + vpush_global_sym(&func_old_type, t); + parse_builtin_params(0, "l"); + gfunc_call(1); + goto builtin_void_ptr_return; + case TOK___builtin_realloc: + t = TOK_realloc; +#if defined(CONFIG_TCC_BCHECK) && defined(TCC_TARGET_PE) + if (tcc_state->do_bounds_check) t = TOK___bound_realloc; +#endif + vpush_global_sym(&func_old_type, t); + parse_builtin_params(0, "vl"); + gfunc_call(2); + goto builtin_void_ptr_return; + case TOK___builtin_calloc: + t = TOK_calloc; +#if defined(CONFIG_TCC_BCHECK) && defined(TCC_TARGET_PE) + if (tcc_state->do_bounds_check) t = TOK___bound_calloc; +#endif + vpush_global_sym(&func_old_type, t); + parse_builtin_params(0, "ll"); + gfunc_call(2); + goto builtin_void_ptr_return; + case TOK___builtin_free: + t = TOK_free; +#if defined(CONFIG_TCC_BCHECK) && defined(TCC_TARGET_PE) + if (tcc_state->do_bounds_check) t = TOK___bound_free; +#endif + vpush_global_sym(&func_old_type, t); + parse_builtin_params(0, "v"); + gfunc_call(1); + goto builtin_void_return; +#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 + case TOK_alloca: + case TOK___builtin_alloca: + vpush_global_sym(&func_old_type, TOK_alloca); + parse_builtin_params(0, "l"); + gfunc_call(1); + goto builtin_void_ptr_return; +#endif + /* pre operations */ case TOK_INC: case TOK_DEC: @@ -7678,6 +7903,9 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, if (n >= 0 && len > n) nb = n; if (!(flags & DIF_SIZE_ONLY)) { + if (sec && !NODATA_WANTED && + (c + nb > sec->data_allocated)) + nb = sec->data_allocated - c; if (len > nb) tcc_warning("initializer-string for array is too long"); /* in order to go faster for common case (char diff --git a/tccmacho.c b/tccmacho.c index bb984dc..9a1c01c 100644 --- a/tccmacho.c +++ b/tccmacho.c @@ -820,7 +820,6 @@ ST_FUNC int macho_output_file(TCCState *s1, const char *filename) macho_write(s1, &mo, fp); } - ret = 0; do_ret: for (i = 0; i < mo.nlc; i++) diff --git a/tcctok.h b/tcctok.h index 54a778b..63b5565 100644 --- a/tcctok.h +++ b/tcctok.h @@ -314,11 +314,7 @@ # ifdef TCC_TARGET_X86_64 DEF(TOK___bound_alloca_nr, "__bound_alloca_nr") # endif - DEF(TOK_malloc, "malloc") - DEF(TOK_free, "free") - DEF(TOK_realloc, "realloc") DEF(TOK_memalign, "memalign") - DEF(TOK_calloc, "calloc") # else DEF(TOK_sigsetjmp, "sigsetjmp") DEF(TOK___sigsetjmp, "__sigsetjmp") @@ -326,6 +322,27 @@ # endif DEF(TOK_mmap, "mmap") DEF(TOK_munmap, "munmap") + DEF(TOK_setjmp, "setjmp") + DEF(TOK__setjmp, "_setjmp") + DEF(TOK_longjmp, "longjmp") + DEF(TOK___bound_memcpy, "__bound_memcpy") + DEF(TOK___bound_memcmp, "__bound_memcmp") + DEF(TOK___bound_memmove, "__bound_memmove") + DEF(TOK___bound_memset, "__bound_memset") + DEF(TOK___bound_strlen, "__bound_strlen") + DEF(TOK___bound_strcpy, "__bound_strcpy") + DEF(TOK___bound_strncpy, "__bound_strncpy") + DEF(TOK___bound_strcmp, "__bound_strcmp") + DEF(TOK___bound_strncmp, "__bound_strncmp") + DEF(TOK___bound_strcat, "__bound_strcat") + DEF(TOK___bound_strchr, "__bound_strchr") + DEF(TOK___bound_strdup, "__bound_strdup") + DEF(TOK___bound_malloc, "__bound_malloc") + DEF(TOK___bound_free, "__bound_free") + DEF(TOK___bound_realloc, "__bound_realloc") + DEF(TOK___bound_calloc, "__bound_calloc") +#endif + DEF(TOK_abort, "abort") DEF(TOK_memcmp, "memcmp") DEF(TOK_strlen, "strlen") DEF(TOK_strcpy, "strcpy") @@ -335,9 +352,30 @@ DEF(TOK_strcat, "strcat") DEF(TOK_strchr, "strchr") DEF(TOK_strdup, "strdup") - DEF(TOK_setjmp, "setjmp") - DEF(TOK__setjmp, "_setjmp") - DEF(TOK_longjmp, "longjmp") + DEF(TOK_malloc, "malloc") + DEF(TOK_free, "free") + DEF(TOK_realloc, "realloc") + DEF(TOK_calloc, "calloc") + + DEF(TOK___builtin_abort, "__builtin_abort") + DEF(TOK___builtin_memcpy, "__builtin_memcpy") + DEF(TOK___builtin_memcmp, "__builtin_memcmp") + DEF(TOK___builtin_memmove, "__builtin_memmove") + DEF(TOK___builtin_memset, "__builtin_memset") + DEF(TOK___builtin_strlen, "__builtin_strlen") + DEF(TOK___builtin_strcpy, "__builtin_strcpy") + DEF(TOK___builtin_strncpy, "__builtin_strncpy") + DEF(TOK___builtin_strcmp, "__builtin_strcmp") + DEF(TOK___builtin_strncmp, "__builtin_strncmp") + DEF(TOK___builtin_strcat, "__builtin_strcat") + DEF(TOK___builtin_strchr, "__builtin_strchr") + DEF(TOK___builtin_strdup, "__builtin_strdup") + DEF(TOK___builtin_malloc, "__builtin_malloc") + DEF(TOK___builtin_free, "__builtin_free") + DEF(TOK___builtin_realloc, "__builtin_realloc") + DEF(TOK___builtin_calloc, "__builtin_calloc") +#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 + DEF(TOK___builtin_alloca, "__builtin_alloca") #endif /* Tiny Assembler */ diff --git a/tests/bug.c b/tests/bug.c new file mode 100644 index 0000000..7ec4410 --- /dev/null +++ b/tests/bug.c @@ -0,0 +1,75 @@ +#include +#include + +void tst1(void) +{ + /* problem in gen_cast. Should mask unsigned types */ + signed char c = (signed char) 0xffffffff; + int r = (unsigned short) c ^ (signed char) 0x99999999; + if (r != 0xffff0066) printf ("%x\n", r); +} + +typedef struct{double x,y;}p; + +void tst2(int n,...) +{ + /* va_arg for struct double does not work on some targets */ + int i; + va_list args; + va_start(args,n); + for (i = 0; i < n; i++) { + p v = va_arg(args,p); + if (v.x != 1 || v.y != 2) printf("%g %g\n", v.x, v.y); + } + va_end(args); +} + +void tst3(void) +{ + /* Should VT_SYM be checked for TOK_builtin_constant_p */ + int r = __builtin_constant_p("c"); + if (r == 0) printf("%d\n",r); +} + +int compile_errors(void) +{ +#if TEST == 1 + { + /* Not constant */ + static int i = (&"Foobar"[1] - &"Foobar"[0]); + } +#endif +#if TEST == 2 + { + /* Not constant */ + struct{int c;}v; + static long i=((char*)&(v.c)-(char*)&v); + } +#endif +#if TEST == 3 + { + /* Not constant */ + static const short ar[] = { &&l1 - &&l1, &&l2 - &&l1 }; + void *p = &&l1 + ar[0]; + goto *p; + l1: return 1; + l2: return 2; + } +#endif +#if TEST == 4 + { + /* Only integer allowed */ + __builtin_return_address(0 + 1) != NULL; + } +#endif + return 0; +} + +int +main(void) +{ + p v = { 1, 2}; + tst1(); + tst2(1, v); + tst3(); +} diff --git a/tests/gcctestsuite.sh b/tests/gcctestsuite.sh index f3cc538..2be274c 100644 --- a/tests/gcctestsuite.sh +++ b/tests/gcctestsuite.sh @@ -1,33 +1,48 @@ #!/bin/sh TESTSUITE_PATH=$HOME/gcc/gcc-3.2/gcc/testsuite/gcc.c-torture -TCC="./tcc -B. -I. -DNO_TRAMPOLINES" -rm -f tcc.sum tcc.log +TCC="./tcc -B. -I. -DNO_TRAMPOLINES" +rm -f tcc.sum tcc.fail +nb_ok="0" nb_failed="0" +nb_exe_failed="0" for src in $TESTSUITE_PATH/compile/*.c ; do - echo $TCC -o /tmp/test.o -c $src - $TCC -o /tmp/test.o -c $src >> tcc.log 2>&1 + echo $TCC -o /tmp/tst.o -c $src + $TCC -o /tmp/tst.o -c $src >> tcc.fail 2>&1 if [ "$?" = "0" ] ; then - result="PASS" + result="PASS" + nb_ok=$(( $nb_ok + 1 )) else - result="FAIL" - nb_failed=$(( $nb_failed + 1 )) + result="FAIL" + nb_failed=$(( $nb_failed + 1 )) fi echo "$result: $src" >> tcc.sum done for src in $TESTSUITE_PATH/execute/*.c ; do - echo $TCC $src - $TCC $src >> tcc.log 2>&1 + echo $TCC $src -o /tmp/tst -lm + $TCC $src -o /tmp/tst -lm >> tcc.fail 2>&1 if [ "$?" = "0" ] ; then - result="PASS" + result="PASS" + if /tmp/tst >> tcc.fail 2>&1 + then + result="PASS" + nb_ok=$(( $nb_ok + 1 )) + else + result="FAILEXE" + nb_exe_failed=$(( $nb_exe_failed + 1 )) + fi else - result="FAIL" - nb_failed=$(( $nb_failed + 1 )) + result="FAIL" + nb_failed=$(( $nb_failed + 1 )) fi echo "$result: $src" >> tcc.sum done +echo "$nb_ok test(s) ok." >> tcc.sum +echo "$nb_ok test(s) ok." echo "$nb_failed test(s) failed." >> tcc.sum echo "$nb_failed test(s) failed." +echo "$nb_exe_failed test(s) exe failed." >> tcc.sum +echo "$nb_exe_failed test(s) exe failed." diff --git a/tests/tests2/117_gcc_test.c b/tests/tests2/117_gcc_test.c new file mode 100644 index 0000000..52b5af7 --- /dev/null +++ b/tests/tests2/117_gcc_test.c @@ -0,0 +1,134 @@ +#include + +void tst_branch(void) +{ + goto *&&a; + printf ("dummy"); +a: ; +} + +void tst_void_ptr(void *pv, int i) +{ + i ? *pv : *pv; // dr106 +} + +void tst_shift(void) +{ + int i = 1; + long l = 1; + + i = i << 32; // illegal. just test + l = l << 64; // illegal. just test +} + +#if !defined(_WIN32) +#include + +void tst_const_addr(void) +{ + void *addr = mmap ((void *)0x20000000, 4096, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS, -1, 0); + if (addr != (void *) -1) { +#if !defined(__riscv) + *(int *)0x20000000 += 42; +#endif + munmap (addr, 4096); + } +} +#endif + +struct zero_struct {}; + +struct zero_struct tst_zero_struct(void) +{ + struct zero_struct ret; + + return ret; +} + +struct big_struct { char a[262144]; }; + +struct big_struct tst_big(struct big_struct tst) +{ + return tst; +} + +void tst_adr (int (*fp)(char *, const char *, ...)) +{ + char buf[10]; + + (*fp)(buf, "%.0f", 5.0); +} + +static const char str[] = "abcdefghijklmnopqrstuvwxyz"; + +void tst_builtin(void) +{ + char *p; + char tmp[100]; + + if (__builtin_offsetof(struct big_struct, a) != 0) __builtin_abort(); + + p = __builtin_memcpy (tmp, str, sizeof(str)); + if (p != tmp) __builtin_abort(); + + if (__builtin_memcmp (p, str, sizeof(str))) __builtin_abort(); + + p = __builtin_memmove(tmp, str, sizeof(str)); + if (__builtin_memcmp (p, str, sizeof(str))) __builtin_abort(); + + p = __builtin_memset(tmp, 0, sizeof (tmp)); + if (p != tmp || tmp[0] != 0 || tmp[99] != 0) __builtin_abort(); + + if (__builtin_strlen(str) != sizeof(str) - 1) __builtin_abort(); + + p = __builtin_strcpy(tmp, str); + if (__builtin_memcmp (p, str, sizeof(str))) __builtin_abort(); + + p = __builtin_strncpy(tmp, str, sizeof(str)); + if (__builtin_memcmp (p, str, sizeof(str))) __builtin_abort(); + + if (__builtin_strcmp (p, str)) __builtin_abort(); + + if (__builtin_strncmp (p, str, sizeof(str))) __builtin_abort(); + + tmp[0] = '\0'; + p = __builtin_strcat(tmp, str); + if (__builtin_memcmp (p, str, sizeof(str))) __builtin_abort(); + + if (__builtin_strchr(p, 'z') != &p[25]) __builtin_abort(); + + p = __builtin_strdup (str); + if (__builtin_memcmp (p, str, sizeof(str))) __builtin_abort(); + __builtin_free(p); + + p = __builtin_malloc (100); + __builtin_memset(p, 0, 100); + p = __builtin_realloc (p, 1000); + __builtin_memset(p, 0, 1000); + __builtin_free(p); + + p = __builtin_calloc(10, 10); + __builtin_memset(p, 0, 100); + __builtin_free(p); + +#if defined(__i386__) || defined(__x86_64__) + p = __builtin_alloca(100); + __builtin_memset(p, 0, 100); +#endif +} + +int +main (void) +{ + struct big_struct big; + + tst_shift(); + tst_void_ptr(&big.a[0], 0); +#if !defined(_WIN32) + tst_const_addr(); +#endif + tst_zero_struct(); + tst_big(big); + tst_adr(&sprintf); + tst_builtin(); +} diff --git a/tests/tests2/117_gcc_test.expect b/tests/tests2/117_gcc_test.expect new file mode 100644 index 0000000..e69de29 diff --git a/tests/tests2/60_errors_and_warnings.c b/tests/tests2/60_errors_and_warnings.c index 40d84a3..fd4367a 100644 --- a/tests/tests2/60_errors_and_warnings.c +++ b/tests/tests2/60_errors_and_warnings.c @@ -339,4 +339,11 @@ int main() } /******************************************************************/ +#elif defined test_var_array + +static struct var_len { int i; const char str[]; } var_array[] = +{ { 1, "abcdefghijklmnopqrstuvwxyz" }, + { 2, "longlonglonglonglong" }, + { 3, "tst3" } }; + #endif diff --git a/tests/tests2/60_errors_and_warnings.expect b/tests/tests2/60_errors_and_warnings.expect index a43bb46..984e4c1 100644 --- a/tests/tests2/60_errors_and_warnings.expect +++ b/tests/tests2/60_errors_and_warnings.expect @@ -159,3 +159,6 @@ bar : 3 ; 3 [test_stray_backslash2] \n + +[test_var_array] +60_errors_and_warnings.c:345: warning: initializer-string for array is too long diff --git a/x86_64-gen.c b/x86_64-gen.c index 36176a5..d2931ca 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -441,6 +441,9 @@ void load(int r, SValue *sv) b = 0xbf0f; /* movswl */ } else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) { b = 0xb70f; /* movzwl */ + } else if ((ft & VT_TYPE) == (VT_VOID)) { + /* Can happen with zero size structs */ + return; } else { assert(((ft & VT_BTYPE) == VT_INT) || ((ft & VT_BTYPE) == VT_LLONG)