aboutsummaryrefslogtreecommitdiff
path: root/tccasm.c
diff options
context:
space:
mode:
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;