mirror of
https://github.com/mirror/tinycc.git
synced 2024-12-24 03:40:09 +08:00
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:
parent
3b943bec5d
commit
6b78e561c8
1
Makefile
1
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\""
|
||||
|
221
arm-asm.c
221
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<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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
25
i386-asm.c
25
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
32
i386-gen.c
32
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;
|
||||
|
@ -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;
|
||||
|
||||
|
44
libtcc.c
44
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
|
||||
|
136
riscv64-asm.c
136
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:
|
||||
|
@ -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
9
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);
|
||||
|
29
tccelf.c
29
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;
|
||||
|
105
tccgen.c
105
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);
|
||||
}
|
||||
|
7
tccpe.c
7
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))
|
||||
|
63
tccpp.c
63
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");
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user