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
This commit is contained in:
grischka 2024-06-11 13:57:22 +02:00
parent 3b943bec5d
commit 6b78e561c8
20 changed files with 227 additions and 508 deletions

View File

@ -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\""

221
arm-asm.c
View File

@ -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<number>'");
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<number>'");
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<number>'");
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<number>'");
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<number>'");
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<number>, s<number>");
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<number>, s<number>");
return;
}
} else if (coprocessor == CP_DOUBLE_PRECISION_FLOAT) {
if (ops[0].type == OP_VREG32 && ops[2].type == OP_VREG64) {
} else {
expect("s<number>, d<number>");
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<number>'");
return;
}
} else if (ops[nb_ops].type == OP_VREG64) {
if (coprocessor != CP_DOUBLE_PRECISION_FLOAT) {
expect("'d<number>'");
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;

View File

@ -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;

View File

@ -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

View File

@ -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:

View File

@ -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));
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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:

View File

@ -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;

9
tcc.h
View File

@ -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);

View File

@ -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;

105
tccgen.c
View File

@ -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);
}

View File

@ -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))

63
tccpp.c
View File

@ -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(&macro_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(&macro_str1, tok, &tokc);
if (*file->buf_ptr == 0)
break;
tok_str_add(&macro_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(&macro_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(&macro_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");
}

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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;