mirror of
https://github.com/mirror/tinycc.git
synced 2025-01-25 06:00:11 +08:00
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.
This commit is contained in:
parent
3494e5de3a
commit
9e0d23cc47
15
i386-asm.c
15
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;
|
||||
|
11
tcc.h
11
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
|
||||
|
240
tccasm.c
240
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;
|
||||
|
12
tccelf.c
12
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",
|
||||
|
63
tccgen.c
63
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. */
|
||||
|
1
tccpp.c
1
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);
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -5,3 +5,6 @@ int x3(void)
|
||||
printf("x3\n");
|
||||
return 3;
|
||||
}
|
||||
|
||||
void callx4(void);
|
||||
__asm__("callx4: call x4; ret");
|
||||
|
Loading…
Reference in New Issue
Block a user