aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--i386-asm.c13
-rw-r--r--tcc.h1
-rw-r--r--tccasm.c28
-rw-r--r--tests/tcctest.c23
4 files changed, 52 insertions, 13 deletions
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;