From 877e164d6ade4167f9d7f6994ece8e06b5d67060 Mon Sep 17 00:00:00 2001 From: grischka Date: Thu, 30 Nov 2017 15:15:22 +0100 Subject: [PATCH] tccasm: use global(_symbol)_stack * removed asm_label stack * removed asm_free_labels() post-processing * using "impossible C type" for asm labels (VT_ASM) * tccgen.c:update_storage(): use it to refresh symbol attributes * tccelf.c:find_elf_sym(): ignore STB_LOCAL symbols * tccgen.c:unary(): asm symbols are supposed to be undeclared in C --- tcc.h | 14 +++++++----- tccasm.c | 67 +++++++++++++++++++------------------------------------- tccelf.c | 10 ++++----- tccgen.c | 60 ++++++++++++++++++++++++++------------------------ 4 files changed, 67 insertions(+), 84 deletions(-) diff --git a/tcc.h b/tcc.h index 6241f42..07b9286 100644 --- a/tcc.h +++ b/tcc.h @@ -440,8 +440,7 @@ struct SymAttr { visibility : 2, dllexport : 1, dllimport : 1, - asmexport : 1, - unused : 4; + unused : 5; }; /* function attributes or temporary attributes for parsing */ @@ -796,8 +795,8 @@ struct TCCState { /* extra attributes (eg. GOT/PLT value) for symtab symbols */ struct sym_attr *sym_attrs; int nb_sym_attrs; + /* tiny assembler state */ - Sym *asm_labels; ElfSym esym_dot; #ifdef TCC_TARGET_PE @@ -911,6 +910,11 @@ struct filespec { #define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE) #define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK)) +/* symbol was created by tccasm.c first */ +#define VT_ASM (VT_VOID | VT_UNSIGNED) +#define VT_ASM_GLOBAL VT_DEFSIGN +#define IS_ASM_SYM(sym) (((sym)->type.t & (VT_BTYPE | VT_ASM)) == VT_ASM) + /* token values */ /* warning: the following compare tokens depend on i386 asm code */ @@ -1147,7 +1151,7 @@ ST_FUNC Sym *sym_push(int v, CType *type, int r, int c); ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep); ST_INLN Sym *struct_find(int v); ST_INLN Sym *sym_find(int v); -ST_FUNC Sym *global_identifier_push_1(Sym **, int v, int t, int c); +ST_FUNC Sym *global_identifier_push(int v, int t, int c); ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen); ST_FUNC int tcc_open(TCCState *s1, const char *filename); @@ -1317,6 +1321,7 @@ ST_FUNC int ieee_finite(double d); ST_FUNC void test_lvalue(void); ST_FUNC void vpushi(int v); ST_FUNC ElfSym *elfsym(Sym *); +ST_FUNC void update_storage(Sym *sym); ST_FUNC Sym *external_global_sym(int v, CType *type, int r); ST_FUNC void vset(CType *type, int r, int v); ST_FUNC void vswap(void); @@ -1588,7 +1593,6 @@ ST_FUNC Sym* get_asm_sym(int name, Sym *csym); ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe); ST_FUNC int asm_int_expr(TCCState *s1); ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess); -ST_FUNC void asm_free_labels(TCCState *st); /* ------------ i386-asm.c ------------ */ ST_FUNC void gen_expr32(ExprValue *pe); #ifdef TCC_TARGET_X86_64 diff --git a/tccasm.c b/tccasm.c index 15f1e43..4fe3f32 100644 --- a/tccasm.c +++ b/tccasm.c @@ -44,11 +44,11 @@ static Sym *asm_label_find(int v) static Sym *asm_label_push(int v, int t) { - Sym *sym = global_identifier_push_1(&tcc_state->asm_labels, v, t, 0); + Sym *sym = global_identifier_push(v, t, 0); /* We always add VT_EXTERN, for sym definition that's tentative (for .set, removed for real defs), for mere references it's correct as is. */ - sym->type.t |= VT_VOID | VT_EXTERN; + sym->type.t |= VT_ASM | VT_EXTERN; sym->r = VT_CONST | VT_SYM; return sym; } @@ -149,7 +149,7 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe) pe->v = 0; pe->sym = &sym_dot; pe->pcrel = 0; - sym_dot.type.t = VT_VOID | VT_STATIC; + sym_dot.type.t = VT_ASM | VT_STATIC; sym_dot.c = -1; tcc_state->esym_dot.st_shndx = cur_text_section->sh_num; tcc_state->esym_dot.st_value = ind; @@ -371,7 +371,7 @@ static Sym* asm_new_label1(TCCState *s1, int label, int is_local, definitions won't have VT_EXTERN set. */ if (esym && esym->st_shndx != SHN_UNDEF && !(sym->type.t & VT_EXTERN)) { /* the label is already defined */ - if (!is_local) { + if (is_local != 1) { tcc_error("assembler label '%s' already defined", get_tok_str(label, NULL)); } else { @@ -381,13 +381,22 @@ static Sym* asm_new_label1(TCCState *s1, int label, int is_local, } } else { new_label: - sym = asm_label_push(label, is_local ? VT_STATIC : 0); + sym = asm_label_push(label, is_local == 1 ? VT_STATIC : 0); } if (!sym->c) put_extern_sym2(sym, NULL, 0, 0, 0); esym = elfsym(sym); esym->st_shndx = sh_num; esym->st_value = value; + + if (is_local != 2) + sym->type.t &= ~VT_EXTERN; + + if (IS_ASM_SYM(sym) && !(sym->type.t & VT_ASM_GLOBAL)) { + sym->type.t |= VT_STATIC; + update_storage(sym); + } + return sym; } @@ -410,39 +419,11 @@ static Sym* set_symbol(TCCState *s1, int label) esym = elfsym(e.sym); if (esym) n += esym->st_value; - sym = asm_new_label1(s1, label, 0, esym ? esym->st_shndx : SHN_ABS, n); + sym = asm_new_label1(s1, label, 2, esym ? esym->st_shndx : SHN_ABS, n); elfsym(sym)->st_other |= ST_ASM_SET; return sym; } -ST_FUNC void asm_free_labels(TCCState *st) -{ - Sym *s, *s1; - - for(s = st->asm_labels; s != NULL; s = s1) { - ElfSym *esym = elfsym(s); - s1 = s->prev; - /* Possibly update binding and visibility from asm directives - if the symbol has no C decl (type is VT_VOID).*/ - s->type.t &= ~VT_EXTERN; - if (esym && s->type.t == VT_VOID) { - if (!s->a.asmexport && esym->st_shndx != SHN_UNDEF) - s->type.t |= VT_STATIC; - if (s->a.visibility) - esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) - | s->a.visibility; - esym->st_info = ELFW(ST_INFO)(s->a.weak ? STB_WEAK - : (s->type.t & VT_STATIC) ? STB_LOCAL - : STB_GLOBAL, - ELFW(ST_TYPE)(esym->st_info)); - } - /* remove label */ - table_ident[s->v - TOK_IDENT]->sym_identifier = s->prev_tok; - sym_free(s); - } - st->asm_labels = NULL; -} - static void use_section1(TCCState *s1, Section *sec) { cur_text_section->data_offset = ind; @@ -696,15 +677,18 @@ static void asm_parse_directive(TCCState *s1, int global) tok1 = tok; do { Sym *sym; - next(); sym = get_asm_sym(tok, NULL); - if (tok1 != TOK_ASMDIR_hidden) - sym->type.t &= ~VT_STATIC, sym->a.asmexport = 1; + if (tok1 != TOK_ASMDIR_hidden) { + sym->type.t &= ~VT_STATIC; + if (IS_ASM_SYM(sym)) + sym->type.t |= VT_ASM_GLOBAL; + } if (tok1 == TOK_ASMDIR_weak) sym->a.weak = 1; else if (tok1 == TOK_ASMDIR_hidden) sym->a.visibility = STV_HIDDEN; + update_storage(sym); next(); } while (tok == ','); break; @@ -947,7 +931,6 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global) } else if (tok >= TOK_ASMDIR_FIRST && tok <= TOK_ASMDIR_LAST) { asm_parse_directive(s1, global); } else if (tok == TOK_PPNUM) { - Sym *sym; const char *p; int n; p = tokc.str.data; @@ -955,9 +938,7 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global) if (*p != '\0') expect("':'"); /* new local label */ - sym = asm_new_label(s1, asm_get_local_label_name(s1, n), 1); - /* Remove the marker for tentative definitions. */ - sym->type.t &= ~VT_EXTERN; + asm_new_label(s1, asm_get_local_label_name(s1, n), 1); next(); skip(':'); goto redo; @@ -967,8 +948,7 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global) next(); if (tok == ':') { /* new label */ - Sym *sym = asm_new_label(s1, opcode, 0); - sym->type.t &= ~VT_EXTERN; + asm_new_label(s1, opcode, 0); next(); goto redo; } else if (tok == '=') { @@ -998,7 +978,6 @@ ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess) ind = cur_text_section->data_offset; nocode_wanted = 0; ret = tcc_assemble_internal(s1, do_preprocess, 1); - asm_free_labels(s1); cur_text_section->data_offset = ind; tcc_debug_end(s1); return ret; diff --git a/tccelf.c b/tccelf.c index 422dfd6..657aa61 100644 --- a/tccelf.c +++ b/tccelf.c @@ -310,8 +310,7 @@ static void rebuild_hash(Section *s, unsigned int nb_buckets) sym = (ElfW(Sym) *)s->data + 1; for(sym_index = 1; sym_index < nb_syms; sym_index++) { - if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL - || sym->st_shndx == SHN_UNDEF) { + if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { h = elf_hash(strtab + sym->st_name) % nb_buckets; *ptr = hash[h]; hash[h] = sym_index; @@ -350,9 +349,8 @@ ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size, int *ptr, *base; ptr = section_ptr_add(hs, sizeof(int)); base = (int *)hs->data; - /* only add global, weak or undef symbols. The latter might - become global late (from asm references). */ - if (ELFW(ST_BIND)(info) != STB_LOCAL || shndx == SHN_UNDEF) { + /* only add global or weak symbols. */ + if (ELFW(ST_BIND)(info) != STB_LOCAL) { /* add another hashing entry */ nbuckets = base[0]; h = elf_hash((unsigned char *) name) % nbuckets; @@ -390,7 +388,7 @@ ST_FUNC int find_elf_sym(Section *s, const char *name) while (sym_index != 0) { sym = &((ElfW(Sym) *)s->data)[sym_index]; name1 = (char *) s->link->data + sym->st_name; - if (!strcmp(name, name1)) + if (!strcmp(name, name1) && ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) return sym_index; sym_index = ((int *)hs->data)[2 + nbuckets + sym_index]; } diff --git a/tccgen.c b/tccgen.c index 2d3f2d0..7ddde72 100644 --- a/tccgen.c +++ b/tccgen.c @@ -275,11 +275,6 @@ ST_FUNC int tccgen_compile(TCCState *s1) decl(VT_CONST); gen_inline_functions(s1); check_vstack(); - -#ifdef CONFIG_TCC_ASM - asm_free_labels(s1); -#endif - /* end of translation unit info */ tcc_debug_end(s1); return 0; @@ -297,28 +292,42 @@ ST_FUNC ElfSym *elfsym(Sym *s) } /* apply storage attributes to Elf symbol */ - -static void update_storage(Sym *sym) +ST_FUNC void update_storage(Sym *sym) { - ElfSym *esym = elfsym(sym); + ElfSym *esym; + int sym_bind, old_sym_bind; + + esym = elfsym(sym); if (!esym) return; + if (sym->a.visibility) esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) | sym->a.visibility; - if (sym->a.weak) - esym->st_info = ELFW(ST_INFO)(STB_WEAK, ELFW(ST_TYPE)(esym->st_info)); + + if (sym->type.t & VT_STATIC) + sym_bind = STB_LOCAL; + else if (sym->a.weak) + sym_bind = STB_WEAK; + else + sym_bind = STB_GLOBAL; + old_sym_bind = ELFW(ST_BIND)(esym->st_info); + if (sym_bind != old_sym_bind) { + esym->st_info = ELFW(ST_INFO)(sym_bind, ELFW(ST_TYPE)(esym->st_info)); + } + #ifdef TCC_TARGET_PE if (sym->a.dllimport) esym->st_other |= ST_PE_IMPORT; if (sym->a.dllexport) esym->st_other |= ST_PE_EXPORT; #endif + #if 0 - printf("storage %s: vis=%d weak=%d exp=%d imp=%d\n", + printf("storage %s: bind=%c vis=%d exp=%d imp=%d\n", get_tok_str(sym->v, NULL), + sym_bind == STB_WEAK ? 'w' : sym_bind == STB_LOCAL ? 'l' : 'g', sym->a.visibility, - sym->a.weak, sym->a.dllexport, sym->a.dllimport ); @@ -578,10 +587,10 @@ ST_FUNC Sym *sym_push(int v, CType *type, int r, int c) } /* push a global identifier */ -ST_FUNC Sym *global_identifier_push_1(Sym **ptop, int v, int t, int c) +ST_FUNC Sym *global_identifier_push(int v, int t, int c) { Sym *s, **ps; - s = sym_push2(ptop, v, t, c); + s = sym_push2(&global_stack, v, t, c); /* don't record anonymous symbol */ if (v < SYM_FIRST_ANOM) { ps = &table_ident[v - TOK_IDENT]->sym_identifier; @@ -595,11 +604,6 @@ ST_FUNC Sym *global_identifier_push_1(Sym **ptop, int v, int t, int c) return s; } -static Sym *global_identifier_push(int v, int t, int c) -{ - return global_identifier_push_1(&global_stack, v, t, c); -} - /* pop symbols until top reaches 'b'. If KEEP is non-zero don't really pop them yet from the list, but do remove them from the token array. */ ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep) @@ -841,6 +845,9 @@ ST_FUNC Sym *external_global_sym(int v, CType *type, int r) s = global_identifier_push(v, type->t | VT_EXTERN, 0); s->type.ref = type->ref; s->r = r | VT_CONST | VT_SYM; + } else if (IS_ASM_SYM(s)) { + s->type.t = type->t | (s->type.t & VT_EXTERN); + s->type.ref = type->ref; } return s; } @@ -849,7 +856,7 @@ ST_FUNC Sym *external_global_sym(int v, CType *type, int r) static void patch_storage(Sym *sym, AttributeDef *ad, CType *type) { if (type) { - if ((sym->type.t & VT_BTYPE) == VT_VOID) /* from asm */ + if (IS_ASM_SYM(sym)) sym->type = *type; else if (!is_compatible_types(&sym->type, type)) tcc_error("incompatible types for redefinition of '%s'", @@ -5026,7 +5033,7 @@ ST_FUNC void unary(void) if (t < TOK_UIDENT) expect("identifier"); s = sym_find(t); - if (!s) { + if (!s || IS_ASM_SYM(s)) { const char *name = get_tok_str(t, NULL); if (tok != '(') tcc_error("'%s' undeclared", name); @@ -7223,12 +7230,8 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym) type.t = (type.t & ~VT_EXTERN) | VT_STATIC; sym = sym_find(v); - if (sym) { + if (sym && !IS_ASM_SYM(sym)) { Sym *ref; - /* If type is VT_VOID the symbol was created by tccasm - first, and we see the first reference from C now. */ - if ((sym->type.t & VT_BTYPE) == VT_VOID) - sym->type = type; if ((sym->type.t & VT_BTYPE) != VT_FUNC) goto func_error1; @@ -7261,15 +7264,14 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym) tcc_error("redefinition of '%s'", get_tok_str(v, NULL)); /* if symbol is already defined, then put complete type */ sym->type = type; + sym->r = VT_SYM | VT_CONST; } else { /* put function symbol */ - sym = global_identifier_push(v, type.t, 0); - sym->type.ref = type.ref; + sym = external_global_sym(v, &type, 0); } sym->type.ref->f.func_body = 1; - sym->r = VT_SYM | VT_CONST; patch_storage(sym, &ad, NULL); /* static inline functions are just recorded as a kind