From 9e0d23cc47359149a39eafffdbb133963980b6ed Mon Sep 17 00:00:00 2001 From: Michael Matz Date: Mon, 27 Nov 2017 04:03:03 +0100 Subject: [PATCH] tccasm: Unify C and asm symbol table This makes the asm symbols use the same members as the C symbols for global decls, e.g. using the ELF symbol to hold offset and section. That allows us to use only one symbol table for C and asm symbols and to get rid of hacks to synch between them. We still need some special handling for symbols that come purely from asm sources. --- i386-asm.c | 15 ++- tcc.h | 11 +- tccasm.c | 240 +++++++++++++++------------------------- tccelf.c | 12 +- tccgen.c | 63 +++++++---- tccpp.c | 1 - tests/asm-c-connect-1.c | 7 ++ tests/asm-c-connect-2.c | 3 + 8 files changed, 164 insertions(+), 188 deletions(-) diff --git a/i386-asm.c b/i386-asm.c index 2e18497..1b992ca 100644 --- a/i386-asm.c +++ b/i386-asm.c @@ -500,12 +500,13 @@ ST_FUNC void gen_expr64(ExprValue *pe) static void gen_disp32(ExprValue *pe) { Sym *sym = pe->sym; - if (sym && sym->r == cur_text_section->sh_num) { + ElfSym *esym = elfsym(sym); + if (esym && esym->st_shndx == cur_text_section->sh_num) { /* same section: we can output an absolute value. Note that the TCC compiler behaves differently here because it always outputs a relocation to ease (future) code elimination in the linker */ - gen_le32(pe->v + sym->jnext - ind - 4); + gen_le32(pe->v + esym->st_value - ind - 4); } else { if (sym && sym->type.t == VT_VOID) { sym->type.t = VT_FUNC; @@ -1017,16 +1018,14 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) if (pa->instr_type & OPC_B) v += s >= 1; if (nb_ops == 1 && pa->op_type[0] == OPT_DISP8) { - Sym *sym; + ElfSym *esym; int jmp_disp; /* see if we can really generate the jump with a byte offset */ - sym = ops[0].e.sym; - if (!sym) + esym = elfsym(ops[0].e.sym); + if (!esym || esym->st_shndx != cur_text_section->sh_num) goto no_short_jump; - if (sym->r != cur_text_section->sh_num) - goto no_short_jump; - jmp_disp = ops[0].e.v + sym->jnext - ind - 2 - (v >= 0xff); + jmp_disp = ops[0].e.v + esym->st_value - ind - 2 - (v >= 0xff); if (jmp_disp == (int8_t)jmp_disp) { /* OK to generate jump */ ops[0].e.sym = 0; diff --git a/tcc.h b/tcc.h index 5fc71a5..6241f42 100644 --- a/tcc.h +++ b/tcc.h @@ -356,6 +356,7 @@ extern long double strtold (const char *__nptr, char **__endptr); #endif /* target address type */ #define addr_t ElfW(Addr) +#define ElfSym ElfW(Sym) #if PTR_SIZE == 8 && !defined TCC_TARGET_PE # define LONG_SIZE 8 @@ -383,7 +384,6 @@ typedef struct TokenSym { struct Sym *sym_label; /* direct pointer to label */ struct Sym *sym_struct; /* direct pointer to structure */ struct Sym *sym_identifier; /* direct pointer to identifier */ - struct Sym *sym_asm_label; /* direct pointer to asm label */ int tok; /* token number */ int len; char str[1]; @@ -440,9 +440,8 @@ struct SymAttr { visibility : 2, dllexport : 1, dllimport : 1, - asmcsym : 1, asmexport : 1, - unused : 3; + unused : 4; }; /* function attributes or temporary attributes for parsing */ @@ -799,6 +798,7 @@ struct TCCState { int nb_sym_attrs; /* tiny assembler state */ Sym *asm_labels; + ElfSym esym_dot; #ifdef TCC_TARGET_PE /* PE info */ @@ -1147,7 +1147,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(int v, int t, int c); +ST_FUNC Sym *global_identifier_push_1(Sym **, 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); @@ -1316,6 +1316,7 @@ ST_INLN int is_float(int t); 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 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); @@ -1618,6 +1619,8 @@ PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp); # define ST_PE_IMPORT 0x20 # define ST_PE_STDCALL 0x40 #endif +#define ST_ASM_SET 0x04 + /* ------------ tccrun.c ----------------- */ #ifdef TCC_IS_NATIVE #ifdef CONFIG_TCC_STATIC diff --git a/tccasm.c b/tccasm.c index e6ad5aa..ba76c17 100644 --- a/tccasm.c +++ b/tccasm.c @@ -36,64 +36,40 @@ static Sym sym_dot; static Sym *asm_label_find(int v) { - v -= TOK_IDENT; - if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) - return NULL; - return table_ident[v]->sym_asm_label; + Sym *sym = sym_find(v); + while (sym && sym->sym_scope) + sym = sym->prev_tok; + return sym; } -static Sym *asm_label_push(Sym **ptop, int v) +static Sym *asm_label_push(int v, int t) { - Sym *s, **ps; - s = sym_push2(ptop, v, 0, 0); - ps = &table_ident[v - TOK_IDENT]->sym_asm_label; - s->prev_tok = *ps; - *ps = s; - return s; + Sym *sym = global_identifier_push_1(&tcc_state->asm_labels, 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->r = VT_CONST | VT_SYM; + return sym; } /* Return a symbol we can use inside the assembler, having name NAME. - The assembler symbol table is different from the C symbol table - (and the Sym members are used differently). But we must be able - to look up file-global C symbols from inside the assembler, e.g. - for global asm blocks to be able to refer to defined C symbols. + Symbols from asm and C source share a namespace. If we generate + an asm symbol it's also a (file-global) C symbol, but it's + either not accessible by name (like "L.123"), or its type information + is such that it's not usable without a proper C declaration. - This routine gives back either an existing asm-internal - symbol, or a new one. In the latter case the new asm-internal - symbol is initialized with info from the C symbol table. - - If CSYM is non-null we take symbol info from it, otherwise - we look up NAME in the C symbol table and use that. */ + Sometimes we need symbols accessible by name from asm, which + are anonymous in C, in this case CSYM can be used to transfer + all information from that symbol to the (possibly newly created) + asm symbol. */ ST_FUNC Sym* get_asm_sym(int name, Sym *csym) { Sym *sym = asm_label_find(name); if (!sym) { - sym = asm_label_push(&tcc_state->asm_labels, name); - sym->type.t = VT_VOID | VT_EXTERN; - if (!csym) { - csym = sym_find(name); - /* We might be called for an asm block from inside a C routine - and so might have local decls on the identifier stack. Search - for the first global one. */ - while (csym && csym->sym_scope) - csym = csym->prev_tok; - } - /* Now, if we have a defined global symbol copy over - section and offset. */ - if (csym && - ((csym->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST)) && - csym->c) { - ElfW(Sym) *esym; - esym = &((ElfW(Sym) *)symtab_section->data)[csym->c]; - sym->c = csym->c; - sym->r = esym->st_shndx; - sym->jnext = esym->st_value; - /* XXX can't yet store st_size anywhere. */ - sym->type.t = VT_VOID | (csym->type.t & VT_STATIC); - /* Mark that this asm symbol doesn't need to be fed back. */ - sym->a.asmcsym = 1; - sym->a.asmexport = !(csym->type.t & VT_STATIC); - } + sym = asm_label_push(name, 0); + if (csym) + sym->c = csym->c; } return sym; } @@ -118,16 +94,15 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe) sym = asm_label_find(label); if (*p == 'b') { /* backward : find the last corresponding defined label */ - if (sym && sym->r == 0) + if (sym && (!sym->c || elfsym(sym)->st_shndx == SHN_UNDEF)) sym = sym->prev_tok; if (!sym) tcc_error("local label '%d' not found backward", n); } else { /* forward */ - if (!sym || sym->r) { + if (!sym || (sym->c && elfsym(sym)->st_shndx != SHN_UNDEF)) { /* if the last label is defined, then define a new one */ - sym = asm_label_push(&s1->asm_labels, label); - sym->type.t = VT_STATIC | VT_VOID | VT_EXTERN; + sym = asm_label_push(label, VT_STATIC); } } pe->v = 0; @@ -175,17 +150,20 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe) pe->sym = &sym_dot; pe->pcrel = 0; sym_dot.type.t = VT_VOID | VT_STATIC; - sym_dot.r = cur_text_section->sh_num; - sym_dot.jnext = ind; + sym_dot.c = -1; + tcc_state->esym_dot.st_shndx = cur_text_section->sh_num; + tcc_state->esym_dot.st_value = ind; next(); break; default: if (tok >= TOK_IDENT) { + ElfSym *esym; /* label case : if the label was not found, add one */ sym = get_asm_sym(tok, NULL); - if (sym->r == SHN_ABS) { + esym = elfsym(sym); + if (esym && esym->st_shndx == SHN_ABS) { /* if absolute symbol, no need to put a symbol value */ - pe->v = sym->jnext; + pe->v = esym->st_value; pe->sym = NULL; pe->pcrel = 0; } else { @@ -299,20 +277,26 @@ static inline void asm_expr_sum(TCCState *s1, ExprValue *pe) } else if (pe->sym == e2.sym) { /* OK */ pe->sym = NULL; /* same symbols can be subtracted to NULL */ - } else if (pe->sym && pe->sym->r == e2.sym->r && pe->sym->r != 0) { - /* we also accept defined symbols in the same section */ - pe->v += pe->sym->jnext - e2.sym->jnext; - pe->sym = NULL; - } else if (e2.sym->r == cur_text_section->sh_num) { - /* When subtracting a defined symbol in current section - this actually makes the value PC-relative. */ - pe->v -= e2.sym->jnext - ind - 4; - pe->pcrel = 1; - e2.sym = NULL; - } else { - cannot_relocate: - tcc_error("invalid operation with label"); - } + } else { + ElfSym *esym1, *esym2; + esym1 = elfsym(pe->sym); + esym2 = elfsym(e2.sym); + if (esym1 && esym1->st_shndx == esym2->st_shndx + && esym1->st_shndx != SHN_UNDEF) { + /* we also accept defined symbols in the same section */ + pe->v += esym1->st_value - esym2->st_value; + pe->sym = NULL; + } else if (esym2->st_shndx == cur_text_section->sh_num) { + /* When subtracting a defined symbol in current section + this actually makes the value PC-relative. */ + pe->v -= esym2->st_value - ind - 4; + pe->pcrel = 1; + e2.sym = NULL; + } else { +cannot_relocate: + tcc_error("invalid operation with label"); + } + } } } } @@ -377,13 +361,15 @@ static Sym* asm_new_label1(TCCState *s1, int label, int is_local, int sh_num, int value) { Sym *sym; + ElfSym *esym; sym = asm_label_find(label); if (sym) { + esym = elfsym(sym); /* A VT_EXTERN symbol, even if it has a section is considered overridable. This is how we "define" .set targets. Real definitions won't have VT_EXTERN set. */ - if (sym->r && !(sym->type.t & VT_EXTERN)) { + if (esym && esym->st_shndx != SHN_UNDEF && !(sym->type.t & VT_EXTERN)) { /* the label is already defined */ if (!is_local) { tcc_error("assembler label '%s' already defined", @@ -395,14 +381,13 @@ static Sym* asm_new_label1(TCCState *s1, int label, int is_local, } } else { new_label: - sym = asm_label_push(&s1->asm_labels, label); - /* If we need a symbol to hold a value, mark it as - tentative only (for .set). If this is for a real label - we'll remove VT_EXTERN. */ - sym->type.t = VT_VOID | (is_local ? VT_STATIC : 0) | VT_EXTERN; + sym = asm_label_push(label, is_local ? VT_STATIC : 0); } - sym->r = sh_num; - sym->jnext = value; + if (!sym->c) + put_extern_sym2(sym, NULL, 0, 0, 0); + esym = elfsym(sym); + esym->st_shndx = sh_num; + esym->st_value = value; return sym; } @@ -417,79 +402,41 @@ static Sym* set_symbol(TCCState *s1, int label) { long n; ExprValue e; + Sym *sym; + ElfSym *esym; next(); asm_expr(s1, &e); n = e.v; - if (e.sym) - n += e.sym->jnext; - return asm_new_label1(s1, label, 0, e.sym ? e.sym->r : SHN_ABS, n); -} - -/* Patch ELF symbol associated with SYM based on the assemblers - understanding. */ -static void patch_binding(Sym *sym) -{ - ElfW(Sym) *esym; - if (0 == sym->c) - return; - esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; - if (sym->a.visibility) - esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) - | sym->a.visibility; - - esym->st_info = ELFW(ST_INFO)(sym->a.weak ? STB_WEAK - : (sym->type.t & VT_STATIC) ? STB_LOCAL - : STB_GLOBAL, - ELFW(ST_TYPE)(esym->st_info)); + esym = elfsym(e.sym); + if (esym) + n += esym->st_value; + sym = asm_new_label1(s1, label, 0, 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; - Section *sec; for(s = st->asm_labels; s != NULL; s = s1) { - int was_ext = s->type.t & VT_EXTERN; + ElfSym *esym = elfsym(s); s1 = s->prev; - /* define symbol value in object file and care for updating - the C and asm symbols */ + /* Possibly update binding and visibility from asm directives. */ s->type.t &= ~VT_EXTERN; - if (!s->a.asmcsym) { - Sym *csym = sym_find(s->v); - ElfW(Sym) *esym = NULL; - if (csym) { - s->a.asmexport |= !(csym->type.t & VT_STATIC); - if (csym->c) { - esym = &((ElfW(Sym) *)symtab_section->data)[csym->c]; - if (s->c) { - /* We have generated code and possibly relocs - referencing the symtab entry s->c (the asm - ELF symbol). If that's undefined but the C - symbol is defined, copy over the info. */ - ElfW(Sym) *asm_esym = &((ElfW(Sym) *)symtab_section->data)[s->c]; - if (asm_esym->st_shndx == SHN_UNDEF) { - *asm_esym = *esym; - } - } - } - } - if (!s->a.asmexport) - s->type.t |= VT_STATIC; - if (s->r) { - if (s->r == SHN_ABS) - sec = SECTION_ABS; - else - sec = st->sections[s->r]; - /* !was_ext so that we run into an multi-def error if - we defined it in C and in asm (non-tentatively) */ - if (!esym || esym->st_shndx == SHN_UNDEF || !was_ext) - put_extern_sym2(s, sec, s->jnext, 0, 0); - } else /* undefined symbols are global */ - s->type.t &= ~VT_STATIC, s->a.asmexport = 1; - patch_binding(s); + if (esym) { + 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_asm_label = NULL; + table_ident[s->v - TOK_IDENT]->sym_identifier = s->prev_tok; sym_free(s); } st->asm_labels = NULL; @@ -715,13 +662,15 @@ static void asm_parse_directive(TCCState *s1, int global) { unsigned long n; ExprValue e; + ElfSym *esym; next(); asm_expr(s1, &e); n = e.v; - if (e.sym) { - if (e.sym->r != cur_text_section->sh_num) + esym = elfsym(e.sym); + if (esym) { + if (esym->st_shndx != cur_text_section->sh_num) expect("constant or same-section symbol"); - n += e.sym->jnext; + n += esym->st_value; } if (n < ind) tcc_error("attempt to .org backwards"); @@ -978,7 +927,6 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global) int opcode; int saved_parse_flags = parse_flags; - /* XXX: undefine C labels */ parse_flags = PARSE_FLAG_ASM_FILE | PARSE_FLAG_TOK_STR; if (do_preprocess) parse_flags |= PARSE_FLAG_PREPROCESS; @@ -1017,18 +965,8 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global) opcode = tok; next(); if (tok == ':') { - /* handle "extern void vide(void); __asm__("vide: ret");" as - "__asm__("globl vide\nvide: ret");" */ - Sym *sym = sym_find(opcode); - if (sym && (sym->type.t & VT_EXTERN) && global) { - sym = asm_label_find(opcode); - if (!sym) { - sym = asm_label_push(&s1->asm_labels, opcode); - sym->type.t = VT_VOID | VT_EXTERN; - } - } /* new label */ - sym = asm_new_label(s1, opcode, 0); + Sym *sym = asm_new_label(s1, opcode, 0); sym->type.t &= ~VT_EXTERN; next(); goto redo; diff --git a/tccelf.c b/tccelf.c index 22ce5df..422dfd6 100644 --- a/tccelf.c +++ b/tccelf.c @@ -310,7 +310,8 @@ 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) { + if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL + || sym->st_shndx == SHN_UNDEF) { h = elf_hash(strtab + sym->st_name) % nb_buckets; *ptr = hash[h]; hash[h] = sym_index; @@ -349,8 +350,9 @@ 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 or weak symbols */ - if (ELFW(ST_BIND)(info) != STB_LOCAL) { + /* 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) { /* add another hashing entry */ nbuckets = base[0]; h = elf_hash((unsigned char *) name) % nbuckets; @@ -486,6 +488,10 @@ ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size, /* data symbol keeps precedence over common/bss */ } else if (s == tcc_state->dynsymtab_section) { /* we accept that two DLL define the same symbol */ + } else if (esym->st_other & ST_ASM_SET) { + /* If the existing symbol came from an asm .set + we can override. */ + goto do_patch; } else { #if 0 printf("new_bind=%x new_shndx=%x new_vis=%x old_bind=%x old_shndx=%x old_vis=%x\n", diff --git a/tccgen.c b/tccgen.c index a86103c..2d3f2d0 100644 --- a/tccgen.c +++ b/tccgen.c @@ -286,14 +286,23 @@ ST_FUNC int tccgen_compile(TCCState *s1) } /* ------------------------------------------------------------------------- */ +ST_FUNC ElfSym *elfsym(Sym *s) +{ + if (!s || !s->c) + return NULL; + if (s->c == -1) + return &tcc_state->esym_dot; + else + return &((ElfSym *)symtab_section->data)[s->c]; +} + /* apply storage attributes to Elf symbol */ static void update_storage(Sym *sym) { - ElfW(Sym) *esym; - if (0 == sym->c) + ElfSym *esym = elfsym(sym); + if (!esym) return; - esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; if (sym->a.visibility) esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) | sym->a.visibility; @@ -325,7 +334,7 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section, int can_add_underscore) { int sym_type, sym_bind, sh_num, info, other, t; - ElfW(Sym) *esym; + ElfSym *esym; const char *name; char buf1[256]; #ifdef CONFIG_TCC_BCHECK @@ -402,7 +411,7 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section, info = ELFW(ST_INFO)(sym_bind, sym_type); sym->c = set_elf_sym(symtab_section, value, size, info, other, sh_num, name); } else { - esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; + esym = elfsym(sym); esym->st_value = value; esym->st_size = size; esym->st_shndx = sh_num; @@ -569,23 +578,28 @@ ST_FUNC Sym *sym_push(int v, CType *type, int r, int c) } /* push a global identifier */ -ST_FUNC Sym *global_identifier_push(int v, int t, int c) +ST_FUNC Sym *global_identifier_push_1(Sym **ptop, int v, int t, int c) { Sym *s, **ps; - s = sym_push2(&global_stack, v, t, c); + s = sym_push2(ptop, v, t, c); /* don't record anonymous symbol */ if (v < SYM_FIRST_ANOM) { ps = &table_ident[v - TOK_IDENT]->sym_identifier; /* modify the top most local identifier, so that sym_identifier will point to 's' when popped */ - while (*ps != NULL) + while (*ps != NULL && (*ps)->sym_scope) ps = &(*ps)->prev_tok; - s->prev_tok = NULL; + s->prev_tok = *ps; *ps = s; } 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) @@ -834,9 +848,13 @@ ST_FUNC Sym *external_global_sym(int v, CType *type, int r) /* Merge some storage attributes. */ static void patch_storage(Sym *sym, AttributeDef *ad, CType *type) { - if (type && !is_compatible_types(&sym->type, type)) - tcc_error("incompatible types for redefinition of '%s'", - get_tok_str(sym->v, NULL)); + if (type) { + if ((sym->type.t & VT_BTYPE) == VT_VOID) /* from asm */ + sym->type = *type; + else if (!is_compatible_types(&sym->type, type)) + tcc_error("incompatible types for redefinition of '%s'", + get_tok_str(sym->v, NULL)); + } #ifdef TCC_TARGET_PE if (sym->a.dllimport != ad->a.dllimport) tcc_error("incompatible dll linkage for redefinition of '%s'", @@ -6426,9 +6444,9 @@ static void init_putv(CType *type, Section *sec, unsigned long c) (vtop->type.t & VT_BTYPE) != VT_PTR) { /* These come from compound literals, memcpy stuff over. */ Section *ssec; - ElfW(Sym) *esym; + ElfSym *esym; ElfW_Rel *rel; - esym = &((ElfW(Sym) *)symtab_section->data)[vtop->sym->c]; + esym = elfsym(vtop->sym); ssec = tcc_state->sections[esym->st_shndx]; memmove (ptr, ssec->data + esym->st_value, size); if (ssec->reloc) { @@ -6895,8 +6913,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, /* no init data, we won't add more to the symbol */ goto no_alloc; } else if (sym->c) { - ElfW(Sym) *esym; - esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; + ElfSym *esym = elfsym(sym); if (esym->st_shndx == data_section->sh_num) tcc_error("redefinition of '%s'", get_tok_str(v, NULL)); } @@ -7030,8 +7047,7 @@ static void gen_function(Sym *sym) sym_pop(&local_stack, NULL, 0); /* end of function */ /* patch symbol size */ - ((ElfW(Sym) *)symtab_section->data)[sym->c].st_size = - ind - func_ind; + elfsym(sym)->st_size = ind - func_ind; tcc_debug_funcend(tcc_state, ind - func_ind); /* It's better to crash than to generate wrong code */ cur_text_section = NULL; @@ -7209,6 +7225,11 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym) sym = sym_find(v); if (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; @@ -7330,12 +7351,12 @@ found: sym = external_sym(v, &type, r, &ad); if (ad.alias_target) { Section tsec; - ElfW(Sym) *esym; + ElfSym *esym; Sym *alias_target; alias_target = sym_find(ad.alias_target); - if (!alias_target || !alias_target->c) + esym = elfsym(alias_target); + if (!esym) tcc_error("unsupported forward __alias__ attribute"); - esym = &((ElfW(Sym) *)symtab_section->data)[alias_target->c]; tsec.sh_num = esym->st_shndx; /* Local statics have a scope until now (for warnings), remove it here. */ diff --git a/tccpp.c b/tccpp.c index d8e7f53..76f9e42 100644 --- a/tccpp.c +++ b/tccpp.c @@ -432,7 +432,6 @@ static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len) ts->sym_label = NULL; ts->sym_struct = NULL; ts->sym_identifier = NULL; - ts->sym_asm_label = NULL; ts->len = len; ts->hash_next = NULL; memcpy(ts->str, str, len); diff --git a/tests/asm-c-connect-1.c b/tests/asm-c-connect-1.c index fbd240c..c3dcf2b 100644 --- a/tests/asm-c-connect-1.c +++ b/tests/asm-c-connect-1.c @@ -14,11 +14,13 @@ static int x1_c(void) asm(".text;"_"x1: call "_"x1_c; ret"); +void callx4(void); int main(int argc, char *argv[]) { asm("call "_"x1"); asm("call "_"x2"); asm("call "_"x3"); + callx4(); return 0; } @@ -30,3 +32,8 @@ int x2(void) } extern int x3(void); + +void x4(void) +{ + printf("x4\n"); +} diff --git a/tests/asm-c-connect-2.c b/tests/asm-c-connect-2.c index 3a8cff2..7ab9dc3 100644 --- a/tests/asm-c-connect-2.c +++ b/tests/asm-c-connect-2.c @@ -5,3 +5,6 @@ int x3(void) printf("x3\n"); return 3; } + +void callx4(void); +__asm__("callx4: call x4; ret");