aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tcc.h2
-rw-r--r--tccasm.c85
-rw-r--r--tccgen.c5
-rw-r--r--tccpp.c1
-rw-r--r--tests/Makefile11
-rw-r--r--tests/asm-c-connect-1.c31
-rw-r--r--tests/asm-c-connect-2.c7
7 files changed, 119 insertions, 23 deletions
diff --git a/tcc.h b/tcc.h
index da26298..1efd046 100644
--- a/tcc.h
+++ b/tcc.h
@@ -383,6 +383,7 @@ typedef struct TokenSym {
struct Sym *sym_label; /* direct pointer to label */
struct Sym *sym_struct; /* direct pointer to structure */
struct Sym *sym_identifier; /* direct pointer to identifier */
+ struct Sym *sym_asm_label; /* direct pointer to asm label */
int tok; /* token number */
int len;
char str[1];
@@ -1584,6 +1585,7 @@ 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);
+ST_FUNC void asm_free_labels(TCCState *st);
/* ------------ i386-asm.c ------------ */
ST_FUNC void gen_expr32(ExprValue *pe);
#ifdef TCC_TARGET_X86_64
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;
diff --git a/tccgen.c b/tccgen.c
index 7d554b5..a86103c 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -275,6 +275,11 @@ ST_FUNC int tccgen_compile(TCCState *s1)
decl(VT_CONST);
gen_inline_functions(s1);
check_vstack();
+
+#ifdef CONFIG_TCC_ASM
+ asm_free_labels(s1);
+#endif
+
/* end of translation unit info */
tcc_debug_end(s1);
return 0;
diff --git a/tccpp.c b/tccpp.c
index 76f9e42..d8e7f53 100644
--- a/tccpp.c
+++ b/tccpp.c
@@ -432,6 +432,7 @@ static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len)
ts->sym_label = NULL;
ts->sym_struct = NULL;
ts->sym_identifier = NULL;
+ ts->sym_asm_label = NULL;
ts->len = len;
ts->hash_next = NULL;
memcpy(ts->str, str, len);
diff --git a/tests/Makefile b/tests/Makefile
index 6a61717..61b585e 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -16,6 +16,7 @@ TESTS = \
memtest \
dlltest \
abitest \
+ asm-c-connect-test \
vla_test-run \
cross-test \
tests2-dir \
@@ -44,7 +45,7 @@ ifeq ($(CONFIG_arm_eabi),yes)
TESTS := $(filter-out test3,$(TESTS))
endif
ifeq (,$(filter i386 x86_64,$(ARCH)))
- TESTS := $(filter-out dlltest,$(TESTS))
+ TESTS := $(filter-out dlltest asm-c-connect-test,$(TESTS))
endif
ifndef CONFIG_cross
TESTS := $(filter-out cross-%,$(TESTS))
@@ -231,6 +232,13 @@ vla_test-run: vla_test$(EXESUF)
@echo ------------ $@ ------------
./vla_test$(EXESUF)
+asm-c-connect$(EXESUF): asm-c-connect-1.c asm-c-connect-2.c
+ $(TCC) -o $@ $^
+
+asm-c-connect-test: asm-c-connect$(EXESUF)
+ @echo ------------ $@ ------------
+ ./asm-c-connect$(EXESUF)
+
cross-test :
@echo ------------ $@ ------------
$(TOP)/i386-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
@@ -264,6 +272,7 @@ cache: tcc_g
clean:
rm -f *~ *.o *.a *.bin *.i *.ref *.out *.out? *.out?b *.cc *.gcc
rm -f *-cc *-gcc *-tcc *.exe hello libtcc_test vla_test tcctest[1234]
+ rm -f asm-c-connect$(EXESUF)
rm -f ex? tcc_g weaktest.*.txt *.def
@$(MAKE) -C tests2 $@
@$(MAKE) -C pp $@
diff --git a/tests/asm-c-connect-1.c b/tests/asm-c-connect-1.c
new file mode 100644
index 0000000..3f7b010
--- /dev/null
+++ b/tests/asm-c-connect-1.c
@@ -0,0 +1,31 @@
+#include <stdio.h>
+
+#if defined _WIN32 && !defined __TINYC__
+# define U "_"
+#else
+# define U
+#endif
+
+const char str[] = "x1\n";
+#ifdef __x86_64__
+asm(U"x1: push %rbp; mov $"U"str, %rdi; call "U"printf; pop %rbp; ret");
+#elif defined (__i386__)
+asm(U"x1: push $"U"str; call "U"printf; pop %eax; ret");
+#endif
+
+int main(int argc, char *argv[])
+{
+ asm("call "U"x1");
+ asm("call "U"x2");
+ asm("call "U"x3");
+ return 0;
+}
+
+static
+int x2(void)
+{
+ printf("x2\n");
+ return 2;
+}
+
+extern int x3(void);
diff --git a/tests/asm-c-connect-2.c b/tests/asm-c-connect-2.c
new file mode 100644
index 0000000..3a8cff2
--- /dev/null
+++ b/tests/asm-c-connect-2.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int x3(void)
+{
+ printf("x3\n");
+ return 3;
+}