| @@ -64,7 +64,7 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe) · 63 unmodified lines |
| 64 | 64 | if (!sym || sym->r) { |
| 65 | 65 | /* if the last label is defined, then define a new one */ |
| 66 | 66 | sym = label_push(&s1->asm_labels, label, 0); |
| 67 | | − sym->type.t = VT_STATIC | VT_VOID; |
| 67 | + sym->type.t = VT_STATIC | VT_VOID | VT_EXTERN; |
| 68 | 68 | } |
| 69 | 69 | } |
| 70 | 70 | pe->v = 0; |
| @@ -123,7 +123,7 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe) · 52 unmodified lines |
| 123 | 123 | if (!sym) { |
| 124 | 124 | sym = label_push(&s1->asm_labels, tok, 0); |
| 125 | 125 | /* NOTE: by default, the symbol is global */ |
| 126 | | − sym->type.t = VT_VOID; |
| 126 | + sym->type.t = VT_VOID | VT_EXTERN; |
| 127 | 127 | } |
| 128 | 128 | if (sym->r == SHN_ABS) { |
| 129 | 129 | /* if absolute symbol, no need to put a symbol value */ |
| @@ -317,14 +317,17 @@ ST_FUNC int asm_int_expr(TCCState *s1) · 187 unmodified lines |
| 317 | 317 | |
| 318 | 318 | /* NOTE: the same name space as C labels is used to avoid using too |
| 319 | 319 | much memory when storing labels in TokenStrings */ |
| 320 | | −static void asm_new_label1(TCCState *s1, int label, int is_local, |
| 320 | +static Sym* asm_new_label1(TCCState *s1, int label, int is_local, |
| 321 | 321 | int sh_num, int value) |
| 322 | 322 | { |
| 323 | 323 | Sym *sym; |
| 324 | 324 | |
| 325 | 325 | sym = label_find(label); |
| 326 | 326 | if (sym) { |
| 327 | | − if (sym->r) { |
| 327 | + /* A VT_EXTERN symbol, even if it has a section is considered |
| 328 | + overridable. This is how we "define" .set targets. Real |
| 329 | + definitions won't have VT_EXTERN set. */ |
| 330 | + if (sym->r && !(sym->type.t & VT_EXTERN)) { |
| 328 | 331 | /* the label is already defined */ |
| 329 | 332 | if (!is_local) { |
| 330 | 333 | tcc_error("assembler label '%s' already defined", |
| @@ -337,15 +340,34 @@ static void asm_new_label1(TCCState *s1, int label, int is_local, · 6 unmodified lines |
| 337 | 340 | } else { |
| 338 | 341 | new_label: |
| 339 | 342 | sym = label_push(&s1->asm_labels, label, 0); |
| 340 | | − sym->type.t = VT_STATIC | VT_VOID; |
| 343 | + /* If we need a symbol to hold a value, mark it as |
| 344 | + tentative only (for .set). If this is for a real label |
| 345 | + we'll remove VT_EXTERN. */ |
| 346 | + sym->type.t = VT_STATIC | VT_VOID | VT_EXTERN; |
| 341 | 347 | } |
| 342 | 348 | sym->r = sh_num; |
| 343 | 349 | sym->jnext = value; |
| 350 | + return sym; |
| 344 | 351 | } |
| 345 | 352 | |
| 346 | | −static void asm_new_label(TCCState *s1, int label, int is_local) |
| 353 | +static Sym* asm_new_label(TCCState *s1, int label, int is_local) |
| 347 | 354 | { |
| 348 | | − asm_new_label1(s1, label, is_local, cur_text_section->sh_num, ind); |
| 355 | + return asm_new_label1(s1, label, is_local, cur_text_section->sh_num, ind); |
| 356 | +} |
| 357 | + |
| 358 | +/* Set the value of LABEL to that of some expression (possibly |
| 359 | + involving other symbols). LABEL can be overwritten later still. */ |
| 360 | +static Sym* set_symbol(TCCState *s1, int label) |
| 361 | +{ |
| 362 | + Sym *sym; |
| 363 | + long n; |
| 364 | + ExprValue e; |
| 365 | + next(); |
| 366 | + asm_expr(s1, &e); |
| 367 | + n = e.v; |
| 368 | + if (e.sym) |
| 369 | + n += e.sym->jnext; |
| 370 | + return asm_new_label1(s1, label, 0, e.sym ? e.sym->r : SHN_ABS, n); |
| 349 | 371 | } |
| 350 | 372 | |
| 351 | 373 | static void asm_free_labels(TCCState *st) |
| @@ -356,6 +378,7 @@ static void asm_free_labels(TCCState *st) · 4 unmodified lines |
| 356 | 378 | for(s = st->asm_labels; s != NULL; s = s1) { |
| 357 | 379 | s1 = s->prev; |
| 358 | 380 | /* define symbol value in object file */ |
| 381 | + s->type.t &= ~VT_EXTERN; |
| 359 | 382 | if (s->r) { |
| 360 | 383 | if (s->r == SHN_ABS) |
| 361 | 384 | sec = SECTION_ABS; |
| @@ -608,6 +631,15 @@ static void asm_parse_directive(TCCState *s1) · 246 unmodified lines |
| 608 | 631 | goto zero_pad; |
| 609 | 632 | } |
| 610 | 633 | break; |
| 634 | + case TOK_ASMDIR_set: |
| 635 | + next(); |
| 636 | + tok1 = tok; |
| 637 | + next(); |
| 638 | + /* Also accept '.set stuff', but don't do anything with this. |
| 639 | + It's used in GAS to set various features like '.set mips16'. */ |
| 640 | + if (tok == ',') |
| 641 | + set_symbol(s1, tok1); |
| 642 | + break; |
| 611 | 643 | case TOK_ASMDIR_globl: |
| 612 | 644 | case TOK_ASMDIR_global: |
| 613 | 645 | case TOK_ASMDIR_weak: |
| @@ -620,7 +652,7 @@ static void asm_parse_directive(TCCState *s1) · 6 unmodified lines |
| 620 | 652 | sym = label_find(tok); |
| 621 | 653 | if (!sym) { |
| 622 | 654 | sym = label_push(&s1->asm_labels, tok, 0); |
| 623 | | − sym->type.t = VT_VOID; |
| 655 | + sym->type.t = VT_VOID | VT_EXTERN; |
| 624 | 656 | } |
| 625 | 657 | if (tok1 != TOK_ASMDIR_hidden) |
| 626 | 658 | sym->type.t &= ~VT_STATIC; |
| @@ -743,7 +775,7 @@ static void asm_parse_directive(TCCState *s1) · 116 unmodified lines |
| 743 | 775 | sym = label_find(tok); |
| 744 | 776 | if (!sym) { |
| 745 | 777 | sym = label_push(&s1->asm_labels, tok, 0); |
| 746 | | − sym->type.t = VT_VOID; |
| 778 | + sym->type.t = VT_VOID | VT_EXTERN; |
| 747 | 779 | } |
| 748 | 780 | |
| 749 | 781 | next(); |
| @@ -875,6 +907,7 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess) · 125 unmodified lines |
| 875 | 907 | } else if (tok >= TOK_ASMDIR_FIRST && tok <= TOK_ASMDIR_LAST) { |
| 876 | 908 | asm_parse_directive(s1); |
| 877 | 909 | } else if (tok == TOK_PPNUM) { |
| 910 | + Sym *sym; |
| 878 | 911 | const char *p; |
| 879 | 912 | int n; |
| 880 | 913 | p = tokc.str.data; |
| @@ -882,7 +915,9 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess) · 1 unmodified line |
| 882 | 915 | if (*p != '\0') |
| 883 | 916 | expect("':'"); |
| 884 | 917 | /* new local label */ |
| 885 | | − asm_new_label(s1, asm_get_local_label_name(s1, n), 1); |
| 918 | + sym = asm_new_label(s1, asm_get_local_label_name(s1, n), 1); |
| 919 | + /* Remove the marker for tentative definitions. */ |
| 920 | + sym->type.t &= ~VT_EXTERN; |
| 886 | 921 | next(); |
| 887 | 922 | skip(':'); |
| 888 | 923 | goto redo; |
| @@ -898,18 +933,16 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess) · 9 unmodified lines |
| 898 | 933 | sym = label_find(opcode); |
| 899 | 934 | if (!sym) { |
| 900 | 935 | sym = label_push(&s1->asm_labels, opcode, 0); |
| 901 | | − sym->type.t = VT_VOID; |
| 936 | + sym->type.t = VT_VOID | VT_EXTERN; |
| 902 | 937 | } |
| 903 | 938 | } |
| 904 | 939 | /* new label */ |
| 905 | | − asm_new_label(s1, opcode, 0); |
| 940 | + sym = asm_new_label(s1, opcode, 0); |
| 941 | + sym->type.t &= ~VT_EXTERN; |
| 906 | 942 | next(); |
| 907 | 943 | goto redo; |
| 908 | 944 | } else if (tok == '=') { |
| 909 | | − int n; |
| 910 | | − next(); |
| 911 | | − n = asm_int_expr(s1); |
| 912 | | − asm_new_label1(s1, opcode, 0, SHN_ABS, n); |
| 945 | + set_symbol(s1, opcode); |
| 913 | 946 | goto redo; |
| 914 | 947 | } else { |
| 915 | 948 | asm_opcode(s1, opcode); |