History

tccasm: Support refs to anon symbols from asm

This happens when e.g. string constants (or other static data) are passed as operands to inline asm as immediates. The produced symbol ref wouldn't be found. So tighten the connection between C and asm-local symbol table even more.

Michael Matz committed 10 years ago

Commit 5bd8aeb1 parent dd57a344 files · +52 −13Browse files

Unified · Split

4 files
  1. i386-asm.c +11 −2
  2. tcc.h +1 −0
  3. tccasm.c +17 −11
  4. tests/tcctest.c +23 −0
i386-asm.c+11−2
@@ -1437,10 +1437,19 @@ ST_FUNC void subst_asm_operand(CString *add_str, · 1436 unmodified lines
14371437 modifier != 'P')
14381438 cstr_ccat(add_str, '$');
14391439 if (r & VT_SYM) {
1440− cstr_cat(add_str, get_tok_str(sv->sym->v, NULL), -1);
1440+ const char *name = get_tok_str(sv->sym->v, NULL);
1441+ if (sv->sym->v >= SYM_FIRST_ANOM) {
1442+ /* In case of anonymuous symbols ("L.42", used
1443+ for static data labels) we can't find them
1444+ in the C symbol table when later looking up
1445+ this name. So enter them now into the asm label
1446+ list when we still know the symbol. */
1447+ get_asm_sym(tok_alloc(name, strlen(name))->tok, sv->sym);
1448+ }
1449+ cstr_cat(add_str, name, -1);
14411450 if ((uint32_t)sv->c.i == 0)
14421451 goto no_offset;
1443− cstr_ccat(add_str, '+');
1452+ cstr_ccat(add_str, '+');
14441453 }
14451454 val = sv->c.i;
14461455 if (modifier == 'n')
tcc.h+1−0
@@ -1529,6 +1529,7 @@ ST_FUNC void asm_instr(void); · 1528 unmodified lines
15291529 ST_FUNC void asm_global_instr(void);
15301530 #ifdef CONFIG_TCC_ASM
15311531 ST_FUNC int find_constraint(ASMOperand *operands, int nb_operands, const char *name, const char **pp);
1532+ST_FUNC Sym* get_asm_sym(int name, Sym *csym);
15321533 ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe);
15331534 ST_FUNC int asm_int_expr(TCCState *s1);
15341535 ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess);
tccasm.c+17−11
@@ -43,19 +43,24 @@ static Sym sym_dot; · 42 unmodified lines
4343
4444 This routine gives back either an existing asm-internal
4545 symbol, or a new one. In the latter case the new asm-internal
46− symbol is initialized with info from the C symbol table. */
47−static Sym* get_asm_sym(int name)
46+ symbol is initialized with info from the C symbol table.
47+
48+ If CSYM is non-null we take symbol info from it, otherwise
49+ we look up NAME in the C symbol table and use that. */
50+ST_FUNC Sym* get_asm_sym(int name, Sym *csym)
4851 {
4952 Sym *sym = label_find(name);
5053 if (!sym) {
51− Sym *csym = sym_find(name);
5254 sym = label_push(&tcc_state->asm_labels, name, 0);
5355 sym->type.t = VT_VOID | VT_EXTERN;
54− /* We might be called for an asm block from inside a C routine
55− and so might have local decls on the identifier stack. Search
56− for the first global one. */
57− while (csym && csym->scope)
58− csym = csym->prev_tok;
56+ if (!csym) {
57+ csym = sym_find(name);
58+ /* We might be called for an asm block from inside a C routine
59+ and so might have local decls on the identifier stack. Search
60+ for the first global one. */
61+ while (csym && csym->scope)
62+ csym = csym->prev_tok;
63+ }
5964 /* Now, if we have a defined global symbol copy over
6065 section and offset. */
6166 if (csym &&
@@ -63,6 +68,7 @@ static Sym* get_asm_sym(int name) · 1 unmodified line
6368 csym->c) {
6469 ElfW(Sym) *esym;
6570 esym = &((ElfW(Sym) *)symtab_section->data)[csym->c];
71+ sym->c = csym->c;
6672 sym->r = esym->st_shndx;
6773 sym->jnext = esym->st_value;
6874 /* XXX can't yet store st_size anywhere. */
@@ -158,7 +164,7 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe) · 89 unmodified lines
158164 default:
159165 if (tok >= TOK_IDENT) {
160166 /* label case : if the label was not found, add one */
161− sym = get_asm_sym(tok);
167+ sym = get_asm_sym(tok, NULL);
162168 if (sym->r == SHN_ABS) {
163169 /* if absolute symbol, no need to put a symbol value */
164170 pe->v = sym->jnext;
@@ -682,7 +688,7 @@ static void asm_parse_directive(TCCState *s1) · 517 unmodified lines
682688 Sym *sym;
683689
684690 next();
685− sym = get_asm_sym(tok);
691+ sym = get_asm_sym(tok, NULL);
686692 if (tok1 != TOK_ASMDIR_hidden)
687693 sym->type.t &= ~VT_STATIC;
688694 if (tok1 == TOK_ASMDIR_weak)
@@ -801,7 +807,7 @@ static void asm_parse_directive(TCCState *s1) · 112 unmodified lines
801807 const char *newtype;
802808
803809 next();
804− sym = get_asm_sym(tok);
810+ sym = get_asm_sym(tok, NULL);
805811 next();
806812 skip(',');
807813 if (tok == TOK_STR) {
tests/tcctest.c+23−0
@@ -2741,6 +2741,28 @@ void override_func2 (void) · 2740 unmodified lines
27412741 printf ("asmc: override2\n");
27422742 }
27432743
2744+/* This checks a construct used by the linux kernel to encode
2745+ references to strings by PC relative references. */
2746+extern int bug_table[] __attribute__((section("__bug_table")));
2747+char * get_asm_string (void)
2748+{
2749+ extern int some_symbol;
2750+ asm volatile (".globl some_symbol\n"
2751+ "jmp .+6\n"
2752+ "1:\n"
2753+ "some_symbol: .long 0\n"
2754+ ".pushsection __bug_table, \"a\"\n"
2755+ ".globl bug_table\n"
2756+ "bug_table:\n"
2757+ /* The first entry (1b-2b) is unused in this test,
2758+ but we include it to check if cross-section
2759+ PC-relative references work. */
2760+ "2:\t.long 1b - 2b, %c0 - 2b\n"
2761+ ".popsection\n" : : "i" ("A string"));
2762+ char * str = ((char*)bug_table) + bug_table[1];
2763+ return str;
2764+}
2765+
27442766 unsigned int set;
27452767
27462768 void asm_test(void)
@@ -2812,6 +2834,7 @@ void asm_test(void) · 65 unmodified lines
28122834 if (!somebool)
28132835 printf("asmbool: failed\n");
28142836 #endif
2837+ printf("asmstr: %s\n", get_asm_string());
28152838 return;
28162839 label1:
28172840 goto label2;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t