while last change fixed one part of label behaviour (undefined ones must be global) it again broke a different aspect (forward defs without .globl must stay local). This fixes both aspects. That a label is local instead of global is difficult to test without resorting to look at the symbol table or using two-file testcases, so we do without. In essence the local/global-ness of symbols should be the same between GAS and TCC for this input: .globl glob1 glob1: call glob1 .globl glob2 call glob2 glob2: glob3: .globl glob3 call glob3 glob4: call glob4 .globl glob4 call glob5 .globl glob5 glob5: call glob6 glob6: .globl glob6 locl1: call locl1 call locl2 locl2: unref1: unref2: .globl unref2 .globl unref3 unref3: call undef
Unified · Split
| @@ -52,7 +52,7 @@ ST_FUNC Sym* get_asm_sym(int name, Sym *csym) · 51 unmodified lines | ||
| 52 | 52 | Sym *sym = label_find(name); |
| 53 | 53 | if (!sym) { |
| 54 | 54 | sym = label_push(&tcc_state->asm_labels, name, 0); |
| 55 | − sym->type.t = VT_VOID | VT_EXTERN; | |
| 55 | + sym->type.t = VT_VOID | VT_STATIC | VT_EXTERN; | |
| 56 | 56 | if (!csym) { |
| 57 | 57 | csym = sym_find(name); |
| 58 | 58 | /* We might be called for an asm block from inside a C routine |
| @@ -72,7 +72,7 @@ ST_FUNC Sym* get_asm_sym(int name, Sym *csym) · 13 unmodified lines | ||
| 72 | 72 | sym->r = esym->st_shndx; |
| 73 | 73 | sym->jnext = esym->st_value; |
| 74 | 74 | /* XXX can't yet store st_size anywhere. */ |
| 75 | − sym->type.t &= ~VT_EXTERN; | |
| 75 | + sym->type.t = VT_VOID | (csym->type.t & VT_STATIC); | |
| 76 | 76 | /* Mark that this asm symbol doesn't need to be fed back. */ |
| 77 | 77 | sym->a.dllimport = 1; |
| 78 | 78 | } |
| @@ -409,6 +409,24 @@ static Sym* set_symbol(TCCState *s1, int label) · 330 unmodified lines | ||
| 409 | 409 | return asm_new_label1(s1, label, 0, e.sym ? e.sym->r : SHN_ABS, n); |
| 410 | 410 | } |
| 411 | 411 | |
| 412 | +/* Patch ELF symbol associated with SYM based on the assemblers | |
| 413 | + understanding. */ | |
| 414 | +static void patch_binding(Sym *sym) | |
| 415 | +{ | |
| 416 | + ElfW(Sym) *esym; | |
| 417 | + if (0 == sym->c) | |
| 418 | + return; | |
| 419 | + esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; | |
| 420 | + if (sym->a.visibility) | |
| 421 | + esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) | |
| 422 | + | sym->a.visibility; | |
| 423 | + | |
| 424 | + esym->st_info = ELFW(ST_INFO)(sym->a.weak ? STB_WEAK | |
| 425 | + : (sym->type.t & VT_STATIC) ? STB_LOCAL | |
| 426 | + : STB_GLOBAL, | |
| 427 | + ELFW(ST_TYPE)(esym->st_info)); | |
| 428 | +} | |
| 429 | + | |
| 412 | 430 | static void asm_free_labels(TCCState *st) |
| 413 | 431 | { |
| 414 | 432 | Sym *s, *s1; |
| @@ -418,13 +436,17 @@ static void asm_free_labels(TCCState *st) · 3 unmodified lines | ||
| 418 | 436 | s1 = s->prev; |
| 419 | 437 | /* define symbol value in object file */ |
| 420 | 438 | s->type.t &= ~VT_EXTERN; |
| 421 | − if (s->r && !s->a.dllimport) { | |
| 422 | − if (s->r == SHN_ABS) | |
| 423 | − sec = SECTION_ABS; | |
| 424 | − else | |
| 425 | − sec = st->sections[s->r]; | |
| 426 | − put_extern_sym2(s, sec, s->jnext, 0, 0); | |
| 427 | − } | |
| 439 | + if (!s->a.dllimport) { | |
| 440 | + if (s->r) { | |
| 441 | + if (s->r == SHN_ABS) | |
| 442 | + sec = SECTION_ABS; | |
| 443 | + else | |
| 444 | + sec = st->sections[s->r]; | |
| 445 | + put_extern_sym2(s, sec, s->jnext, 0, 0); | |
| 446 | + } else /* undefined symbols are global */ | |
| 447 | + s->type.t &= ~VT_STATIC; | |
| 448 | + } | |
| 449 | + patch_binding(s); | |
| 428 | 450 | /* remove label */ |
| 429 | 451 | table_ident[s->v - TOK_IDENT]->sym_label = NULL; |
| 430 | 452 | sym_free(s); |