From 6b78e561c8bf312fefdb4fda692494edd5da01ea Mon Sep 17 00:00:00 2001 From: grischka Date: Tue, 11 Jun 2024 13:57:22 +0200 Subject: [PATCH] div fixes - Makefile: don't produce unknown targets - libtcc.c: tcc_set_linker(): improve parser - tcc.h: tcc_internal_error(): don't record __FILE__ (for privacy reasons) - tccgen.c: - reject pointer + float operation - use 'int level' for builtin_frame/return_address - save_regs(): remove VT_ARRAY (confuses riscv64-gen) - tccpe.c: store just basename of loaded dlls (rather than full path) - tccpp.c: remove unused TAL defines - *-link.c: add missing ST_FUNC - i386-gen.c: fix thiscall - riscv64-asm.c/arm-asm.c: stay simple C89 - avoid .designators, decl after statement - avoid multiple instances of same static const objects - use skip() instead of next() & expect() - use cstr_printf() instead of snprintf() & cstr_cat() - tcc_error(), expect(): never return --- Makefile | 1 + arm-asm.c | 221 +++------------------ arm-link.c | 6 +- arm64-link.c | 6 +- c67-link.c | 6 +- i386-asm.c | 25 +-- i386-gen.c | 32 +-- i386-link.c | 6 +- libtcc.c | 44 ++-- riscv64-asm.c | 136 +++---------- riscv64-link.c | 6 +- tcc.h | 9 +- tccelf.c | 29 +-- tccgen.c | 105 +++++----- tccpe.c | 7 +- tccpp.c | 63 +++--- tests/tests2/60_errors_and_warnings.c | 7 + tests/tests2/60_errors_and_warnings.expect | 3 + tests/thiscall/thiscall-test.c | 17 -- x86_64-link.c | 6 +- 20 files changed, 227 insertions(+), 508 deletions(-) delete mode 100644 tests/thiscall/thiscall-test.c diff --git a/Makefile b/Makefile index 2b247ea7..13260d07 100644 --- a/Makefile +++ b/Makefile @@ -198,6 +198,7 @@ DEFINES += $(if $(ELF-$T),-DCONFIG_TCC_ELFINTERP="\"$(ELF-$T)\"") DEFINES += $(DEF-$(or $(findstring win,$T),unx)) ifneq ($(X),) +$(if $(DEF-$T),,$(error error: unknown target: '$T')) DEF-all += -DCONFIG_TCC_CROSSPREFIX="\"$X\"" ifneq ($(CONFIG_WIN32),yes) DEF-win += -DCONFIG_TCCDIR="\"$(tccdir)/win32\"" diff --git a/arm-asm.c b/arm-asm.c index 2362d172..54c063ae 100644 --- a/arm-asm.c +++ b/arm-asm.c @@ -92,7 +92,6 @@ static void parse_operand(TCCState *s1, Operand *op) reg = asm_parse_regvar(tok); if (reg == -1) { expect("register"); - return; } else next(); // skip register name @@ -103,9 +102,7 @@ static void parse_operand(TCCState *s1, Operand *op) break; next(); // skip ',' } - if (tok != '}') - expect("'}'"); - next(); // skip '}' + skip('}'); if (regset == 0) { // ARM instructions don't support empty regset. tcc_error("empty register list is not supported"); @@ -186,7 +183,6 @@ ST_FUNC void gen_expr32(ExprValue *pe) static uint32_t condition_code_of_token(int token) { if (token < TOK_ASM_nopeq) { expect("condition-enabled instruction"); - return 0; } else return (token - TOK_ASM_nopeq) & 15; } @@ -262,19 +258,14 @@ static void asm_binary_opcode(TCCState *s1, int token) uint32_t encoded_rotation = 0; uint64_t amount; parse_operand(s1, &ops[0]); - if (tok == ',') - next(); - else - expect("','"); + skip(','); parse_operand(s1, &ops[1]); if (ops[0].type != OP_REG32) { expect("(destination operand) register"); - return; } if (ops[0].reg == 15) { tcc_error("'%s' does not support 'pc' as operand", get_tok_str(token, NULL)); - return; } if (ops[0].reg == 13) @@ -308,7 +299,6 @@ static void asm_binary_opcode(TCCState *s1, int token) if (ops[1].reg == 15) { tcc_error("'%s' does not support 'pc' as operand", get_tok_str(token, NULL)); - return; } if (ops[1].reg == 13) @@ -321,7 +311,6 @@ static void asm_binary_opcode(TCCState *s1, int token) parse_operand(s1, &rotation); if (rotation.type != OP_IM8) { expect("immediate value for rotation"); - return; } else { amount = rotation.e.v; switch (amount) { @@ -336,7 +325,6 @@ static void asm_binary_opcode(TCCState *s1, int token) break; default: expect("'8' or '16' or '24'"); - return; } } } @@ -378,32 +366,21 @@ static void asm_coprocessor_opcode(TCCState *s1, int token) { next(); } else { expect("'p'"); - return; } - - if (tok == ',') - next(); - else - expect("','"); - + skip(','); parse_operand(s1, &opcode1); if (opcode1.type != OP_IM8 || opcode1.e.v > 15) { tcc_error("opcode1 of instruction '%s' must be an immediate value between 0 and 15", get_tok_str(token, NULL)); - return; } for (i = 0; i < 3; ++i) { - if (tok == ',') - next(); - else - expect("','"); + skip(','); if (i == 0 && token != TOK_ASM_cdp2 && (ARM_INSTRUCTION_GROUP(token) == TOK_ASM_mrceq || ARM_INSTRUCTION_GROUP(token) == TOK_ASM_mcreq)) { if (tok >= TOK_ASM_r0 && tok <= TOK_ASM_r15) { registers[i] = tok - TOK_ASM_r0; next(); } else { expect("'r'"); - return; } } else { if (tok >= TOK_ASM_c0 && tok <= TOK_ASM_c15) { @@ -411,7 +388,6 @@ static void asm_coprocessor_opcode(TCCState *s1, int token) { next(); } else { expect("'c'"); - return; } } } @@ -424,7 +400,6 @@ static void asm_coprocessor_opcode(TCCState *s1, int token) { } if (opcode2.type != OP_IM8 || opcode2.e.v > 15) { tcc_error("opcode2 of instruction '%s' must be an immediate value between 0 and 15", get_tok_str(token, NULL)); - return; } if (token == TOK_ASM_cdp2) { @@ -446,7 +421,6 @@ static void asm_coprocessor_opcode(TCCState *s1, int token) { // opcode1 encoding changes! highest and lowest bit gone. if (opcode1.e.v > 7) { tcc_error("opcode1 of instruction '%s' must be an immediate value between 0 and 7", get_tok_str(token, NULL)); - return; } asm_emit_coprocessor_opcode(high_nibble, coprocessor, (opcode1.e.v << 1) | mrc, registers[0], registers[1], registers[2], opcode2.e.v, 1); break; @@ -490,10 +464,8 @@ static void asm_block_data_transfer_opcode(TCCState *s1, int token) } if (nb_ops < 1) { expect("at least one operand"); - return; } else if (ops[nb_ops - 1].type != OP_REGSET32) { expect("(last operand) register list"); - return; } // block data transfer: 1 0 0 P U S W L << 20 (general case): @@ -683,12 +655,10 @@ static void asm_data_processing_opcode(TCCState *s1, int token) } else if (nb_ops == 3) { if (opcode_nos == 0xd || opcode_nos == 0xf || opcode_nos == 0xa || opcode_nos == 0xb || opcode_nos == 0x8 || opcode_nos == 0x9) { // mov, mvn, cmp, cmn, tst, teq tcc_error("'%s' cannot be used with three operands", get_tok_str(token, NULL)); - return; } } if (nb_ops != 3) { expect("two or three operands"); - return; } else { uint32_t opcode = 0; uint32_t immediate_value; @@ -697,7 +667,6 @@ static void asm_data_processing_opcode(TCCState *s1, int token) if ((ops[0].type == OP_REG32 && ops[0].reg == 15) || (ops[1].type == OP_REG32 && ops[1].reg == 15)) { tcc_error("Using the 'pc' register in data processing instructions that have a register-controlled shift is not implemented by ARM"); - return; } } @@ -806,7 +775,6 @@ static void asm_data_processing_opcode(TCCState *s1, int token) if (half_immediate_rotation >= 16) { immediate_value = ops[2].e.v; tcc_error("immediate value 0x%X cannot be encoded into ARM immediate", (unsigned) immediate_value); - return; } operands |= immediate_value; operands |= half_immediate_rotation << 8; @@ -846,12 +814,10 @@ static void asm_shift_opcode(TCCState *s1, int token) } if (nb_ops < 2) { expect("at least two operands"); - return; } if (ops[0].type != OP_REG32) { expect("(destination operand) register"); - return; } else operands |= ENCODE_RD(ops[0].reg); @@ -876,7 +842,6 @@ static void asm_shift_opcode(TCCState *s1, int token) } if (nb_ops != 3) { expect("two or three operands"); - return; } switch (ARM_INSTRUCTION_GROUP(token)) { @@ -896,7 +861,6 @@ static void asm_shift_opcode(TCCState *s1, int token) operands |= ENCODE_IMMEDIATE_FLAG; operands |= ops[1].e.v; tcc_error("Using an immediate value as the source operand is not possible with '%s' instruction on ARM", get_tok_str(token, NULL)); - return; } switch (ops[2].type) { @@ -934,7 +898,6 @@ static void asm_shift_opcode(TCCState *s1, int token) break; default: expect("shift instruction"); - return; } asm_emit_opcode(token, opcode | operands); } @@ -963,7 +926,6 @@ static void asm_multiplication_opcode(TCCState *s1, int token) break; default: expect("at least three operands"); - return; } nb_ops = 3; } @@ -1037,7 +999,6 @@ static void asm_long_multiplication_opcode(TCCState *s1, int token) } if (nb_ops != 4) { expect("four operands"); - return; } // long multiply (special case): @@ -1117,12 +1078,10 @@ static void asm_single_data_transfer_opcode(TCCState *s1, int token) opcode |= ENCODE_RD(ops[0].reg); else { expect("(destination operand) register"); - return; } if (tok != ',') expect("at least two arguments"); - else - next(); // skip ',' + next(); // skip ',' switch (ARM_INSTRUCTION_GROUP(token)) { case TOK_ASM_strexbeq: @@ -1130,7 +1089,6 @@ static void asm_single_data_transfer_opcode(TCCState *s1, int token) parse_operand(s1, &strex_operand); if (strex_operand.type != OP_REG32) { expect("register"); - return; } if (tok != ',') expect("at least three arguments"); @@ -1139,17 +1097,12 @@ static void asm_single_data_transfer_opcode(TCCState *s1, int token) break; } - if (tok != '[') - expect("'['"); - else - next(); // skip '[' - + skip('['); parse_operand(s1, &ops[1]); if (ops[1].type == OP_REG32) opcode |= ENCODE_RN(ops[1].reg); else { expect("(first source operand) register"); - return; } if (tok == ']') { next(); @@ -1166,7 +1119,6 @@ static void asm_single_data_transfer_opcode(TCCState *s1, int token) if (ops[2].type == OP_REG32) { if (ops[2].reg == 15) { tcc_error("Using 'pc' for register offset in '%s' is not implemented by ARM", get_tok_str(token, NULL)); - return; } if (tok == ',') { next(); @@ -1182,10 +1134,7 @@ static void asm_single_data_transfer_opcode(TCCState *s1, int token) opcode |= 1 << 24; // add offset before transfer } if (!closed_bracket) { - if (tok != ']') - expect("']'"); - else - next(); // skip ']' + skip(']'); opcode |= 1 << 24; // add offset before transfer if (tok == '!') { exclam = 1; @@ -1257,14 +1206,11 @@ static void asm_single_data_transfer_opcode(TCCState *s1, int token) case TOK_ASM_strexeq: if ((opcode & 0xFFF) || nb_shift) { tcc_error("neither offset nor shift allowed with 'strex'"); - return; } else if (opcode & ENCODE_IMMEDIATE_FLAG) { // if set, it means it's NOT immediate tcc_error("offset not allowed with 'strex'"); - return; } if ((opcode & (1 << 24)) == 0) { // add offset after transfer tcc_error("adding offset after transfer not allowed with 'strex'"); - return; } opcode |= 0xf90; // Used to mean: barrel shifter is enabled, barrel shift register is r15, mode is LSL @@ -1277,14 +1223,11 @@ static void asm_single_data_transfer_opcode(TCCState *s1, int token) case TOK_ASM_ldrexeq: if ((opcode & 0xFFF) || nb_shift) { tcc_error("neither offset nor shift allowed with 'ldrex'"); - return; } else if (opcode & ENCODE_IMMEDIATE_FLAG) { // if set, it means it's NOT immediate tcc_error("offset not allowed with 'ldrex'"); - return; } if ((opcode & (1 << 24)) == 0) { // add offset after transfer tcc_error("adding offset after transfer not allowed with 'ldrex'"); - return; } opcode |= 1 << 20; // L opcode |= 0x00f; @@ -1313,10 +1256,9 @@ static void asm_emit_coprocessor_data_transfer(uint32_t high_nibble, uint8_t cp_ //assert(CRd < 16); opcode |= ENCODE_RD(CRd); - if (Rn->type != OP_REG32) { + if (Rn->type != OP_REG32) expect("register"); - return; - } + //assert(Rn->reg < 16); opcode |= ENCODE_RN(Rn->reg); if (preincrement) @@ -1335,12 +1277,10 @@ static void asm_emit_coprocessor_data_transfer(uint32_t high_nibble, uint8_t cp_ opcode |= 1 << 23; // up if (v & 3) { tcc_error("immediate offset must be a multiple of 4"); - return; } v >>= 2; if (v > 255) { tcc_error("immediate offset must be between -1020 and 1020"); - return; } opcode |= v; } else if (offset->type == OP_REG32) { @@ -1349,7 +1289,6 @@ static void asm_emit_coprocessor_data_transfer(uint32_t high_nibble, uint8_t cp_ opcode |= ENCODE_IMMEDIATE_FLAG; /* if set, it means it's NOT immediate */ opcode |= offset->reg; tcc_error("Using register offset to register address is not possible here"); - return; } else if (offset->type == OP_VREG64) { opcode |= 16; opcode |= offset->reg; @@ -1380,36 +1319,22 @@ static void asm_coprocessor_data_transfer_opcode(TCCState *s1, int token) next(); } else { expect("'c'"); - return; } - if (tok == ',') - next(); - else - expect("','"); + skip(','); if (tok >= TOK_ASM_c0 && tok <= TOK_ASM_c15) { coprocessor_destination_register = tok - TOK_ASM_c0; next(); } else { expect("'c'"); - return; } - if (tok == ',') - next(); - else - expect("','"); - - if (tok != '[') - expect("'['"); - else - next(); // skip '[' - + skip(','); + skip('['); parse_operand(s1, &ops[1]); if (ops[1].type != OP_REG32) { expect("(first source operand) register"); - return; } if (tok == ']') { next(); @@ -1426,11 +1351,9 @@ static void asm_coprocessor_data_transfer_opcode(TCCState *s1, int token) if (ops[2].type == OP_REG32) { if (ops[2].reg == 15) { tcc_error("Using 'pc' for register offset in '%s' is not implemented by ARM", get_tok_str(token, NULL)); - return; } } else if (ops[2].type == OP_VREG64) { tcc_error("'%s' does not support VFP register operand", get_tok_str(token, NULL)); - return; } } else { // end of input expression in brackets--assume 0 offset @@ -1439,10 +1362,7 @@ static void asm_coprocessor_data_transfer_opcode(TCCState *s1, int token) preincrement = 1; // add offset before transfer } if (!closed_bracket) { - if (tok != ']') - expect("']'"); - else - next(); // skip ']' + skip(']'); preincrement = 1; // add offset before transfer if (tok == '!') { exclam = 1; @@ -1511,40 +1431,26 @@ static void asm_floating_point_single_data_transfer_opcode(TCCState *s1, int tok next(); } else { expect("floating point register"); - return; } - if (tok == ',') - next(); - else - expect("','"); - - if (tok != '[') - expect("'['"); - else - next(); // skip '[' - + skip(','); + skip('['); parse_operand(s1, &ops[1]); if (ops[1].type != OP_REG32) { expect("(first source operand) register"); - return; } if (tok == ',') { next(); // skip ',' parse_operand(s1, &ops[2]); if (ops[2].type != OP_IM8 && ops[2].type != OP_IM8N) { expect("immediate offset"); - return; } } else { // end of input expression in brackets--assume 0 offset ops[2].type = OP_IM8; ops[2].e.v = 0; } - if (tok != ']') - expect("']'"); - else - next(); // skip ']' + skip(']'); switch (ARM_INSTRUCTION_GROUP(token)) { case TOK_ASM_vldreq: @@ -1583,19 +1489,10 @@ static void asm_floating_point_block_data_transfer_opcode(TCCState *s1, int toke op0_exclam = 1; next(); // skip '!' } - if (tok == ',') - next(); // skip comma - else { - expect("','"); - return; - } + skip(','); } - if (tok != '{') { - expect("'{'"); - return; - } - next(); // skip '{' + skip('{'); first_regset_register = asm_parse_vfp_regvar(tok, 1); if ((first_regset_register = asm_parse_vfp_regvar(tok, 1)) != -1) { coprocessor = CP_DOUBLE_PRECISION_FLOAT; @@ -1605,7 +1502,6 @@ static void asm_floating_point_block_data_transfer_opcode(TCCState *s1, int toke next(); } else { expect("floating-point register"); - return; } if (tok == '-') { @@ -1614,21 +1510,14 @@ static void asm_floating_point_block_data_transfer_opcode(TCCState *s1, int toke next(); else { expect("floating-point register"); - return; } } else last_regset_register = first_regset_register; if (last_regset_register < first_regset_register) { tcc_error("registers will be processed in ascending order by hardware--but are not specified in ascending order here"); - return; } - if (tok != '}') { - expect("'}'"); - return; - } - next(); // skip '}' - + skip('}'); // Note: 0 (one down) is not implemented by us regardless. regset_item_count = last_regset_register - first_regset_register + 1; if (coprocessor == CP_DOUBLE_PRECISION_FLOAT) @@ -1659,7 +1548,6 @@ static void asm_floating_point_block_data_transfer_opcode(TCCState *s1, int toke break; default: expect("floating point block data transfer instruction"); - return; } if (ops[0].type != OP_REG32) expect("(first operand) register"); @@ -1713,7 +1601,6 @@ static uint32_t vmov_parse_immediate_value() { if (tok != TOK_PPNUM) { expect("immediate value"); - return 0; } p = tokc.str.data; errno = 0; @@ -1721,7 +1608,6 @@ static uint32_t vmov_parse_immediate_value() { if (errno || integral_value >= 32) { tcc_error("invalid floating-point immediate value"); - return 0; } value = (uint32_t) integral_value * VMOV_ONE; @@ -1754,7 +1640,6 @@ static uint8_t vmov_encode_immediate_value(uint32_t value) } if (r == -1 || value < beginning || value > end) { tcc_error("invalid decimal number for vmov: %d", value); - return 0; } n = vmov_linear_approx_index(beginning, end, value); return n | (((3 - r) & 0x7) << 4); @@ -1788,7 +1673,6 @@ static void asm_floating_point_immediate_data_processing_opcode_tail(TCCState *s operands[1] = 5; if (immediate_value) { expect("Immediate value 0"); - return; } break; case TOK_ASM_vcmpeeq_f32: @@ -1797,7 +1681,6 @@ static void asm_floating_point_immediate_data_processing_opcode_tail(TCCState *s operands[1] = 5; if (immediate_value) { expect("Immediate value 0"); - return; } break; case TOK_ASM_vmoveq_f32: @@ -1813,7 +1696,6 @@ static void asm_floating_point_immediate_data_processing_opcode_tail(TCCState *s break; default: expect("known floating point with immediate instruction"); - return; } if (coprocessor == CP_SINGLE_PRECISION_FLOAT) { @@ -1833,7 +1715,6 @@ static void asm_floating_point_reg_arm_reg_transfer_opcode_tail(TCCState *s1, in // "vmov.f32 r2, s3" or "vmov.f32 s3, r2" if (nb_ops != 2 || nb_arm_regs != 1) { tcc_error("vmov.f32 only implemented for one VFP register operand and one ARM register operands"); - return; } if (ops[0].type != OP_REG32) { // determine mode: load or store // need to swap operands 0 and 1 @@ -1860,7 +1741,6 @@ static void asm_floating_point_reg_arm_reg_transfer_opcode_tail(TCCState *s1, in case CP_DOUBLE_PRECISION_FLOAT: if (nb_ops != 3 || nb_arm_regs != 2) { tcc_error("vmov.f32 only implemented for one VFP register operand and two ARM register operands"); - return; } // Determine whether it's a store into a VFP register (vmov "d1, r2, r3") rather than "vmov r2, r3, d1" if (ops[0].type == OP_VREG64) { @@ -1873,11 +1753,9 @@ static void asm_floating_point_reg_arm_reg_transfer_opcode_tail(TCCState *s1, in memcpy(&ops[2], &temp, sizeof(ops[2])); } else { tcc_error("vmov.f64 only implemented for one VFP register operand and two ARM register operands"); - return; } } else if (ops[0].type != OP_REG32 || ops[1].type != OP_REG32 || ops[2].type != OP_VREG64) { tcc_error("vmov.f64 only implemented for one VFP register operand and two ARM register operands"); - return; } else { opcode1 |= 1; } @@ -1915,7 +1793,6 @@ static void asm_floating_point_vcvt_data_processing_opcode(TCCState *s1, int tok break; default: tcc_error("Unknown coprocessor for instruction '%s'", get_tok_str(token, NULL)); - return; } parse_operand(s1, &ops[0]); @@ -1942,10 +1819,7 @@ static void asm_floating_point_vcvt_data_processing_opcode(TCCState *s1, int tok break; } - if (tok == ',') - next(); - else - expect("','"); + skip(','); parse_operand(s1, &ops[2]); switch (ARM_INSTRUCTION_GROUP(token)) { @@ -1977,7 +1851,6 @@ static void asm_floating_point_vcvt_data_processing_opcode(TCCState *s1, int tok if (ops[0].type == OP_VREG64 && ops[2].type == OP_VREG32) { } else { expect("d, s"); - return; } break; default: @@ -1985,13 +1858,11 @@ static void asm_floating_point_vcvt_data_processing_opcode(TCCState *s1, int tok if (ops[0].type == OP_VREG32 && ops[2].type == OP_VREG32) { } else { expect("s, s"); - return; } } else if (coprocessor == CP_DOUBLE_PRECISION_FLOAT) { if (ops[0].type == OP_VREG32 && ops[2].type == OP_VREG64) { } else { expect("s, d"); - return; } } } @@ -2074,16 +1945,13 @@ static void asm_floating_point_data_processing_opcode(TCCState *s1, int token) { } else if (ops[nb_ops].type == OP_VREG32) { if (coprocessor != CP_SINGLE_PRECISION_FLOAT) { expect("'s'"); - return; } } else if (ops[nb_ops].type == OP_VREG64) { if (coprocessor != CP_DOUBLE_PRECISION_FLOAT) { expect("'d'"); - return; } } else { expect("floating point register"); - return; } ++nb_ops; if (tok == ',') @@ -2100,7 +1968,6 @@ static void asm_floating_point_data_processing_opcode(TCCState *s1, int token) { } if (nb_ops < 3) { tcc_error("Not enough operands for '%s' (%u)", get_tok_str(token, NULL), nb_ops); - return; } } @@ -2199,7 +2066,6 @@ static void asm_floating_point_data_processing_opcode(TCCState *s1, int token) { break; default: expect("known floating point instruction"); - return; } if (coprocessor == CP_SINGLE_PRECISION_FLOAT) { @@ -2256,46 +2122,34 @@ static void asm_floating_point_status_register_opcode(TCCState* s1, int token) parse_operand(s1, &arm_operand); if (arm_operand.type == OP_REG32 && arm_operand.reg == 15) { tcc_error("'%s' does not support 'pc' as operand", get_tok_str(token, NULL)); - return; } } - if (tok != ',') - expect("','"); - else - next(); // skip ',' + skip(','); vfp_sys_reg = asm_parse_vfp_status_regvar(tok); next(); // skip vfp sys reg if (arm_operand.type == OP_REG32 && arm_operand.reg == 15 && vfp_sys_reg != 1) { tcc_error("'%s' only supports the variant 'vmrs apsr_nzcv, fpscr' here", get_tok_str(token, NULL)); - return; } break; case TOK_ASM_vmsreq: opcode = 0xe; vfp_sys_reg = asm_parse_vfp_status_regvar(tok); next(); // skip vfp sys reg - if (tok != ',') - expect("','"); - else - next(); // skip ',' + skip(','); parse_operand(s1, &arm_operand); if (arm_operand.type == OP_REG32 && arm_operand.reg == 15) { tcc_error("'%s' does not support 'pc' as operand", get_tok_str(token, NULL)); - return; } break; default: expect("floating point status register instruction"); - return; } if (vfp_sys_reg == -1) { expect("VFP system register"); - return; } if (arm_operand.type != OP_REG32) { expect("ARM register"); - return; } asm_emit_coprocessor_opcode(condition_code_of_token(token), coprocessor, opcode, arm_operand.reg, vfp_sys_reg, 0x10, 0, 0); } @@ -2327,24 +2181,17 @@ static void asm_misc_single_data_transfer_opcode(TCCState *s1, int token) opcode |= ENCODE_RD(ops[0].reg); else { expect("(destination operand) register"); - return; } if (tok != ',') expect("at least two arguments"); else next(); // skip ',' - - if (tok != '[') - expect("'['"); - else - next(); // skip '[' - + skip('['); parse_operand(s1, &ops[1]); if (ops[1].type == OP_REG32) opcode |= ENCODE_RN(ops[1].reg); else { expect("(first source operand) register"); - return; } if (tok == ']') { next(); @@ -2365,10 +2212,7 @@ static void asm_misc_single_data_transfer_opcode(TCCState *s1, int token) opcode |= 1 << 24; // add offset before transfer } if (!closed_bracket) { - if (tok != ']') - expect("']'"); - else - next(); // skip ']' + skip(']'); opcode |= 1 << 24; // add offset before transfer if (tok == '!') { exclam = 1; @@ -2379,7 +2223,6 @@ static void asm_misc_single_data_transfer_opcode(TCCState *s1, int token) if (exclam) { if ((opcode & (1 << 24)) == 0) { tcc_error("result of '%s' would be unpredictable here", get_tok_str(token, NULL)); - return; } opcode |= 1 << 21; // write offset back into register } @@ -2465,7 +2308,6 @@ static void asm_branch_opcode(TCCState *s1, int token) esym = elfsym(e.sym); if (!esym || esym->st_shndx != cur_text_section->sh_num) { tcc_error("invalid branch target"); - return; } jmp_disp = encbranchoffset(ind, e.v + esym->st_value, 1); break; @@ -2518,7 +2360,6 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) return; default: expect("instruction"); - return; } } @@ -2740,7 +2581,6 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier) { int r, reg, size, val; - char buf[64]; r = sv->r; if ((r & VT_VALMASK) == VT_CONST) { @@ -2767,19 +2607,16 @@ ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier) val = sv->c.i; if (modifier == 'n') val = -val; - snprintf(buf, sizeof(buf), "%d", (int) sv->c.i); - cstr_cat(add_str, buf, -1); + cstr_printf(add_str, "%d", (int) sv->c.i); no_offset:; } else if ((r & VT_VALMASK) == VT_LOCAL) { - snprintf(buf, sizeof(buf), "[fp,#%d]", (int) sv->c.i); - cstr_cat(add_str, buf, -1); + cstr_printf(add_str, "[fp,#%d]", (int) sv->c.i); } else if (r & VT_LVAL) { reg = r & VT_VALMASK; if (reg >= VT_CONST) tcc_internal_error(""); - snprintf(buf, sizeof(buf), "[%s]", + cstr_printf(add_str, "[%s]", get_tok_str(TOK_ASM_r0 + reg, NULL)); - cstr_cat(add_str, buf, -1); } else { /* register case */ reg = r & VT_VALMASK; @@ -2808,8 +2645,7 @@ ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier) reg = TOK_ASM_r0 + reg; break; } - snprintf(buf, sizeof(buf), "%s", get_tok_str(reg, NULL)); - cstr_cat(add_str, buf, -1); + cstr_printf(add_str, "%s", get_tok_str(reg, NULL)); } } @@ -2928,7 +2764,6 @@ static inline int constraint_priority(const char *str) break; default: tcc_error("unknown constraint '%c'", c); - pr = 0; } if (pr > priority) priority = pr; diff --git a/arm-link.c b/arm-link.c index 242bb945..fc751fd2 100644 --- a/arm-link.c +++ b/arm-link.c @@ -30,7 +30,7 @@ enum float_abi { #ifdef NEED_RELOC_TYPE /* Returns 1 for a code relocation, 0 for a data relocation. For unknown relocations, returns -1. */ -int code_reloc (int reloc_type) +ST_FUNC int code_reloc (int reloc_type) { switch (reloc_type) { case R_ARM_MOVT_ABS: @@ -68,7 +68,7 @@ int code_reloc (int reloc_type) /* Returns an enumerator to describe whether and when the relocation needs a GOT and/or PLT entry to be created. See tcc.h for a description of the different values. */ -int gotplt_entry_type (int reloc_type) +ST_FUNC int gotplt_entry_type (int reloc_type) { switch (reloc_type) { case R_ARM_NONE: @@ -179,7 +179,7 @@ ST_FUNC void relocate_plt(TCCState *s1) #endif #endif -void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val) +ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val) { ElfW(Sym) *sym; int sym_index, esym_index; diff --git a/arm64-link.c b/arm64-link.c index 568ac1fe..9cd8989b 100644 --- a/arm64-link.c +++ b/arm64-link.c @@ -24,7 +24,7 @@ #ifdef NEED_RELOC_TYPE /* Returns 1 for a code relocation, 0 for a data relocation. For unknown relocations, returns -1. */ -int code_reloc (int reloc_type) +ST_FUNC int code_reloc (int reloc_type) { switch (reloc_type) { case R_AARCH64_ABS32: @@ -58,7 +58,7 @@ int code_reloc (int reloc_type) /* Returns an enumerator to describe whether and when the relocation needs a GOT and/or PLT entry to be created. See tcc.h for a description of the different values. */ -int gotplt_entry_type (int reloc_type) +ST_FUNC int gotplt_entry_type (int reloc_type) { switch (reloc_type) { case R_AARCH64_PREL32: @@ -168,7 +168,7 @@ ST_FUNC void relocate_plt(TCCState *s1) #endif #endif -void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val) +ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val) { int sym_index = ELFW(R_SYM)(rel->r_info), esym_index; #ifdef DEBUG_RELOC diff --git a/c67-link.c b/c67-link.c index 8e7a8b2f..187c13dc 100644 --- a/c67-link.c +++ b/c67-link.c @@ -24,7 +24,7 @@ /* Returns 1 for a code relocation, 0 for a data relocation. For unknown relocations, returns -1. */ -int code_reloc (int reloc_type) +ST_FUNC int code_reloc (int reloc_type) { switch (reloc_type) { case R_C60_32: @@ -45,7 +45,7 @@ int code_reloc (int reloc_type) /* Returns an enumerator to describe whether and when the relocation needs a GOT and/or PLT entry to be created. See tcc.h for a description of the different values. */ -int gotplt_entry_type (int reloc_type) +ST_FUNC int gotplt_entry_type (int reloc_type) { switch (reloc_type) { case R_C60_32: @@ -91,7 +91,7 @@ ST_FUNC void relocate_plt(TCCState *s1) } } -void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val) +ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val) { switch(type) { case R_C60_32: diff --git a/i386-asm.c b/i386-asm.c index ea734ae8..33783d5f 100644 --- a/i386-asm.c +++ b/i386-asm.c @@ -143,10 +143,12 @@ enum { # define TREG_XAX TREG_RAX # define TREG_XCX TREG_RCX # define TREG_XDX TREG_RDX +# define TOK_ASM_xax TOK_ASM_rax #else # define TREG_XAX TREG_EAX # define TREG_XCX TREG_ECX # define TREG_XDX TREG_EDX +# define TOK_ASM_xax TOK_ASM_eax #endif typedef struct ASMInstr { @@ -1505,7 +1507,6 @@ ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier) { int r, reg, size, val; - char buf[64]; r = sv->r; if ((r & VT_VALMASK) == VT_CONST) { @@ -1532,32 +1533,19 @@ ST_FUNC void subst_asm_operand(CString *add_str, val = sv->c.i; if (modifier == 'n') val = -val; - snprintf(buf, sizeof(buf), "%d", (int)sv->c.i); - cstr_cat(add_str, buf, -1); + cstr_printf(add_str, "%d", (int)sv->c.i); no_offset:; #ifdef TCC_TARGET_X86_64 if (r & VT_LVAL) cstr_cat(add_str, "(%rip)", -1); #endif } else if ((r & VT_VALMASK) == VT_LOCAL) { -#ifdef TCC_TARGET_X86_64 - snprintf(buf, sizeof(buf), "%d(%%rbp)", (int)sv->c.i); -#else - snprintf(buf, sizeof(buf), "%d(%%ebp)", (int)sv->c.i); -#endif - cstr_cat(add_str, buf, -1); + cstr_printf(add_str, "%d(%%%s)", (int)sv->c.i, get_tok_str(TOK_ASM_xax + 5, NULL)); } else if (r & VT_LVAL) { reg = r & VT_VALMASK; if (reg >= VT_CONST) tcc_internal_error(""); - snprintf(buf, sizeof(buf), "(%%%s)", -#ifdef TCC_TARGET_X86_64 - get_tok_str(TOK_ASM_rax + reg, NULL) -#else - get_tok_str(TOK_ASM_eax + reg, NULL) -#endif - ); - cstr_cat(add_str, buf, -1); + cstr_printf(add_str, "(%%%s)", get_tok_str(TOK_ASM_xax + reg, NULL)); } else { /* register case */ reg = r & VT_VALMASK; @@ -1617,8 +1605,7 @@ ST_FUNC void subst_asm_operand(CString *add_str, break; #endif } - snprintf(buf, sizeof(buf), "%%%s", get_tok_str(reg, NULL)); - cstr_cat(add_str, buf, -1); + cstr_printf(add_str, "%%%s", get_tok_str(reg, NULL)); } } diff --git a/i386-gen.c b/i386-gen.c index b95c0adb..a892dca0 100644 --- a/i386-gen.c +++ b/i386-gen.c @@ -410,9 +410,7 @@ ST_FUNC void gfunc_call(int nb_args) { int size, align, r, args_size, i, func_call; Sym *func_sym; - // Look ahead to the function on the stack to get the function call type - int func_call2 = ((vtop - nb_args)->type.ref)->f.func_call; - + #ifdef CONFIG_TCC_BCHECK if (tcc_state->do_bounds_check) gbound_args(nb_args); @@ -420,12 +418,6 @@ ST_FUNC void gfunc_call(int nb_args) args_size = 0; for(i = 0;i < nb_args; i++) { - if (func_call2 == FUNC_THISCALL && i == (nb_args - 1)) { - // If thiscall, zap the last push, as it is `this`. Instead, mov into ecx - size = 0; - load(get_reg(RC_ECX), vtop); - } - else if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { size = type_size(&vtop->type, &align); /* align to stack align size */ @@ -486,12 +478,15 @@ ST_FUNC void gfunc_call(int nb_args) func_call = func_sym->f.func_call; /* fast call case */ if ((func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) || - func_call == FUNC_FASTCALLW) { + func_call == FUNC_FASTCALLW || func_call == FUNC_THISCALL) { int fastcall_nb_regs; const uint8_t *fastcall_regs_ptr; if (func_call == FUNC_FASTCALLW) { fastcall_regs_ptr = fastcallw_regs; fastcall_nb_regs = 2; + } else if (func_call == FUNC_THISCALL) { + fastcall_regs_ptr = fastcallw_regs; + fastcall_nb_regs = 1; } else { fastcall_regs_ptr = fastcall_regs; fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1; @@ -531,7 +526,6 @@ ST_FUNC void gfunc_prolog(Sym *func_sym) const uint8_t *fastcall_regs_ptr; Sym *sym; CType *type; - int thiscall_nb_regs; sym = func_type->ref; func_call = sym->f.func_call; @@ -545,15 +539,13 @@ ST_FUNC void gfunc_prolog(Sym *func_sym) } else if (func_call == FUNC_FASTCALLW) { fastcall_nb_regs = 2; fastcall_regs_ptr = fastcallw_regs; + } else if (func_call == FUNC_THISCALL) { + fastcall_nb_regs = 1; + fastcall_regs_ptr = fastcallw_regs; } else { fastcall_nb_regs = 0; fastcall_regs_ptr = NULL; } - - if (func_call == FUNC_THISCALL) { - thiscall_nb_regs = 1; - } - param_index = 0; ind += FUNC_PROLOG_SIZE; @@ -589,14 +581,6 @@ ST_FUNC void gfunc_prolog(Sym *func_sym) o(0x89); /* movl */ gen_modrm(fastcall_regs_ptr[param_index], VT_LOCAL, NULL, loc); param_addr = loc; - } - else if(param_index < thiscall_nb_regs) { - /* Why ? */ - /* save THISCALL register; ECX */ - loc -= 4; - o(0x89); /* movl */ - gen_modrm(TREG_ECX, VT_LOCAL, NULL, loc); - param_addr = loc; } else { param_addr = addr; addr += size; diff --git a/i386-link.c b/i386-link.c index 2fb14637..278df264 100644 --- a/i386-link.c +++ b/i386-link.c @@ -25,7 +25,7 @@ #ifdef NEED_RELOC_TYPE /* Returns 1 for a code relocation, 0 for a data relocation. For unknown relocations, returns -1. */ -int code_reloc (int reloc_type) +ST_FUNC int code_reloc (int reloc_type) { switch (reloc_type) { case R_386_RELATIVE: @@ -55,7 +55,7 @@ int code_reloc (int reloc_type) /* Returns an enumerator to describe whether and when the relocation needs a GOT and/or PLT entry to be created. See tcc.h for a description of the different values. */ -int gotplt_entry_type (int reloc_type) +ST_FUNC int gotplt_entry_type (int reloc_type) { switch (reloc_type) { case R_386_RELATIVE: @@ -171,7 +171,7 @@ ST_FUNC void relocate_plt(TCCState *s1) #endif #endif -void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val) +ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val) { int sym_index, esym_index; diff --git a/libtcc.c b/libtcc.c index 9d4fdac0..5b6606e9 100644 --- a/libtcc.c +++ b/libtcc.c @@ -201,7 +201,8 @@ ST_FUNC char *tcc_load_text(int fd) { int len = lseek(fd, 0, SEEK_END); char *buf = load_data(fd, 0, len + 1); - buf[len] = 0; + if (buf) + buf[len] = 0; return buf; } @@ -336,7 +337,8 @@ PUB_FUNC void *tcc_malloc_debug(unsigned long size, const char *file, int line) { int ofs; mem_debug_header_t *header; - + if (!size) + return NULL; header = tcc_malloc(sizeof(mem_debug_header_t) + size); header->magic1 = MEM_DEBUG_MAGIC1; header->magic2 = MEM_DEBUG_MAGIC2; @@ -346,7 +348,6 @@ PUB_FUNC void *tcc_malloc_debug(unsigned long size, const char *file, int line) ofs = strlen(file) - MEM_DEBUG_FILE_LEN; strncpy(header->file_name, file + (ofs > 0 ? ofs : 0), MEM_DEBUG_FILE_LEN); header->file_name[MEM_DEBUG_FILE_LEN] = 0; - WAIT_SEM(&mem_sem); header->next = mem_debug_chain; header->prev = NULL; @@ -357,7 +358,6 @@ PUB_FUNC void *tcc_malloc_debug(unsigned long size, const char *file, int line) if (mem_cur_size > mem_max_size) mem_max_size = mem_cur_size; POST_SEM(&mem_sem); - return MEM_USER_PTR(header); } @@ -367,7 +367,6 @@ PUB_FUNC void tcc_free_debug(void *ptr) if (!ptr) return; header = malloc_check(ptr, "tcc_free"); - WAIT_SEM(&mem_sem); mem_cur_size -= header->size; header->size = (unsigned)-1; @@ -385,7 +384,8 @@ PUB_FUNC void *tcc_mallocz_debug(unsigned long size, const char *file, int line) { void *ptr; ptr = tcc_malloc_debug(size,file,line); - memset(ptr, 0, size); + if (size) + memset(ptr, 0, size); return ptr; } @@ -393,10 +393,14 @@ PUB_FUNC void *tcc_realloc_debug(void *ptr, unsigned long size, const char *file { mem_debug_header_t *header; int mem_debug_chain_update = 0; + if (!ptr) return tcc_malloc_debug(size, file, line); + if (!size) { + tcc_free_debug(ptr); + return NULL; + } header = malloc_check(ptr, "tcc_realloc"); - WAIT_SEM(&mem_sem); mem_cur_size -= header->size; mem_debug_chain_update = (header == mem_debug_chain); @@ -413,7 +417,6 @@ PUB_FUNC void *tcc_realloc_debug(void *ptr, unsigned long size, const char *file if (mem_cur_size > mem_max_size) mem_max_size = mem_cur_size; POST_SEM(&mem_sem); - return MEM_USER_PTR(header); } @@ -441,6 +444,7 @@ PUB_FUNC void tcc_memcheck(int d) } fflush(stderr); mem_cur_size = 0; + mem_max_size = 0; mem_debug_chain = NULL; #if MEM_DEBUG-0 == 2 exit(2); @@ -1425,24 +1429,24 @@ static int tcc_set_linker(TCCState *s, const char *option) s->pe_stack_size = strtoul(p, &end, 10); } else if (link_option(option, "subsystem=", &p)) { #if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) - if (!strcmp(p, "native")) { + if (strstart("native", &p)) { s->pe_subsystem = 1; - } else if (!strcmp(p, "console")) { + } else if (strstart("console", &p)) { s->pe_subsystem = 3; - } else if (!strcmp(p, "gui") || !strcmp(p, "windows")) { + } else if (strstart("gui", &p) || strstart("windows", &p)) { s->pe_subsystem = 2; - } else if (!strcmp(p, "posix")) { + } else if (strstart("posix", &p)) { s->pe_subsystem = 7; - } else if (!strcmp(p, "efiapp")) { + } else if (strstart("efiapp", &p)) { s->pe_subsystem = 10; - } else if (!strcmp(p, "efiboot")) { + } else if (strstart("efiboot", &p)) { s->pe_subsystem = 11; - } else if (!strcmp(p, "efiruntime")) { + } else if (strstart("efiruntime", &p)) { s->pe_subsystem = 12; - } else if (!strcmp(p, "efirom")) { + } else if (strstart("efirom", &p)) { s->pe_subsystem = 13; #elif defined(TCC_TARGET_ARM) - if (!strcmp(p, "wince")) { + if (strstart("wince", &p)) { s->pe_subsystem = 9; #endif } else @@ -2211,3 +2215,9 @@ PUB_FUNC void tcc_print_stats(TCCState *s1, unsigned total_time) fprintf(stderr, " %d max (bytes)\n", mem_max_size); #endif } + +#if ONE_SOURCE +# undef malloc +# undef realloc +# undef free +#endif diff --git a/riscv64-asm.c b/riscv64-asm.c index 2b4f496b..8b7c4cef 100644 --- a/riscv64-asm.c +++ b/riscv64-asm.c @@ -48,6 +48,10 @@ typedef struct Operand { }; } Operand; +static const Operand zero = { OP_REG, { 0 }}; +static const Operand ra = { OP_REG, { 1 }}; +static const Operand zimm = { OP_IM12S }; + static void asm_binary_opcode(TCCState* s1, int token); ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str); ST_FUNC void asm_compute_constraints(ASMOperand *operands, int nb_operands, int nb_outputs, const uint8_t *clobber_regs, int *pout_reg); @@ -128,9 +132,6 @@ static void asm_emit_opcode(uint32_t opcode) { static void asm_nullary_opcode(TCCState *s1, int token) { - static const Operand nil = {.type = OP_REG}; - static const Operand zimm = {.type = OP_IM12S}; - switch (token) { // Sync instructions @@ -150,7 +151,7 @@ static void asm_nullary_opcode(TCCState *s1, int token) // Other case TOK_ASM_nop: - asm_emit_i(token, (4 << 2) | 3, &nil, &nil, &zimm); + asm_emit_i(token, (4 << 2) | 3, &zero, &zero, &zimm); return; case TOK_ASM_wfi: @@ -165,10 +166,10 @@ static void asm_nullary_opcode(TCCState *s1, int token) /* C extension */ case TOK_ASM_c_ebreak: - asm_emit_cr(token, 2 | (9 << 12), &nil, &nil); + asm_emit_cr(token, 2 | (9 << 12), &zero, &zero); return; case TOK_ASM_c_nop: - asm_emit_ci(token, 1, &nil, &zimm); + asm_emit_ci(token, 1, &zero, &zimm); return; default: @@ -266,33 +267,24 @@ static void parse_jump_offset_operand(TCCState *s1, Operand *op){ static void parse_operands(TCCState *s1, Operand* ops, int count){ int i; for (i = 0; i < count; i++) { - if ( i != 0 ) { - if ( tok == ',') - next(); - else - expect("','"); - } + if ( i != 0 ) + skip(','); parse_operand(s1, &ops[i]); } } /* parse `X, imm(Y)` to {X, Y, imm} operands */ static void parse_mem_access_operands(TCCState *s1, Operand* ops){ - static const Operand zimm = {.type = OP_IM12S}; Operand op; parse_operand(s1, &ops[0]); - if ( tok == ',') - next(); - else - expect("','"); - + skip(','); if ( tok == '(') { /* `X, (Y)` case*/ next(); parse_operand(s1, &ops[1]); - if ( tok == ')') next(); else expect("')'"); + skip(')'); ops[2] = zimm; } else { parse_operand(s1, &ops[2]); @@ -300,7 +292,7 @@ static void parse_mem_access_operands(TCCState *s1, Operand* ops){ /* `X, imm(Y)` case*/ next(); parse_operand(s1, &ops[1]); - if ( tok == ')') next(); else expect("')'"); + skip(')'); } else { /* `X, Y` case*/ /* we parsed Y thinking it was imm, swap and default imm to zero */ @@ -314,8 +306,6 @@ static void parse_mem_access_operands(TCCState *s1, Operand* ops){ /* This is special: First operand is optional */ static void asm_jal_opcode(TCCState *s1, int token){ - static const Operand ra = {.type = OP_REG, .reg = 1}; - static const Operand zero = {.type = OP_REG}; Operand ops[2]; if (token == TOK_ASM_j ){ @@ -333,8 +323,6 @@ static void asm_jal_opcode(TCCState *s1, int token){ /* This is special: It can be a pseudointruction or a instruction */ static void asm_jalr_opcode(TCCState *s1, int token){ - static const Operand zimm = {.type = OP_IM12S}; - static const Operand ra = {.type = OP_REG, .reg = 1}; Operand ops[3]; Operand op; @@ -355,7 +343,7 @@ static void asm_jalr_opcode(TCCState *s1, int token){ /* `X, (Y)` case*/ next(); parse_operand(s1, &ops[1]); - if ( tok == ')') next(); else expect("')'"); + skip(')'); ops[2] = zimm; } else { parse_operand(s1, &ops[2]); @@ -363,7 +351,7 @@ static void asm_jalr_opcode(TCCState *s1, int token){ /* `X, imm(Y)` case*/ next(); parse_operand(s1, &ops[1]); - if ( tok == ')') next(); else expect("')'"); + skip(')'); } else { /* `X, Y` case*/ /* we parsed Y thinking it was imm, swap and default imm to zero */ @@ -382,8 +370,6 @@ static void asm_unary_opcode(TCCState *s1, int token) { uint32_t opcode = (0x1C << 2) | 3 | (2 << 12); Operand op; - static const Operand zero = {.type = OP_REG}; - static const Operand zimm = {.type = OP_IM12S}; parse_operands(s1, &op, 1); /* Note: Those all map to CSR--so they are pseudo-instructions. */ @@ -451,14 +437,11 @@ static void asm_emit_u(int token, uint32_t opcode, const Operand* rd, const Oper { if (rd->type != OP_REG) { tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL)); - return; } if (rs2->type != OP_IM12S && rs2->type != OP_IM32) { tcc_error("'%s': Expected second source operand that is an immediate value", get_tok_str(token, NULL)); - return; } else if (rs2->e.v >= 0x100000) { tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 0xfffff", get_tok_str(token, NULL)); - return; } /* U-type instruction: 31...12 imm[31:12] @@ -486,7 +469,7 @@ static void asm_fence_opcode(TCCState *s1, int token){ if ( pred > 0xF || pred < 0) { tcc_error("'%s': Expected first operand that is a valid predecessor operand", get_tok_str(token, NULL)); } - if ( tok == ',') next(); else expect("','"); + skip(','); succ = parse_fence_operand(); if ( succ > 0xF || succ < 0) { tcc_error("'%s': Expected second operand that is a valid successor operand", get_tok_str(token, NULL)); @@ -497,8 +480,7 @@ static void asm_fence_opcode(TCCState *s1, int token){ static void asm_binary_opcode(TCCState* s1, int token) { - static const Operand zero = {.type = OP_REG, .reg = 0}; - Operand imm = {.type = OP_IM12S, .e = {.v = 0}}; + Operand imm = { OP_IM12S }; Operand ops[2]; int32_t lo; uint32_t hi; @@ -710,15 +692,12 @@ static void asm_emit_r(int token, uint32_t opcode, const Operand* rd, const Oper { if (rd->type != OP_REG) { tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL)); - return; } if (rs1->type != OP_REG) { tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token, NULL)); - return; } if (rs2->type != OP_REG) { tcc_error("'%s': Expected second source operand that is a register or immediate", get_tok_str(token, NULL)); - return; } /* R-type instruction: 31...25 funct7 @@ -735,15 +714,12 @@ static void asm_emit_i(int token, uint32_t opcode, const Operand* rd, const Oper { if (rd->type != OP_REG) { tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL)); - return; } if (rs1->type != OP_REG) { tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token, NULL)); - return; } if (rs2->type != OP_IM12S) { tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 8191", get_tok_str(token, NULL)); - return; } /* I-type instruction: 31...20 imm[11:0] @@ -761,11 +737,9 @@ static void asm_emit_j(int token, uint32_t opcode, const Operand* rd, const Oper if (rd->type != OP_REG) { tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL)); - return; } if (rs2->type != OP_IM12S && rs2->type != OP_IM32) { tcc_error("'%s': Expected second source operand that is an immediate value", get_tok_str(token, NULL)); - return; } imm = rs2->e.v; @@ -773,12 +747,10 @@ static void asm_emit_j(int token, uint32_t opcode, const Operand* rd, const Oper /* even offsets in a +- 1 MiB range */ if ((int)imm > (1 << 20) -1 || (int)imm <= -1 * ((1 << 20) -1)) { tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 0x1fffff", get_tok_str(token, NULL)); - return; } if (imm & 1) { tcc_error("'%s': Expected second source operand that is an even immediate value", get_tok_str(token, NULL)); - return; } /* J-type instruction: 31 imm[20] @@ -851,11 +823,11 @@ static void asm_mem_access_opcode(TCCState *s1, int token) } } -static void asm_branch_opcode(TCCState *s1, int token, int argc){ +static void asm_branch_opcode(TCCState *s1, int token, int argc) +{ Operand ops[3]; - Operand zero = {.type = OP_REG}; parse_operands(s1, &ops[0], argc-1); - if ( tok == ',') next(); else { expect(","); } + skip(','); parse_branch_offset_operand(s1, &ops[argc-1]); switch(token){ @@ -1118,22 +1090,21 @@ static void asm_ternary_opcode(TCCState *s1, int token) static void asm_atomic_opcode(TCCState *s1, int token) { - static const Operand zero = {.type = OP_REG}; Operand ops[3]; parse_operand(s1, &ops[0]); - if ( tok == ',') next(); else expect("','"); + skip(','); if ( token <= TOK_ASM_lr_d_aqrl && token >= TOK_ASM_lr_w ) { ops[1] = zero; } else { parse_operand(s1, &ops[1]); - if ( tok == ',') next(); else expect("','"); + skip(','); } - if ( tok == '(') next(); else expect("'('"); + skip('('); parse_operand(s1, &ops[2]); - if ( tok == ')') next(); else expect("')'"); + skip(')'); switch(token){ case TOK_ASM_lr_w: @@ -1217,15 +1188,12 @@ static void asm_emit_s(int token, uint32_t opcode, const Operand* rs1, const Ope { if (rs1->type != OP_REG) { tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token, NULL)); - return; } if (rs2->type != OP_REG) { tcc_error("'%s': Expected second source operand that is a register", get_tok_str(token, NULL)); - return; } if (imm->type != OP_IM12S) { tcc_error("'%s': Expected third operand that is an immediate value between 0 and 8191", get_tok_str(token, NULL)); - return; } { uint16_t v = imm->e.v; @@ -1247,15 +1215,12 @@ static void asm_emit_b(int token, uint32_t opcode, const Operand *rs1, const Ope if (rs1->type != OP_REG) { tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token, NULL)); - return; } if (rs2->type != OP_REG) { tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL)); - return; } if (imm->type != OP_IM12S) { tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 8191", get_tok_str(token, NULL)); - return; } offset = imm->e.v; @@ -1541,7 +1506,6 @@ static int asm_parse_csrvar(int t) ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier) { int r, reg, val; - char buf[64]; r = sv->r; if ((r & VT_VALMASK) == VT_CONST) { @@ -1572,13 +1536,11 @@ ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier) if (modifier == 'z' && sv->c.i == 0) { cstr_cat(add_str, "zero", -1); } else { - snprintf(buf, sizeof(buf), "%d", (int) sv->c.i); - cstr_cat(add_str, buf, -1); + cstr_printf(add_str, "%d", (int) sv->c.i); } no_offset:; } else if ((r & VT_VALMASK) == VT_LOCAL) { - snprintf(buf, sizeof(buf), "%d", (int) sv->c.i); - cstr_cat(add_str, buf, -1); + cstr_printf(add_str, "%d", (int) sv->c.i); } else if (r & VT_LVAL) { reg = r & VT_VALMASK; if (reg >= VT_CONST) @@ -1591,8 +1553,7 @@ ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier) /* general purpose register */ reg = TOK_ASM_x0 + reg; } - snprintf(buf, sizeof(buf), "%s", get_tok_str(reg, NULL)); - cstr_cat(add_str, buf, -1); + cstr_cat(add_str, get_tok_str(reg, NULL), -1); } else { /* register case */ reg = r & VT_VALMASK; @@ -1606,8 +1567,7 @@ ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier) /* general purpose register */ reg = TOK_ASM_x0 + reg; } - snprintf(buf, sizeof(buf), "%s", get_tok_str(reg, NULL)); - cstr_cat(add_str, buf, -1); + cstr_cat(add_str, get_tok_str(reg, NULL), -1); } } @@ -1775,12 +1735,9 @@ static inline int constraint_priority(const char *str) pr = 4; break; case 'v': - tcc_error("unimp: vector constraints '%d'", c); - pr = 0; - break; + tcc_error("unimp: constraint '%c'", c); default: tcc_error("unknown constraint '%d'", c); - pr = 0; } if (pr > priority) priority = pr; @@ -2093,12 +2050,10 @@ static void asm_emit_ca(int token, uint16_t opcode, const Operand *rd, const Ope if (rd->type != OP_REG) { tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL)); - return; } if (rs2->type != OP_REG) { tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL)); - return; } /* subtract index of x8 */ @@ -2108,12 +2063,10 @@ static void asm_emit_ca(int token, uint16_t opcode, const Operand *rd, const Ope /* only registers {x,f}8 to {x,f}15 are valid (3-bit) */ if (dst > 7) { tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token, NULL)); - return; } if (src > 7) { tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token, NULL)); - return; } /* CA-type instruction: @@ -2133,26 +2086,22 @@ static void asm_emit_cb(int token, uint16_t opcode, const Operand *rs1, const Op if (rs1->type != OP_REG) { tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL)); - return; } if (imm->type != OP_IM12S && imm->type != OP_IM32) { tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL)); - return; } offset = imm->e.v; if (offset & 1) { tcc_error("'%s': Expected source operand that is an even immediate value", get_tok_str(token, NULL)); - return; } src = rs1->reg - 8; if (src > 7) { tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token, NULL)); - return; } /* CB-type instruction: @@ -2187,12 +2136,10 @@ static void asm_emit_ci(int token, uint16_t opcode, const Operand *rd, const Ope if (rd->type != OP_REG) { tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL)); - return; } if (imm->type != OP_IM12S && imm->type != OP_IM32) { tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL)); - return; } immediate = imm->e.v; @@ -2241,31 +2188,26 @@ static void asm_emit_ciw(int token, uint16_t opcode, const Operand *rd, const Op if (rd->type != OP_REG) { tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL)); - return; } if (imm->type != OP_IM12S && imm->type != OP_IM32) { tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL)); - return; } dst = rd->reg - 8; if (dst > 7) { tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token, NULL)); - return; } nzuimm = imm->e.v; if (nzuimm > 0x3fc) { tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0x3ff", get_tok_str(token, NULL)); - return; } if (nzuimm & 3) { tcc_error("'%s': Expected source operand that is a non-zero immediate value divisible by 4", get_tok_str(token, NULL)); - return; } /* CIW-type instruction: @@ -2285,14 +2227,12 @@ static void asm_emit_cj(int token, uint16_t opcode, const Operand *imm) /* +-2 KiB range */ if (imm->type != OP_IM12S) { tcc_error("'%s': Expected source operand that is a 12-bit immediate value", get_tok_str(token, NULL)); - return; } offset = imm->e.v; if (offset & 1) { tcc_error("'%s': Expected source operand that is an even immediate value", get_tok_str(token, NULL)); - return; } /* CJ-type instruction: @@ -2311,17 +2251,14 @@ static void asm_emit_cl(int token, uint16_t opcode, const Operand *rd, const Ope if (rd->type != OP_REG) { tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL)); - return; } if (rs1->type != OP_REG) { tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL)); - return; } if (imm->type != OP_IM12S && imm->type != OP_IM32) { tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL)); - return; } dst = rd->reg - 8; @@ -2329,24 +2266,20 @@ static void asm_emit_cl(int token, uint16_t opcode, const Operand *rd, const Ope if (dst > 7) { tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token, NULL)); - return; } if (src > 7) { tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token, NULL)); - return; } offset = imm->e.v; if (offset > 0xff) { tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0xff", get_tok_str(token, NULL)); - return; } if (offset & 3) { tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token, NULL)); - return; } /* CL-type instruction: @@ -2378,12 +2311,10 @@ static void asm_emit_cr(int token, uint16_t opcode, const Operand *rd, const Ope { if (rd->type != OP_REG) { tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL)); - return; } if (rs2->type != OP_REG) { tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL)); - return; } /* CR-type instruction: @@ -2403,17 +2334,14 @@ static void asm_emit_cs(int token, uint16_t opcode, const Operand *rs2, const Op if (rs2->type != OP_REG) { tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL)); - return; } if (rs1->type != OP_REG) { tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL)); - return; } if (imm->type != OP_IM12S && imm->type != OP_IM32) { tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL)); - return; } base = rs1->reg - 8; @@ -2421,24 +2349,20 @@ static void asm_emit_cs(int token, uint16_t opcode, const Operand *rs2, const Op if (base > 7) { tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token, NULL)); - return; } if (src > 7) { tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token, NULL)); - return; } offset = imm->e.v; if (offset > 0xff) { tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0xff", get_tok_str(token, NULL)); - return; } if (offset & 3) { tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token, NULL)); - return; } /* CS-type instruction: @@ -2471,24 +2395,20 @@ static void asm_emit_css(int token, uint16_t opcode, const Operand *rs2, const O if (rs2->type != OP_REG) { tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL)); - return; } if (imm->type != OP_IM12S && imm->type != OP_IM32) { tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL)); - return; } offset = imm->e.v; if (offset > 0xff) { tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0xff", get_tok_str(token, NULL)); - return; } if (offset & 3) { tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token, NULL)); - return; } /* CSS-type instruction: diff --git a/riscv64-link.c b/riscv64-link.c index 39c0c5d2..f10e7c03 100644 --- a/riscv64-link.c +++ b/riscv64-link.c @@ -24,7 +24,7 @@ /* Returns 1 for a code relocation, 0 for a data relocation. For unknown relocations, returns -1. */ -int code_reloc (int reloc_type) +ST_FUNC int code_reloc (int reloc_type) { switch (reloc_type) { @@ -62,7 +62,7 @@ int code_reloc (int reloc_type) /* Returns an enumerator to describe whether and when the relocation needs a GOT and/or PLT entry to be created. See tcc.h for a description of the different values. */ -int gotplt_entry_type (int reloc_type) +ST_FUNC int gotplt_entry_type (int reloc_type) { switch (reloc_type) { case R_RISCV_ALIGN: @@ -169,7 +169,7 @@ ST_FUNC void relocate_plt(TCCState *s1) } } -void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, +ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val) { uint64_t off64; diff --git a/tcc.h b/tcc.h index 84429ac1..e4c38b53 100644 --- a/tcc.h +++ b/tcc.h @@ -89,7 +89,6 @@ extern long double strtold (const char *__nptr, char **__endptr); # ifndef va_copy # define va_copy(a,b) a = b # endif -# undef CONFIG_TCC_STATIC #endif #ifndef O_BINARY @@ -487,7 +486,7 @@ typedef int nwchar_t; typedef struct CString { int size; /* size in bytes */ int size_allocated; - void *data; /* either 'char *' or 'nwchar_t *' */ + char *data; /* nwchar_t* in cases */ } CString; /* type definition */ @@ -1157,7 +1156,7 @@ struct filespec { #define TOK_TWODOTS 0xa2 /* C++ token ? */ #define TOK_TWOSHARPS 0xa3 /* ## preprocessing token */ #define TOK_PLCHLDR 0xa4 /* placeholder token as defined in C99 */ -#define TOK_PPJOIN 0xa6 /* A '##' in the right position to mean pasting */ +#define TOK_PPJOIN (TOK_TWOSHARPS | SYM_FIELD) /* A '##' in a macro to mean pasting */ #define TOK_SOTYPE 0xa7 /* alias of '(' for parsing sizeof (type) */ /* assignment operators */ @@ -1253,8 +1252,8 @@ ST_FUNC void libc_free(void *ptr); PUB_FUNC int _tcc_error_noabort(const char *fmt, ...) PRINTF_LIKE(1,2); PUB_FUNC NORETURN void _tcc_error(const char *fmt, ...) PRINTF_LIKE(1,2); PUB_FUNC void _tcc_warning(const char *fmt, ...) PRINTF_LIKE(1,2); -#define tcc_internal_error(msg) tcc_error("internal compiler error\n"\ - "%s:%d: in %s(): " msg, __FILE__,__LINE__,__FUNCTION__) +#define tcc_internal_error(msg) \ + tcc_error("internal compiler error in %s:%d: %s", __FUNCTION__,__LINE__,msg) /* other utilities */ ST_FUNC void dynarray_add(void *ptab, int *nb_ptr, void *data); diff --git a/tccelf.c b/tccelf.c index fab49c48..c01854ad 100644 --- a/tccelf.c +++ b/tccelf.c @@ -153,9 +153,12 @@ ST_FUNC void tccelf_begin_file(TCCState *s1) s = s1->symtab, s->reloc = s->hash, s->hash = NULL; #if defined TCC_TARGET_X86_64 && defined TCC_TARGET_PE s1->uw_sym = 0; + s1->uw_offs = 0; #endif } +static void update_relocs(TCCState *s1, Section *s, int *old_to_new_syms, int first_sym); + /* At the end of compilation, convert any UNDEF syms to global, and merge with previously existing symbols */ ST_FUNC void tccelf_end_file(TCCState *s1) @@ -172,7 +175,6 @@ 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) { int sym_bind = ELFW(ST_BIND)(sym->st_info); int sym_type = ELFW(ST_TYPE)(sym->st_info); @@ -187,26 +189,12 @@ ST_FUNC void tccelf_end_file(TCCState *s1) #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); } /* now update relocations */ - for (i = 1; i < s1->nb_sections; i++) { - Section *sr = s1->sections[i]; - if (sr->sh_type == SHT_RELX && sr->link == s) { - ElfW_Rel *rel = (ElfW_Rel*)(sr->data + sr->sh_offset); - ElfW_Rel *rel_end = (ElfW_Rel*)(sr->data + sr->data_offset); - for (; rel < rel_end; ++rel) { - int n = ELFW(R_SYM)(rel->r_info) - first_sym; - if (n < 0) /* zero sym_index in reloc (can happen with asm) */ - continue; - rel->r_info = ELFW(R_INFO)(tr[n], ELFW(R_TYPE)(rel->r_info)); - } - } - } + update_relocs(s1, s, tr, first_sym); tcc_free(tr); - /* record text/data/bss output for -bench info */ for (i = 0; i < 4; ++i) { s = s1->sections[i + 1]; @@ -801,7 +789,7 @@ ST_FUNC struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc) return &s1->sym_attrs[index]; } -static void modify_reloctions_old_to_new(TCCState *s1, Section *s, int *old_to_new_syms) +static void update_relocs(TCCState *s1, Section *s, int *old_to_new_syms, int first_sym) { int i, type, sym_index; Section *sr; @@ -813,6 +801,8 @@ static void modify_reloctions_old_to_new(TCCState *s1, Section *s, int *old_to_n for_each_elem(sr, 0, rel, ElfW_Rel) { sym_index = ELFW(R_SYM)(rel->r_info); type = ELFW(R_TYPE)(rel->r_info); + if ((sym_index -= first_sym) < 0) + continue; /* zero sym_index in reloc (can happen with asm) */ sym_index = old_to_new_syms[sym_index]; rel->r_info = ELFW(R_INFO)(sym_index, type); } @@ -863,8 +853,7 @@ static void sort_syms(TCCState *s1, Section *s) memcpy(s->data, new_syms, nb_syms * sizeof(ElfW(Sym))); tcc_free(new_syms); - modify_reloctions_old_to_new(s1, s, old_to_new_syms); - + update_relocs(s1, s, old_to_new_syms, 0); tcc_free(old_to_new_syms); } @@ -1012,7 +1001,7 @@ static void update_gnu_hash(TCCState *s1, Section *gnu_hash) tcc_free(buck); tcc_free(nextbuck); - modify_reloctions_old_to_new(s1, dynsym, old_to_new_syms); + update_relocs(s1, dynsym, old_to_new_syms, 0); /* modify the versions */ vs = versym_section; diff --git a/tccgen.c b/tccgen.c index 22d42bfe..abde20c4 100644 --- a/tccgen.c +++ b/tccgen.c @@ -657,8 +657,6 @@ ST_FUNC Sym *sym_find2(Sym *s, int v) while (s) { if (s->v == v) return s; - else if (s->v == -1) - return NULL; s = s->prev; } return NULL; @@ -1398,6 +1396,7 @@ ST_FUNC void save_reg_upstack(int r, int n) p->r = (p->r & ~(VT_VALMASK | VT_BOUNDED)) | VT_LLOCAL; } else { p->r = VT_LVAL | VT_LOCAL; + p->type.t &= ~VT_ARRAY; /* cannot combine VT_LVAL with VT_ARRAY */ } p->sym = NULL; p->r2 = VT_CONST; @@ -2838,14 +2837,25 @@ static int compare_types(CType *type1, CType *type2, int unqualified) } } +#define CMP_OP 'C' +#define SHIFT_OP 'S' + /* Check if OP1 and OP2 can be "combined" with operation OP, the combined type is stored in DEST if non-null (except for pointer plus/minus) . */ static int combine_types(CType *dest, SValue *op1, SValue *op2, int op) { - CType *type1 = &op1->type, *type2 = &op2->type, type; - int t1 = type1->t, t2 = type2->t, bt1 = t1 & VT_BTYPE, bt2 = t2 & VT_BTYPE; + CType *type1, *type2, type; + int t1, t2, bt1, bt2; int ret = 1; + /* for shifts, 'combine' only left operand */ + if (op == SHIFT_OP) + op2 = op1; + + type1 = &op1->type, type2 = &op2->type; + t1 = type1->t, t2 = type2->t; + bt1 = t1 & VT_BTYPE, bt2 = t2 & VT_BTYPE; + type.t = VT_VOID; type.ref = NULL; @@ -2854,7 +2864,10 @@ static int combine_types(CType *dest, SValue *op1, SValue *op2, int op) /* NOTE: as an extension, we accept void on only one side */ type.t = VT_VOID; } else if (bt1 == VT_PTR || bt2 == VT_PTR) { - if (op == '+') ; /* Handled in caller */ + if (op == '+') { + if (!is_integer_btype(bt1 == VT_PTR ? bt2 : bt1)) + ret = 0; + } /* http://port70.net/~nsz/c/c99/n1256.html#6.5.15p6 */ /* If one is a null ptr constant the result type is the other. */ else if (is_null_pointer (op2)) type = *type1; @@ -2862,7 +2875,7 @@ static int combine_types(CType *dest, SValue *op1, SValue *op2, int op) else if (bt1 != bt2) { /* accept comparison or cond-expr between pointer and integer with a warning */ - if ((op == '?' || TOK_ISCOND(op)) + if ((op == '?' || op == CMP_OP) && (is_integer_btype(bt1) || is_integer_btype(bt2))) tcc_warning("pointer/integer mismatch in %s", op == '?' ? "conditional expression" : "comparison"); @@ -2877,7 +2890,7 @@ static int combine_types(CType *dest, SValue *op1, SValue *op2, int op) int newquals, copied = 0; if (pbt1 != VT_VOID && pbt2 != VT_VOID && !compare_types(pt1, pt2, 1/*unqualif*/)) { - if (op != '?' && !TOK_ISCOND(op)) + if (op != '?' && op != CMP_OP) ret = 0; else type_incompatibility_warning(type1, type2, @@ -2918,7 +2931,7 @@ static int combine_types(CType *dest, SValue *op1, SValue *op2, int op) } } } - if (TOK_ISCOND(op)) + if (op == CMP_OP) type.t = VT_SIZE_T; } else if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) { if (op != '?' || !compare_types(type1, type2, 1)) @@ -2961,6 +2974,12 @@ ST_FUNC void gen_op(int op) { int t1, t2, bt1, bt2, t; CType type1, combtype; + int op_class = op; + + if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL) + op_class = SHIFT_OP; + else if (TOK_ISCOND(op)) /* == != > ... */ + op_class = CMP_OP; redo: t1 = vtop[-1].type.t; @@ -2980,18 +2999,19 @@ redo: vswap(); } goto redo; - } else if (!combine_types(&combtype, vtop - 1, vtop, op)) { + } else if (!combine_types(&combtype, vtop - 1, vtop, op_class)) { +op_err: tcc_error("invalid operand types for binary operation"); } else if (bt1 == VT_PTR || bt2 == VT_PTR) { /* at least one operand is a pointer */ /* relational op: must be both pointers */ int align; - if (TOK_ISCOND(op)) + if (op_class == CMP_OP) goto std_op; /* if both pointers, then it must be the '-' op */ if (bt1 == VT_PTR && bt2 == VT_PTR) { if (op != '-') - tcc_error("cannot use pointers here"); + goto op_err; vpush_type_size(pointed_type(&vtop[-1].type), &align); vtop->type.t &= ~VT_UNSIGNED; vrott(3); @@ -3002,14 +3022,15 @@ redo: } else { /* exactly one pointer : must be '+' or '-'. */ if (op != '-' && op != '+') - tcc_error("cannot use pointers here"); + goto op_err; /* Put pointer as first operand */ if (bt2 == VT_PTR) { vswap(); t = t1, t1 = t2, t2 = t; + bt2 = bt1; } #if PTR_SIZE == 4 - if ((vtop[0].type.t & VT_BTYPE) == VT_LLONG) + if (bt2 == VT_LLONG) /* XXX: truncate here because gen_opl can't handle ptr + long long */ gen_cast_s(VT_INT); #endif @@ -3039,17 +3060,15 @@ redo: /* floats can only be used for a few operations */ if (is_float(combtype.t) && op != '+' && op != '-' && op != '*' && op != '/' - && !TOK_ISCOND(op)) - tcc_error("invalid operands for binary operation"); - else if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL) { - t = bt1 == VT_LLONG ? VT_LLONG : VT_INT; - if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (t | VT_UNSIGNED)) - t |= VT_UNSIGNED; - t |= (VT_LONG & t1); - combtype.t = t; + && op_class != CMP_OP) { + goto op_err; } std_op: t = t2 = combtype.t; + /* special case for shifts and long long: we keep the shift as + an integer */ + if (op_class == SHIFT_OP) + t2 = VT_INT; /* XXX: currently, some unsigned operations are explicit, so we modify them here */ if (t & VT_UNSIGNED) { @@ -3071,16 +3090,12 @@ redo: vswap(); gen_cast_s(t); vswap(); - /* special case for shifts and long long: we keep the shift as - an integer */ - if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL) - t2 = VT_INT; gen_cast_s(t2); if (is_float(t)) gen_opif(op); else gen_opic(op); - if (TOK_ISCOND(op)) { + if (op_class == CMP_OP) { /* relational op: the result is an int */ vtop->type.t = VT_INT; } else { @@ -3416,13 +3431,10 @@ ST_FUNC int type_size(CType *type, int *a) } else if (bt == VT_PTR) { if (type->t & VT_ARRAY) { int ts; - s = type->ref; ts = type_size(&s->type, a); - if (ts < 0 && s->c < 0) ts = -ts; - return ts * s->c; } else { *a = PTR_SIZE; @@ -3435,18 +3447,9 @@ ST_FUNC int type_size(CType *type, int *a) *a = LDOUBLE_ALIGN; return LDOUBLE_SIZE; } else if (bt == VT_DOUBLE || bt == VT_LLONG) { -#ifdef TCC_TARGET_I386 -#ifdef TCC_TARGET_PE - *a = 8; -#else +#if (defined TCC_TARGET_I386 && !defined TCC_TARGET_PE) \ + || (defined TCC_TARGET_ARM && !defined TCC_ARM_EABI) *a = 4; -#endif -#elif defined(TCC_TARGET_ARM) -#ifdef TCC_ARM_EABI - *a = 8; -#else - *a = 4; -#endif #else *a = 8; #endif @@ -3974,12 +3977,12 @@ redo: case TOK_FASTCALL2: case TOK_FASTCALL3: ad->f.func_call = FUNC_FASTCALLW; - break; + break; case TOK_THISCALL1: case TOK_THISCALL2: case TOK_THISCALL3: ad->f.func_call = FUNC_THISCALL; - break; + break; #endif case TOK_MODE: skip('('); @@ -5714,16 +5717,12 @@ ST_FUNC void unary(void) case TOK_builtin_return_address: { int tok1 = tok; - int64_t level; + int level; next(); skip('('); - level = expr_const64(); - if (level < 0) { - tcc_error("%s only takes positive integers", - tok1 == TOK_builtin_return_address ? - "__builtin_return_address" : - "__builtin_frame_address"); - } + level = expr_const(); + if (level < 0) + tcc_error("%s only takes positive integers", get_tok_str(tok1, 0)); skip(')'); type.t = VT_VOID; mk_pointer(&type); @@ -7400,12 +7399,10 @@ static void init_putz(init_params *p, unsigned long c, int size) } else { vpush_helper_func(TOK_memset); vseti(VT_LOCAL, c); -#ifdef TCC_TARGET_ARM - vpushs(size); - vpushi(0); -#else vpushi(0); vpushs(size); +#if defined TCC_TARGET_ARM && defined TCC_ARM_EABI + vswap(); /* using __aeabi_memset(void*, size_t, int) */ #endif gfunc_call(3); } diff --git a/tccpe.c b/tccpe.c index 60a8efcf..c87814d3 100644 --- a/tccpe.c +++ b/tccpe.c @@ -889,7 +889,7 @@ static void pe_build_imports(struct pe_info *pe) dllindex = p->dll_index; if (dllindex) - name = tcc_basename((dllref = pe->s1->loaded_dlls[dllindex-1])->name); + name = (dllref = pe->s1->loaded_dlls[dllindex-1])->name; else name = "", dllref = NULL; @@ -1767,6 +1767,9 @@ static int pe_load_def(TCCState *s1, int fd) char dllname[80], *buf, *line, *p, *x, next; buf = tcc_load_text(fd); + if (!buf) + return ret; + for (line = buf;; ++line) { p = get_token(&line, &next); if (!(*p && *p != ';')) @@ -1815,7 +1818,7 @@ quit: static int pe_load_dll(TCCState *s1, int fd, const char *filename) { char *p, *q; - DLLReference *ref = tcc_add_dllref(s1, filename, 0); + DLLReference *ref = tcc_add_dllref(s1, tcc_basename(filename), 0); if (ref->found) return 0; if (get_dllexports(fd, &p)) diff --git a/tccpp.c b/tccpp.c index d9d2bbc3..7f9bb627 100644 --- a/tccpp.c +++ b/tccpp.c @@ -92,7 +92,6 @@ static const unsigned char tok_two_chars[] = '-','>', TOK_ARROW, '.','.', TOK_TWODOTS, '#','#', TOK_TWOSHARPS, - '#','#', TOK_PPJOIN, 0 }; @@ -137,10 +136,8 @@ ST_FUNC void expect(const char *msg) #define TOKSYM_TAL_SIZE (768 * 1024) /* allocator for tiny TokenSym in table_ident */ #define TOKSTR_TAL_SIZE (768 * 1024) /* allocator for tiny TokenString instances */ -#define CSTR_TAL_SIZE (256 * 1024) /* allocator for tiny CString instances */ -#define TOKSYM_TAL_LIMIT 256 /* prefer unique limits to distinguish allocators debug msgs */ -#define TOKSTR_TAL_LIMIT 128 /* 32 * sizeof(int) */ -#define CSTR_TAL_LIMIT 1024 +#define TOKSYM_TAL_LIMIT 256 /* prefer unique limits to distinguish allocators debug msgs */ +#define TOKSTR_TAL_LIMIT 1024 /* 256 * sizeof(int) */ typedef struct TinyAlloc { unsigned limit; @@ -185,8 +182,8 @@ tail_call: if (!al) return; #ifdef TAL_INFO - fprintf(stderr, "limit=%5d, size=%5g MB, nb_peak=%6d, nb_total=%8d, nb_missed=%6d, usage=%5.1f%%\n", - al->limit, al->size / 1024.0 / 1024.0, al->nb_peak, al->nb_total, al->nb_missed, + fprintf(stderr, "limit %4d size %7d nb_peak %5d nb_total %7d nb_missed %5d usage %5.1f%%\n", + al->limit, al->size, al->nb_peak, al->nb_total, al->nb_missed, (al->peak_p - al->buffer) * 100.0 / al->size); #endif #if TAL_DEBUG && TAL_DEBUG != 3 /* do not check TAL leaks with -DMEM_DEBUG=3 */ @@ -345,7 +342,7 @@ ST_INLN void cstr_ccat(CString *cstr, int ch) size = cstr->size + 1; if (size > cstr->size_allocated) cstr_realloc(cstr, size); - ((unsigned char *)cstr->data)[size - 1] = ch; + cstr->data[size - 1] = ch; cstr->size = size; } @@ -368,6 +365,7 @@ ST_INLN void cstr_u8cat(CString *cstr, int ch) cstr_cat(cstr, buf, e - buf); } +/* add string of 'len', or of its len/len+1 when 'len' == -1/0 */ ST_FUNC void cstr_cat(CString *cstr, const char *str, int len) { int size; @@ -376,7 +374,7 @@ ST_FUNC void cstr_cat(CString *cstr, const char *str, int len) size = cstr->size + len; if (size > cstr->size_allocated) cstr_realloc(cstr, size); - memmove(((unsigned char *)cstr->data) + cstr->size, str, len); + memmove(cstr->data + cstr->size, str, len); cstr->size = size; } @@ -387,7 +385,7 @@ ST_FUNC void cstr_wccat(CString *cstr, int ch) size = cstr->size + sizeof(nwchar_t); if (size > cstr->size_allocated) cstr_realloc(cstr, size); - *(nwchar_t *)(((unsigned char *)cstr->data) + size - sizeof(nwchar_t)) = ch; + *(nwchar_t *)(cstr->data + size - sizeof(nwchar_t)) = ch; cstr->size = size; } @@ -418,7 +416,7 @@ ST_FUNC int cstr_vprintf(CString *cstr, const char *fmt, va_list ap) cstr_realloc(cstr, size); size = cstr->size_allocated - cstr->size; va_copy(v, ap); - len = vsnprintf((char*)cstr->data + cstr->size, size, fmt, v); + len = vsnprintf(cstr->data + cstr->size, size, fmt, v); va_end(v); if (len >= 0 && len < size) break; @@ -1920,7 +1918,8 @@ ST_FUNC void preprocess(int is_bof) if (file->fd > 0) total_lines += file->line_num - n; file->line_num = n; - break; + goto ignore; /* skip optional level number */ + case TOK_ERROR: case TOK_WARNING: q = buf; @@ -3070,12 +3069,13 @@ static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args) /* handle the '##' operator. return the resulting string (which must be freed). */ static inline int *macro_twosharps(const int *ptr0) { - int t1, t2, n; + int t1, t2, n, l; CValue cv1, cv2; TokenString macro_str1; const int *ptr; tok_str_new(¯o_str1); + cstr_reset(&tokcstr); for (ptr = ptr0;;) { TOK_GET(&t1, &ptr, &cv1); if (t1 == 0) @@ -3090,29 +3090,31 @@ static inline int *macro_twosharps(const int *ptr0) while ((t2 = *++ptr) == ' ' || t2 == TOK_PPJOIN) ; TOK_GET(&t2, &ptr, &cv2); - if (t1 == TOK_PLCHLDR && t2 == TOK_PLCHLDR) + if (t2 == TOK_PLCHLDR) continue; - cstr_reset(&tokcstr); - if (t1 != TOK_PLCHLDR) + if (t1 != TOK_PLCHLDR) { cstr_cat(&tokcstr, get_tok_str(t1, &cv1), -1); - n = tokcstr.size; - if (t2 != TOK_PLCHLDR) - cstr_cat(&tokcstr, get_tok_str(t2, &cv2), -1); - cstr_ccat(&tokcstr, '\0'); - //printf("paste <%s>\n", (char*)tokcstr.data); + t1 = TOK_PLCHLDR; + } + cstr_cat(&tokcstr, get_tok_str(t2, &cv2), -1); + } + if (tokcstr.size) { + cstr_ccat(&tokcstr, 0); tcc_open_bf(tcc_state, ":paste:", tokcstr.size); memcpy(file->buffer, tokcstr.data, tokcstr.size); tok_flags = 0; /* don't interpret '#' */ - next_nomacro(); - if (*file->buf_ptr == 0) { - t1 = tok, cv1 = tokc; - } else { + for (n = 0;;n = l) { + next_nomacro(); + tok_str_add2(¯o_str1, tok, &tokc); + if (*file->buf_ptr == 0) + break; + tok_str_add(¯o_str1, ' '); + l = file->buf_ptr - file->buffer; tcc_warning("pasting \"%.*s\" and \"%s\" does not give a valid" - " preprocessing token", n, file->buffer, file->buffer + n); - tok_str_add2(¯o_str1, t1, &cv1); - t1 = t2, cv1 = cv2; + " preprocessing token", l - n, file->buffer + n, file->buf_ptr); } tcc_close(); + cstr_reset(&tokcstr); } if (t1 != TOK_PLCHLDR) tok_str_add2(¯o_str1, t1, &cv1); @@ -3450,9 +3452,8 @@ redo: /* do nothing */ } else { ++macro_ptr; - if (t >= TOK_IDENT) { - t &= ~SYM_FIELD; /* remove 'nosubst' marker */ - } else if (t == '\\') { + t &= ~SYM_FIELD; /* remove 'nosubst' marker */ + if (t == '\\') { if (!(parse_flags & PARSE_FLAG_ACCEPT_STRAYS)) tcc_error("stray '\\' in program"); } diff --git a/tests/tests2/60_errors_and_warnings.c b/tests/tests2/60_errors_and_warnings.c index 47da0487..434c46b7 100644 --- a/tests/tests2/60_errors_and_warnings.c +++ b/tests/tests2/60_errors_and_warnings.c @@ -483,4 +483,11 @@ struct A { # if X(1,2) //undefined function macro # endif +#elif defined test_pointer_plus_double + +int *invalid_operation(int *p, double d) +{ + return p + d; +} + #endif diff --git a/tests/tests2/60_errors_and_warnings.expect b/tests/tests2/60_errors_and_warnings.expect index 124d37ef..a8ef8194 100644 --- a/tests/tests2/60_errors_and_warnings.expect +++ b/tests/tests2/60_errors_and_warnings.expect @@ -237,3 +237,6 @@ arg[1] = "Y" [test_pp_error_2] 60_errors_and_warnings.c:483: error: bad preprocessor expression: #if 0 ( 1 , 2 ) + +[test_pointer_plus_double] +60_errors_and_warnings.c:490: error: invalid operand types for binary operation diff --git a/tests/thiscall/thiscall-test.c b/tests/thiscall/thiscall-test.c deleted file mode 100644 index a13b9a40..00000000 --- a/tests/thiscall/thiscall-test.c +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef __thiscall - #define __thiscall __attribute__((thiscall)) -#endif -#ifndef __cdecl - #define __cdecl __attribute__((cdecl)) -#endif -#ifndef __stdcall - #define __stdcall __attribute__((stdcall)) -#endif - -void ( __thiscall * const thisCall1 ) ( void * _this, int a ) = ( void ( __thiscall * ) ( void * _this, int a ) ) 0x4788a0; - -int main() { - thisCall1((void*) 0xDEADBEEF, 1000); - - return 1; -} \ No newline at end of file diff --git a/x86_64-link.c b/x86_64-link.c index 1b6aa092..42f753c9 100644 --- a/x86_64-link.c +++ b/x86_64-link.c @@ -25,7 +25,7 @@ #ifdef NEED_RELOC_TYPE /* Returns 1 for a code relocation, 0 for a data relocation. For unknown relocations, returns -1. */ -int code_reloc (int reloc_type) +ST_FUNC int code_reloc (int reloc_type) { switch (reloc_type) { case R_X86_64_32: @@ -64,7 +64,7 @@ int code_reloc (int reloc_type) /* Returns an enumerator to describe whether and when the relocation needs a GOT and/or PLT entry to be created. See tcc.h for a description of the different values. */ -int gotplt_entry_type (int reloc_type) +ST_FUNC int gotplt_entry_type (int reloc_type) { switch (reloc_type) { case R_X86_64_GLOB_DAT: @@ -186,7 +186,7 @@ ST_FUNC void relocate_plt(TCCState *s1) #endif #endif -void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val) +ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val) { int sym_index, esym_index;