aboutsummaryrefslogtreecommitdiff
path: root/tccasm.c
diff options
context:
space:
mode:
authorMichael Matz <matz@suse.de>2017-11-22 17:57:43 +0100
committerMichael Matz <matz@suse.de>2017-11-22 17:57:43 +0100
commite7c71e24730ae07241980812c8b747963f216260 (patch)
tree6fc0609791b351c7f83da07c3f8d2548d747094c /tccasm.c
parent330c01bfc6fa6721fd455911a966bce041df31d8 (diff)
downloadtinycc-e7c71e24730ae07241980812c8b747963f216260.tar.gz
tinycc-e7c71e24730ae07241980812c8b747963f216260.tar.bz2
tccasm: synch C and asm symtab tighter
See testcase. The C and asm symtab are still separate, but integrated tighter: the asm labels are only synched at file end, not after each asm snippet (this fixes references from one to another asm block), the C and asm syms are synched both ways, so defining things in asm and refering from C, or the other way around works. In effect this model reflects what happens with GCC better. For this the asm labels aren't using the C label namespace anymore, but their own, which increases the size of each TokenSym by a pointer.
Diffstat (limited to 'tccasm.c')
-rw-r--r--tccasm.c85
1 files changed, 63 insertions, 22 deletions
diff --git a/tccasm.c b/tccasm.c
index 848f976..7761c39 100644
--- a/tccasm.c
+++ b/tccasm.c
@@ -31,10 +31,27 @@ ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n)
return ts->tok;
}
-ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe);
static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global);
static Sym sym_dot;
+static Sym *asm_label_find(int v)
+{
+ v -= TOK_IDENT;
+ if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT))
+ return NULL;
+ return table_ident[v]->sym_asm_label;
+}
+
+static Sym *asm_label_push(Sym **ptop, int v)
+{
+ Sym *s, **ps;
+ s = sym_push2(ptop, v, 0, 0);
+ ps = &table_ident[v - TOK_IDENT]->sym_asm_label;
+ s->prev_tok = *ps;
+ *ps = s;
+ return s;
+}
+
/* Return a symbol we can use inside the assembler, having name NAME.
The assembler symbol table is different from the C symbol table
(and the Sym members are used differently). But we must be able
@@ -49,10 +66,10 @@ static Sym sym_dot;
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);
+ Sym *sym = asm_label_find(name);
if (!sym) {
- sym = label_push(&tcc_state->asm_labels, name, 0);
- sym->type.t = VT_VOID | VT_STATIC | VT_EXTERN;
+ sym = asm_label_push(&tcc_state->asm_labels, name);
+ sym->type.t = VT_VOID | VT_EXTERN;
if (!csym) {
csym = sym_find(name);
/* We might be called for an asm block from inside a C routine
@@ -75,6 +92,7 @@ ST_FUNC Sym* get_asm_sym(int name, Sym *csym)
sym->type.t = VT_VOID | (csym->type.t & VT_STATIC);
/* Mark that this asm symbol doesn't need to be fed back. */
sym->a.dllimport = 1;
+ sym->a.dllexport = !(csym->type.t & VT_STATIC);
}
}
return sym;
@@ -97,7 +115,7 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
if (*p == 'b' || *p == 'f') {
/* backward or forward label */
label = asm_get_local_label_name(s1, n);
- sym = label_find(label);
+ sym = asm_label_find(label);
if (*p == 'b') {
/* backward : find the last corresponding defined label */
if (sym && sym->r == 0)
@@ -108,7 +126,7 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
/* forward */
if (!sym || sym->r) {
/* if the last label is defined, then define a new one */
- sym = label_push(&s1->asm_labels, label, 0);
+ sym = asm_label_push(&s1->asm_labels, label);
sym->type.t = VT_STATIC | VT_VOID | VT_EXTERN;
}
}
@@ -355,14 +373,12 @@ ST_FUNC int asm_int_expr(TCCState *s1)
return e.v;
}
-/* NOTE: the same name space as C labels is used to avoid using too
- much memory when storing labels in TokenStrings */
static Sym* asm_new_label1(TCCState *s1, int label, int is_local,
int sh_num, int value)
{
Sym *sym;
- sym = label_find(label);
+ sym = asm_label_find(label);
if (sym) {
/* A VT_EXTERN symbol, even if it has a section is considered
overridable. This is how we "define" .set targets. Real
@@ -379,11 +395,11 @@ static Sym* asm_new_label1(TCCState *s1, int label, int is_local,
}
} else {
new_label:
- sym = label_push(&s1->asm_labels, label, 0);
+ sym = asm_label_push(&s1->asm_labels, label);
/* If we need a symbol to hold a value, mark it as
tentative only (for .set). If this is for a real label
we'll remove VT_EXTERN. */
- sym->type.t = VT_STATIC | VT_VOID | VT_EXTERN;
+ sym->type.t = VT_VOID | (is_local ? VT_STATIC : 0) | VT_EXTERN;
}
sym->r = sh_num;
sym->jnext = value;
@@ -427,28 +443,53 @@ static void patch_binding(Sym *sym)
ELFW(ST_TYPE)(esym->st_info));
}
-static void asm_free_labels(TCCState *st)
+ST_FUNC void asm_free_labels(TCCState *st)
{
Sym *s, *s1;
Section *sec;
for(s = st->asm_labels; s != NULL; s = s1) {
+ int was_ext = s->type.t & VT_EXTERN;
s1 = s->prev;
- /* define symbol value in object file */
+ /* define symbol value in object file and care for updating
+ the C and asm symbols */
s->type.t &= ~VT_EXTERN;
if (!s->a.dllimport) {
+ Sym *csym = sym_find(s->v);
+ ElfW(Sym) *esym = NULL;
+ if (csym) {
+ s->a.dllexport |= !(csym->type.t & VT_STATIC);
+ if (csym->c) {
+ esym = &((ElfW(Sym) *)symtab_section->data)[csym->c];
+ if (s->c) {
+ /* We have generated code and possibly relocs
+ referencing the symtab entry s->c (the asm
+ ELF symbol). If that's undefined but the C
+ symbol is defined, copy over the info. */
+ ElfW(Sym) *asm_esym = &((ElfW(Sym) *)symtab_section->data)[s->c];
+ if (asm_esym->st_shndx == SHN_UNDEF) {
+ *asm_esym = *esym;
+ }
+ }
+ }
+ }
+ if (!s->a.dllexport)
+ s->type.t |= VT_STATIC;
if (s->r) {
if (s->r == SHN_ABS)
sec = SECTION_ABS;
else
sec = st->sections[s->r];
- put_extern_sym2(s, sec, s->jnext, 0, 0);
+ /* !was_ext so that we run into an multi-def error if
+ we defined it in C and in asm (non-tentatively) */
+ if (!esym || esym->st_shndx == SHN_UNDEF || !was_ext)
+ put_extern_sym2(s, sec, s->jnext, 0, 0);
} else /* undefined symbols are global */
- s->type.t &= ~VT_STATIC;
+ s->type.t &= ~VT_STATIC, s->a.dllexport = 1;
+ patch_binding(s);
}
- patch_binding(s);
/* remove label */
- table_ident[s->v - TOK_IDENT]->sym_label = NULL;
+ table_ident[s->v - TOK_IDENT]->sym_asm_label = NULL;
sym_free(s);
}
st->asm_labels = NULL;
@@ -709,7 +750,7 @@ static void asm_parse_directive(TCCState *s1, int global)
next();
sym = get_asm_sym(tok, NULL);
if (tok1 != TOK_ASMDIR_hidden)
- sym->type.t &= ~VT_STATIC;
+ sym->type.t &= ~VT_STATIC, sym->a.dllexport = 1;
if (tok1 == TOK_ASMDIR_weak)
sym->a.weak = 1;
else if (tok1 == TOK_ASMDIR_hidden)
@@ -804,7 +845,7 @@ static void asm_parse_directive(TCCState *s1, int global)
Sym *sym;
next();
- sym = label_find(tok);
+ sym = asm_label_find(tok);
if (!sym) {
tcc_error("label not found: %s", get_tok_str(tok, NULL));
}
@@ -980,9 +1021,9 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
"__asm__("globl vide\nvide: ret");" */
Sym *sym = sym_find(opcode);
if (sym && (sym->type.t & VT_EXTERN) && global) {
- sym = label_find(opcode);
+ sym = asm_label_find(opcode);
if (!sym) {
- sym = label_push(&s1->asm_labels, opcode, 0);
+ sym = asm_label_push(&s1->asm_labels, opcode);
sym->type.t = VT_VOID | VT_EXTERN;
}
}
@@ -1004,7 +1045,6 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
parse_flags &= ~PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
}
- asm_free_labels(s1);
parse_flags = saved_parse_flags;
return 0;
}
@@ -1019,6 +1059,7 @@ ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess)
ind = cur_text_section->data_offset;
nocode_wanted = 0;
ret = tcc_assemble_internal(s1, do_preprocess, 1);
+ asm_free_labels(s1);
cur_text_section->data_offset = ind;
tcc_debug_end(s1);
return ret;