aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--i386-asm.c15
-rw-r--r--tcc.h11
-rw-r--r--tccasm.c240
-rw-r--r--tccelf.c12
-rw-r--r--tccgen.c63
-rw-r--r--tccpp.c1
-rw-r--r--tests/asm-c-connect-1.c7
-rw-r--r--tests/asm-c-connect-2.c3
8 files changed, 164 insertions, 188 deletions
diff --git a/i386-asm.c b/i386-asm.c
index 2e18497..1b992ca 100644
--- a/i386-asm.c
+++ b/i386-asm.c
@@ -500,12 +500,13 @@ ST_FUNC void gen_expr64(ExprValue *pe)
static void gen_disp32(ExprValue *pe)
{
Sym *sym = pe->sym;
- if (sym && sym->r == cur_text_section->sh_num) {
+ ElfSym *esym = elfsym(sym);
+ if (esym && esym->st_shndx == cur_text_section->sh_num) {
/* same section: we can output an absolute value. Note
that the TCC compiler behaves differently here because
it always outputs a relocation to ease (future) code
elimination in the linker */
- gen_le32(pe->v + sym->jnext - ind - 4);
+ gen_le32(pe->v + esym->st_value - ind - 4);
} else {
if (sym && sym->type.t == VT_VOID) {
sym->type.t = VT_FUNC;
@@ -1017,16 +1018,14 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
if (pa->instr_type & OPC_B)
v += s >= 1;
if (nb_ops == 1 && pa->op_type[0] == OPT_DISP8) {
- Sym *sym;
+ ElfSym *esym;
int jmp_disp;
/* see if we can really generate the jump with a byte offset */
- sym = ops[0].e.sym;
- if (!sym)
+ esym = elfsym(ops[0].e.sym);
+ if (!esym || esym->st_shndx != cur_text_section->sh_num)
goto no_short_jump;
- if (sym->r != cur_text_section->sh_num)
- goto no_short_jump;
- jmp_disp = ops[0].e.v + sym->jnext - ind - 2 - (v >= 0xff);
+ jmp_disp = ops[0].e.v + esym->st_value - ind - 2 - (v >= 0xff);
if (jmp_disp == (int8_t)jmp_disp) {
/* OK to generate jump */
ops[0].e.sym = 0;
diff --git a/tcc.h b/tcc.h
index 5fc71a5..6241f42 100644
--- a/tcc.h
+++ b/tcc.h
@@ -356,6 +356,7 @@ extern long double strtold (const char *__nptr, char **__endptr);
#endif
/* target address type */
#define addr_t ElfW(Addr)
+#define ElfSym ElfW(Sym)
#if PTR_SIZE == 8 && !defined TCC_TARGET_PE
# define LONG_SIZE 8
@@ -383,7 +384,6 @@ 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];
@@ -440,9 +440,8 @@ struct SymAttr {
visibility : 2,
dllexport : 1,
dllimport : 1,
- asmcsym : 1,
asmexport : 1,
- unused : 3;
+ unused : 4;
};
/* function attributes or temporary attributes for parsing */
@@ -799,6 +798,7 @@ struct TCCState {
int nb_sym_attrs;
/* tiny assembler state */
Sym *asm_labels;
+ ElfSym esym_dot;
#ifdef TCC_TARGET_PE
/* PE info */
@@ -1147,7 +1147,7 @@ ST_FUNC Sym *sym_push(int v, CType *type, int r, int c);
ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep);
ST_INLN Sym *struct_find(int v);
ST_INLN Sym *sym_find(int v);
-ST_FUNC Sym *global_identifier_push(int v, int t, int c);
+ST_FUNC Sym *global_identifier_push_1(Sym **, int v, int t, int c);
ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen);
ST_FUNC int tcc_open(TCCState *s1, const char *filename);
@@ -1316,6 +1316,7 @@ ST_INLN int is_float(int t);
ST_FUNC int ieee_finite(double d);
ST_FUNC void test_lvalue(void);
ST_FUNC void vpushi(int v);
+ST_FUNC ElfSym *elfsym(Sym *);
ST_FUNC Sym *external_global_sym(int v, CType *type, int r);
ST_FUNC void vset(CType *type, int r, int v);
ST_FUNC void vswap(void);
@@ -1618,6 +1619,8 @@ PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp);
# define ST_PE_IMPORT 0x20
# define ST_PE_STDCALL 0x40
#endif
+#define ST_ASM_SET 0x04
+
/* ------------ tccrun.c ----------------- */
#ifdef TCC_IS_NATIVE
#ifdef CONFIG_TCC_STATIC
diff --git a/tccasm.c b/tccasm.c
index e6ad5aa..ba76c17 100644
--- a/tccasm.c
+++ b/tccasm.c
@@ -36,64 +36,40 @@ 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;
+ Sym *sym = sym_find(v);
+ while (sym && sym->sym_scope)
+ sym = sym->prev_tok;
+ return sym;
}
-static Sym *asm_label_push(Sym **ptop, int v)
+static Sym *asm_label_push(int v, int t)
{
- 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;
+ Sym *sym = global_identifier_push_1(&tcc_state->asm_labels, v, t, 0);
+ /* We always add VT_EXTERN, for sym definition that's tentative
+ (for .set, removed for real defs), for mere references it's correct
+ as is. */
+ sym->type.t |= VT_VOID | VT_EXTERN;
+ sym->r = VT_CONST | VT_SYM;
+ return sym;
}
/* 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
- to look up file-global C symbols from inside the assembler, e.g.
- for global asm blocks to be able to refer to defined C symbols.
+ Symbols from asm and C source share a namespace. If we generate
+ an asm symbol it's also a (file-global) C symbol, but it's
+ either not accessible by name (like "L.123"), or its type information
+ is such that it's not usable without a proper C declaration.
- 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.
-
- If CSYM is non-null we take symbol info from it, otherwise
- we look up NAME in the C symbol table and use that. */
+ Sometimes we need symbols accessible by name from asm, which
+ are anonymous in C, in this case CSYM can be used to transfer
+ all information from that symbol to the (possibly newly created)
+ asm symbol. */
ST_FUNC Sym* get_asm_sym(int name, Sym *csym)
{
Sym *sym = asm_label_find(name);
if (!sym) {
- 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
- and so might have local decls on the identifier stack. Search
- for the first global one. */
- while (csym && csym->sym_scope)
- csym = csym->prev_tok;
- }
- /* Now, if we have a defined global symbol copy over
- section and offset. */
- if (csym &&
- ((csym->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST)) &&
- 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. */
- sym->type.t = VT_VOID | (csym->type.t & VT_STATIC);
- /* Mark that this asm symbol doesn't need to be fed back. */
- sym->a.asmcsym = 1;
- sym->a.asmexport = !(csym->type.t & VT_STATIC);
- }
+ sym = asm_label_push(name, 0);
+ if (csym)
+ sym->c = csym->c;
}
return sym;
}
@@ -118,16 +94,15 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
sym = asm_label_find(label);
if (*p == 'b') {
/* backward : find the last corresponding defined label */
- if (sym && sym->r == 0)
+ if (sym && (!sym->c || elfsym(sym)->st_shndx == SHN_UNDEF))
sym = sym->prev_tok;
if (!sym)
tcc_error("local label '%d' not found backward", n);
} else {
/* forward */
- if (!sym || sym->r) {
+ if (!sym || (sym->c && elfsym(sym)->st_shndx != SHN_UNDEF)) {
/* if the last label is defined, then define a new one */
- sym = asm_label_push(&s1->asm_labels, label);
- sym->type.t = VT_STATIC | VT_VOID | VT_EXTERN;
+ sym = asm_label_push(label, VT_STATIC);
}
}
pe->v = 0;
@@ -175,17 +150,20 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
pe->sym = &sym_dot;
pe->pcrel = 0;
sym_dot.type.t = VT_VOID | VT_STATIC;
- sym_dot.r = cur_text_section->sh_num;
- sym_dot.jnext = ind;
+ sym_dot.c = -1;
+ tcc_state->esym_dot.st_shndx = cur_text_section->sh_num;
+ tcc_state->esym_dot.st_value = ind;
next();
break;
default:
if (tok >= TOK_IDENT) {
+ ElfSym *esym;
/* label case : if the label was not found, add one */
sym = get_asm_sym(tok, NULL);
- if (sym->r == SHN_ABS) {
+ esym = elfsym(sym);
+ if (esym && esym->st_shndx == SHN_ABS) {
/* if absolute symbol, no need to put a symbol value */
- pe->v = sym->jnext;
+ pe->v = esym->st_value;
pe->sym = NULL;
pe->pcrel = 0;
} else {
@@ -299,20 +277,26 @@ static inline void asm_expr_sum(TCCState *s1, ExprValue *pe)
} else if (pe->sym == e2.sym) {
/* OK */
pe->sym = NULL; /* same symbols can be subtracted to NULL */
- } else if (pe->sym && pe->sym->r == e2.sym->r && pe->sym->r != 0) {
- /* we also accept defined symbols in the same section */
- pe->v += pe->sym->jnext - e2.sym->jnext;
- pe->sym = NULL;
- } else if (e2.sym->r == cur_text_section->sh_num) {
- /* When subtracting a defined symbol in current section
- this actually makes the value PC-relative. */
- pe->v -= e2.sym->jnext - ind - 4;
- pe->pcrel = 1;
- e2.sym = NULL;
- } else {
- cannot_relocate:
- tcc_error("invalid operation with label");
- }
+ } else {
+ ElfSym *esym1, *esym2;
+ esym1 = elfsym(pe->sym);
+ esym2 = elfsym(e2.sym);
+ if (esym1 && esym1->st_shndx == esym2->st_shndx
+ && esym1->st_shndx != SHN_UNDEF) {
+ /* we also accept defined symbols in the same section */
+ pe->v += esym1->st_value - esym2->st_value;
+ pe->sym = NULL;
+ } else if (esym2->st_shndx == cur_text_section->sh_num) {
+ /* When subtracting a defined symbol in current section
+ this actually makes the value PC-relative. */
+ pe->v -= esym2->st_value - ind - 4;
+ pe->pcrel = 1;
+ e2.sym = NULL;
+ } else {
+cannot_relocate:
+ tcc_error("invalid operation with label");
+ }
+ }
}
}
}
@@ -377,13 +361,15 @@ static Sym* asm_new_label1(TCCState *s1, int label, int is_local,
int sh_num, int value)
{
Sym *sym;
+ ElfSym *esym;
sym = asm_label_find(label);
if (sym) {
+ esym = elfsym(sym);
/* A VT_EXTERN symbol, even if it has a section is considered
overridable. This is how we "define" .set targets. Real
definitions won't have VT_EXTERN set. */
- if (sym->r && !(sym->type.t & VT_EXTERN)) {
+ if (esym && esym->st_shndx != SHN_UNDEF && !(sym->type.t & VT_EXTERN)) {
/* the label is already defined */
if (!is_local) {
tcc_error("assembler label '%s' already defined",
@@ -395,14 +381,13 @@ static Sym* asm_new_label1(TCCState *s1, int label, int is_local,
}
} else {
new_label:
- 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_VOID | (is_local ? VT_STATIC : 0) | VT_EXTERN;
+ sym = asm_label_push(label, is_local ? VT_STATIC : 0);
}
- sym->r = sh_num;
- sym->jnext = value;
+ if (!sym->c)
+ put_extern_sym2(sym, NULL, 0, 0, 0);
+ esym = elfsym(sym);
+ esym->st_shndx = sh_num;
+ esym->st_value = value;
return sym;
}
@@ -417,79 +402,41 @@ static Sym* set_symbol(TCCState *s1, int label)
{
long n;
ExprValue e;
+ Sym *sym;
+ ElfSym *esym;
next();
asm_expr(s1, &e);
n = e.v;
- if (e.sym)
- n += e.sym->jnext;
- return asm_new_label1(s1, label, 0, e.sym ? e.sym->r : SHN_ABS, n);
-}
-
-/* Patch ELF symbol associated with SYM based on the assemblers
- understanding. */
-static void patch_binding(Sym *sym)
-{
- ElfW(Sym) *esym;
- if (0 == sym->c)
- return;
- esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
- if (sym->a.visibility)
- esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1))
- | sym->a.visibility;
-
- esym->st_info = ELFW(ST_INFO)(sym->a.weak ? STB_WEAK
- : (sym->type.t & VT_STATIC) ? STB_LOCAL
- : STB_GLOBAL,
- ELFW(ST_TYPE)(esym->st_info));
+ esym = elfsym(e.sym);
+ if (esym)
+ n += esym->st_value;
+ sym = asm_new_label1(s1, label, 0, esym ? esym->st_shndx : SHN_ABS, n);
+ elfsym(sym)->st_other |= ST_ASM_SET;
+ return sym;
}
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;
+ ElfSym *esym = elfsym(s);
s1 = s->prev;
- /* define symbol value in object file and care for updating
- the C and asm symbols */
+ /* Possibly update binding and visibility from asm directives. */
s->type.t &= ~VT_EXTERN;
- if (!s->a.asmcsym) {
- Sym *csym = sym_find(s->v);
- ElfW(Sym) *esym = NULL;
- if (csym) {
- s->a.asmexport |= !(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.asmexport)
- s->type.t |= VT_STATIC;
- if (s->r) {
- if (s->r == SHN_ABS)
- sec = SECTION_ABS;
- else
- sec = st->sections[s->r];
- /* !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->a.asmexport = 1;
- patch_binding(s);
+ if (esym) {
+ if (!s->a.asmexport && esym->st_shndx != SHN_UNDEF)
+ s->type.t |= VT_STATIC;
+ if (s->a.visibility)
+ esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1))
+ | s->a.visibility;
+ esym->st_info = ELFW(ST_INFO)(s->a.weak ? STB_WEAK
+ : (s->type.t & VT_STATIC) ? STB_LOCAL
+ : STB_GLOBAL,
+ ELFW(ST_TYPE)(esym->st_info));
}
/* remove label */
- table_ident[s->v - TOK_IDENT]->sym_asm_label = NULL;
+ table_ident[s->v - TOK_IDENT]->sym_identifier = s->prev_tok;
sym_free(s);
}
st->asm_labels = NULL;
@@ -715,13 +662,15 @@ static void asm_parse_directive(TCCState *s1, int global)
{
unsigned long n;
ExprValue e;
+ ElfSym *esym;
next();
asm_expr(s1, &e);
n = e.v;
- if (e.sym) {
- if (e.sym->r != cur_text_section->sh_num)
+ esym = elfsym(e.sym);
+ if (esym) {
+ if (esym->st_shndx != cur_text_section->sh_num)
expect("constant or same-section symbol");
- n += e.sym->jnext;
+ n += esym->st_value;
}
if (n < ind)
tcc_error("attempt to .org backwards");
@@ -978,7 +927,6 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
int opcode;
int saved_parse_flags = parse_flags;
- /* XXX: undefine C labels */
parse_flags = PARSE_FLAG_ASM_FILE | PARSE_FLAG_TOK_STR;
if (do_preprocess)
parse_flags |= PARSE_FLAG_PREPROCESS;
@@ -1017,18 +965,8 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
opcode = tok;
next();
if (tok == ':') {
- /* handle "extern void vide(void); __asm__("vide: ret");" as
- "__asm__("globl vide\nvide: ret");" */
- Sym *sym = sym_find(opcode);
- if (sym && (sym->type.t & VT_EXTERN) && global) {
- sym = asm_label_find(opcode);
- if (!sym) {
- sym = asm_label_push(&s1->asm_labels, opcode);
- sym->type.t = VT_VOID | VT_EXTERN;
- }
- }
/* new label */
- sym = asm_new_label(s1, opcode, 0);
+ Sym *sym = asm_new_label(s1, opcode, 0);
sym->type.t &= ~VT_EXTERN;
next();
goto redo;
diff --git a/tccelf.c b/tccelf.c
index 22ce5df..422dfd6 100644
--- a/tccelf.c
+++ b/tccelf.c
@@ -310,7 +310,8 @@ static void rebuild_hash(Section *s, unsigned int nb_buckets)
sym = (ElfW(Sym) *)s->data + 1;
for(sym_index = 1; sym_index < nb_syms; sym_index++) {
- if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
+ if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL
+ || sym->st_shndx == SHN_UNDEF) {
h = elf_hash(strtab + sym->st_name) % nb_buckets;
*ptr = hash[h];
hash[h] = sym_index;
@@ -349,8 +350,9 @@ ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size,
int *ptr, *base;
ptr = section_ptr_add(hs, sizeof(int));
base = (int *)hs->data;
- /* only add global or weak symbols */
- if (ELFW(ST_BIND)(info) != STB_LOCAL) {
+ /* only add global, weak or undef symbols. The latter might
+ become global late (from asm references). */
+ if (ELFW(ST_BIND)(info) != STB_LOCAL || shndx == SHN_UNDEF) {
/* add another hashing entry */
nbuckets = base[0];
h = elf_hash((unsigned char *) name) % nbuckets;
@@ -486,6 +488,10 @@ ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size,
/* data symbol keeps precedence over common/bss */
} else if (s == tcc_state->dynsymtab_section) {
/* we accept that two DLL define the same symbol */
+ } else if (esym->st_other & ST_ASM_SET) {
+ /* If the existing symbol came from an asm .set
+ we can override. */
+ goto do_patch;
} else {
#if 0
printf("new_bind=%x new_shndx=%x new_vis=%x old_bind=%x old_shndx=%x old_vis=%x\n",
diff --git a/tccgen.c b/tccgen.c
index a86103c..2d3f2d0 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -286,14 +286,23 @@ ST_FUNC int tccgen_compile(TCCState *s1)
}
/* ------------------------------------------------------------------------- */
+ST_FUNC ElfSym *elfsym(Sym *s)
+{
+ if (!s || !s->c)
+ return NULL;
+ if (s->c == -1)
+ return &tcc_state->esym_dot;
+ else
+ return &((ElfSym *)symtab_section->data)[s->c];
+}
+
/* apply storage attributes to Elf symbol */
static void update_storage(Sym *sym)
{
- ElfW(Sym) *esym;
- if (0 == sym->c)
+ ElfSym *esym = elfsym(sym);
+ if (!esym)
return;
- esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
if (sym->a.visibility)
esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1))
| sym->a.visibility;
@@ -325,7 +334,7 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section,
int can_add_underscore)
{
int sym_type, sym_bind, sh_num, info, other, t;
- ElfW(Sym) *esym;
+ ElfSym *esym;
const char *name;
char buf1[256];
#ifdef CONFIG_TCC_BCHECK
@@ -402,7 +411,7 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section,
info = ELFW(ST_INFO)(sym_bind, sym_type);
sym->c = set_elf_sym(symtab_section, value, size, info, other, sh_num, name);
} else {
- esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
+ esym = elfsym(sym);
esym->st_value = value;
esym->st_size = size;
esym->st_shndx = sh_num;
@@ -569,23 +578,28 @@ ST_FUNC Sym *sym_push(int v, CType *type, int r, int c)
}
/* push a global identifier */
-ST_FUNC Sym *global_identifier_push(int v, int t, int c)
+ST_FUNC Sym *global_identifier_push_1(Sym **ptop, int v, int t, int c)
{
Sym *s, **ps;
- s = sym_push2(&global_stack, v, t, c);
+ s = sym_push2(ptop, v, t, c);
/* don't record anonymous symbol */
if (v < SYM_FIRST_ANOM) {
ps = &table_ident[v - TOK_IDENT]->sym_identifier;
/* modify the top most local identifier, so that
sym_identifier will point to 's' when popped */
- while (*ps != NULL)
+ while (*ps != NULL && (*ps)->sym_scope)
ps = &(*ps)->prev_tok;
- s->prev_tok = NULL;
+ s->prev_tok = *ps;
*ps = s;
}
return s;
}
+static Sym *global_identifier_push(int v, int t, int c)
+{
+ return global_identifier_push_1(&global_stack, v, t, c);
+}
+
/* pop symbols until top reaches 'b'. If KEEP is non-zero don't really
pop them yet from the list, but do remove them from the token array. */
ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep)
@@ -834,9 +848,13 @@ ST_FUNC Sym *external_global_sym(int v, CType *type, int r)
/* Merge some storage attributes. */
static void patch_storage(Sym *sym, AttributeDef *ad, CType *type)
{
- if (type && !is_compatible_types(&sym->type, type))
- tcc_error("incompatible types for redefinition of '%s'",
- get_tok_str(sym->v, NULL));
+ if (type) {
+ if ((sym->type.t & VT_BTYPE) == VT_VOID) /* from asm */
+ sym->type = *type;
+ else if (!is_compatible_types(&sym->type, type))
+ tcc_error("incompatible types for redefinition of '%s'",
+ get_tok_str(sym->v, NULL));
+ }
#ifdef TCC_TARGET_PE
if (sym->a.dllimport != ad->a.dllimport)
tcc_error("incompatible dll linkage for redefinition of '%s'",
@@ -6426,9 +6444,9 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
(vtop->type.t & VT_BTYPE) != VT_PTR) {
/* These come from compound literals, memcpy stuff over. */
Section *ssec;
- ElfW(Sym) *esym;
+ ElfSym *esym;
ElfW_Rel *rel;
- esym = &((ElfW(Sym) *)symtab_section->data)[vtop->sym->c];
+ esym = elfsym(vtop->sym);
ssec = tcc_state->sections[esym->st_shndx];
memmove (ptr, ssec->data + esym->st_value, size);
if (ssec->reloc) {
@@ -6895,8 +6913,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
/* no init data, we won't add more to the symbol */
goto no_alloc;
} else if (sym->c) {
- ElfW(Sym) *esym;
- esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
+ ElfSym *esym = elfsym(sym);
if (esym->st_shndx == data_section->sh_num)
tcc_error("redefinition of '%s'", get_tok_str(v, NULL));
}
@@ -7030,8 +7047,7 @@ static void gen_function(Sym *sym)
sym_pop(&local_stack, NULL, 0);
/* end of function */
/* patch symbol size */
- ((ElfW(Sym) *)symtab_section->data)[sym->c].st_size =
- ind - func_ind;
+ elfsym(sym)->st_size = ind - func_ind;
tcc_debug_funcend(tcc_state, ind - func_ind);
/* It's better to crash than to generate wrong code */
cur_text_section = NULL;
@@ -7209,6 +7225,11 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym)
sym = sym_find(v);
if (sym) {
Sym *ref;
+ /* If type is VT_VOID the symbol was created by tccasm
+ first, and we see the first reference from C now. */
+ if ((sym->type.t & VT_BTYPE) == VT_VOID)
+ sym->type = type;
+
if ((sym->type.t & VT_BTYPE) != VT_FUNC)
goto func_error1;
@@ -7330,12 +7351,12 @@ found:
sym = external_sym(v, &type, r, &ad);
if (ad.alias_target) {
Section tsec;
- ElfW(Sym) *esym;
+ ElfSym *esym;
Sym *alias_target;
alias_target = sym_find(ad.alias_target);
- if (!alias_target || !alias_target->c)
+ esym = elfsym(alias_target);
+ if (!esym)
tcc_error("unsupported forward __alias__ attribute");
- esym = &((ElfW(Sym) *)symtab_section->data)[alias_target->c];
tsec.sh_num = esym->st_shndx;
/* Local statics have a scope until now (for
warnings), remove it here. */
diff --git a/tccpp.c b/tccpp.c
index d8e7f53..76f9e42 100644
--- a/tccpp.c
+++ b/tccpp.c
@@ -432,7 +432,6 @@ 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/asm-c-connect-1.c b/tests/asm-c-connect-1.c
index fbd240c..c3dcf2b 100644
--- a/tests/asm-c-connect-1.c
+++ b/tests/asm-c-connect-1.c
@@ -14,11 +14,13 @@ static int x1_c(void)
asm(".text;"_"x1: call "_"x1_c; ret");
+void callx4(void);
int main(int argc, char *argv[])
{
asm("call "_"x1");
asm("call "_"x2");
asm("call "_"x3");
+ callx4();
return 0;
}
@@ -30,3 +32,8 @@ int x2(void)
}
extern int x3(void);
+
+void x4(void)
+{
+ printf("x4\n");
+}
diff --git a/tests/asm-c-connect-2.c b/tests/asm-c-connect-2.c
index 3a8cff2..7ab9dc3 100644
--- a/tests/asm-c-connect-2.c
+++ b/tests/asm-c-connect-2.c
@@ -5,3 +5,6 @@ int x3(void)
printf("x3\n");
return 3;
}
+
+void callx4(void);
+__asm__("callx4: call x4; ret");