From 9668499b9f1e7f6619082040c9aa179d19173318 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 18 Oct 2004 00:18:20 +0000 Subject: [PATCH] primitive fastcall functions support - -fno-common option - -Ttext linker option - bit field fixes - section alignment fixes --- tcc.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 120 insertions(+), 10 deletions(-) diff --git a/tcc.c b/tcc.c index 563dc73d..0d5d6307 100644 --- a/tcc.c +++ b/tcc.c @@ -205,12 +205,12 @@ typedef struct DLLReference { typedef struct AttributeDef { int aligned; Section *section; - unsigned char func_call; /* FUNC_CDECL or FUNC_STDCALL */ + unsigned char func_call; /* FUNC_CDECL, FUNC_STDCALL, FUNC_FASTCALLx */ } AttributeDef; #define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */ #define SYM_FIELD 0x20000000 /* struct/union field symbol space */ -#define SYM_FIRST_ANOM (1 << (31 - VT_STRUCT_SHIFT)) /* first anonymous sym */ +#define SYM_FIRST_ANOM 0x10000000 /* first anonymous sym */ /* stored in 'Sym.c' field */ #define FUNC_NEW 1 /* ansi function prototype */ @@ -220,6 +220,9 @@ typedef struct AttributeDef { /* stored in 'Sym.r' field */ #define FUNC_CDECL 0 /* standard c call */ #define FUNC_STDCALL 1 /* pascal c call */ +#define FUNC_FASTCALL1 2 /* first param in %eax */ +#define FUNC_FASTCALL2 3 /* first parameters in %eax, %edx */ +#define FUNC_FASTCALL3 4 /* first parameter in %eax, %edx, %ecx */ /* field 'Sym.t' for macros */ #define MACRO_OBJ 0 /* object like macro */ @@ -299,10 +302,12 @@ static int parse_flags; #define PARSE_FLAG_LINEFEED 0x0004 /* line feed is returned as a token. line feed is also returned at eof */ +#define PARSE_FLAG_ASM_COMMENTS 0x0008 /* '#' can be used for line comment */ static Section *text_section, *data_section, *bss_section; /* predefined sections */ static Section *cur_text_section; /* current section where function code is generated */ +static Section *last_text_section; /* to handle .previous asm directive */ /* bound check related sections */ static Section *bounds_section; /* contains global data bound description */ static Section *lbounds_section; /* contains local data bound description */ @@ -413,6 +418,8 @@ struct TCCState { int nostdinc; /* if true, no standard headers are added */ int nostdlib; /* if true, no standard libraries are added */ + int nocommon; /* if true, do not use common symbols for .bss data */ + /* if true, static linking is performed */ int static_link; @@ -422,6 +429,10 @@ struct TCCState { /* if true, only link in referenced objects from archive */ int alacarte_link; + /* address of text section */ + unsigned long text_addr; + int has_text_addr; + /* C language options */ int char_is_unsigned; @@ -789,9 +800,12 @@ typedef struct ASMOperand { char asm_str[16]; /* computed asm string for operand */ SValue *vt; /* C value of the expression */ int ref_index; /* if >= 0, gives reference to a output constraint */ + int input_index; /* if >= 0, gives reference to an input constraint */ int priority; /* priority, used to assign registers */ int reg; /* if >= 0, register number used for this operand */ int is_llong; /* true if double register value */ + int is_memory; /* true if memory operand */ + int is_rw; /* for '+' modifier */ } ASMOperand; static void asm_expr(TCCState *s1, ExprValue *pe); @@ -804,6 +818,7 @@ static int tcc_assemble(TCCState *s1, int do_preprocess); #endif static void asm_instr(void); +static void asm_global_instr(void); /* true if float/double/long double type */ static inline int is_float(int t) @@ -914,6 +929,22 @@ static char *pstrcat(char *buf, int buf_size, const char *s) return buf; } +static int strstart(const char *str, const char *val, const char **ptr) +{ + const char *p, *q; + p = str; + q = val; + while (*q != '\0') { + if (*p != *q) + return 0; + p++; + q++; + } + if (ptr) + *ptr = p; + return 1; +} + /* memory management */ #ifdef MEM_DEBUG int mem_cur_size; @@ -1086,6 +1117,8 @@ Section *find_section(TCCState *s1, const char *name) return new_section(s1, name, SHT_PROGBITS, SHF_ALLOC); } +#define SECTION_ABS ((void *)1) + /* update sym->c so that it points to an external symbol in section 'section' with value 'value' */ static void put_extern_sym(Sym *sym, Section *section, @@ -1095,10 +1128,12 @@ static void put_extern_sym(Sym *sym, Section *section, Elf32_Sym *esym; const char *name; - if (section) - sh_num = section->sh_num; - else + if (section == NULL) sh_num = SHN_UNDEF; + else if (section == SECTION_ABS) + sh_num = SHN_ABS; + else + sh_num = section->sh_num; if (!sym->c) { if ((sym->type.t & VT_BTYPE) == VT_FUNC) sym_type = STT_FUNC; @@ -2850,7 +2885,8 @@ static void preprocess(int is_bof) /* '!' is ignored to allow C scripts. numbers are ignored to emulate cpp behaviour */ } else { - error("invalid preprocessing directive #%s", get_tok_str(tok, &tokc)); + if (!(saved_parse_flags & PARSE_FLAG_ASM_COMMENTS)) + error("invalid preprocessing directive #%s", get_tok_str(tok, &tokc)); } break; } @@ -3367,7 +3403,12 @@ static inline void next_nomacro1(void) p++; tok = TOK_TWOSHARPS; } else { - tok = '#'; + if (parse_flags & PARSE_FLAG_ASM_COMMENTS) { + p = parse_line_comment(p - 1); + goto redo_no_start; + } else { + tok = '#'; + } } } break; @@ -3815,7 +3856,6 @@ static int macro_subst_tok(TokenString *tok_str, char buf[32]; /* if symbol is a macro, prepare substitution */ - /* special macros */ if (tok == TOK___LINE__) { snprintf(buf, sizeof(buf), "%d", file->line_num); @@ -5745,6 +5785,9 @@ static int is_compatible_func(CType *type1, CType *type2) s2 = type2->ref; if (!is_compatible_types(&s1->type, &s2->type)) return 0; + /* check func_call */ + if (s1->r != s2->r) + return 0; /* XXX: not complete */ if (s1->c == FUNC_OLD || s2->c == FUNC_OLD) return 1; @@ -5985,7 +6028,8 @@ void vstore(void) warning("assignment of read-only location"); } else { delayed_cast = 0; - gen_assign_cast(&vtop[-1].type); + if (!(ft & VT_BITFIELD)) + gen_assign_cast(&vtop[-1].type); } if (sbt == VT_STRUCT) { @@ -6164,6 +6208,20 @@ static void parse_attribute(AttributeDef *ad) case TOK_STDCALL3: ad->func_call = FUNC_STDCALL; break; +#ifdef TCC_TARGET_I386 + case TOK_REGPARM1: + case TOK_REGPARM2: + skip('('); + n = expr_const(); + if (n > 3) + n = 3; + else if (n < 0) + n = 0; + if (n > 0) + ad->func_call = FUNC_FASTCALL1 + n - 1; + skip(')'); + break; +#endif default: if (tcc_state->warn_unsupported) warning("'%s' attribute ignored", get_tok_str(t, NULL)); @@ -6280,6 +6338,8 @@ static void struct_decl(CType *type, int u) get_tok_str(v, NULL)); } size = type_size(&type1, &align); + if (align < ad.aligned) + align = ad.aligned; lbit_pos = 0; if (bit_size >= 0) { bt = type1.t & VT_BTYPE; @@ -8418,6 +8478,12 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, if (sym->type.t & VT_EXTERN) { /* if the variable is extern, it was not allocated */ sym->type.t &= ~VT_EXTERN; + /* set array size if it was ommited in extern + declaration */ + if ((sym->type.t & VT_ARRAY) && + sym->type.ref->c < 0 && + type->ref->c >= 0) + sym->type.ref->c = type->ref->c; } else { /* we accept several definitions of the same global variable. this is tricky, because we @@ -8437,6 +8503,8 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, if (!sec) { if (has_init) sec = data_section; + else if (tcc_state->nocommon) + sec = bss_section; } if (sec) { data_offset = sec->data_offset; @@ -8453,6 +8521,9 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, if (sec->sh_type != SHT_NOBITS && data_offset > sec->data_allocated) section_realloc(sec, data_offset); + /* align section if needed */ + if (align > sec->sh_addralign) + sec->sh_addralign = align; } else { addr = 0; /* avoid warning */ } @@ -8646,6 +8717,12 @@ static void decl(int l) next(); continue; } + if (l == VT_CONST && + (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) { + /* global asm block */ + asm_global_instr(); + continue; + } /* special test for old K&R protos without explicit int type. Only accepted when defining global data */ if (l == VT_LOCAL || tok < TOK_DEFINE) @@ -8683,7 +8760,6 @@ static void decl(int l) ParseState saved_parse_state; int block_level; #endif - if (l == VT_LOCAL) error("cannot use local functions"); if (!(type.t & VT_FUNC)) @@ -8738,6 +8814,19 @@ static void decl(int l) funcname = get_tok_str(v, NULL); sym = sym_find(v); if (sym) { + if ((sym->type.t & VT_BTYPE) != VT_FUNC) + goto func_error1; + /* specific case: if not func_call defined, we put + the one of the prototype */ + /* XXX: should have default value */ + if (sym->type.ref->r != FUNC_CDECL && + type.ref->r == FUNC_CDECL) + type.ref->r = sym->type.ref->r; + if (!is_compatible_types(&sym->type, &type)) { + func_error1: + error("incompatible types for redefinition of '%s'", + get_tok_str(v, NULL)); + } /* if symbol is already defined, then put complete type */ sym->type = type; } else { @@ -8790,6 +8879,9 @@ static void decl(int l) sym->type.t |= VT_TYPEDEF; } else if ((type.t & VT_BTYPE) == VT_FUNC) { /* external function definition */ + /* specific case for func_call attribute */ + if (ad.func_call) + type.ref->r = ad.func_call; external_sym(v, &type, 0); } else { /* not lvalue if array */ @@ -9013,6 +9105,10 @@ static void asm_instr(void) { error("inline asm() not supported"); } +static void asm_global_instr(void) +{ + error("inline asm() not supported"); +} #endif #include "tccelf.c" @@ -9794,6 +9890,7 @@ int tcc_set_warning(TCCState *s, const char *warning_name, int value) static const FlagDef flag_defs[] = { { offsetof(TCCState, char_is_unsigned), 0, "unsigned-char" }, { offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" }, + { offsetof(TCCState, nocommon), FD_INVERT, "common" }, }; /* set/reset a flag */ @@ -9897,6 +9994,7 @@ enum { TCC_OPTION_shared, TCC_OPTION_o, TCC_OPTION_r, + TCC_OPTION_Wl, TCC_OPTION_W, TCC_OPTION_O, TCC_OPTION_m, @@ -9932,6 +10030,7 @@ static const TCCOption tcc_options[] = { { "run", TCC_OPTION_run, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, { "rdynamic", TCC_OPTION_rdynamic, 0 }, { "r", TCC_OPTION_r, 0 }, + { "Wl,", TCC_OPTION_Wl, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, { "W", TCC_OPTION_W, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, { "O", TCC_OPTION_O, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, { "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG }, @@ -10144,6 +10243,17 @@ int parse_args(TCCState *s, int argc, char **argv) case TCC_OPTION_rdynamic: s->rdynamic = 1; break; + case TCC_OPTION_Wl: + { + const char *p; + if (strstart(optarg, "-Ttext,", &p)) { + s->text_addr = strtoul(p, NULL, 16); + s->has_text_addr = 1; + } else { + error("unsupported ld option '%s'", optarg); + } + } + break; default: if (s->warn_unsupported) { unsupported_option: -- 2.11.4.GIT