mirror of
https://github.com/frida/tinycc
synced 2024-12-24 05:56:49 +03:00
tccasm: use global(_symbol)_stack
* removed asm_label stack * removed asm_free_labels() post-processing * using "impossible C type" for asm labels (VT_ASM) * tccgen.c:update_storage(): use it to refresh symbol attributes * tccelf.c:find_elf_sym(): ignore STB_LOCAL symbols * tccgen.c:unary(): asm symbols are supposed to be undeclared in C
This commit is contained in:
parent
cc6cb7f0e2
commit
877e164d6a
14
tcc.h
14
tcc.h
@ -440,8 +440,7 @@ struct SymAttr {
|
||||
visibility : 2,
|
||||
dllexport : 1,
|
||||
dllimport : 1,
|
||||
asmexport : 1,
|
||||
unused : 4;
|
||||
unused : 5;
|
||||
};
|
||||
|
||||
/* function attributes or temporary attributes for parsing */
|
||||
@ -796,8 +795,8 @@ struct TCCState {
|
||||
/* extra attributes (eg. GOT/PLT value) for symtab symbols */
|
||||
struct sym_attr *sym_attrs;
|
||||
int nb_sym_attrs;
|
||||
|
||||
/* tiny assembler state */
|
||||
Sym *asm_labels;
|
||||
ElfSym esym_dot;
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
@ -911,6 +910,11 @@ struct filespec {
|
||||
#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE)
|
||||
#define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK))
|
||||
|
||||
/* symbol was created by tccasm.c first */
|
||||
#define VT_ASM (VT_VOID | VT_UNSIGNED)
|
||||
#define VT_ASM_GLOBAL VT_DEFSIGN
|
||||
#define IS_ASM_SYM(sym) (((sym)->type.t & (VT_BTYPE | VT_ASM)) == VT_ASM)
|
||||
|
||||
/* token values */
|
||||
|
||||
/* warning: the following compare tokens depend on i386 asm code */
|
||||
@ -1147,7 +1151,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_1(Sym **, int v, int t, int c);
|
||||
ST_FUNC Sym *global_identifier_push(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);
|
||||
@ -1317,6 +1321,7 @@ 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 void update_storage(Sym *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);
|
||||
@ -1588,7 +1593,6 @@ 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
|
||||
|
67
tccasm.c
67
tccasm.c
@ -44,11 +44,11 @@ static Sym *asm_label_find(int v)
|
||||
|
||||
static Sym *asm_label_push(int v, int t)
|
||||
{
|
||||
Sym *sym = global_identifier_push_1(&tcc_state->asm_labels, v, t, 0);
|
||||
Sym *sym = global_identifier_push(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->type.t |= VT_ASM | VT_EXTERN;
|
||||
sym->r = VT_CONST | VT_SYM;
|
||||
return sym;
|
||||
}
|
||||
@ -149,7 +149,7 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
|
||||
pe->v = 0;
|
||||
pe->sym = &sym_dot;
|
||||
pe->pcrel = 0;
|
||||
sym_dot.type.t = VT_VOID | VT_STATIC;
|
||||
sym_dot.type.t = VT_ASM | VT_STATIC;
|
||||
sym_dot.c = -1;
|
||||
tcc_state->esym_dot.st_shndx = cur_text_section->sh_num;
|
||||
tcc_state->esym_dot.st_value = ind;
|
||||
@ -371,7 +371,7 @@ static Sym* asm_new_label1(TCCState *s1, int label, int is_local,
|
||||
definitions won't have VT_EXTERN set. */
|
||||
if (esym && esym->st_shndx != SHN_UNDEF && !(sym->type.t & VT_EXTERN)) {
|
||||
/* the label is already defined */
|
||||
if (!is_local) {
|
||||
if (is_local != 1) {
|
||||
tcc_error("assembler label '%s' already defined",
|
||||
get_tok_str(label, NULL));
|
||||
} else {
|
||||
@ -381,13 +381,22 @@ static Sym* asm_new_label1(TCCState *s1, int label, int is_local,
|
||||
}
|
||||
} else {
|
||||
new_label:
|
||||
sym = asm_label_push(label, is_local ? VT_STATIC : 0);
|
||||
sym = asm_label_push(label, is_local == 1 ? VT_STATIC : 0);
|
||||
}
|
||||
if (!sym->c)
|
||||
put_extern_sym2(sym, NULL, 0, 0, 0);
|
||||
esym = elfsym(sym);
|
||||
esym->st_shndx = sh_num;
|
||||
esym->st_value = value;
|
||||
|
||||
if (is_local != 2)
|
||||
sym->type.t &= ~VT_EXTERN;
|
||||
|
||||
if (IS_ASM_SYM(sym) && !(sym->type.t & VT_ASM_GLOBAL)) {
|
||||
sym->type.t |= VT_STATIC;
|
||||
update_storage(sym);
|
||||
}
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
@ -410,39 +419,11 @@ static Sym* set_symbol(TCCState *s1, int label)
|
||||
esym = elfsym(e.sym);
|
||||
if (esym)
|
||||
n += esym->st_value;
|
||||
sym = asm_new_label1(s1, label, 0, esym ? esym->st_shndx : SHN_ABS, n);
|
||||
sym = asm_new_label1(s1, label, 2, 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;
|
||||
|
||||
for(s = st->asm_labels; s != NULL; s = s1) {
|
||||
ElfSym *esym = elfsym(s);
|
||||
s1 = s->prev;
|
||||
/* Possibly update binding and visibility from asm directives
|
||||
if the symbol has no C decl (type is VT_VOID).*/
|
||||
s->type.t &= ~VT_EXTERN;
|
||||
if (esym && s->type.t == VT_VOID) {
|
||||
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_identifier = s->prev_tok;
|
||||
sym_free(s);
|
||||
}
|
||||
st->asm_labels = NULL;
|
||||
}
|
||||
|
||||
static void use_section1(TCCState *s1, Section *sec)
|
||||
{
|
||||
cur_text_section->data_offset = ind;
|
||||
@ -696,15 +677,18 @@ static void asm_parse_directive(TCCState *s1, int global)
|
||||
tok1 = tok;
|
||||
do {
|
||||
Sym *sym;
|
||||
|
||||
next();
|
||||
sym = get_asm_sym(tok, NULL);
|
||||
if (tok1 != TOK_ASMDIR_hidden)
|
||||
sym->type.t &= ~VT_STATIC, sym->a.asmexport = 1;
|
||||
if (tok1 != TOK_ASMDIR_hidden) {
|
||||
sym->type.t &= ~VT_STATIC;
|
||||
if (IS_ASM_SYM(sym))
|
||||
sym->type.t |= VT_ASM_GLOBAL;
|
||||
}
|
||||
if (tok1 == TOK_ASMDIR_weak)
|
||||
sym->a.weak = 1;
|
||||
else if (tok1 == TOK_ASMDIR_hidden)
|
||||
sym->a.visibility = STV_HIDDEN;
|
||||
update_storage(sym);
|
||||
next();
|
||||
} while (tok == ',');
|
||||
break;
|
||||
@ -947,7 +931,6 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
|
||||
} else if (tok >= TOK_ASMDIR_FIRST && tok <= TOK_ASMDIR_LAST) {
|
||||
asm_parse_directive(s1, global);
|
||||
} else if (tok == TOK_PPNUM) {
|
||||
Sym *sym;
|
||||
const char *p;
|
||||
int n;
|
||||
p = tokc.str.data;
|
||||
@ -955,9 +938,7 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
|
||||
if (*p != '\0')
|
||||
expect("':'");
|
||||
/* new local label */
|
||||
sym = asm_new_label(s1, asm_get_local_label_name(s1, n), 1);
|
||||
/* Remove the marker for tentative definitions. */
|
||||
sym->type.t &= ~VT_EXTERN;
|
||||
asm_new_label(s1, asm_get_local_label_name(s1, n), 1);
|
||||
next();
|
||||
skip(':');
|
||||
goto redo;
|
||||
@ -967,8 +948,7 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
|
||||
next();
|
||||
if (tok == ':') {
|
||||
/* new label */
|
||||
Sym *sym = asm_new_label(s1, opcode, 0);
|
||||
sym->type.t &= ~VT_EXTERN;
|
||||
asm_new_label(s1, opcode, 0);
|
||||
next();
|
||||
goto redo;
|
||||
} else if (tok == '=') {
|
||||
@ -998,7 +978,6 @@ 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;
|
||||
|
10
tccelf.c
10
tccelf.c
@ -310,8 +310,7 @@ 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
|
||||
|| sym->st_shndx == SHN_UNDEF) {
|
||||
if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
|
||||
h = elf_hash(strtab + sym->st_name) % nb_buckets;
|
||||
*ptr = hash[h];
|
||||
hash[h] = sym_index;
|
||||
@ -350,9 +349,8 @@ 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, weak or undef symbols. The latter might
|
||||
become global late (from asm references). */
|
||||
if (ELFW(ST_BIND)(info) != STB_LOCAL || shndx == SHN_UNDEF) {
|
||||
/* only add global or weak symbols. */
|
||||
if (ELFW(ST_BIND)(info) != STB_LOCAL) {
|
||||
/* add another hashing entry */
|
||||
nbuckets = base[0];
|
||||
h = elf_hash((unsigned char *) name) % nbuckets;
|
||||
@ -390,7 +388,7 @@ ST_FUNC int find_elf_sym(Section *s, const char *name)
|
||||
while (sym_index != 0) {
|
||||
sym = &((ElfW(Sym) *)s->data)[sym_index];
|
||||
name1 = (char *) s->link->data + sym->st_name;
|
||||
if (!strcmp(name, name1))
|
||||
if (!strcmp(name, name1) && ELFW(ST_BIND)(sym->st_info) != STB_LOCAL)
|
||||
return sym_index;
|
||||
sym_index = ((int *)hs->data)[2 + nbuckets + sym_index];
|
||||
}
|
||||
|
60
tccgen.c
60
tccgen.c
@ -275,11 +275,6 @@ 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;
|
||||
@ -297,28 +292,42 @@ ST_FUNC ElfSym *elfsym(Sym *s)
|
||||
}
|
||||
|
||||
/* apply storage attributes to Elf symbol */
|
||||
|
||||
static void update_storage(Sym *sym)
|
||||
ST_FUNC void update_storage(Sym *sym)
|
||||
{
|
||||
ElfSym *esym = elfsym(sym);
|
||||
ElfSym *esym;
|
||||
int sym_bind, old_sym_bind;
|
||||
|
||||
esym = elfsym(sym);
|
||||
if (!esym)
|
||||
return;
|
||||
|
||||
if (sym->a.visibility)
|
||||
esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1))
|
||||
| sym->a.visibility;
|
||||
if (sym->a.weak)
|
||||
esym->st_info = ELFW(ST_INFO)(STB_WEAK, ELFW(ST_TYPE)(esym->st_info));
|
||||
|
||||
if (sym->type.t & VT_STATIC)
|
||||
sym_bind = STB_LOCAL;
|
||||
else if (sym->a.weak)
|
||||
sym_bind = STB_WEAK;
|
||||
else
|
||||
sym_bind = STB_GLOBAL;
|
||||
old_sym_bind = ELFW(ST_BIND)(esym->st_info);
|
||||
if (sym_bind != old_sym_bind) {
|
||||
esym->st_info = ELFW(ST_INFO)(sym_bind, ELFW(ST_TYPE)(esym->st_info));
|
||||
}
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
if (sym->a.dllimport)
|
||||
esym->st_other |= ST_PE_IMPORT;
|
||||
if (sym->a.dllexport)
|
||||
esym->st_other |= ST_PE_EXPORT;
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
printf("storage %s: vis=%d weak=%d exp=%d imp=%d\n",
|
||||
printf("storage %s: bind=%c vis=%d exp=%d imp=%d\n",
|
||||
get_tok_str(sym->v, NULL),
|
||||
sym_bind == STB_WEAK ? 'w' : sym_bind == STB_LOCAL ? 'l' : 'g',
|
||||
sym->a.visibility,
|
||||
sym->a.weak,
|
||||
sym->a.dllexport,
|
||||
sym->a.dllimport
|
||||
);
|
||||
@ -578,10 +587,10 @@ ST_FUNC Sym *sym_push(int v, CType *type, int r, int c)
|
||||
}
|
||||
|
||||
/* push a global identifier */
|
||||
ST_FUNC Sym *global_identifier_push_1(Sym **ptop, int v, int t, int c)
|
||||
ST_FUNC Sym *global_identifier_push(int v, int t, int c)
|
||||
{
|
||||
Sym *s, **ps;
|
||||
s = sym_push2(ptop, v, t, c);
|
||||
s = sym_push2(&global_stack, v, t, c);
|
||||
/* don't record anonymous symbol */
|
||||
if (v < SYM_FIRST_ANOM) {
|
||||
ps = &table_ident[v - TOK_IDENT]->sym_identifier;
|
||||
@ -595,11 +604,6 @@ ST_FUNC Sym *global_identifier_push_1(Sym **ptop, int v, int t, int c)
|
||||
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)
|
||||
@ -841,6 +845,9 @@ ST_FUNC Sym *external_global_sym(int v, CType *type, int r)
|
||||
s = global_identifier_push(v, type->t | VT_EXTERN, 0);
|
||||
s->type.ref = type->ref;
|
||||
s->r = r | VT_CONST | VT_SYM;
|
||||
} else if (IS_ASM_SYM(s)) {
|
||||
s->type.t = type->t | (s->type.t & VT_EXTERN);
|
||||
s->type.ref = type->ref;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
@ -849,7 +856,7 @@ ST_FUNC Sym *external_global_sym(int v, CType *type, int r)
|
||||
static void patch_storage(Sym *sym, AttributeDef *ad, CType *type)
|
||||
{
|
||||
if (type) {
|
||||
if ((sym->type.t & VT_BTYPE) == VT_VOID) /* from asm */
|
||||
if (IS_ASM_SYM(sym))
|
||||
sym->type = *type;
|
||||
else if (!is_compatible_types(&sym->type, type))
|
||||
tcc_error("incompatible types for redefinition of '%s'",
|
||||
@ -5026,7 +5033,7 @@ ST_FUNC void unary(void)
|
||||
if (t < TOK_UIDENT)
|
||||
expect("identifier");
|
||||
s = sym_find(t);
|
||||
if (!s) {
|
||||
if (!s || IS_ASM_SYM(s)) {
|
||||
const char *name = get_tok_str(t, NULL);
|
||||
if (tok != '(')
|
||||
tcc_error("'%s' undeclared", name);
|
||||
@ -7223,12 +7230,8 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym)
|
||||
type.t = (type.t & ~VT_EXTERN) | VT_STATIC;
|
||||
|
||||
sym = sym_find(v);
|
||||
if (sym) {
|
||||
if (sym && !IS_ASM_SYM(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;
|
||||
@ -7261,15 +7264,14 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym)
|
||||
tcc_error("redefinition of '%s'", get_tok_str(v, NULL));
|
||||
/* if symbol is already defined, then put complete type */
|
||||
sym->type = type;
|
||||
sym->r = VT_SYM | VT_CONST;
|
||||
|
||||
} else {
|
||||
/* put function symbol */
|
||||
sym = global_identifier_push(v, type.t, 0);
|
||||
sym->type.ref = type.ref;
|
||||
sym = external_global_sym(v, &type, 0);
|
||||
}
|
||||
|
||||
sym->type.ref->f.func_body = 1;
|
||||
sym->r = VT_SYM | VT_CONST;
|
||||
patch_storage(sym, &ad, NULL);
|
||||
|
||||
/* static inline functions are just recorded as a kind
|
||||
|
Loading…
Reference in New Issue
Block a user