diff --git a/i386-asm.c b/i386-asm.c index 473088b..336ef1b 100644 --- a/i386-asm.c +++ b/i386-asm.c @@ -1437,10 +1437,19 @@ ST_FUNC void subst_asm_operand(CString *add_str, modifier != 'P') cstr_ccat(add_str, '$'); if (r & VT_SYM) { - cstr_cat(add_str, get_tok_str(sv->sym->v, NULL), -1); + const char *name = get_tok_str(sv->sym->v, NULL); + if (sv->sym->v >= SYM_FIRST_ANOM) { + /* In case of anonymuous symbols ("L.42", used + for static data labels) we can't find them + in the C symbol table when later looking up + this name. So enter them now into the asm label + list when we still know the symbol. */ + get_asm_sym(tok_alloc(name, strlen(name))->tok, sv->sym); + } + cstr_cat(add_str, name, -1); if ((uint32_t)sv->c.i == 0) goto no_offset; - cstr_ccat(add_str, '+'); + cstr_ccat(add_str, '+'); } val = sv->c.i; if (modifier == 'n') diff --git a/tcc.h b/tcc.h index 17c24a2..a9641f6 100644 --- a/tcc.h +++ b/tcc.h @@ -1529,6 +1529,7 @@ ST_FUNC void asm_instr(void); ST_FUNC void asm_global_instr(void); #ifdef CONFIG_TCC_ASM ST_FUNC int find_constraint(ASMOperand *operands, int nb_operands, const char *name, const char **pp); +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); diff --git a/tccasm.c b/tccasm.c index 1819950..7e9c6e6 100644 --- a/tccasm.c +++ b/tccasm.c @@ -43,19 +43,24 @@ static Sym sym_dot; 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. */ -static Sym* get_asm_sym(int name) + 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. */ +ST_FUNC Sym* get_asm_sym(int name, Sym *csym) { Sym *sym = label_find(name); if (!sym) { - Sym *csym = sym_find(name); sym = label_push(&tcc_state->asm_labels, name, 0); sym->type.t = VT_VOID | VT_EXTERN; - /* 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->scope) - csym = csym->prev_tok; + 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->scope) + csym = csym->prev_tok; + } /* Now, if we have a defined global symbol copy over section and offset. */ if (csym && @@ -63,6 +68,7 @@ static Sym* get_asm_sym(int name) 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. */ @@ -158,7 +164,7 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe) default: if (tok >= TOK_IDENT) { /* label case : if the label was not found, add one */ - sym = get_asm_sym(tok); + sym = get_asm_sym(tok, NULL); if (sym->r == SHN_ABS) { /* if absolute symbol, no need to put a symbol value */ pe->v = sym->jnext; @@ -682,7 +688,7 @@ static void asm_parse_directive(TCCState *s1) Sym *sym; next(); - sym = get_asm_sym(tok); + sym = get_asm_sym(tok, NULL); if (tok1 != TOK_ASMDIR_hidden) sym->type.t &= ~VT_STATIC; if (tok1 == TOK_ASMDIR_weak) @@ -801,7 +807,7 @@ static void asm_parse_directive(TCCState *s1) const char *newtype; next(); - sym = get_asm_sym(tok); + sym = get_asm_sym(tok, NULL); next(); skip(','); if (tok == TOK_STR) { diff --git a/tests/tcctest.c b/tests/tcctest.c index f8e2040..b8e534f 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -2741,6 +2741,28 @@ void override_func2 (void) printf ("asmc: override2\n"); } +/* This checks a construct used by the linux kernel to encode + references to strings by PC relative references. */ +extern int bug_table[] __attribute__((section("__bug_table"))); +char * get_asm_string (void) +{ + extern int some_symbol; + asm volatile (".globl some_symbol\n" + "jmp .+6\n" + "1:\n" + "some_symbol: .long 0\n" + ".pushsection __bug_table, \"a\"\n" + ".globl bug_table\n" + "bug_table:\n" + /* The first entry (1b-2b) is unused in this test, + but we include it to check if cross-section + PC-relative references work. */ + "2:\t.long 1b - 2b, %c0 - 2b\n" + ".popsection\n" : : "i" ("A string")); + char * str = ((char*)bug_table) + bug_table[1]; + return str; +} + unsigned int set; void asm_test(void) @@ -2812,6 +2834,7 @@ void asm_test(void) if (!somebool) printf("asmbool: failed\n"); #endif + printf("asmstr: %s\n", get_asm_string()); return; label1: goto label2;