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.
Unified · Split
| @@ -500,12 +500,13 @@ ST_FUNC void gen_expr64(ExprValue *pe) · 499 unmodified lines | ||
| 500 | 500 | static void gen_disp32(ExprValue *pe) |
| 501 | 501 | { |
| 502 | 502 | Sym *sym = pe->sym; |
| 503 | − if (sym && sym->r == cur_text_section->sh_num) { | |
| 503 | + ElfSym *esym = elfsym(sym); | |
| 504 | + if (esym && esym->st_shndx == cur_text_section->sh_num) { | |
| 504 | 505 | /* same section: we can output an absolute value. Note |
| 505 | 506 | that the TCC compiler behaves differently here because |
| 506 | 507 | it always outputs a relocation to ease (future) code |
| 507 | 508 | elimination in the linker */ |
| 508 | − gen_le32(pe->v + sym->jnext - ind - 4); | |
| 509 | + gen_le32(pe->v + esym->st_value - ind - 4); | |
| 509 | 510 | } else { |
| 510 | 511 | if (sym && sym->type.t == VT_VOID) { |
| 511 | 512 | sym->type.t = VT_FUNC; |
| @@ -1017,16 +1018,14 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 505 unmodified lines | ||
| 1017 | 1018 | if (pa->instr_type & OPC_B) |
| 1018 | 1019 | v += s >= 1; |
| 1019 | 1020 | if (nb_ops == 1 && pa->op_type[0] == OPT_DISP8) { |
| 1020 | − Sym *sym; | |
| 1021 | + ElfSym *esym; | |
| 1021 | 1022 | int jmp_disp; |
| 1022 | 1023 | |
| 1023 | 1024 | /* see if we can really generate the jump with a byte offset */ |
| 1024 | − sym = ops[0].e.sym; | |
| 1025 | − if (!sym) | |
| 1025 | + esym = elfsym(ops[0].e.sym); | |
| 1026 | + if (!esym || esym->st_shndx != cur_text_section->sh_num) | |
| 1026 | 1027 | goto no_short_jump; |
| 1027 | − if (sym->r != cur_text_section->sh_num) | |
| 1028 | − goto no_short_jump; | |
| 1029 | − jmp_disp = ops[0].e.v + sym->jnext - ind - 2 - (v >= 0xff); | |
| 1028 | + jmp_disp = ops[0].e.v + esym->st_value - ind - 2 - (v >= 0xff); | |
| 1030 | 1029 | if (jmp_disp == (int8_t)jmp_disp) { |
| 1031 | 1030 | /* OK to generate jump */ |
| 1032 | 1031 | ops[0].e.sym = 0; |
| @@ -356,6 +356,7 @@ extern long double strtold (const char *__nptr, char **__endptr); · 355 unmodified lines | ||
| 356 | 356 | #endif |
| 357 | 357 | /* target address type */ |
| 358 | 358 | #define addr_t ElfW(Addr) |
| 359 | +#define ElfSym ElfW(Sym) | |
| 359 | 360 | |
| 360 | 361 | #if PTR_SIZE == 8 && !defined TCC_TARGET_PE |
| 361 | 362 | # define LONG_SIZE 8 |
| @@ -383,7 +384,6 @@ typedef struct TokenSym { · 21 unmodified lines | ||
| 383 | 384 | struct Sym *sym_label; /* direct pointer to label */ |
| 384 | 385 | struct Sym *sym_struct; /* direct pointer to structure */ |
| 385 | 386 | struct Sym *sym_identifier; /* direct pointer to identifier */ |
| 386 | − struct Sym *sym_asm_label; /* direct pointer to asm label */ | |
| 387 | 387 | int tok; /* token number */ |
| 388 | 388 | int len; |
| 389 | 389 | char str[1]; |
| @@ -440,9 +440,8 @@ struct SymAttr { · 50 unmodified lines | ||
| 440 | 440 | visibility : 2, |
| 441 | 441 | dllexport : 1, |
| 442 | 442 | dllimport : 1, |
| 443 | − asmcsym : 1, | |
| 444 | 443 | asmexport : 1, |
| 445 | − unused : 3; | |
| 444 | + unused : 4; | |
| 446 | 445 | }; |
| 447 | 446 | |
| 448 | 447 | /* function attributes or temporary attributes for parsing */ |
| @@ -799,6 +798,7 @@ struct TCCState { · 350 unmodified lines | ||
| 799 | 798 | int nb_sym_attrs; |
| 800 | 799 | /* tiny assembler state */ |
| 801 | 800 | Sym *asm_labels; |
| 801 | + ElfSym esym_dot; | |
| 802 | 802 | |
| 803 | 803 | #ifdef TCC_TARGET_PE |
| 804 | 804 | /* PE info */ |
| @@ -1147,7 +1147,7 @@ ST_FUNC Sym *sym_push(int v, CType *type, int r, int c); · 342 unmodified lines | ||
| 1147 | 1147 | ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep); |
| 1148 | 1148 | ST_INLN Sym *struct_find(int v); |
| 1149 | 1149 | ST_INLN Sym *sym_find(int v); |
| 1150 | −ST_FUNC Sym *global_identifier_push(int v, int t, int c); | |
| 1150 | +ST_FUNC Sym *global_identifier_push_1(Sym **, int v, int t, int c); | |
| 1151 | 1151 | |
| 1152 | 1152 | ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen); |
| 1153 | 1153 | ST_FUNC int tcc_open(TCCState *s1, const char *filename); |
| @@ -1316,6 +1316,7 @@ ST_INLN int is_float(int t); · 162 unmodified lines | ||
| 1316 | 1316 | ST_FUNC int ieee_finite(double d); |
| 1317 | 1317 | ST_FUNC void test_lvalue(void); |
| 1318 | 1318 | ST_FUNC void vpushi(int v); |
| 1319 | +ST_FUNC ElfSym *elfsym(Sym *); | |
| 1319 | 1320 | ST_FUNC Sym *external_global_sym(int v, CType *type, int r); |
| 1320 | 1321 | ST_FUNC void vset(CType *type, int r, int v); |
| 1321 | 1322 | ST_FUNC void vswap(void); |
| @@ -1618,6 +1619,8 @@ PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp); · 296 unmodified lines | ||
| 1618 | 1619 | # define ST_PE_IMPORT 0x20 |
| 1619 | 1620 | # define ST_PE_STDCALL 0x40 |
| 1620 | 1621 | #endif |
| 1622 | +#define ST_ASM_SET 0x04 | |
| 1623 | + | |
| 1621 | 1624 | /* ------------ tccrun.c ----------------- */ |
| 1622 | 1625 | #ifdef TCC_IS_NATIVE |
| 1623 | 1626 | #ifdef CONFIG_TCC_STATIC |
| @@ -36,64 +36,40 @@ static Sym sym_dot; · 35 unmodified lines | ||
| 36 | 36 | |
| 37 | 37 | static Sym *asm_label_find(int v) |
| 38 | 38 | { |
| 39 | − v -= TOK_IDENT; | |
| 40 | − if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) | |
| 41 | − return NULL; | |
| 42 | − return table_ident[v]->sym_asm_label; | |
| 39 | + Sym *sym = sym_find(v); | |
| 40 | + while (sym && sym->sym_scope) | |
| 41 | + sym = sym->prev_tok; | |
| 42 | + return sym; | |
| 43 | 43 | } |
| 44 | 44 | |
| 45 | −static Sym *asm_label_push(Sym **ptop, int v) | |
| 45 | +static Sym *asm_label_push(int v, int t) | |
| 46 | 46 | { |
| 47 | − Sym *s, **ps; | |
| 48 | − s = sym_push2(ptop, v, 0, 0); | |
| 49 | − ps = &table_ident[v - TOK_IDENT]->sym_asm_label; | |
| 50 | − s->prev_tok = *ps; | |
| 51 | − *ps = s; | |
| 52 | − return s; | |
| 47 | + Sym *sym = global_identifier_push_1(&tcc_state->asm_labels, v, t, 0); | |
| 48 | + /* We always add VT_EXTERN, for sym definition that's tentative | |
| 49 | + (for .set, removed for real defs), for mere references it's correct | |
| 50 | + as is. */ | |
| 51 | + sym->type.t |= VT_VOID | VT_EXTERN; | |
| 52 | + sym->r = VT_CONST | VT_SYM; | |
| 53 | + return sym; | |
| 53 | 54 | } |
| 54 | 55 | |
| 55 | 56 | /* Return a symbol we can use inside the assembler, having name NAME. |
| 56 | − The assembler symbol table is different from the C symbol table | |
| 57 | − (and the Sym members are used differently). But we must be able | |
| 58 | − to look up file-global C symbols from inside the assembler, e.g. | |
| 59 | − for global asm blocks to be able to refer to defined C symbols. | |
| 60 | − | |
| 61 | − This routine gives back either an existing asm-internal | |
| 62 | − symbol, or a new one. In the latter case the new asm-internal | |
| 63 | − symbol is initialized with info from the C symbol table. | |
| 64 | − | |
| 65 | − If CSYM is non-null we take symbol info from it, otherwise | |
| 66 | − we look up NAME in the C symbol table and use that. */ | |
| 57 | + Symbols from asm and C source share a namespace. If we generate | |
| 58 | + an asm symbol it's also a (file-global) C symbol, but it's | |
| 59 | + either not accessible by name (like "L.123"), or its type information | |
| 60 | + is such that it's not usable without a proper C declaration. | |
| 61 | + | |
| 62 | + Sometimes we need symbols accessible by name from asm, which | |
| 63 | + are anonymous in C, in this case CSYM can be used to transfer | |
| 64 | + all information from that symbol to the (possibly newly created) | |
| 65 | + asm symbol. */ | |
| 67 | 66 | ST_FUNC Sym* get_asm_sym(int name, Sym *csym) |
| 68 | 67 | { |
| 69 | 68 | Sym *sym = asm_label_find(name); |
| 70 | 69 | if (!sym) { |
| 71 | − sym = asm_label_push(&tcc_state->asm_labels, name); | |
| 72 | − sym->type.t = VT_VOID | VT_EXTERN; | |
| 73 | − if (!csym) { | |
| 74 | − csym = sym_find(name); | |
| 75 | − /* We might be called for an asm block from inside a C routine | |
| 76 | − and so might have local decls on the identifier stack. Search | |
| 77 | − for the first global one. */ | |
| 78 | − while (csym && csym->sym_scope) | |
| 79 | − csym = csym->prev_tok; | |
| 80 | − } | |
| 81 | − /* Now, if we have a defined global symbol copy over | |
| 82 | − section and offset. */ | |
| 83 | − if (csym && | |
| 84 | − ((csym->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST)) && | |
| 85 | − csym->c) { | |
| 86 | − ElfW(Sym) *esym; | |
| 87 | − esym = &((ElfW(Sym) *)symtab_section->data)[csym->c]; | |
| 88 | − sym->c = csym->c; | |
| 89 | − sym->r = esym->st_shndx; | |
| 90 | − sym->jnext = esym->st_value; | |
| 91 | − /* XXX can't yet store st_size anywhere. */ | |
| 92 | − sym->type.t = VT_VOID | (csym->type.t & VT_STATIC); | |
| 93 | − /* Mark that this asm symbol doesn't need to be fed back. */ | |
| 94 | − sym->a.asmcsym = 1; | |
| 95 | − sym->a.asmexport = !(csym->type.t & VT_STATIC); | |
| 96 | − } | |
| 70 | + sym = asm_label_push(name, 0); | |
| 71 | + if (csym) | |
| 72 | + sym->c = csym->c; | |
| 97 | 73 | } |
| 98 | 74 | return sym; |
| 99 | 75 | } |
| @@ -118,16 +94,15 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe) · 18 unmodified lines | ||
| 118 | 94 | sym = asm_label_find(label); |
| 119 | 95 | if (*p == 'b') { |
| 120 | 96 | /* backward : find the last corresponding defined label */ |
| 121 | − if (sym && sym->r == 0) | |
| 97 | + if (sym && (!sym->c || elfsym(sym)->st_shndx == SHN_UNDEF)) | |
| 122 | 98 | sym = sym->prev_tok; |
| 123 | 99 | if (!sym) |
| 124 | 100 | tcc_error("local label '%d' not found backward", n); |
| 125 | 101 | } else { |
| 126 | 102 | /* forward */ |
| 127 | − if (!sym || sym->r) { | |
| 103 | + if (!sym || (sym->c && elfsym(sym)->st_shndx != SHN_UNDEF)) { | |
| 128 | 104 | /* if the last label is defined, then define a new one */ |
| 129 | − sym = asm_label_push(&s1->asm_labels, label); | |
| 130 | − sym->type.t = VT_STATIC | VT_VOID | VT_EXTERN; | |
| 105 | + sym = asm_label_push(label, VT_STATIC); | |
| 131 | 106 | } |
| 132 | 107 | } |
| 133 | 108 | pe->v = 0; |
| @@ -175,17 +150,20 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe) · 41 unmodified lines | ||
| 175 | 150 | pe->sym = &sym_dot; |
| 176 | 151 | pe->pcrel = 0; |
| 177 | 152 | sym_dot.type.t = VT_VOID | VT_STATIC; |
| 178 | − sym_dot.r = cur_text_section->sh_num; | |
| 179 | − sym_dot.jnext = ind; | |
| 153 | + sym_dot.c = -1; | |
| 154 | + tcc_state->esym_dot.st_shndx = cur_text_section->sh_num; | |
| 155 | + tcc_state->esym_dot.st_value = ind; | |
| 180 | 156 | next(); |
| 181 | 157 | break; |
| 182 | 158 | default: |
| 183 | 159 | if (tok >= TOK_IDENT) { |
| 160 | + ElfSym *esym; | |
| 184 | 161 | /* label case : if the label was not found, add one */ |
| 185 | 162 | sym = get_asm_sym(tok, NULL); |
| 186 | − if (sym->r == SHN_ABS) { | |
| 163 | + esym = elfsym(sym); | |
| 164 | + if (esym && esym->st_shndx == SHN_ABS) { | |
| 187 | 165 | /* if absolute symbol, no need to put a symbol value */ |
| 188 | − pe->v = sym->jnext; | |
| 166 | + pe->v = esym->st_value; | |
| 189 | 167 | pe->sym = NULL; |
| 190 | 168 | pe->pcrel = 0; |
| 191 | 169 | } else { |
| @@ -299,20 +277,26 @@ static inline void asm_expr_sum(TCCState *s1, ExprValue *pe) · 107 unmodified lines | ||
| 299 | 277 | } else if (pe->sym == e2.sym) { |
| 300 | 278 | /* OK */ |
| 301 | 279 | pe->sym = NULL; /* same symbols can be subtracted to NULL */ |
| 302 | − } else if (pe->sym && pe->sym->r == e2.sym->r && pe->sym->r != 0) { | |
| 303 | − /* we also accept defined symbols in the same section */ | |
| 304 | − pe->v += pe->sym->jnext - e2.sym->jnext; | |
| 305 | − pe->sym = NULL; | |
| 306 | − } else if (e2.sym->r == cur_text_section->sh_num) { | |
| 307 | − /* When subtracting a defined symbol in current section | |
| 308 | − this actually makes the value PC-relative. */ | |
| 309 | − pe->v -= e2.sym->jnext - ind - 4; | |
| 310 | − pe->pcrel = 1; | |
| 311 | − e2.sym = NULL; | |
| 312 | − } else { | |
| 313 | − cannot_relocate: | |
| 314 | − tcc_error("invalid operation with label"); | |
| 315 | − } | |
| 280 | + } else { | |
| 281 | + ElfSym *esym1, *esym2; | |
| 282 | + esym1 = elfsym(pe->sym); | |
| 283 | + esym2 = elfsym(e2.sym); | |
| 284 | + if (esym1 && esym1->st_shndx == esym2->st_shndx | |
| 285 | + && esym1->st_shndx != SHN_UNDEF) { | |
| 286 | + /* we also accept defined symbols in the same section */ | |
| 287 | + pe->v += esym1->st_value - esym2->st_value; | |
| 288 | + pe->sym = NULL; | |
| 289 | + } else if (esym2->st_shndx == cur_text_section->sh_num) { | |
| 290 | + /* When subtracting a defined symbol in current section | |
| 291 | + this actually makes the value PC-relative. */ | |
| 292 | + pe->v -= esym2->st_value - ind - 4; | |
| 293 | + pe->pcrel = 1; | |
| 294 | + e2.sym = NULL; | |
| 295 | + } else { | |
| 296 | +cannot_relocate: | |
| 297 | + tcc_error("invalid operation with label"); | |
| 298 | + } | |
| 299 | + } | |
| 316 | 300 | } |
| 317 | 301 | } |
| 318 | 302 | } |
| @@ -377,13 +361,15 @@ static Sym* asm_new_label1(TCCState *s1, int label, int is_local, · 58 unmodified lines | ||
| 377 | 361 | int sh_num, int value) |
| 378 | 362 | { |
| 379 | 363 | Sym *sym; |
| 364 | + ElfSym *esym; | |
| 380 | 365 | |
| 381 | 366 | sym = asm_label_find(label); |
| 382 | 367 | if (sym) { |
| 368 | + esym = elfsym(sym); | |
| 383 | 369 | /* A VT_EXTERN symbol, even if it has a section is considered |
| 384 | 370 | overridable. This is how we "define" .set targets. Real |
| 385 | 371 | definitions won't have VT_EXTERN set. */ |
| 386 | − if (sym->r && !(sym->type.t & VT_EXTERN)) { | |
| 372 | + if (esym && esym->st_shndx != SHN_UNDEF && !(sym->type.t & VT_EXTERN)) { | |
| 387 | 373 | /* the label is already defined */ |
| 388 | 374 | if (!is_local) { |
| 389 | 375 | tcc_error("assembler label '%s' already defined", |
| @@ -395,14 +381,13 @@ static Sym* asm_new_label1(TCCState *s1, int label, int is_local, · 5 unmodified lines | ||
| 395 | 381 | } |
| 396 | 382 | } else { |
| 397 | 383 | new_label: |
| 398 | − sym = asm_label_push(&s1->asm_labels, label); | |
| 399 | − /* If we need a symbol to hold a value, mark it as | |
| 400 | − tentative only (for .set). If this is for a real label | |
| 401 | − we'll remove VT_EXTERN. */ | |
| 402 | − sym->type.t = VT_VOID | (is_local ? VT_STATIC : 0) | VT_EXTERN; | |
| 384 | + sym = asm_label_push(label, is_local ? VT_STATIC : 0); | |
| 403 | 385 | } |
| 404 | − sym->r = sh_num; | |
| 405 | − sym->jnext = value; | |
| 386 | + if (!sym->c) | |
| 387 | + put_extern_sym2(sym, NULL, 0, 0, 0); | |
| 388 | + esym = elfsym(sym); | |
| 389 | + esym->st_shndx = sh_num; | |
| 390 | + esym->st_value = value; | |
| 406 | 391 | return sym; |
| 407 | 392 | } |
| 408 | 393 | |
| @@ -417,79 +402,41 @@ static Sym* set_symbol(TCCState *s1, int label) · 8 unmodified lines | ||
| 417 | 402 | { |
| 418 | 403 | long n; |
| 419 | 404 | ExprValue e; |
| 405 | + Sym *sym; | |
| 406 | + ElfSym *esym; | |
| 420 | 407 | next(); |
| 421 | 408 | asm_expr(s1, &e); |
| 422 | 409 | n = e.v; |
| 423 | − if (e.sym) | |
| 424 | − n += e.sym->jnext; | |
| 425 | − return asm_new_label1(s1, label, 0, e.sym ? e.sym->r : SHN_ABS, n); | |
| 426 | −} | |
| 427 | − | |
| 428 | −/* Patch ELF symbol associated with SYM based on the assemblers | |
| 429 | − understanding. */ | |
| 430 | −static void patch_binding(Sym *sym) | |
| 431 | −{ | |
| 432 | − ElfW(Sym) *esym; | |
| 433 | − if (0 == sym->c) | |
| 434 | − return; | |
| 435 | − esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; | |
| 436 | − if (sym->a.visibility) | |
| 437 | − esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) | |
| 438 | − | sym->a.visibility; | |
| 439 | − | |
| 440 | − esym->st_info = ELFW(ST_INFO)(sym->a.weak ? STB_WEAK | |
| 441 | − : (sym->type.t & VT_STATIC) ? STB_LOCAL | |
| 442 | − : STB_GLOBAL, | |
| 443 | − ELFW(ST_TYPE)(esym->st_info)); | |
| 410 | + esym = elfsym(e.sym); | |
| 411 | + if (esym) | |
| 412 | + n += esym->st_value; | |
| 413 | + sym = asm_new_label1(s1, label, 0, esym ? esym->st_shndx : SHN_ABS, n); | |
| 414 | + elfsym(sym)->st_other |= ST_ASM_SET; | |
| 415 | + return sym; | |
| 444 | 416 | } |
| 445 | 417 | |
| 446 | 418 | ST_FUNC void asm_free_labels(TCCState *st) |
| 447 | 419 | { |
| 448 | 420 | Sym *s, *s1; |
| 449 | − Section *sec; | |
| 450 | 421 | |
| 451 | 422 | for(s = st->asm_labels; s != NULL; s = s1) { |
| 452 | − int was_ext = s->type.t & VT_EXTERN; | |
| 423 | + ElfSym *esym = elfsym(s); | |
| 453 | 424 | s1 = s->prev; |
| 454 | − /* define symbol value in object file and care for updating | |
| 455 | − the C and asm symbols */ | |
| 425 | + /* Possibly update binding and visibility from asm directives. */ | |
| 456 | 426 | s->type.t &= ~VT_EXTERN; |
| 457 | − if (!s->a.asmcsym) { | |
| 458 | − Sym *csym = sym_find(s->v); | |
| 459 | − ElfW(Sym) *esym = NULL; | |
| 460 | − if (csym) { | |
| 461 | − s->a.asmexport |= !(csym->type.t & VT_STATIC); | |
| 462 | − if (csym->c) { | |
| 463 | − esym = &((ElfW(Sym) *)symtab_section->data)[csym->c]; | |
| 464 | − if (s->c) { | |
| 465 | − /* We have generated code and possibly relocs | |
| 466 | − referencing the symtab entry s->c (the asm | |
| 467 | − ELF symbol). If that's undefined but the C | |
| 468 | − symbol is defined, copy over the info. */ | |
| 469 | − ElfW(Sym) *asm_esym = &((ElfW(Sym) *)symtab_section->data)[s->c]; | |
| 470 | − if (asm_esym->st_shndx == SHN_UNDEF) { | |
| 471 | − *asm_esym = *esym; | |
| 472 | − } | |
| 473 | − } | |
| 474 | − } | |
| 475 | − } | |
| 476 | − if (!s->a.asmexport) | |
| 477 | − s->type.t |= VT_STATIC; | |
| 478 | − if (s->r) { | |
| 479 | − if (s->r == SHN_ABS) | |
| 480 | − sec = SECTION_ABS; | |
| 481 | − else | |
| 482 | − sec = st->sections[s->r]; | |
| 483 | − /* !was_ext so that we run into an multi-def error if | |
| 484 | − we defined it in C and in asm (non-tentatively) */ | |
| 485 | − if (!esym || esym->st_shndx == SHN_UNDEF || !was_ext) | |
| 486 | − put_extern_sym2(s, sec, s->jnext, 0, 0); | |
| 487 | − } else /* undefined symbols are global */ | |
| 488 | − s->type.t &= ~VT_STATIC, s->a.asmexport = 1; | |
| 489 | − patch_binding(s); | |
| 427 | + if (esym) { | |
| 428 | + if (!s->a.asmexport && esym->st_shndx != SHN_UNDEF) | |
| 429 | + s->type.t |= VT_STATIC; | |
| 430 | + if (s->a.visibility) | |
| 431 | + esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) | |
| 432 | + | s->a.visibility; | |
| 433 | + esym->st_info = ELFW(ST_INFO)(s->a.weak ? STB_WEAK | |
| 434 | + : (s->type.t & VT_STATIC) ? STB_LOCAL | |
| 435 | + : STB_GLOBAL, | |
| 436 | + ELFW(ST_TYPE)(esym->st_info)); | |
| 490 | 437 | } |
| 491 | 438 | /* remove label */ |
| 492 | − table_ident[s->v - TOK_IDENT]->sym_asm_label = NULL; | |
| 439 | + table_ident[s->v - TOK_IDENT]->sym_identifier = s->prev_tok; | |
| 493 | 440 | sym_free(s); |
| 494 | 441 | } |
| 495 | 442 | st->asm_labels = NULL; |
| @@ -715,13 +662,15 @@ static void asm_parse_directive(TCCState *s1, int global) · 219 unmodified lines | ||
| 715 | 662 | { |
| 716 | 663 | unsigned long n; |
| 717 | 664 | ExprValue e; |
| 665 | + ElfSym *esym; | |
| 718 | 666 | next(); |
| 719 | 667 | asm_expr(s1, &e); |
| 720 | 668 | n = e.v; |
| 721 | − if (e.sym) { | |
| 722 | − if (e.sym->r != cur_text_section->sh_num) | |
| 669 | + esym = elfsym(e.sym); | |
| 670 | + if (esym) { | |
| 671 | + if (esym->st_shndx != cur_text_section->sh_num) | |
| 723 | 672 | expect("constant or same-section symbol"); |
| 724 | − n += e.sym->jnext; | |
| 673 | + n += esym->st_value; | |
| 725 | 674 | } |
| 726 | 675 | if (n < ind) |
| 727 | 676 | tcc_error("attempt to .org backwards"); |
| @@ -978,7 +927,6 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global) · 250 unmodified lines | ||
| 978 | 927 | int opcode; |
| 979 | 928 | int saved_parse_flags = parse_flags; |
| 980 | 929 | |
| 981 | − /* XXX: undefine C labels */ | |
| 982 | 930 | parse_flags = PARSE_FLAG_ASM_FILE | PARSE_FLAG_TOK_STR; |
| 983 | 931 | if (do_preprocess) |
| 984 | 932 | parse_flags |= PARSE_FLAG_PREPROCESS; |
| @@ -1017,18 +965,8 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global) · 32 unmodified lines | ||
| 1017 | 965 | opcode = tok; |
| 1018 | 966 | next(); |
| 1019 | 967 | if (tok == ':') { |
| 1020 | − /* handle "extern void vide(void); __asm__("vide: ret");" as | |
| 1021 | − "__asm__("globl vide\nvide: ret");" */ | |
| 1022 | − Sym *sym = sym_find(opcode); | |
| 1023 | − if (sym && (sym->type.t & VT_EXTERN) && global) { | |
| 1024 | − sym = asm_label_find(opcode); | |
| 1025 | − if (!sym) { | |
| 1026 | − sym = asm_label_push(&s1->asm_labels, opcode); | |
| 1027 | − sym->type.t = VT_VOID | VT_EXTERN; | |
| 1028 | − } | |
| 1029 | − } | |
| 1030 | 968 | /* new label */ |
| 1031 | − sym = asm_new_label(s1, opcode, 0); | |
| 969 | + Sym *sym = asm_new_label(s1, opcode, 0); | |
| 1032 | 970 | sym->type.t &= ~VT_EXTERN; |
| 1033 | 971 | next(); |
| 1034 | 972 | goto redo; |
| @@ -310,7 +310,8 @@ static void rebuild_hash(Section *s, unsigned int nb_buckets) · 309 unmodified lines | ||
| 310 | 310 | |
| 311 | 311 | sym = (ElfW(Sym) *)s->data + 1; |
| 312 | 312 | for(sym_index = 1; sym_index < nb_syms; sym_index++) { |
| 313 | − if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { | |
| 313 | + if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL | |
| 314 | + || sym->st_shndx == SHN_UNDEF) { | |
| 314 | 315 | h = elf_hash(strtab + sym->st_name) % nb_buckets; |
| 315 | 316 | *ptr = hash[h]; |
| 316 | 317 | hash[h] = sym_index; |
| @@ -349,8 +350,9 @@ ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size, · 32 unmodified lines | ||
| 349 | 350 | int *ptr, *base; |
| 350 | 351 | ptr = section_ptr_add(hs, sizeof(int)); |
| 351 | 352 | base = (int *)hs->data; |
| 352 | − /* only add global or weak symbols */ | |
| 353 | − if (ELFW(ST_BIND)(info) != STB_LOCAL) { | |
| 353 | + /* only add global, weak or undef symbols. The latter might | |
| 354 | + become global late (from asm references). */ | |
| 355 | + if (ELFW(ST_BIND)(info) != STB_LOCAL || shndx == SHN_UNDEF) { | |
| 354 | 356 | /* add another hashing entry */ |
| 355 | 357 | nbuckets = base[0]; |
| 356 | 358 | 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, · 129 unmodified lines | ||
| 486 | 488 | /* data symbol keeps precedence over common/bss */ |
| 487 | 489 | } else if (s == tcc_state->dynsymtab_section) { |
| 488 | 490 | /* we accept that two DLL define the same symbol */ |
| 491 | + } else if (esym->st_other & ST_ASM_SET) { | |
| 492 | + /* If the existing symbol came from an asm .set | |
| 493 | + we can override. */ | |
| 494 | + goto do_patch; | |
| 489 | 495 | } else { |
| 490 | 496 | #if 0 |
| 491 | 497 | printf("new_bind=%x new_shndx=%x new_vis=%x old_bind=%x old_shndx=%x old_vis=%x\n", |
| @@ -286,14 +286,23 @@ ST_FUNC int tccgen_compile(TCCState *s1) · 285 unmodified lines | ||
| 286 | 286 | } |
| 287 | 287 | |
| 288 | 288 | /* ------------------------------------------------------------------------- */ |
| 289 | +ST_FUNC ElfSym *elfsym(Sym *s) | |
| 290 | +{ | |
| 291 | + if (!s || !s->c) | |
| 292 | + return NULL; | |
| 293 | + if (s->c == -1) | |
| 294 | + return &tcc_state->esym_dot; | |
| 295 | + else | |
| 296 | + return &((ElfSym *)symtab_section->data)[s->c]; | |
| 297 | +} | |
| 298 | + | |
| 289 | 299 | /* apply storage attributes to Elf symbol */ |
| 290 | 300 | |
| 291 | 301 | static void update_storage(Sym *sym) |
| 292 | 302 | { |
| 293 | − ElfW(Sym) *esym; | |
| 294 | − if (0 == sym->c) | |
| 303 | + ElfSym *esym = elfsym(sym); | |
| 304 | + if (!esym) | |
| 295 | 305 | return; |
| 296 | − esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; | |
| 297 | 306 | if (sym->a.visibility) |
| 298 | 307 | esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) |
| 299 | 308 | | sym->a.visibility; |
| @@ -325,7 +334,7 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section, · 25 unmodified lines | ||
| 325 | 334 | int can_add_underscore) |
| 326 | 335 | { |
| 327 | 336 | int sym_type, sym_bind, sh_num, info, other, t; |
| 328 | − ElfW(Sym) *esym; | |
| 337 | + ElfSym *esym; | |
| 329 | 338 | const char *name; |
| 330 | 339 | char buf1[256]; |
| 331 | 340 | #ifdef CONFIG_TCC_BCHECK |
| @@ -402,7 +411,7 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section, · 70 unmodified lines | ||
| 402 | 411 | info = ELFW(ST_INFO)(sym_bind, sym_type); |
| 403 | 412 | sym->c = set_elf_sym(symtab_section, value, size, info, other, sh_num, name); |
| 404 | 413 | } else { |
| 405 | − esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; | |
| 414 | + esym = elfsym(sym); | |
| 406 | 415 | esym->st_value = value; |
| 407 | 416 | esym->st_size = size; |
| 408 | 417 | esym->st_shndx = sh_num; |
| @@ -569,23 +578,28 @@ ST_FUNC Sym *sym_push(int v, CType *type, int r, int c) · 160 unmodified lines | ||
| 569 | 578 | } |
| 570 | 579 | |
| 571 | 580 | /* push a global identifier */ |
| 572 | −ST_FUNC Sym *global_identifier_push(int v, int t, int c) | |
| 581 | +ST_FUNC Sym *global_identifier_push_1(Sym **ptop, int v, int t, int c) | |
| 573 | 582 | { |
| 574 | 583 | Sym *s, **ps; |
| 575 | − s = sym_push2(&global_stack, v, t, c); | |
| 584 | + s = sym_push2(ptop, v, t, c); | |
| 576 | 585 | /* don't record anonymous symbol */ |
| 577 | 586 | if (v < SYM_FIRST_ANOM) { |
| 578 | 587 | ps = &table_ident[v - TOK_IDENT]->sym_identifier; |
| 579 | 588 | /* modify the top most local identifier, so that |
| 580 | 589 | sym_identifier will point to 's' when popped */ |
| 581 | − while (*ps != NULL) | |
| 590 | + while (*ps != NULL && (*ps)->sym_scope) | |
| 582 | 591 | ps = &(*ps)->prev_tok; |
| 583 | − s->prev_tok = NULL; | |
| 592 | + s->prev_tok = *ps; | |
| 584 | 593 | *ps = s; |
| 585 | 594 | } |
| 586 | 595 | return s; |
| 587 | 596 | } |
| 588 | 597 | |
| 598 | +static Sym *global_identifier_push(int v, int t, int c) | |
| 599 | +{ | |
| 600 | + return global_identifier_push_1(&global_stack, v, t, c); | |
| 601 | +} | |
| 602 | + | |
| 589 | 603 | /* pop symbols until top reaches 'b'. If KEEP is non-zero don't really |
| 590 | 604 | pop them yet from the list, but do remove them from the token array. */ |
| 591 | 605 | 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) · 242 unmodified lines | ||
| 834 | 848 | /* Merge some storage attributes. */ |
| 835 | 849 | static void patch_storage(Sym *sym, AttributeDef *ad, CType *type) |
| 836 | 850 | { |
| 837 | − if (type && !is_compatible_types(&sym->type, type)) | |
| 838 | − tcc_error("incompatible types for redefinition of '%s'", | |
| 839 | − get_tok_str(sym->v, NULL)); | |
| 851 | + if (type) { | |
| 852 | + if ((sym->type.t & VT_BTYPE) == VT_VOID) /* from asm */ | |
| 853 | + sym->type = *type; | |
| 854 | + else if (!is_compatible_types(&sym->type, type)) | |
| 855 | + tcc_error("incompatible types for redefinition of '%s'", | |
| 856 | + get_tok_str(sym->v, NULL)); | |
| 857 | + } | |
| 840 | 858 | #ifdef TCC_TARGET_PE |
| 841 | 859 | if (sym->a.dllimport != ad->a.dllimport) |
| 842 | 860 | tcc_error("incompatible dll linkage for redefinition of '%s'", |
| @@ -6426,9 +6444,9 @@ static void init_putv(CType *type, Section *sec, unsigned long c) · 5583 unmodified lines | ||
| 6426 | 6444 | (vtop->type.t & VT_BTYPE) != VT_PTR) { |
| 6427 | 6445 | /* These come from compound literals, memcpy stuff over. */ |
| 6428 | 6446 | Section *ssec; |
| 6429 | − ElfW(Sym) *esym; | |
| 6447 | + ElfSym *esym; | |
| 6430 | 6448 | ElfW_Rel *rel; |
| 6431 | − esym = &((ElfW(Sym) *)symtab_section->data)[vtop->sym->c]; | |
| 6449 | + esym = elfsym(vtop->sym); | |
| 6432 | 6450 | ssec = tcc_state->sections[esym->st_shndx]; |
| 6433 | 6451 | memmove (ptr, ssec->data + esym->st_value, size); |
| 6434 | 6452 | if (ssec->reloc) { |
| @@ -6895,8 +6913,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 460 unmodified lines | ||
| 6895 | 6913 | /* no init data, we won't add more to the symbol */ |
| 6896 | 6914 | goto no_alloc; |
| 6897 | 6915 | } else if (sym->c) { |
| 6898 | − ElfW(Sym) *esym; | |
| 6899 | − esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; | |
| 6916 | + ElfSym *esym = elfsym(sym); | |
| 6900 | 6917 | if (esym->st_shndx == data_section->sh_num) |
| 6901 | 6918 | tcc_error("redefinition of '%s'", get_tok_str(v, NULL)); |
| 6902 | 6919 | } |
| @@ -7030,8 +7047,7 @@ static void gen_function(Sym *sym) · 127 unmodified lines | ||
| 7030 | 7047 | sym_pop(&local_stack, NULL, 0); |
| 7031 | 7048 | /* end of function */ |
| 7032 | 7049 | /* patch symbol size */ |
| 7033 | − ((ElfW(Sym) *)symtab_section->data)[sym->c].st_size = | |
| 7034 | − ind - func_ind; | |
| 7050 | + elfsym(sym)->st_size = ind - func_ind; | |
| 7035 | 7051 | tcc_debug_funcend(tcc_state, ind - func_ind); |
| 7036 | 7052 | /* It's better to crash than to generate wrong code */ |
| 7037 | 7053 | cur_text_section = NULL; |
| @@ -7209,6 +7225,11 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym) · 171 unmodified lines | ||
| 7209 | 7225 | sym = sym_find(v); |
| 7210 | 7226 | if (sym) { |
| 7211 | 7227 | Sym *ref; |
| 7228 | + /* If type is VT_VOID the symbol was created by tccasm | |
| 7229 | + first, and we see the first reference from C now. */ | |
| 7230 | + if ((sym->type.t & VT_BTYPE) == VT_VOID) | |
| 7231 | + sym->type = type; | |
| 7232 | + | |
| 7212 | 7233 | if ((sym->type.t & VT_BTYPE) != VT_FUNC) |
| 7213 | 7234 | goto func_error1; |
| 7214 | 7235 | |
| @@ -7330,12 +7351,12 @@ found: · 115 unmodified lines | ||
| 7330 | 7351 | sym = external_sym(v, &type, r, &ad); |
| 7331 | 7352 | if (ad.alias_target) { |
| 7332 | 7353 | Section tsec; |
| 7333 | − ElfW(Sym) *esym; | |
| 7354 | + ElfSym *esym; | |
| 7334 | 7355 | Sym *alias_target; |
| 7335 | 7356 | alias_target = sym_find(ad.alias_target); |
| 7336 | − if (!alias_target || !alias_target->c) | |
| 7357 | + esym = elfsym(alias_target); | |
| 7358 | + if (!esym) | |
| 7337 | 7359 | tcc_error("unsupported forward __alias__ attribute"); |
| 7338 | − esym = &((ElfW(Sym) *)symtab_section->data)[alias_target->c]; | |
| 7339 | 7360 | tsec.sh_num = esym->st_shndx; |
| 7340 | 7361 | /* Local statics have a scope until now (for |
| 7341 | 7362 | warnings), remove it here. */ |
| @@ -432,7 +432,6 @@ static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len) · 431 unmodified lines | ||
| 432 | 432 | ts->sym_label = NULL; |
| 433 | 433 | ts->sym_struct = NULL; |
| 434 | 434 | ts->sym_identifier = NULL; |
| 435 | − ts->sym_asm_label = NULL; | |
| 436 | 435 | ts->len = len; |
| 437 | 436 | ts->hash_next = NULL; |
| 438 | 437 | memcpy(ts->str, str, len); |
| @@ -14,11 +14,13 @@ static int x1_c(void) · 13 unmodified lines | ||
| 14 | 14 | |
| 15 | 15 | asm(".text;"_"x1: call "_"x1_c; ret"); |
| 16 | 16 | |
| 17 | +void callx4(void); | |
| 17 | 18 | int main(int argc, char *argv[]) |
| 18 | 19 | { |
| 19 | 20 | asm("call "_"x1"); |
| 20 | 21 | asm("call "_"x2"); |
| 21 | 22 | asm("call "_"x3"); |
| 23 | + callx4(); | |
| 22 | 24 | return 0; |
| 23 | 25 | } |
| 24 | 26 | |
| @@ -30,3 +32,8 @@ int x2(void) · 5 unmodified lines | ||
| 30 | 32 | } |
| 31 | 33 | |
| 32 | 34 | extern int x3(void); |
| 35 | + | |
| 36 | +void x4(void) | |
| 37 | +{ | |
| 38 | + printf("x4\n"); | |
| 39 | +} | |
| @@ -5,3 +5,6 @@ int x3(void) · 4 unmodified lines | ||
| 5 | 5 | printf("x3\n"); |
| 6 | 6 | return 3; |
| 7 | 7 | } |
| 8 | + | |
| 9 | +void callx4(void); | |
| 10 | +__asm__("callx4: call x4; ret"); | |