tccasm: Unify C and asm symbol table

This makes the asm symbols use the same members as the C symbols
for global decls, e.g. using the ELF symbol to hold offset and
section.  That allows us to use only one symbol table for C and
asm symbols and to get rid of hacks to synch between them.

We still need some special handling for symbols that come purely
from asm sources.
master
Michael Matz 2017-11-27 04:03:03 +01:00
parent 3494e5de3a
commit 9e0d23cc47
8 changed files with 164 additions and 188 deletions

View File

@ -500,12 +500,13 @@ ST_FUNC void gen_expr64(ExprValue *pe)
static void gen_disp32(ExprValue *pe) static void gen_disp32(ExprValue *pe)
{ {
Sym *sym = pe->sym; 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 /* same section: we can output an absolute value. Note
that the TCC compiler behaves differently here because that the TCC compiler behaves differently here because
it always outputs a relocation to ease (future) code it always outputs a relocation to ease (future) code
elimination in the linker */ elimination in the linker */
gen_le32(pe->v + sym->jnext - ind - 4); gen_le32(pe->v + esym->st_value - ind - 4);
} else { } else {
if (sym && sym->type.t == VT_VOID) { if (sym && sym->type.t == VT_VOID) {
sym->type.t = VT_FUNC; sym->type.t = VT_FUNC;
@ -1017,16 +1018,14 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
if (pa->instr_type & OPC_B) if (pa->instr_type & OPC_B)
v += s >= 1; v += s >= 1;
if (nb_ops == 1 && pa->op_type[0] == OPT_DISP8) { if (nb_ops == 1 && pa->op_type[0] == OPT_DISP8) {
Sym *sym; ElfSym *esym;
int jmp_disp; int jmp_disp;
/* see if we can really generate the jump with a byte offset */ /* see if we can really generate the jump with a byte offset */
sym = ops[0].e.sym; esym = elfsym(ops[0].e.sym);
if (!sym) if (!esym || esym->st_shndx != cur_text_section->sh_num)
goto no_short_jump; goto no_short_jump;
if (sym->r != cur_text_section->sh_num) jmp_disp = ops[0].e.v + esym->st_value - ind - 2 - (v >= 0xff);
goto no_short_jump;
jmp_disp = ops[0].e.v + sym->jnext - ind - 2 - (v >= 0xff);
if (jmp_disp == (int8_t)jmp_disp) { if (jmp_disp == (int8_t)jmp_disp) {
/* OK to generate jump */ /* OK to generate jump */
ops[0].e.sym = 0; ops[0].e.sym = 0;

11
tcc.h
View File

@ -356,6 +356,7 @@ extern long double strtold (const char *__nptr, char **__endptr);
#endif #endif
/* target address type */ /* target address type */
#define addr_t ElfW(Addr) #define addr_t ElfW(Addr)
#define ElfSym ElfW(Sym)
#if PTR_SIZE == 8 && !defined TCC_TARGET_PE #if PTR_SIZE == 8 && !defined TCC_TARGET_PE
# define LONG_SIZE 8 # define LONG_SIZE 8
@ -383,7 +384,6 @@ typedef struct TokenSym {
struct Sym *sym_label; /* direct pointer to label */ struct Sym *sym_label; /* direct pointer to label */
struct Sym *sym_struct; /* direct pointer to structure */ struct Sym *sym_struct; /* direct pointer to structure */
struct Sym *sym_identifier; /* direct pointer to identifier */ struct Sym *sym_identifier; /* direct pointer to identifier */
struct Sym *sym_asm_label; /* direct pointer to asm label */
int tok; /* token number */ int tok; /* token number */
int len; int len;
char str[1]; char str[1];
@ -440,9 +440,8 @@ struct SymAttr {
visibility : 2, visibility : 2,
dllexport : 1, dllexport : 1,
dllimport : 1, dllimport : 1,
asmcsym : 1,
asmexport : 1, asmexport : 1,
unused : 3; unused : 4;
}; };
/* function attributes or temporary attributes for parsing */ /* function attributes or temporary attributes for parsing */
@ -799,6 +798,7 @@ struct TCCState {
int nb_sym_attrs; int nb_sym_attrs;
/* tiny assembler state */ /* tiny assembler state */
Sym *asm_labels; Sym *asm_labels;
ElfSym esym_dot;
#ifdef TCC_TARGET_PE #ifdef TCC_TARGET_PE
/* PE info */ /* 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_FUNC void sym_pop(Sym **ptop, Sym *b, int keep);
ST_INLN Sym *struct_find(int v); ST_INLN Sym *struct_find(int v);
ST_INLN Sym *sym_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 void tcc_open_bf(TCCState *s1, const char *filename, int initlen);
ST_FUNC int tcc_open(TCCState *s1, const char *filename); 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 int ieee_finite(double d);
ST_FUNC void test_lvalue(void); ST_FUNC void test_lvalue(void);
ST_FUNC void vpushi(int v); 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 Sym *external_global_sym(int v, CType *type, int r);
ST_FUNC void vset(CType *type, int r, int v); ST_FUNC void vset(CType *type, int r, int v);
ST_FUNC void vswap(void); 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_IMPORT 0x20
# define ST_PE_STDCALL 0x40 # define ST_PE_STDCALL 0x40
#endif #endif
#define ST_ASM_SET 0x04
/* ------------ tccrun.c ----------------- */ /* ------------ tccrun.c ----------------- */
#ifdef TCC_IS_NATIVE #ifdef TCC_IS_NATIVE
#ifdef CONFIG_TCC_STATIC #ifdef CONFIG_TCC_STATIC

240
tccasm.c
View File

@ -36,64 +36,40 @@ static Sym sym_dot;
static Sym *asm_label_find(int v) static Sym *asm_label_find(int v)
{ {
v -= TOK_IDENT; Sym *sym = sym_find(v);
if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) while (sym && sym->sym_scope)
return NULL; sym = sym->prev_tok;
return table_ident[v]->sym_asm_label; return sym;
} }
static Sym *asm_label_push(Sym **ptop, int v) static Sym *asm_label_push(int v, int t)
{ {
Sym *s, **ps; Sym *sym = global_identifier_push_1(&tcc_state->asm_labels, v, t, 0);
s = sym_push2(ptop, v, 0, 0); /* We always add VT_EXTERN, for sym definition that's tentative
ps = &table_ident[v - TOK_IDENT]->sym_asm_label; (for .set, removed for real defs), for mere references it's correct
s->prev_tok = *ps; as is. */
*ps = s; sym->type.t |= VT_VOID | VT_EXTERN;
return s; sym->r = VT_CONST | VT_SYM;
return sym;
} }
/* Return a symbol we can use inside the assembler, having name NAME. /* Return a symbol we can use inside the assembler, having name NAME.
The assembler symbol table is different from the C symbol table Symbols from asm and C source share a namespace. If we generate
(and the Sym members are used differently). But we must be able an asm symbol it's also a (file-global) C symbol, but it's
to look up file-global C symbols from inside the assembler, e.g. either not accessible by name (like "L.123"), or its type information
for global asm blocks to be able to refer to defined C symbols. is such that it's not usable without a proper C declaration.
This routine gives back either an existing asm-internal Sometimes we need symbols accessible by name from asm, which
symbol, or a new one. In the latter case the new asm-internal are anonymous in C, in this case CSYM can be used to transfer
symbol is initialized with info from the C symbol table. all information from that symbol to the (possibly newly created)
asm symbol. */
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) ST_FUNC Sym* get_asm_sym(int name, Sym *csym)
{ {
Sym *sym = asm_label_find(name); Sym *sym = asm_label_find(name);
if (!sym) { if (!sym) {
sym = asm_label_push(&tcc_state->asm_labels, name); sym = asm_label_push(name, 0);
sym->type.t = VT_VOID | VT_EXTERN; if (csym)
if (!csym) { sym->c = csym->c;
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);
}
} }
return sym; return sym;
} }
@ -118,16 +94,15 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
sym = asm_label_find(label); sym = asm_label_find(label);
if (*p == 'b') { if (*p == 'b') {
/* backward : find the last corresponding defined label */ /* 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; sym = sym->prev_tok;
if (!sym) if (!sym)
tcc_error("local label '%d' not found backward", n); tcc_error("local label '%d' not found backward", n);
} else { } else {
/* forward */ /* 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 */ /* if the last label is defined, then define a new one */
sym = asm_label_push(&s1->asm_labels, label); sym = asm_label_push(label, VT_STATIC);
sym->type.t = VT_STATIC | VT_VOID | VT_EXTERN;
} }
} }
pe->v = 0; pe->v = 0;
@ -175,17 +150,20 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
pe->sym = &sym_dot; pe->sym = &sym_dot;
pe->pcrel = 0; pe->pcrel = 0;
sym_dot.type.t = VT_VOID | VT_STATIC; sym_dot.type.t = VT_VOID | VT_STATIC;
sym_dot.r = cur_text_section->sh_num; sym_dot.c = -1;
sym_dot.jnext = ind; tcc_state->esym_dot.st_shndx = cur_text_section->sh_num;
tcc_state->esym_dot.st_value = ind;
next(); next();
break; break;
default: default:
if (tok >= TOK_IDENT) { if (tok >= TOK_IDENT) {
ElfSym *esym;
/* label case : if the label was not found, add one */ /* label case : if the label was not found, add one */
sym = get_asm_sym(tok, NULL); 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 */ /* if absolute symbol, no need to put a symbol value */
pe->v = sym->jnext; pe->v = esym->st_value;
pe->sym = NULL; pe->sym = NULL;
pe->pcrel = 0; pe->pcrel = 0;
} else { } else {
@ -299,20 +277,26 @@ static inline void asm_expr_sum(TCCState *s1, ExprValue *pe)
} else if (pe->sym == e2.sym) { } else if (pe->sym == e2.sym) {
/* OK */ /* OK */
pe->sym = NULL; /* same symbols can be subtracted to NULL */ pe->sym = NULL; /* same symbols can be subtracted to NULL */
} else if (pe->sym && pe->sym->r == e2.sym->r && pe->sym->r != 0) { } else {
/* we also accept defined symbols in the same section */ ElfSym *esym1, *esym2;
pe->v += pe->sym->jnext - e2.sym->jnext; esym1 = elfsym(pe->sym);
pe->sym = NULL; esym2 = elfsym(e2.sym);
} else if (e2.sym->r == cur_text_section->sh_num) { if (esym1 && esym1->st_shndx == esym2->st_shndx
/* When subtracting a defined symbol in current section && esym1->st_shndx != SHN_UNDEF) {
this actually makes the value PC-relative. */ /* we also accept defined symbols in the same section */
pe->v -= e2.sym->jnext - ind - 4; pe->v += esym1->st_value - esym2->st_value;
pe->pcrel = 1; pe->sym = NULL;
e2.sym = NULL; } else if (esym2->st_shndx == cur_text_section->sh_num) {
} else { /* When subtracting a defined symbol in current section
cannot_relocate: this actually makes the value PC-relative. */
tcc_error("invalid operation with label"); 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) int sh_num, int value)
{ {
Sym *sym; Sym *sym;
ElfSym *esym;
sym = asm_label_find(label); sym = asm_label_find(label);
if (sym) { if (sym) {
esym = elfsym(sym);
/* A VT_EXTERN symbol, even if it has a section is considered /* A VT_EXTERN symbol, even if it has a section is considered
overridable. This is how we "define" .set targets. Real overridable. This is how we "define" .set targets. Real
definitions won't have VT_EXTERN set. */ 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 */ /* the label is already defined */
if (!is_local) { if (!is_local) {
tcc_error("assembler label '%s' already defined", tcc_error("assembler label '%s' already defined",
@ -395,14 +381,13 @@ static Sym* asm_new_label1(TCCState *s1, int label, int is_local,
} }
} else { } else {
new_label: new_label:
sym = asm_label_push(&s1->asm_labels, label); sym = asm_label_push(label, is_local ? VT_STATIC : 0);
/* 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->r = sh_num; if (!sym->c)
sym->jnext = value; put_extern_sym2(sym, NULL, 0, 0, 0);
esym = elfsym(sym);
esym->st_shndx = sh_num;
esym->st_value = value;
return sym; return sym;
} }
@ -417,79 +402,41 @@ static Sym* set_symbol(TCCState *s1, int label)
{ {
long n; long n;
ExprValue e; ExprValue e;
Sym *sym;
ElfSym *esym;
next(); next();
asm_expr(s1, &e); asm_expr(s1, &e);
n = e.v; n = e.v;
if (e.sym) esym = elfsym(e.sym);
n += e.sym->jnext; if (esym)
return asm_new_label1(s1, label, 0, e.sym ? e.sym->r : SHN_ABS, n); 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;
/* Patch ELF symbol associated with SYM based on the assemblers return sym;
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));
} }
ST_FUNC void asm_free_labels(TCCState *st) ST_FUNC void asm_free_labels(TCCState *st)
{ {
Sym *s, *s1; Sym *s, *s1;
Section *sec;
for(s = st->asm_labels; s != NULL; s = s1) { for(s = st->asm_labels; s != NULL; s = s1) {
int was_ext = s->type.t & VT_EXTERN; ElfSym *esym = elfsym(s);
s1 = s->prev; s1 = s->prev;
/* define symbol value in object file and care for updating /* Possibly update binding and visibility from asm directives. */
the C and asm symbols */
s->type.t &= ~VT_EXTERN; s->type.t &= ~VT_EXTERN;
if (!s->a.asmcsym) { if (esym) {
Sym *csym = sym_find(s->v); if (!s->a.asmexport && esym->st_shndx != SHN_UNDEF)
ElfW(Sym) *esym = NULL; s->type.t |= VT_STATIC;
if (csym) { if (s->a.visibility)
s->a.asmexport |= !(csym->type.t & VT_STATIC); esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1))
if (csym->c) { | s->a.visibility;
esym = &((ElfW(Sym) *)symtab_section->data)[csym->c]; esym->st_info = ELFW(ST_INFO)(s->a.weak ? STB_WEAK
if (s->c) { : (s->type.t & VT_STATIC) ? STB_LOCAL
/* We have generated code and possibly relocs : STB_GLOBAL,
referencing the symtab entry s->c (the asm ELFW(ST_TYPE)(esym->st_info));
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);
} }
/* remove label */ /* 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); sym_free(s);
} }
st->asm_labels = NULL; st->asm_labels = NULL;
@ -715,13 +662,15 @@ static void asm_parse_directive(TCCState *s1, int global)
{ {
unsigned long n; unsigned long n;
ExprValue e; ExprValue e;
ElfSym *esym;
next(); next();
asm_expr(s1, &e); asm_expr(s1, &e);
n = e.v; n = e.v;
if (e.sym) { esym = elfsym(e.sym);
if (e.sym->r != cur_text_section->sh_num) if (esym) {
if (esym->st_shndx != cur_text_section->sh_num)
expect("constant or same-section symbol"); expect("constant or same-section symbol");
n += e.sym->jnext; n += esym->st_value;
} }
if (n < ind) if (n < ind)
tcc_error("attempt to .org backwards"); 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 opcode;
int saved_parse_flags = parse_flags; int saved_parse_flags = parse_flags;
/* XXX: undefine C labels */
parse_flags = PARSE_FLAG_ASM_FILE | PARSE_FLAG_TOK_STR; parse_flags = PARSE_FLAG_ASM_FILE | PARSE_FLAG_TOK_STR;
if (do_preprocess) if (do_preprocess)
parse_flags |= PARSE_FLAG_PREPROCESS; parse_flags |= PARSE_FLAG_PREPROCESS;
@ -1017,18 +965,8 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
opcode = tok; opcode = tok;
next(); next();
if (tok == ':') { 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 */ /* new label */
sym = asm_new_label(s1, opcode, 0); Sym *sym = asm_new_label(s1, opcode, 0);
sym->type.t &= ~VT_EXTERN; sym->type.t &= ~VT_EXTERN;
next(); next();
goto redo; goto redo;

View File

@ -310,7 +310,8 @@ static void rebuild_hash(Section *s, unsigned int nb_buckets)
sym = (ElfW(Sym) *)s->data + 1; sym = (ElfW(Sym) *)s->data + 1;
for(sym_index = 1; sym_index < nb_syms; sym_index++) { 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; h = elf_hash(strtab + sym->st_name) % nb_buckets;
*ptr = hash[h]; *ptr = hash[h];
hash[h] = sym_index; 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; int *ptr, *base;
ptr = section_ptr_add(hs, sizeof(int)); ptr = section_ptr_add(hs, sizeof(int));
base = (int *)hs->data; base = (int *)hs->data;
/* only add global or weak symbols */ /* only add global, weak or undef symbols. The latter might
if (ELFW(ST_BIND)(info) != STB_LOCAL) { become global late (from asm references). */
if (ELFW(ST_BIND)(info) != STB_LOCAL || shndx == SHN_UNDEF) {
/* add another hashing entry */ /* add another hashing entry */
nbuckets = base[0]; nbuckets = base[0];
h = elf_hash((unsigned char *) name) % nbuckets; 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 */ /* data symbol keeps precedence over common/bss */
} else if (s == tcc_state->dynsymtab_section) { } else if (s == tcc_state->dynsymtab_section) {
/* we accept that two DLL define the same symbol */ /* 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 { } else {
#if 0 #if 0
printf("new_bind=%x new_shndx=%x new_vis=%x old_bind=%x old_shndx=%x old_vis=%x\n", printf("new_bind=%x new_shndx=%x new_vis=%x old_bind=%x old_shndx=%x old_vis=%x\n",

View File

@ -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 */ /* apply storage attributes to Elf symbol */
static void update_storage(Sym *sym) static void update_storage(Sym *sym)
{ {
ElfW(Sym) *esym; ElfSym *esym = elfsym(sym);
if (0 == sym->c) if (!esym)
return; return;
esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
if (sym->a.visibility) if (sym->a.visibility)
esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1))
| sym->a.visibility; | sym->a.visibility;
@ -325,7 +334,7 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section,
int can_add_underscore) int can_add_underscore)
{ {
int sym_type, sym_bind, sh_num, info, other, t; int sym_type, sym_bind, sh_num, info, other, t;
ElfW(Sym) *esym; ElfSym *esym;
const char *name; const char *name;
char buf1[256]; char buf1[256];
#ifdef CONFIG_TCC_BCHECK #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); info = ELFW(ST_INFO)(sym_bind, sym_type);
sym->c = set_elf_sym(symtab_section, value, size, info, other, sh_num, name); sym->c = set_elf_sym(symtab_section, value, size, info, other, sh_num, name);
} else { } else {
esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; esym = elfsym(sym);
esym->st_value = value; esym->st_value = value;
esym->st_size = size; esym->st_size = size;
esym->st_shndx = sh_num; 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 */ /* 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; Sym *s, **ps;
s = sym_push2(&global_stack, v, t, c); s = sym_push2(ptop, v, t, c);
/* don't record anonymous symbol */ /* don't record anonymous symbol */
if (v < SYM_FIRST_ANOM) { if (v < SYM_FIRST_ANOM) {
ps = &table_ident[v - TOK_IDENT]->sym_identifier; ps = &table_ident[v - TOK_IDENT]->sym_identifier;
/* modify the top most local identifier, so that /* modify the top most local identifier, so that
sym_identifier will point to 's' when popped */ sym_identifier will point to 's' when popped */
while (*ps != NULL) while (*ps != NULL && (*ps)->sym_scope)
ps = &(*ps)->prev_tok; ps = &(*ps)->prev_tok;
s->prev_tok = NULL; s->prev_tok = *ps;
*ps = s; *ps = s;
} }
return 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 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. */ 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) 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. */ /* Merge some storage attributes. */
static void patch_storage(Sym *sym, AttributeDef *ad, CType *type) static void patch_storage(Sym *sym, AttributeDef *ad, CType *type)
{ {
if (type && !is_compatible_types(&sym->type, type)) if (type) {
tcc_error("incompatible types for redefinition of '%s'", if ((sym->type.t & VT_BTYPE) == VT_VOID) /* from asm */
get_tok_str(sym->v, NULL)); 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 #ifdef TCC_TARGET_PE
if (sym->a.dllimport != ad->a.dllimport) if (sym->a.dllimport != ad->a.dllimport)
tcc_error("incompatible dll linkage for redefinition of '%s'", 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) { (vtop->type.t & VT_BTYPE) != VT_PTR) {
/* These come from compound literals, memcpy stuff over. */ /* These come from compound literals, memcpy stuff over. */
Section *ssec; Section *ssec;
ElfW(Sym) *esym; ElfSym *esym;
ElfW_Rel *rel; ElfW_Rel *rel;
esym = &((ElfW(Sym) *)symtab_section->data)[vtop->sym->c]; esym = elfsym(vtop->sym);
ssec = tcc_state->sections[esym->st_shndx]; ssec = tcc_state->sections[esym->st_shndx];
memmove (ptr, ssec->data + esym->st_value, size); memmove (ptr, ssec->data + esym->st_value, size);
if (ssec->reloc) { 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 */ /* no init data, we won't add more to the symbol */
goto no_alloc; goto no_alloc;
} else if (sym->c) { } else if (sym->c) {
ElfW(Sym) *esym; ElfSym *esym = elfsym(sym);
esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
if (esym->st_shndx == data_section->sh_num) if (esym->st_shndx == data_section->sh_num)
tcc_error("redefinition of '%s'", get_tok_str(v, NULL)); 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); sym_pop(&local_stack, NULL, 0);
/* end of function */ /* end of function */
/* patch symbol size */ /* patch symbol size */
((ElfW(Sym) *)symtab_section->data)[sym->c].st_size = elfsym(sym)->st_size = ind - func_ind;
ind - func_ind;
tcc_debug_funcend(tcc_state, ind - func_ind); tcc_debug_funcend(tcc_state, ind - func_ind);
/* It's better to crash than to generate wrong code */ /* It's better to crash than to generate wrong code */
cur_text_section = NULL; 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); sym = sym_find(v);
if (sym) { if (sym) {
Sym *ref; 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) if ((sym->type.t & VT_BTYPE) != VT_FUNC)
goto func_error1; goto func_error1;
@ -7330,12 +7351,12 @@ found:
sym = external_sym(v, &type, r, &ad); sym = external_sym(v, &type, r, &ad);
if (ad.alias_target) { if (ad.alias_target) {
Section tsec; Section tsec;
ElfW(Sym) *esym; ElfSym *esym;
Sym *alias_target; Sym *alias_target;
alias_target = sym_find(ad.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"); tcc_error("unsupported forward __alias__ attribute");
esym = &((ElfW(Sym) *)symtab_section->data)[alias_target->c];
tsec.sh_num = esym->st_shndx; tsec.sh_num = esym->st_shndx;
/* Local statics have a scope until now (for /* Local statics have a scope until now (for
warnings), remove it here. */ warnings), remove it here. */

View File

@ -432,7 +432,6 @@ static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len)
ts->sym_label = NULL; ts->sym_label = NULL;
ts->sym_struct = NULL; ts->sym_struct = NULL;
ts->sym_identifier = NULL; ts->sym_identifier = NULL;
ts->sym_asm_label = NULL;
ts->len = len; ts->len = len;
ts->hash_next = NULL; ts->hash_next = NULL;
memcpy(ts->str, str, len); memcpy(ts->str, str, len);

View File

@ -14,11 +14,13 @@ static int x1_c(void)
asm(".text;"_"x1: call "_"x1_c; ret"); asm(".text;"_"x1: call "_"x1_c; ret");
void callx4(void);
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
asm("call "_"x1"); asm("call "_"x1");
asm("call "_"x2"); asm("call "_"x2");
asm("call "_"x3"); asm("call "_"x3");
callx4();
return 0; return 0;
} }
@ -30,3 +32,8 @@ int x2(void)
} }
extern int x3(void); extern int x3(void);
void x4(void)
{
printf("x4\n");
}

View File

@ -5,3 +5,6 @@ int x3(void)
printf("x3\n"); printf("x3\n");
return 3; return 3;
} }
void callx4(void);
__asm__("callx4: call x4; ret");